github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/gc/init.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 package gc 6 7 import ( 8 "cmd/compile/internal/types" 9 ) 10 11 // A function named init is a special case. 12 // It is called by the initialization before main is run. 13 // To make it unique within a package and also uncallable, 14 // the name, normally "pkg.init", is altered to "pkg.init.0". 15 var renameinitgen int 16 17 func renameinit() *types.Sym { 18 s := lookupN("init.", renameinitgen) 19 renameinitgen++ 20 return s 21 } 22 23 // anyinit reports whether there any interesting init statements. 24 func anyinit(n []*Node) bool { 25 for _, ln := range n { 26 switch ln.Op { 27 case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY: 28 case OAS: 29 if !ln.Left.isBlank() || !candiscard(ln.Right) { 30 return true 31 } 32 default: 33 return true 34 } 35 } 36 37 // is this main 38 if localpkg.Name == "main" { 39 return true 40 } 41 42 // is there an explicit init function 43 if renameinitgen > 0 { 44 return true 45 } 46 47 // are there any imported init functions 48 for _, s := range types.InitSyms { 49 if s.Def != nil { 50 return true 51 } 52 } 53 54 // then none 55 return false 56 } 57 58 // fninit hand-crafts package initialization code. 59 // 60 // func init.ializers() { (0) 61 // <init stmts> 62 // } 63 // var initdone· uint8 (1) 64 // func init() { (2) 65 // if initdone· > 1 { (3) 66 // return (3a) 67 // } 68 // if initdone· == 1 { (4) 69 // throw() (4a) 70 // } 71 // initdone· = 1 (5) 72 // // over all matching imported symbols 73 // <pkg>.init() (6) 74 // init.ializers() (7) 75 // init.<n>() // if any (8) 76 // initdone· = 2 (9) 77 // return (10) 78 // } 79 func fninit(n []*Node) { 80 lineno = autogeneratedPos 81 nf := initfix(n) 82 if !anyinit(nf) { 83 return 84 } 85 86 // (0) 87 // Make a function that contains all the initialization statements. 88 // This is a separate function because we want it to appear in 89 // stack traces, where the init function itself does not. 90 var initializers *types.Sym 91 if len(nf) > 0 { 92 lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt 93 initializers = lookup("init.ializers") 94 disableExport(initializers) 95 fn := dclfunc(initializers, nod(OTFUNC, nil, nil)) 96 fn.Nbody.Set(nf) 97 funcbody() 98 99 fn = typecheck(fn, ctxStmt) 100 Curfn = fn 101 typecheckslice(nf, ctxStmt) 102 Curfn = nil 103 funccompile(fn) 104 lineno = autogeneratedPos 105 } 106 107 var r []*Node 108 109 // (1) 110 gatevar := newname(lookup("initdone·")) 111 addvar(gatevar, types.Types[TUINT8], PEXTERN) 112 113 // (2) 114 initsym := lookup("init") 115 fn := dclfunc(initsym, nod(OTFUNC, nil, nil)) 116 117 // (3) 118 a := nod(OIF, nil, nil) 119 a.Left = nod(OGT, gatevar, nodintconst(1)) 120 a.SetLikely(true) 121 r = append(r, a) 122 // (3a) 123 a.Nbody.Set1(nod(ORETURN, nil, nil)) 124 125 // (4) 126 b := nod(OIF, nil, nil) 127 b.Left = nod(OEQ, gatevar, nodintconst(1)) 128 // this actually isn't likely, but code layout is better 129 // like this: no JMP needed after the call. 130 b.SetLikely(true) 131 r = append(r, b) 132 // (4a) 133 b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil)) 134 135 // (5) 136 a = nod(OAS, gatevar, nodintconst(1)) 137 138 r = append(r, a) 139 140 // (6) 141 for _, s := range types.InitSyms { 142 if s == initsym { 143 continue 144 } 145 n := resolve(oldname(s)) 146 if n.Op == ONONAME { 147 // No package-scope init function; just a 148 // local variable, field name, or something. 149 continue 150 } 151 n.checkInitFuncSignature() 152 a = nod(OCALL, n, nil) 153 r = append(r, a) 154 } 155 156 // (7) 157 if initializers != nil { 158 n := newname(initializers) 159 addvar(n, functype(nil, nil, nil), PFUNC) 160 r = append(r, nod(OCALL, n, nil)) 161 } 162 163 // (8) 164 165 // maxInlineInitCalls is the threshold at which we switch 166 // from generating calls inline to generating a static array 167 // of functions and calling them in a loop. 168 // See CL 41500 for more discussion. 169 const maxInlineInitCalls = 500 170 171 if renameinitgen < maxInlineInitCalls { 172 // Not many init functions. Just call them all directly. 173 for i := 0; i < renameinitgen; i++ { 174 s := lookupN("init.", i) 175 n := asNode(s.Def) 176 n.checkInitFuncSignature() 177 a = nod(OCALL, n, nil) 178 r = append(r, a) 179 } 180 } else { 181 // Lots of init functions. 182 // Set up an array of functions and loop to call them. 183 // This is faster to compile and similar at runtime. 184 185 // Build type [renameinitgen]func(). 186 typ := types.NewArray(functype(nil, nil, nil), int64(renameinitgen)) 187 188 // Make and fill array. 189 fnarr := staticname(typ) 190 fnarr.Name.SetReadonly(true) 191 for i := 0; i < renameinitgen; i++ { 192 s := lookupN("init.", i) 193 lhs := nod(OINDEX, fnarr, nodintconst(int64(i))) 194 rhs := asNode(s.Def) 195 rhs.checkInitFuncSignature() 196 as := nod(OAS, lhs, rhs) 197 as = typecheck(as, ctxStmt) 198 genAsStatic(as) 199 } 200 201 // Generate a loop that calls each function in turn. 202 // for i := 0; i < renameinitgen; i++ { 203 // fnarr[i]() 204 // } 205 i := temp(types.Types[TINT]) 206 fnidx := nod(OINDEX, fnarr, i) 207 fnidx.SetBounded(true) 208 209 zero := nod(OAS, i, nodintconst(0)) 210 cond := nod(OLT, i, nodintconst(int64(renameinitgen))) 211 incr := nod(OAS, i, nod(OADD, i, nodintconst(1))) 212 body := nod(OCALL, fnidx, nil) 213 214 loop := nod(OFOR, cond, incr) 215 loop.Nbody.Set1(body) 216 loop.Ninit.Set1(zero) 217 218 loop = typecheck(loop, ctxStmt) 219 r = append(r, loop) 220 } 221 222 // (9) 223 a = nod(OAS, gatevar, nodintconst(2)) 224 225 r = append(r, a) 226 227 // (10) 228 a = nod(ORETURN, nil, nil) 229 230 r = append(r, a) 231 exportsym(fn.Func.Nname) 232 233 fn.Nbody.Set(r) 234 funcbody() 235 236 Curfn = fn 237 fn = typecheck(fn, ctxStmt) 238 typecheckslice(r, ctxStmt) 239 Curfn = nil 240 funccompile(fn) 241 } 242 243 func (n *Node) checkInitFuncSignature() { 244 if n.Type.NumRecvs()+n.Type.NumParams()+n.Type.NumResults() > 0 { 245 Fatalf("init function cannot have receiver, params, or results: %v (%v)", n, n.Type) 246 } 247 }