From fcee3777fdb15eb6e34cb55925a8d5b0cd97e079 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 27 Apr 2017 06:29:07 -0700 Subject: [PATCH] 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 TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/esc.go | 152 ++++++++++++++++++++++++++++ src/cmd/compile/internal/gc/gen.go | 155 ----------------------------- 2 files changed, 152 insertions(+), 155 deletions(-) diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index aaf590da02..29083ca6cb 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -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. diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go index 941c41502a..09c04466d4 100644 --- a/src/cmd/compile/internal/gc/gen.go +++ b/src/cmd/compile/internal/gc/gen.go @@ -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. -- 2.48.1