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