github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/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 Lookupf("init.%d", renameinit_initgen) 31 } 32 33 // hand-craft the following initialization code 34 // var initdone· uint8 (1) 35 // func init() (2) 36 // if initdone· != 0 { (3) 37 // if initdone· == 2 (4) 38 // return 39 // throw(); (5) 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 *NodeList) bool { 50 // are there any interesting init statements 51 for l := n; l != nil; l = l.Next { 52 switch l.N.Op { 53 case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY: 54 break 55 56 case OAS, OASWB: 57 if isblank(l.N.Left) && candiscard(l.N.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 *NodeList) { 92 if Debug['A'] != 0 { 93 // sys.go or unsafe.go during compiler build 94 return 95 } 96 97 n = initfix(n) 98 if !anyinit(n) { 99 return 100 } 101 102 var r *NodeList 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 122 a.Left = Nod(ONE, gatevar, Nodintconst(0)) 123 r = list(r, a) 124 125 // (4) 126 b := Nod(OIF, nil, nil) 127 128 b.Left = Nod(OEQ, gatevar, Nodintconst(2)) 129 b.Nbody = list1(Nod(ORETURN, nil, nil)) 130 a.Nbody = list1(b) 131 132 // (5) 133 b = syslook("throwinit", 0) 134 135 b = Nod(OCALL, b, nil) 136 a.Nbody = list(a.Nbody, b) 137 138 // (6) 139 a = Nod(OAS, gatevar, Nodintconst(1)) 140 141 r = list(r, a) 142 143 // (7) 144 for _, s := range initSyms { 145 if s.Def != nil && s != initsym { 146 // could check that it is fn of no args/returns 147 a = Nod(OCALL, s.Def, nil) 148 r = list(r, a) 149 } 150 } 151 152 // (8) 153 r = concat(r, n) 154 155 // (9) 156 // could check that it is fn of no args/returns 157 for i := 1; ; i++ { 158 s := Lookupf("init.%d", i) 159 if s.Def == nil { 160 break 161 } 162 a = Nod(OCALL, s.Def, nil) 163 r = list(r, a) 164 } 165 166 // (10) 167 a = Nod(OAS, gatevar, Nodintconst(2)) 168 169 r = list(r, a) 170 171 // (11) 172 a = Nod(ORETURN, nil, nil) 173 174 r = list(r, a) 175 exportsym(fn.Func.Nname) 176 177 fn.Nbody = r 178 funcbody(fn) 179 180 Curfn = fn 181 typecheck(&fn, Etop) 182 typechecklist(r, Etop) 183 Curfn = nil 184 funccompile(fn) 185 }