github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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 import "cmd/compile/internal/types" 8 9 // a function named init is a special case. 10 // it is called by the initialization before 11 // main is run. to make it unique within a 12 // package and also uncallable, the name, 13 // normally "pkg.init", is altered to "pkg.init.1". 14 15 var renameinit_initgen int 16 17 func renameinit() *types.Sym { 18 renameinit_initgen++ 19 return lookupN("init.", renameinit_initgen) 20 } 21 22 // anyinit reports whether there any interesting init statements. 23 func anyinit(n []*Node) bool { 24 for _, ln := range n { 25 switch ln.Op { 26 case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY: 27 case OAS: 28 if !isblank(ln.Left) || !candiscard(ln.Right) { 29 return true 30 } 31 default: 32 return true 33 } 34 } 35 36 // is this main 37 if localpkg.Name == "main" { 38 return true 39 } 40 41 // is there an explicit init function 42 if s := lookup("init.1"); s.Def != nil { 43 return true 44 } 45 46 // are there any imported init functions 47 for _, s := range types.InitSyms { 48 if s.Def != nil { 49 return true 50 } 51 } 52 53 // then none 54 return false 55 } 56 57 // fninit hand-crafts package initialization code. 58 // 59 // var initdone· uint8 (1) 60 // func init() { (2) 61 // if initdone· > 1 { (3) 62 // return (3a) 63 // } 64 // if initdone· == 1 { (4) 65 // throw() (4a) 66 // } 67 // initdone· = 1 (5) 68 // // over all matching imported symbols 69 // <pkg>.init() (6) 70 // { <init stmts> } (7) 71 // init.<n>() // if any (8) 72 // initdone· = 2 (9) 73 // return (10) 74 // } 75 func fninit(n []*Node) { 76 lineno = autogeneratedPos 77 nf := initfix(n) 78 if !anyinit(nf) { 79 return 80 } 81 82 var r []*Node 83 84 // (1) 85 gatevar := newname(lookup("initdone·")) 86 addvar(gatevar, types.Types[TUINT8], PEXTERN) 87 88 // (2) 89 initsym := lookup("init") 90 fn := dclfunc(initsym, nod(OTFUNC, nil, nil)) 91 92 // (3) 93 a := nod(OIF, nil, nil) 94 a.Left = nod(OGT, gatevar, nodintconst(1)) 95 a.Likely = 1 96 r = append(r, a) 97 // (3a) 98 a.Nbody.Set1(nod(ORETURN, nil, nil)) 99 100 // (4) 101 b := nod(OIF, nil, nil) 102 b.Left = nod(OEQ, gatevar, nodintconst(1)) 103 // this actually isn't likely, but code layout is better 104 // like this: no JMP needed after the call. 105 b.Likely = 1 106 r = append(r, b) 107 // (4a) 108 b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil)) 109 110 // (5) 111 a = nod(OAS, gatevar, nodintconst(1)) 112 113 r = append(r, a) 114 115 // (6) 116 for _, s := range types.InitSyms { 117 if s.Def != nil && s != initsym { 118 // could check that it is fn of no args/returns 119 a = nod(OCALL, asNode(s.Def), nil) 120 r = append(r, a) 121 } 122 } 123 124 // (7) 125 r = append(r, nf...) 126 127 // (8) 128 // could check that it is fn of no args/returns 129 for i := 1; ; i++ { 130 s := lookupN("init.", i) 131 if s.Def == nil { 132 break 133 } 134 a = nod(OCALL, asNode(s.Def), nil) 135 r = append(r, a) 136 } 137 138 // (9) 139 a = nod(OAS, gatevar, nodintconst(2)) 140 141 r = append(r, a) 142 143 // (10) 144 a = nod(ORETURN, nil, nil) 145 146 r = append(r, a) 147 exportsym(fn.Func.Nname) 148 149 fn.Nbody.Set(r) 150 funcbody(fn) 151 152 Curfn = fn 153 fn = typecheck(fn, Etop) 154 typecheckslice(r, Etop) 155 Curfn = nil 156 funccompile(fn) 157 }