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