2020-11-29 09:38:52 -05:00
|
|
|
// 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 {
|
2020-12-03 18:43:18 -05:00
|
|
|
n = n.copy()
|
2020-11-29 09:38:52 -05:00
|
|
|
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 {
|
2020-12-03 18:43:18 -05:00
|
|
|
c := n.copy()
|
2020-11-29 09:38:52 -05:00
|
|
|
if n, ok := n.(OrigNode); ok && n.Orig() == n {
|
2020-12-03 18:43:18 -05:00
|
|
|
c.(OrigNode).SetOrig(c)
|
2020-11-29 09:38:52 -05:00
|
|
|
}
|
2020-12-03 18:43:18 -05:00
|
|
|
return c
|
2020-11-29 09:38:52 -05:00
|
|
|
}
|
|
|
|
|
|
[dev.regabi] cmd/compile: adjustments to Copy and DeepCopy
DeepCopy is not called DeepSepCopy, so it should use Copy, not SepCopy.
Also, the old gc.treecopy, which became ir.DeepCopy, only copied
the Left, Right, and List fields - not Init, Rlist, Body - and I didn't
notice when I moved it over. A general utility function should of
course copy the whole node, so do that.
Finally, the semantics of Copy should not depend on whether a
particular child node is held directly in a field or in a slice,
so make Copy duplicate the slice backing arrays as well.
(Logically, those backing arrays are part of the node storage.)
Passes buildall w/ toolstash -cmp.
Change-Id: I18fbe3f2b40078f566ed6370684d5585052b36a1
Reviewed-on: https://go-review.googlesource.com/c/go/+/275309
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-02 22:42:24 -05:00
|
|
|
func copyList(x Nodes) Nodes {
|
2020-12-03 21:02:19 -05:00
|
|
|
c := make([]Node, x.Len())
|
|
|
|
|
copy(c, x.Slice())
|
|
|
|
|
return AsNodes(c)
|
[dev.regabi] cmd/compile: adjustments to Copy and DeepCopy
DeepCopy is not called DeepSepCopy, so it should use Copy, not SepCopy.
Also, the old gc.treecopy, which became ir.DeepCopy, only copied
the Left, Right, and List fields - not Init, Rlist, Body - and I didn't
notice when I moved it over. A general utility function should of
course copy the whole node, so do that.
Finally, the semantics of Copy should not depend on whether a
particular child node is held directly in a field or in a slice,
so make Copy duplicate the slice backing arrays as well.
(Logically, those backing arrays are part of the node storage.)
Passes buildall w/ toolstash -cmp.
Change-Id: I18fbe3f2b40078f566ed6370684d5585052b36a1
Reviewed-on: https://go-review.googlesource.com/c/go/+/275309
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-02 22:42:24 -05:00
|
|
|
}
|
|
|
|
|
|
2020-11-29 09:38:52 -05:00
|
|
|
// 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.
|
2020-12-03 12:57:38 -05:00
|
|
|
//
|
|
|
|
|
// TODO(rsc): Once Nodes implement EditChildren, remove the DeepCopyNode interface.
|
2020-11-29 09:38:52 -05:00
|
|
|
func DeepCopy(pos src.XPos, n Node) Node {
|
2020-12-03 12:57:38 -05:00
|
|
|
var edit func(Node) Node
|
|
|
|
|
edit = func(x Node) Node {
|
|
|
|
|
if x, ok := x.(DeepCopyNode); ok {
|
|
|
|
|
return x.DeepCopy(pos)
|
2020-11-29 09:38:52 -05:00
|
|
|
}
|
2020-12-03 12:57:38 -05:00
|
|
|
switch x.Op() {
|
|
|
|
|
case OPACK, ONAME, ONONAME, OLITERAL, ONIL, OTYPE:
|
|
|
|
|
return x
|
2020-11-29 09:38:52 -05:00
|
|
|
}
|
2020-12-03 12:57:38 -05:00
|
|
|
x = Copy(x)
|
|
|
|
|
if pos.IsKnown() {
|
|
|
|
|
x.SetPos(pos)
|
|
|
|
|
}
|
|
|
|
|
EditChildren(x, edit)
|
|
|
|
|
return x
|
2020-11-29 09:38:52 -05:00
|
|
|
}
|
2020-12-03 12:57:38 -05:00
|
|
|
return edit(n)
|
2020-11-29 09:38:52 -05:00
|
|
|
}
|
|
|
|
|
|
[dev.regabi] cmd/compile: adjustments to Copy and DeepCopy
DeepCopy is not called DeepSepCopy, so it should use Copy, not SepCopy.
Also, the old gc.treecopy, which became ir.DeepCopy, only copied
the Left, Right, and List fields - not Init, Rlist, Body - and I didn't
notice when I moved it over. A general utility function should of
course copy the whole node, so do that.
Finally, the semantics of Copy should not depend on whether a
particular child node is held directly in a field or in a slice,
so make Copy duplicate the slice backing arrays as well.
(Logically, those backing arrays are part of the node storage.)
Passes buildall w/ toolstash -cmp.
Change-Id: I18fbe3f2b40078f566ed6370684d5585052b36a1
Reviewed-on: https://go-review.googlesource.com/c/go/+/275309
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-02 22:42:24 -05:00
|
|
|
// DeepCopyList returns a list of deep copies (using DeepCopy) of the nodes in list.
|
|
|
|
|
func DeepCopyList(pos src.XPos, list []Node) []Node {
|
2020-11-29 09:38:52 -05:00
|
|
|
var out []Node
|
|
|
|
|
for _, n := range list {
|
|
|
|
|
out = append(out, DeepCopy(pos, n))
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|