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