mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Removes all external uses of Linksym and Pkglookup, which are the only two exported functions that return Syms. Also add Duffcopy and Duffzero since they're used often enough across SSA backends. Passes toolstash -cmp. Change-Id: I8d3fd048ad5cd676fc46378f09a917569ffc9b2c Reviewed-on: https://go-review.googlesource.com/36418 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
227 lines
6.1 KiB
Go
227 lines
6.1 KiB
Go
// Copyright 2009 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.
|
|
|
|
// Portable half of code generator; mainly statements and control flow.
|
|
|
|
package gc
|
|
|
|
import (
|
|
"cmd/internal/obj"
|
|
"fmt"
|
|
)
|
|
|
|
func Sysfunc(name string) *obj.LSym {
|
|
return Linksym(Pkglookup(name, Runtimepkg))
|
|
}
|
|
|
|
// 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 {
|
|
// probably a type error already.
|
|
// dump("addrescapes", n);
|
|
default:
|
|
break
|
|
|
|
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
|
|
|
|
case OIND, ODOTPTR:
|
|
break
|
|
|
|
// 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 {
|
|
return n.Op == ONAME && (n.Class == PPARAM || n.Class == PPARAMOUT) && n.Name.Param.Heapaddr != nil
|
|
}
|
|
|
|
// isParamHeapCopy reports whether this is the on-heap copy of
|
|
// a function parameter that moved to the heap.
|
|
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(ptrto(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.AutoTemp = 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 := nod(ONAME, nil, nil)
|
|
stackcopy.Sym = n.Sym
|
|
stackcopy.Type = n.Type
|
|
stackcopy.Xoffset = n.Xoffset
|
|
stackcopy.Class = 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.Class = PAUTOHEAP
|
|
n.Ullman = 2
|
|
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)
|
|
}
|
|
}
|
|
|
|
// make a new Node off the books
|
|
func tempname(nn *Node, t *Type) {
|
|
if Curfn == nil {
|
|
Fatalf("no curfn for tempname")
|
|
}
|
|
if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
|
|
Dump("tempname", Curfn)
|
|
Fatalf("adding tempname to wrong closure function")
|
|
}
|
|
|
|
if t == nil {
|
|
yyerror("tempname called with nil type")
|
|
t = Types[TINT32]
|
|
}
|
|
|
|
// give each tmp a different name so that there
|
|
// a chance to registerizer them.
|
|
// Add a preceding . to avoid clash with legal names.
|
|
s := lookupN(".autotmp_", statuniqgen)
|
|
statuniqgen++
|
|
n := nod(ONAME, nil, nil)
|
|
n.Sym = s
|
|
s.Def = n
|
|
n.Type = t
|
|
n.Class = PAUTO
|
|
n.Addable = true
|
|
n.Ullman = 1
|
|
n.Esc = EscNever
|
|
n.Name.Curfn = Curfn
|
|
n.Name.AutoTemp = true
|
|
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
|
|
|
|
dowidth(t)
|
|
n.Xoffset = 0
|
|
*nn = *n
|
|
}
|
|
|
|
func temp(t *Type) *Node {
|
|
var n Node
|
|
tempname(&n, t)
|
|
n.Sym.Def.Used = true
|
|
return n.Orig
|
|
}
|