github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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 // a function named init is a special case. 8 // it is called by the initialization before 9 // main is run. to make it unique within a 10 // package and also uncallable, the name, 11 // normally "pkg.init", is altered to "pkg.init.1". 12 13 var renameinit_initgen int 14 15 func renameinit() *Sym { 16 renameinit_initgen++ 17 return lookupN("init.", renameinit_initgen) 18 } 19 20 // hand-craft the following initialization code 21 // var initdone· uint8 (1) 22 // func init() { (2) 23 // if initdone· > 1 { (3) 24 // return (3a) 25 // } 26 // if initdone· == 1 { (4) 27 // throw() (4a) 28 // } 29 // initdone· = 1 (5) 30 // // over all matching imported symbols 31 // <pkg>.init() (6) 32 // { <init stmts> } (7) 33 // init.<n>() // if any (8) 34 // initdone· = 2 (9) 35 // return (10) 36 // } 37 func anyinit(n []*Node) bool { 38 // are there any interesting init statements 39 for _, ln := range n { 40 switch ln.Op { 41 case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY: 42 break 43 44 case OAS: 45 if isblank(ln.Left) && candiscard(ln.Right) { 46 break 47 } 48 fallthrough 49 default: 50 return true 51 } 52 } 53 54 // is this main 55 if localpkg.Name == "main" { 56 return true 57 } 58 59 // is there an explicit init function 60 s := lookup("init.1") 61 62 if s.Def != nil { 63 return true 64 } 65 66 // are there any imported init functions 67 for _, s := range initSyms { 68 if s.Def != nil { 69 return true 70 } 71 } 72 73 // then none 74 return false 75 } 76 77 func fninit(n []*Node) { 78 // This code is using the last value of lineno for position information 79 // (see comment in noder.go, noder.file method, for details). 80 81 nf := initfix(n) 82 if !anyinit(nf) { 83 return 84 } 85 86 var r []*Node 87 88 // (1) 89 gatevar := newname(lookup("initdone·")) 90 addvar(gatevar, Types[TUINT8], PEXTERN) 91 92 // (2) 93 Maxarg = 0 94 95 fn := nod(ODCLFUNC, nil, nil) 96 initsym := lookup("init") 97 fn.Func.Nname = newname(initsym) 98 fn.Func.Nname.Name.Defn = fn 99 fn.Func.Nname.Name.Param.Ntype = nod(OTFUNC, nil, nil) 100 declare(fn.Func.Nname, PFUNC) 101 funchdr(fn) 102 103 // (3) 104 a := nod(OIF, nil, nil) 105 a.Left = nod(OGT, gatevar, nodintconst(1)) 106 a.Likely = 1 107 r = append(r, a) 108 // (3a) 109 a.Nbody.Set1(nod(ORETURN, nil, nil)) 110 111 // (4) 112 b := nod(OIF, nil, nil) 113 b.Left = nod(OEQ, gatevar, nodintconst(1)) 114 // this actually isn't likely, but code layout is better 115 // like this: no JMP needed after the call. 116 b.Likely = 1 117 r = append(r, b) 118 // (4a) 119 b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil)) 120 121 // (5) 122 a = nod(OAS, gatevar, nodintconst(1)) 123 124 r = append(r, a) 125 126 // (6) 127 for _, s := range initSyms { 128 if s.Def != nil && s != initsym { 129 // could check that it is fn of no args/returns 130 a = nod(OCALL, s.Def, nil) 131 r = append(r, a) 132 } 133 } 134 135 // (7) 136 r = append(r, nf...) 137 138 // (8) 139 // could check that it is fn of no args/returns 140 for i := 1; ; i++ { 141 s := lookupN("init.", i) 142 if s.Def == nil { 143 break 144 } 145 a = nod(OCALL, s.Def, nil) 146 r = append(r, a) 147 } 148 149 // (9) 150 a = nod(OAS, gatevar, nodintconst(2)) 151 152 r = append(r, a) 153 154 // (10) 155 a = nod(ORETURN, nil, nil) 156 157 r = append(r, a) 158 exportsym(fn.Func.Nname) 159 160 fn.Nbody.Set(r) 161 funcbody(fn) 162 163 Curfn = fn 164 fn = typecheck(fn, Etop) 165 typecheckslice(r, Etop) 166 Curfn = nil 167 funccompile(fn) 168 }