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