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