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