github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/cmd/compile/internal/gc/gen.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Portable half of code generator; mainly statements and control flow. 6 7 package gc 8 9 import ( 10 "cmd/compile/internal/types" 11 "cmd/internal/obj" 12 "cmd/internal/src" 13 "fmt" 14 "strconv" 15 ) 16 17 func Sysfunc(name string) *obj.LSym { 18 return Linksym(Runtimepkg.Lookup(name)) 19 } 20 21 // addrescapes tags node n as having had its address taken 22 // by "increasing" the "value" of n.Esc to EscHeap. 23 // Storage is allocated as necessary to allow the address 24 // to be taken. 25 func addrescapes(n *Node) { 26 switch n.Op { 27 // probably a type error already. 28 // dump("addrescapes", n); 29 default: 30 break 31 32 case ONAME: 33 if n == nodfp { 34 break 35 } 36 37 // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping. 38 // on PPARAM it means something different. 39 if n.Class == PAUTO && n.Esc == EscNever { 40 break 41 } 42 43 // If a closure reference escapes, mark the outer variable as escaping. 44 if n.IsClosureVar() { 45 addrescapes(n.Name.Defn) 46 break 47 } 48 49 if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO { 50 break 51 } 52 53 // This is a plain parameter or local variable that needs to move to the heap, 54 // but possibly for the function outside the one we're compiling. 55 // That is, if we have: 56 // 57 // func f(x int) { 58 // func() { 59 // global = &x 60 // } 61 // } 62 // 63 // then we're analyzing the inner closure but we need to move x to the 64 // heap in f, not in the inner closure. Flip over to f before calling moveToHeap. 65 oldfn := Curfn 66 Curfn = n.Name.Curfn 67 if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE { 68 Curfn = Curfn.Func.Closure 69 } 70 ln := lineno 71 lineno = Curfn.Pos 72 moveToHeap(n) 73 Curfn = oldfn 74 lineno = ln 75 76 case OIND, ODOTPTR: 77 break 78 79 // ODOTPTR has already been introduced, 80 // so these are the non-pointer ODOT and OINDEX. 81 // In &x[0], if x is a slice, then x does not 82 // escape--the pointer inside x does, but that 83 // is always a heap pointer anyway. 84 case ODOT, OINDEX, OPAREN, OCONVNOP: 85 if !n.Left.Type.IsSlice() { 86 addrescapes(n.Left) 87 } 88 } 89 } 90 91 // isParamStackCopy reports whether this is the on-stack copy of a 92 // function parameter that moved to the heap. 93 func (n *Node) isParamStackCopy() bool { 94 return n.Op == ONAME && (n.Class == PPARAM || n.Class == PPARAMOUT) && n.Name.Param.Heapaddr != nil 95 } 96 97 // isParamHeapCopy reports whether this is the on-heap copy of 98 // a function parameter that moved to the heap. 99 func (n *Node) isParamHeapCopy() bool { 100 return n.Op == ONAME && n.Class == PAUTOHEAP && n.Name.Param.Stackcopy != nil 101 } 102 103 // moveToHeap records the parameter or local variable n as moved to the heap. 104 func moveToHeap(n *Node) { 105 if Debug['r'] != 0 { 106 Dump("MOVE", n) 107 } 108 if compiling_runtime { 109 yyerror("%v escapes to heap, not allowed in runtime.", n) 110 } 111 if n.Class == PAUTOHEAP { 112 Dump("n", n) 113 Fatalf("double move to heap") 114 } 115 116 // Allocate a local stack variable to hold the pointer to the heap copy. 117 // temp will add it to the function declaration list automatically. 118 heapaddr := temp(types.NewPtr(n.Type)) 119 heapaddr.Sym = lookup("&" + n.Sym.Name) 120 heapaddr.Orig.Sym = heapaddr.Sym 121 122 // Unset AutoTemp to persist the &foo variable name through SSA to 123 // liveness analysis. 124 // TODO(mdempsky/drchase): Cleaner solution? 125 heapaddr.Name.SetAutoTemp(false) 126 127 // Parameters have a local stack copy used at function start/end 128 // in addition to the copy in the heap that may live longer than 129 // the function. 130 if n.Class == PPARAM || n.Class == PPARAMOUT { 131 if n.Xoffset == BADWIDTH { 132 Fatalf("addrescapes before param assignment") 133 } 134 135 // We rewrite n below to be a heap variable (indirection of heapaddr). 136 // Preserve a copy so we can still write code referring to the original, 137 // and substitute that copy into the function declaration list 138 // so that analyses of the local (on-stack) variables use it. 139 stackcopy := newname(n.Sym) 140 stackcopy.SetAddable(false) 141 stackcopy.Type = n.Type 142 stackcopy.Xoffset = n.Xoffset 143 stackcopy.Class = n.Class 144 stackcopy.Name.Param.Heapaddr = heapaddr 145 if n.Class == PPARAMOUT { 146 // Make sure the pointer to the heap copy is kept live throughout the function. 147 // The function could panic at any point, and then a defer could recover. 148 // Thus, we need the pointer to the heap copy always available so the 149 // post-deferreturn code can copy the return value back to the stack. 150 // See issue 16095. 151 heapaddr.SetIsOutputParamHeapAddr(true) 152 } 153 n.Name.Param.Stackcopy = stackcopy 154 155 // Substitute the stackcopy into the function variable list so that 156 // liveness and other analyses use the underlying stack slot 157 // and not the now-pseudo-variable n. 158 found := false 159 for i, d := range Curfn.Func.Dcl { 160 if d == n { 161 Curfn.Func.Dcl[i] = stackcopy 162 found = true 163 break 164 } 165 // Parameters are before locals, so can stop early. 166 // This limits the search even in functions with many local variables. 167 if d.Class == PAUTO { 168 break 169 } 170 } 171 if !found { 172 Fatalf("cannot find %v in local variable list", n) 173 } 174 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) 175 } 176 177 // Modify n in place so that uses of n now mean indirection of the heapaddr. 178 n.Class = PAUTOHEAP 179 n.Xoffset = 0 180 n.Name.Param.Heapaddr = heapaddr 181 n.Esc = EscHeap 182 if Debug['m'] != 0 { 183 fmt.Printf("%v: moved to heap: %v\n", n.Line(), n) 184 } 185 } 186 187 // autotmpname returns the name for an autotmp variable numbered n. 188 func autotmpname(n int) string { 189 // Give each tmp a different name so that they can be registerized. 190 // Add a preceding . to avoid clashing with legal names. 191 const prefix = ".autotmp_" 192 // Start with a buffer big enough to hold a large n. 193 b := []byte(prefix + " ")[:len(prefix)] 194 b = strconv.AppendInt(b, int64(n), 10) 195 _ = b 196 return types.InternString(b) 197 } 198 199 // make a new Node off the books 200 func tempnamel(pos src.XPos, curfn *Node, nn *Node, t *types.Type) { 201 if curfn == nil { 202 Fatalf("no curfn for tempname") 203 } 204 if curfn.Func.Closure != nil && curfn.Op == OCLOSURE { 205 Dump("tempname", curfn) 206 Fatalf("adding tempname to wrong closure function") 207 } 208 if t == nil { 209 Fatalf("tempname called with nil type") 210 } 211 212 s := &types.Sym{ 213 Name: autotmpname(len(curfn.Func.Dcl)), 214 Pkg: localpkg, 215 } 216 n := newnamel(pos, s) 217 s.Def = asTypesNode(n) 218 n.Type = t 219 n.Class = PAUTO 220 n.Esc = EscNever 221 n.Name.Curfn = curfn 222 n.Name.SetAutoTemp(true) 223 curfn.Func.Dcl = append(curfn.Func.Dcl, n) 224 225 dowidth(t) 226 *nn = *n 227 } 228 229 func temp(t *types.Type) *Node { 230 var n Node 231 tempnamel(lineno, Curfn, &n, t) 232 asNode(n.Sym.Def).SetUsed(true) 233 return n.Orig 234 } 235 236 func tempAt(pos src.XPos, curfn *Node, t *types.Type) *Node { 237 var n Node 238 tempnamel(pos, curfn, &n, t) 239 asNode(n.Sym.Def).SetUsed(true) 240 return n.Orig 241 }