github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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 !isblank(ln.Left) || !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.Def != nil && s != initsym { 119 n := asNode(s.Def) 120 n.checkInitFuncSignature() 121 a = nod(OCALL, n, nil) 122 r = append(r, a) 123 } 124 } 125 126 // (7) 127 r = append(r, nf...) 128 129 // (8) 130 131 // maxInlineInitCalls is the threshold at which we switch 132 // from generating calls inline to generating a static array 133 // of functions and calling them in a loop. 134 // See CL 41500 for more discussion. 135 const maxInlineInitCalls = 500 136 137 if renameinitgen < maxInlineInitCalls { 138 // Not many init functions. Just call them all directly. 139 for i := 0; i < renameinitgen; i++ { 140 s := lookupN("init.", i) 141 n := asNode(s.Def) 142 n.checkInitFuncSignature() 143 a = nod(OCALL, n, nil) 144 r = append(r, a) 145 } 146 } else { 147 // Lots of init functions. 148 // Set up an array of functions and loop to call them. 149 // This is faster to compile and similar at runtime. 150 151 // Build type [renameinitgen]func(). 152 typ := types.NewArray(functype(nil, nil, nil), int64(renameinitgen)) 153 154 // Make and fill array. 155 fnarr := staticname(typ) 156 fnarr.Name.SetReadonly(true) 157 for i := 0; i < renameinitgen; i++ { 158 s := lookupN("init.", i) 159 lhs := nod(OINDEX, fnarr, nodintconst(int64(i))) 160 rhs := asNode(s.Def) 161 rhs.checkInitFuncSignature() 162 as := nod(OAS, lhs, rhs) 163 as = typecheck(as, Etop) 164 genAsStatic(as) 165 } 166 167 // Generate a loop that calls each function in turn. 168 // for i := 0; i < renameinitgen; i++ { 169 // fnarr[i]() 170 // } 171 i := temp(types.Types[TINT]) 172 fnidx := nod(OINDEX, fnarr, i) 173 fnidx.SetBounded(true) 174 175 zero := nod(OAS, i, nodintconst(0)) 176 cond := nod(OLT, i, nodintconst(int64(renameinitgen))) 177 incr := nod(OAS, i, nod(OADD, i, nodintconst(1))) 178 body := nod(OCALL, fnidx, nil) 179 180 loop := nod(OFOR, cond, incr) 181 loop.Nbody.Set1(body) 182 loop.Ninit.Set1(zero) 183 184 loop = typecheck(loop, Etop) 185 loop = walkstmt(loop) 186 r = append(r, loop) 187 } 188 189 // (9) 190 a = nod(OAS, gatevar, nodintconst(2)) 191 192 r = append(r, a) 193 194 // (10) 195 a = nod(ORETURN, nil, nil) 196 197 r = append(r, a) 198 exportsym(fn.Func.Nname) 199 200 fn.Nbody.Set(r) 201 funcbody() 202 203 Curfn = fn 204 fn = typecheck(fn, Etop) 205 typecheckslice(r, Etop) 206 Curfn = nil 207 funccompile(fn) 208 } 209 210 func (n *Node) checkInitFuncSignature() { 211 if n.Type.NumRecvs()+n.Type.NumParams()+n.Type.NumResults() > 0 { 212 Fatalf("init function cannot have receiver, params, or results: %v (%v)", n, n.Type) 213 } 214 }