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, OASWB: 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 nf := initfix(n) 79 if !anyinit(nf) { 80 return 81 } 82 83 var r []*Node 84 85 // (1) 86 gatevar := newname(lookup("initdone")) 87 addvar(gatevar, Types[TUINT8], PEXTERN) 88 89 // (2) 90 Maxarg = 0 91 92 fn := nod(ODCLFUNC, nil, nil) 93 initsym := lookup("init") 94 fn.Func.Nname = newname(initsym) 95 fn.Func.Nname.Name.Defn = fn 96 fn.Func.Nname.Name.Param.Ntype = nod(OTFUNC, nil, nil) 97 declare(fn.Func.Nname, PFUNC) 98 funchdr(fn) 99 100 // (3) 101 a := nod(OIF, nil, nil) 102 a.Left = nod(OGT, gatevar, nodintconst(1)) 103 a.Likely = 1 104 r = append(r, a) 105 // (3a) 106 a.Nbody.Set1(nod(ORETURN, nil, nil)) 107 108 // (4) 109 b := nod(OIF, nil, nil) 110 b.Left = nod(OEQ, gatevar, nodintconst(1)) 111 // this actually isn't likely, but code layout is better 112 // like this: no JMP needed after the call. 113 b.Likely = 1 114 r = append(r, b) 115 // (4a) 116 b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil)) 117 118 // (5) 119 a = nod(OAS, gatevar, nodintconst(1)) 120 121 r = append(r, a) 122 123 // (6) 124 for _, s := range initSyms { 125 if s.Def != nil && s != initsym { 126 // could check that it is fn of no args/returns 127 a = nod(OCALL, s.Def, nil) 128 r = append(r, a) 129 } 130 } 131 132 // (7) 133 r = append(r, nf...) 134 135 // (8) 136 // could check that it is fn of no args/returns 137 for i := 1; ; i++ { 138 s := lookupN("init.", i) 139 if s.Def == nil { 140 break 141 } 142 a = nod(OCALL, s.Def, nil) 143 r = append(r, a) 144 } 145 146 // (9) 147 a = nod(OAS, gatevar, nodintconst(2)) 148 149 r = append(r, a) 150 151 // (10) 152 a = nod(ORETURN, nil, nil) 153 154 r = append(r, a) 155 exportsym(fn.Func.Nname) 156 157 fn.Nbody.Set(r) 158 funcbody(fn) 159 160 Curfn = fn 161 fn = typecheck(fn, Etop) 162 typecheckslice(r, Etop) 163 Curfn = nil 164 funccompile(fn) 165 } 166