]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: move gc.treecopy to ir.DeepCopy
authorRuss Cox <rsc@golang.org>
Sun, 29 Nov 2020 14:38:52 +0000 (09:38 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 30 Nov 2020 18:34:07 +0000 (18:34 +0000)
This is a general operation on IR nodes, so it belongs in ir.
The copied implementation is adapted to support the
extension pattern, allowing nodes to implement their
own DeepCopy implementations if needed.

This is the first step toward higher-level operations instead
of Left, Right, etc. It will allow the new type syntax nodes
to be properly immutable and opt out of those fine-grained methods.

Passes buildall w/ toolstash -cmp.

Change-Id: Ibd64061e01daf14aebc6586cb2eb2b12057ca85a
Reviewed-on: https://go-review.googlesource.com/c/go/+/274102
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/noder.go
src/cmd/compile/internal/gc/order.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/ir/copy.go [new file with mode: 0644]
src/cmd/compile/internal/ir/node.go

index 8ae5874d3b46374ecca862a23e1cf2f68893439a..1c433b5d30085d4da9577b05b56ba3ebc31b0491 100644 (file)
@@ -451,7 +451,7 @@ func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []ir.Node {
                }
                v := values[i]
                if decl.Values == nil {
-                       v = treecopy(v, n.Pos())
+                       v = ir.DeepCopy(n.Pos(), v)
                }
 
                n.SetOp(ir.OLITERAL)
index 6a91b8c91bdd4c114de5d2f10f31f3af4ea061dd..d4db7be9119f96f19830bcd6c5a024d51019b496 100644 (file)
@@ -609,7 +609,10 @@ func (o *Order) stmt(n ir.Node) {
 
                        n.SetLeft(o.safeExpr(n.Left()))
 
-                       l := treecopy(n.Left(), src.NoXPos)
+                       // TODO(rsc): Why is this DeepCopy?
+                       // We should know enough about the form here
+                       // to do something more provably shallower.
+                       l := ir.DeepCopy(src.NoXPos, n.Left())
                        if l.Op() == ir.OINDEXMAP {
                                l.SetIndexMapLValue(false)
                        }
@@ -1123,8 +1126,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
                        needCopy = mapKeyReplaceStrConv(n.Right())
 
                        if instrumenting {
-                               // Race detector needs the copy so it can
-                               // call treecopy on the result.
+                               // Race detector needs the copy.
                                needCopy = true
                        }
                }
index 336465db9800d5c6f391771f753f2ffe4bfc2b2a..25490246e6d0b937e8cf5478df1c81a43719ec3c 100644 (file)
@@ -181,42 +181,6 @@ func nodstr(s string) ir.Node {
        return ir.NewLiteral(constant.MakeString(s))
 }
 
-// treecopy recursively copies n, with the exception of
-// ONAME, OLITERAL, OTYPE, and ONONAME leaves.
-// If pos.IsKnown(), it sets the source position of newly
-// allocated nodes to pos.
-func treecopy(n ir.Node, pos src.XPos) ir.Node {
-       if n == nil {
-               return nil
-       }
-
-       switch n.Op() {
-       default:
-               m := ir.SepCopy(n)
-               m.SetLeft(treecopy(n.Left(), pos))
-               m.SetRight(treecopy(n.Right(), pos))
-               m.PtrList().Set(listtreecopy(n.List().Slice(), pos))
-               if pos.IsKnown() {
-                       m.SetPos(pos)
-               }
-               if m.Name() != nil && n.Op() != ir.ODCLFIELD {
-                       ir.Dump("treecopy", n)
-                       base.Fatalf("treecopy Name")
-               }
-               return m
-
-       case ir.OPACK:
-               // OPACK nodes are never valid in const value declarations,
-               // but allow them like any other declared symbol to avoid
-               // crashing (golang.org/issue/11361).
-               fallthrough
-
-       case ir.ONAME, ir.ONONAME, ir.OLITERAL, ir.ONIL, ir.OTYPE:
-               return n
-
-       }
-}
-
 func isptrto(t *types.Type, et types.EType) bool {
        if t == nil {
                return false
@@ -1375,14 +1339,6 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
        return true
 }
 
-func listtreecopy(l []ir.Node, pos src.XPos) []ir.Node {
-       var out []ir.Node
-       for _, n := range l {
-               out = append(out, treecopy(n, pos))
-       }
-       return out
-}
-
 func liststmt(l []ir.Node) ir.Node {
        n := ir.Nod(ir.OBLOCK, nil, nil)
        n.PtrList().Set(l)
diff --git a/src/cmd/compile/internal/ir/copy.go b/src/cmd/compile/internal/ir/copy.go
new file mode 100644 (file)
index 0000000..7a1611d
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ir
+
+import (
+       "cmd/compile/internal/base"
+       "cmd/internal/src"
+)
+
+// A Node may implement the Orig and SetOrig method to
+// maintain a pointer to the "unrewritten" form of a Node.
+// If a Node does not implement OrigNode, it is its own Orig.
+//
+// Note that both SepCopy and Copy have definitions compatible
+// with a Node that does not implement OrigNode: such a Node
+// is its own Orig, and in that case, that's what both want to return
+// anyway (SepCopy unconditionally, and Copy only when the input
+// is its own Orig as well, but if the output does not implement
+// OrigNode, then neither does the input, making the condition true).
+type OrigNode interface {
+       Node
+       Orig() Node
+       SetOrig(Node)
+}
+
+// Orig returns the “original” node for n.
+// If n implements OrigNode, Orig returns n.Orig().
+// Otherwise Orig returns n itself.
+func Orig(n Node) Node {
+       if n, ok := n.(OrigNode); ok {
+               o := n.Orig()
+               if o == nil {
+                       Dump("Orig nil", n)
+                       base.Fatalf("Orig returned nil")
+               }
+               return o
+       }
+       return n
+}
+
+// SepCopy returns a separate shallow copy of n,
+// breaking any Orig link to any other nodes.
+func SepCopy(n Node) Node {
+       n = n.RawCopy()
+       if n, ok := n.(OrigNode); ok {
+               n.SetOrig(n)
+       }
+       return n
+}
+
+// Copy returns a shallow copy of n.
+// If Orig(n) == n, then Orig(Copy(n)) == the copy.
+// Otherwise the Orig link is preserved as well.
+//
+// The specific semantics surrounding Orig are subtle but right for most uses.
+// See issues #26855 and #27765 for pitfalls.
+func Copy(n Node) Node {
+       copy := n.RawCopy()
+       if n, ok := n.(OrigNode); ok && n.Orig() == n {
+               copy.(OrigNode).SetOrig(copy)
+       }
+       return copy
+}
+
+// A Node can implement DeepCopyNode to provide a custom implementation
+// of DeepCopy. If the compiler only needs access to a Node's structure during
+// DeepCopy, then a Node can implement DeepCopyNode instead of providing
+// fine-grained mutable access with Left, SetLeft, Right, SetRight, and so on.
+type DeepCopyNode interface {
+       Node
+       DeepCopy(pos src.XPos) Node
+}
+
+// DeepCopy returns a “deep” copy of n, with its entire structure copied
+// (except for shared nodes like ONAME, ONONAME, OLITERAL, and OTYPE).
+// If pos.IsKnown(), it sets the source position of newly allocated Nodes to pos.
+//
+// The default implementation is to traverse the Node graph, making
+// a shallow copy of each node and then updating each field to point
+// at shallow copies of children, recursively, using Left, SetLeft, and so on.
+//
+// If a Node wishes to provide an alternate implementation, it can
+// implement a DeepCopy method: see the DeepCopyNode interface.
+func DeepCopy(pos src.XPos, n Node) Node {
+       if n == nil {
+               return nil
+       }
+
+       if n, ok := n.(DeepCopyNode); ok {
+               return n.DeepCopy(pos)
+       }
+
+       switch n.Op() {
+       default:
+               m := SepCopy(n)
+               m.SetLeft(DeepCopy(pos, n.Left()))
+               m.SetRight(DeepCopy(pos, n.Right()))
+               m.PtrList().Set(deepCopyList(pos, n.List().Slice()))
+               if pos.IsKnown() {
+                       m.SetPos(pos)
+               }
+               if m.Name() != nil {
+                       Dump("DeepCopy", n)
+                       base.Fatalf("DeepCopy Name")
+               }
+               return m
+
+       case OPACK:
+               // OPACK nodes are never valid in const value declarations,
+               // but allow them like any other declared symbol to avoid
+               // crashing (golang.org/issue/11361).
+               fallthrough
+
+       case ONAME, ONONAME, OLITERAL, ONIL, OTYPE:
+               return n
+       }
+}
+
+func deepCopyList(pos src.XPos, list []Node) []Node {
+       var out []Node
+       for _, n := range list {
+               out = append(out, DeepCopy(pos, n))
+       }
+       return out
+}
index 47c38c2ab5ddeb53489802314a720649a298038b..653410d175be947ec1b282103965158b3f5db833 100644 (file)
@@ -1021,59 +1021,6 @@ func (n *node) RawCopy() Node {
        return &copy
 }
 
-// A Node may implement the Orig and SetOrig method to
-// maintain a pointer to the "unrewritten" form of a Node.
-// If a Node does not implement OrigNode, it is its own Orig.
-//
-// Note that both SepCopy and Copy have definitions compatible
-// with a Node that does not implement OrigNode: such a Node
-// is its own Orig, and in that case, that's what both want to return
-// anyway (SepCopy unconditionally, and Copy only when the input
-// is its own Orig as well, but if the output does not implement
-// OrigNode, then neither does the input, making the condition true).
-type OrigNode interface {
-       Node
-       Orig() Node
-       SetOrig(Node)
-}
-
-func Orig(n Node) Node {
-       if n, ok := n.(OrigNode); ok {
-               o := n.Orig()
-               if o == nil {
-                       Dump("Orig nil", n)
-                       base.Fatalf("Orig returned nil")
-               }
-               return o
-       }
-       return n
-}
-
-// sepcopy returns a separate shallow copy of n, with the copy's
-// Orig pointing to itself.
-func SepCopy(n Node) Node {
-       n = n.RawCopy()
-       if n, ok := n.(OrigNode); ok {
-               n.SetOrig(n)
-       }
-       return n
-}
-
-// copy returns shallow copy of n and adjusts the copy's Orig if
-// necessary: In general, if n.Orig points to itself, the copy's
-// Orig should point to itself as well. Otherwise, if n is modified,
-// the copy's Orig node appears modified, too, and then doesn't
-// represent the original node anymore.
-// (This caused the wrong complit Op to be used when printing error
-// messages; see issues #26855, #27765).
-func Copy(n Node) Node {
-       copy := n.RawCopy()
-       if n, ok := n.(OrigNode); ok && n.Orig() == n {
-               copy.(OrigNode).SetOrig(copy)
-       }
-       return copy
-}
-
 // isNil reports whether n represents the universal untyped zero value "nil".
 func IsNil(n Node) bool {
        // Check n.Orig because constant propagation may produce typed nil constants,