mirror of https://github.com/golang/go.git
cmd/compile: move addrescapes and moveToHeap to esc.go
They were used only in esc.go. 100% code movement. Also, remove the rather outdated comment at the top of gen.go. It's not really clear what gen.go is for any more. Change-Id: Iaedfe7015ef6f5c11c49f3e6721b15d779a00faa Reviewed-on: https://go-review.googlesource.com/41971 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
14f3ca56ed
commit
fcee3777fd
|
|
@ -2014,6 +2014,158 @@ recurse:
|
|||
e.pdepth--
|
||||
}
|
||||
|
||||
// addrescapes tags node n as having had its address taken
|
||||
// by "increasing" the "value" of n.Esc to EscHeap.
|
||||
// Storage is allocated as necessary to allow the address
|
||||
// to be taken.
|
||||
func addrescapes(n *Node) {
|
||||
switch n.Op {
|
||||
default:
|
||||
// Unexpected Op, probably due to a previous type error. Ignore.
|
||||
|
||||
case OIND, ODOTPTR:
|
||||
// Nothing to do.
|
||||
|
||||
case ONAME:
|
||||
if n == nodfp {
|
||||
break
|
||||
}
|
||||
|
||||
// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
|
||||
// on PPARAM it means something different.
|
||||
if n.Class() == PAUTO && n.Esc == EscNever {
|
||||
break
|
||||
}
|
||||
|
||||
// If a closure reference escapes, mark the outer variable as escaping.
|
||||
if n.IsClosureVar() {
|
||||
addrescapes(n.Name.Defn)
|
||||
break
|
||||
}
|
||||
|
||||
if n.Class() != PPARAM && n.Class() != PPARAMOUT && n.Class() != PAUTO {
|
||||
break
|
||||
}
|
||||
|
||||
// This is a plain parameter or local variable that needs to move to the heap,
|
||||
// but possibly for the function outside the one we're compiling.
|
||||
// That is, if we have:
|
||||
//
|
||||
// func f(x int) {
|
||||
// func() {
|
||||
// global = &x
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// then we're analyzing the inner closure but we need to move x to the
|
||||
// heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
|
||||
oldfn := Curfn
|
||||
Curfn = n.Name.Curfn
|
||||
if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
|
||||
Curfn = Curfn.Func.Closure
|
||||
}
|
||||
ln := lineno
|
||||
lineno = Curfn.Pos
|
||||
moveToHeap(n)
|
||||
Curfn = oldfn
|
||||
lineno = ln
|
||||
|
||||
// ODOTPTR has already been introduced,
|
||||
// so these are the non-pointer ODOT and OINDEX.
|
||||
// In &x[0], if x is a slice, then x does not
|
||||
// escape--the pointer inside x does, but that
|
||||
// is always a heap pointer anyway.
|
||||
case ODOT, OINDEX, OPAREN, OCONVNOP:
|
||||
if !n.Left.Type.IsSlice() {
|
||||
addrescapes(n.Left)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// moveToHeap records the parameter or local variable n as moved to the heap.
|
||||
func moveToHeap(n *Node) {
|
||||
if Debug['r'] != 0 {
|
||||
Dump("MOVE", n)
|
||||
}
|
||||
if compiling_runtime {
|
||||
yyerror("%v escapes to heap, not allowed in runtime.", n)
|
||||
}
|
||||
if n.Class() == PAUTOHEAP {
|
||||
Dump("n", n)
|
||||
Fatalf("double move to heap")
|
||||
}
|
||||
|
||||
// Allocate a local stack variable to hold the pointer to the heap copy.
|
||||
// temp will add it to the function declaration list automatically.
|
||||
heapaddr := temp(types.NewPtr(n.Type))
|
||||
heapaddr.Sym = lookup("&" + n.Sym.Name)
|
||||
heapaddr.Orig.Sym = heapaddr.Sym
|
||||
|
||||
// Unset AutoTemp to persist the &foo variable name through SSA to
|
||||
// liveness analysis.
|
||||
// TODO(mdempsky/drchase): Cleaner solution?
|
||||
heapaddr.Name.SetAutoTemp(false)
|
||||
|
||||
// Parameters have a local stack copy used at function start/end
|
||||
// in addition to the copy in the heap that may live longer than
|
||||
// the function.
|
||||
if n.Class() == PPARAM || n.Class() == PPARAMOUT {
|
||||
if n.Xoffset == BADWIDTH {
|
||||
Fatalf("addrescapes before param assignment")
|
||||
}
|
||||
|
||||
// We rewrite n below to be a heap variable (indirection of heapaddr).
|
||||
// Preserve a copy so we can still write code referring to the original,
|
||||
// and substitute that copy into the function declaration list
|
||||
// so that analyses of the local (on-stack) variables use it.
|
||||
stackcopy := newname(n.Sym)
|
||||
stackcopy.SetAddable(false)
|
||||
stackcopy.Type = n.Type
|
||||
stackcopy.Xoffset = n.Xoffset
|
||||
stackcopy.SetClass(n.Class())
|
||||
stackcopy.Name.Param.Heapaddr = heapaddr
|
||||
if n.Class() == PPARAMOUT {
|
||||
// Make sure the pointer to the heap copy is kept live throughout the function.
|
||||
// The function could panic at any point, and then a defer could recover.
|
||||
// Thus, we need the pointer to the heap copy always available so the
|
||||
// post-deferreturn code can copy the return value back to the stack.
|
||||
// See issue 16095.
|
||||
heapaddr.SetIsOutputParamHeapAddr(true)
|
||||
}
|
||||
n.Name.Param.Stackcopy = stackcopy
|
||||
|
||||
// Substitute the stackcopy into the function variable list so that
|
||||
// liveness and other analyses use the underlying stack slot
|
||||
// and not the now-pseudo-variable n.
|
||||
found := false
|
||||
for i, d := range Curfn.Func.Dcl {
|
||||
if d == n {
|
||||
Curfn.Func.Dcl[i] = stackcopy
|
||||
found = true
|
||||
break
|
||||
}
|
||||
// Parameters are before locals, so can stop early.
|
||||
// This limits the search even in functions with many local variables.
|
||||
if d.Class() == PAUTO {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
Fatalf("cannot find %v in local variable list", n)
|
||||
}
|
||||
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
|
||||
}
|
||||
|
||||
// Modify n in place so that uses of n now mean indirection of the heapaddr.
|
||||
n.SetClass(PAUTOHEAP)
|
||||
n.Xoffset = 0
|
||||
n.Name.Param.Heapaddr = heapaddr
|
||||
n.Esc = EscHeap
|
||||
if Debug['m'] != 0 {
|
||||
fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
|
||||
}
|
||||
}
|
||||
|
||||
// This special tag is applied to uintptr variables
|
||||
// that we believe may hold unsafe.Pointers for
|
||||
// calls into assembly functions.
|
||||
|
|
|
|||
|
|
@ -2,15 +2,12 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Portable half of code generator; mainly statements and control flow.
|
||||
|
||||
package gc
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
|
@ -18,74 +15,6 @@ func Sysfunc(name string) *obj.LSym {
|
|||
return Runtimepkg.Lookup(name).Linksym()
|
||||
}
|
||||
|
||||
// addrescapes tags node n as having had its address taken
|
||||
// by "increasing" the "value" of n.Esc to EscHeap.
|
||||
// Storage is allocated as necessary to allow the address
|
||||
// to be taken.
|
||||
func addrescapes(n *Node) {
|
||||
switch n.Op {
|
||||
default:
|
||||
// Unexpected Op, probably due to a previous type error. Ignore.
|
||||
|
||||
case OIND, ODOTPTR:
|
||||
// Nothing to do.
|
||||
|
||||
case ONAME:
|
||||
if n == nodfp {
|
||||
break
|
||||
}
|
||||
|
||||
// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
|
||||
// on PPARAM it means something different.
|
||||
if n.Class() == PAUTO && n.Esc == EscNever {
|
||||
break
|
||||
}
|
||||
|
||||
// If a closure reference escapes, mark the outer variable as escaping.
|
||||
if n.IsClosureVar() {
|
||||
addrescapes(n.Name.Defn)
|
||||
break
|
||||
}
|
||||
|
||||
if n.Class() != PPARAM && n.Class() != PPARAMOUT && n.Class() != PAUTO {
|
||||
break
|
||||
}
|
||||
|
||||
// This is a plain parameter or local variable that needs to move to the heap,
|
||||
// but possibly for the function outside the one we're compiling.
|
||||
// That is, if we have:
|
||||
//
|
||||
// func f(x int) {
|
||||
// func() {
|
||||
// global = &x
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// then we're analyzing the inner closure but we need to move x to the
|
||||
// heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
|
||||
oldfn := Curfn
|
||||
Curfn = n.Name.Curfn
|
||||
if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
|
||||
Curfn = Curfn.Func.Closure
|
||||
}
|
||||
ln := lineno
|
||||
lineno = Curfn.Pos
|
||||
moveToHeap(n)
|
||||
Curfn = oldfn
|
||||
lineno = ln
|
||||
|
||||
// ODOTPTR has already been introduced,
|
||||
// so these are the non-pointer ODOT and OINDEX.
|
||||
// In &x[0], if x is a slice, then x does not
|
||||
// escape--the pointer inside x does, but that
|
||||
// is always a heap pointer anyway.
|
||||
case ODOT, OINDEX, OPAREN, OCONVNOP:
|
||||
if !n.Left.Type.IsSlice() {
|
||||
addrescapes(n.Left)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isParamStackCopy reports whether this is the on-stack copy of a
|
||||
// function parameter that moved to the heap.
|
||||
func (n *Node) isParamStackCopy() bool {
|
||||
|
|
@ -98,90 +27,6 @@ func (n *Node) isParamHeapCopy() bool {
|
|||
return n.Op == ONAME && n.Class() == PAUTOHEAP && n.Name.Param.Stackcopy != nil
|
||||
}
|
||||
|
||||
// moveToHeap records the parameter or local variable n as moved to the heap.
|
||||
func moveToHeap(n *Node) {
|
||||
if Debug['r'] != 0 {
|
||||
Dump("MOVE", n)
|
||||
}
|
||||
if compiling_runtime {
|
||||
yyerror("%v escapes to heap, not allowed in runtime.", n)
|
||||
}
|
||||
if n.Class() == PAUTOHEAP {
|
||||
Dump("n", n)
|
||||
Fatalf("double move to heap")
|
||||
}
|
||||
|
||||
// Allocate a local stack variable to hold the pointer to the heap copy.
|
||||
// temp will add it to the function declaration list automatically.
|
||||
heapaddr := temp(types.NewPtr(n.Type))
|
||||
heapaddr.Sym = lookup("&" + n.Sym.Name)
|
||||
heapaddr.Orig.Sym = heapaddr.Sym
|
||||
|
||||
// Unset AutoTemp to persist the &foo variable name through SSA to
|
||||
// liveness analysis.
|
||||
// TODO(mdempsky/drchase): Cleaner solution?
|
||||
heapaddr.Name.SetAutoTemp(false)
|
||||
|
||||
// Parameters have a local stack copy used at function start/end
|
||||
// in addition to the copy in the heap that may live longer than
|
||||
// the function.
|
||||
if n.Class() == PPARAM || n.Class() == PPARAMOUT {
|
||||
if n.Xoffset == BADWIDTH {
|
||||
Fatalf("addrescapes before param assignment")
|
||||
}
|
||||
|
||||
// We rewrite n below to be a heap variable (indirection of heapaddr).
|
||||
// Preserve a copy so we can still write code referring to the original,
|
||||
// and substitute that copy into the function declaration list
|
||||
// so that analyses of the local (on-stack) variables use it.
|
||||
stackcopy := newname(n.Sym)
|
||||
stackcopy.SetAddable(false)
|
||||
stackcopy.Type = n.Type
|
||||
stackcopy.Xoffset = n.Xoffset
|
||||
stackcopy.SetClass(n.Class())
|
||||
stackcopy.Name.Param.Heapaddr = heapaddr
|
||||
if n.Class() == PPARAMOUT {
|
||||
// Make sure the pointer to the heap copy is kept live throughout the function.
|
||||
// The function could panic at any point, and then a defer could recover.
|
||||
// Thus, we need the pointer to the heap copy always available so the
|
||||
// post-deferreturn code can copy the return value back to the stack.
|
||||
// See issue 16095.
|
||||
heapaddr.SetIsOutputParamHeapAddr(true)
|
||||
}
|
||||
n.Name.Param.Stackcopy = stackcopy
|
||||
|
||||
// Substitute the stackcopy into the function variable list so that
|
||||
// liveness and other analyses use the underlying stack slot
|
||||
// and not the now-pseudo-variable n.
|
||||
found := false
|
||||
for i, d := range Curfn.Func.Dcl {
|
||||
if d == n {
|
||||
Curfn.Func.Dcl[i] = stackcopy
|
||||
found = true
|
||||
break
|
||||
}
|
||||
// Parameters are before locals, so can stop early.
|
||||
// This limits the search even in functions with many local variables.
|
||||
if d.Class() == PAUTO {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
Fatalf("cannot find %v in local variable list", n)
|
||||
}
|
||||
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
|
||||
}
|
||||
|
||||
// Modify n in place so that uses of n now mean indirection of the heapaddr.
|
||||
n.SetClass(PAUTOHEAP)
|
||||
n.Xoffset = 0
|
||||
n.Name.Param.Heapaddr = heapaddr
|
||||
n.Esc = EscHeap
|
||||
if Debug['m'] != 0 {
|
||||
fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
|
||||
}
|
||||
}
|
||||
|
||||
// autotmpname returns the name for an autotmp variable numbered n.
|
||||
func autotmpname(n int) string {
|
||||
// Give each tmp a different name so that they can be registerized.
|
||||
|
|
|
|||
Loading…
Reference in New Issue