github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/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 // var initdone· uint8 (1) 61 // func init() { (2) 62 // if initdone· > 1 { (3) 63 // return (3a) 64 // } 65 // if initdone· == 1 { (4) 66 // throw() (4a) 67 // } 68 // initdone· = 1 (5) 69 // // over all matching imported symbols 70 // <pkg>.init() (6) 71 // { <init stmts> } (7) 72 // init.<n>() // if any (8) 73 // initdone· = 2 (9) 74 // return (10) 75 // } 76 func fninit(n []*Node) { 77 lineno = autogeneratedPos 78 nf := initfix(n) 79 if !anyinit(nf) { 80 return 81 } 82 83 var r []*Node 84 85 // (1) 86 gatevar := newname(lookup("initdone·")) 87 addvar(gatevar, types.Types[TUINT8], PEXTERN) 88 89 // (2) 90 initsym := lookup("init") 91 fn := dclfunc(initsym, nod(OTFUNC, nil, nil)) 92 93 // (3) 94 a := nod(OIF, nil, nil) 95 a.Left = nod(OGT, gatevar, nodintconst(1)) 96 a.SetLikely(true) 97 r = append(r, a) 98 // (3a) 99 a.Nbody.Set1(nod(ORETURN, nil, nil)) 100 101 // (4) 102 b := nod(OIF, nil, nil) 103 b.Left = nod(OEQ, gatevar, nodintconst(1)) 104 // this actually isn't likely, but code layout is better 105 // like this: no JMP needed after the call. 106 b.SetLikely(true) 107 r = append(r, b) 108 // (4a) 109 b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil)) 110 111 // (5) 112 a = nod(OAS, gatevar, nodintconst(1)) 113 114 r = append(r, a) 115 116 // (6) 117 for _, s := range types.InitSyms { 118 if s == initsym { 119 continue 120 } 121 n := resolve(oldname(s)) 122 if n.Op == ONONAME { 123 // No package-scope init function; just a 124 // local variable, field name, or something. 125 continue 126 } 127 n.checkInitFuncSignature() 128 a = nod(OCALL, n, nil) 129 r = append(r, a) 130 } 131 132 // (7) 133 r = append(r, nf...) 134 135 // (8) 136 137 // maxInlineInitCalls is the threshold at which we switch 138 // from generating calls inline to generating a static array 139 // of functions and calling them in a loop. 140 // See CL 41500 for more discussion. 141 const maxInlineInitCalls = 500 142 143 if renameinitgen < maxInlineInitCalls { 144 // Not many init functions. Just call them all directly. 145 for i := 0; i < renameinitgen; i++ { 146 s := lookupN("init.", i) 147 n := asNode(s.Def) 148 n.checkInitFuncSignature() 149 a = nod(OCALL, n, nil) 150 r = append(r, a) 151 } 152 } else { 153 // Lots of init functions. 154 // Set up an array of functions and loop to call them. 155 // This is faster to compile and similar at runtime. 156 157 // Build type [renameinitgen]func(). 158 typ := types.NewArray(functype(nil, nil, nil), int64(renameinitgen)) 159 160 // Make and fill array. 161 fnarr := staticname(typ) 162 fnarr.Name.SetReadonly(true) 163 for i := 0; i < renameinitgen; i++ { 164 s := lookupN("init.", i) 165 lhs := nod(OINDEX, fnarr, nodintconst(int64(i))) 166 rhs := asNode(s.Def) 167 rhs.checkInitFuncSignature() 168 as := nod(OAS, lhs, rhs) 169 as = typecheck(as, Etop) 170 genAsStatic(as) 171 } 172 173 // Generate a loop that calls each function in turn. 174 // for i := 0; i < renameinitgen; i++ { 175 // fnarr[i]() 176 // } 177 i := temp(types.Types[TINT]) 178 fnidx := nod(OINDEX, fnarr, i) 179 fnidx.SetBounded(true) 180 181 zero := nod(OAS, i, nodintconst(0)) 182 cond := nod(OLT, i, nodintconst(int64(renameinitgen))) 183 incr := nod(OAS, i, nod(OADD, i, nodintconst(1))) 184 body := nod(OCALL, fnidx, nil) 185 186 loop := nod(OFOR, cond, incr) 187 loop.Nbody.Set1(body) 188 loop.Ninit.Set1(zero) 189 190 loop = typecheck(loop, Etop) 191 r = append(r, loop) 192 } 193 194 // (9) 195 a = nod(OAS, gatevar, nodintconst(2)) 196 197 r = append(r, a) 198 199 // (10) 200 a = nod(ORETURN, nil, nil) 201 202 r = append(r, a) 203 exportsym(fn.Func.Nname) 204 205 fn.Nbody.Set(r) 206 funcbody() 207 208 Curfn = fn 209 fn = typecheck(fn, Etop) 210 typecheckslice(r, Etop) 211 Curfn = nil 212 funccompile(fn) 213 } 214 215 func (n *Node) checkInitFuncSignature() { 216 if n.Type.NumRecvs()+n.Type.NumParams()+n.Type.NumResults() > 0 { 217 Fatalf("init function cannot have receiver, params, or results: %v (%v)", n, n.Type) 218 } 219 }