// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package gc // a function named init is a special case. // it is called by the initialization before // main is run. to make it unique within a // package and also uncallable, the name, // normally "pkg.init", is altered to "pkg.init.1". var renameinit_initgen int func renameinit() *Sym { renameinit_initgen++ return lookupN("init.", renameinit_initgen) } // hand-craft the following initialization code // var initdone· uint8 (1) // func init() { (2) // if initdone· > 1 { (3) // return (3a) // } // if initdone· == 1 { (4) // throw() (4a) // } // initdone· = 1 (5) // // over all matching imported symbols // <pkg>.init() (6) // { <init stmts> } (7) // init.<n>() // if any (8) // initdone· = 2 (9) // return (10) // } func anyinit(n []*Node) bool { // are there any interesting init statements for _, ln := range n { switch ln.Op { case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY: break case OAS, OASWB: if isblank(ln.Left) && candiscard(ln.Right) { break } fallthrough default: return true } } // is this main if localpkg.Name == "main" { return true } // is there an explicit init function s := lookup("init.1") if s.Def != nil { return true } // are there any imported init functions for _, s := range initSyms { if s.Def != nil { return true } } // then none return false } func fninit(n []*Node) { if Debug['A'] != 0 { // sys.go or unsafe.go during compiler build return } nf := initfix(n) if !anyinit(nf) { return } var r []*Node // (1) gatevar := newname(lookup("initdone·")) addvar(gatevar, Types[TUINT8], PEXTERN) // (2) Maxarg = 0 fn := nod(ODCLFUNC, nil, nil) initsym := lookup("init") fn.Func.Nname = newname(initsym) fn.Func.Nname.Name.Defn = fn fn.Func.Nname.Name.Param.Ntype = nod(OTFUNC, nil, nil) declare(fn.Func.Nname, PFUNC) funchdr(fn) // (3) a := nod(OIF, nil, nil) a.Left = nod(OGT, gatevar, nodintconst(1)) a.Likely = 1 r = append(r, a) // (3a) a.Nbody.Set1(nod(ORETURN, nil, nil)) // (4) b := nod(OIF, nil, nil) b.Left = nod(OEQ, gatevar, nodintconst(1)) // this actually isn't likely, but code layout is better // like this: no JMP needed after the call. b.Likely = 1 r = append(r, b) // (4a) b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil)) // (5) a = nod(OAS, gatevar, nodintconst(1)) r = append(r, a) // (6) for _, s := range initSyms { if s.Def != nil && s != initsym { // could check that it is fn of no args/returns a = nod(OCALL, s.Def, nil) r = append(r, a) } } // (7) r = append(r, nf...) // (8) // could check that it is fn of no args/returns for i := 1; ; i++ { s := lookupN("init.", i) if s.Def == nil { break } a = nod(OCALL, s.Def, nil) r = append(r, a) } // (9) a = nod(OAS, gatevar, nodintconst(2)) r = append(r, a) // (10) a = nod(ORETURN, nil, nil) r = append(r, a) exportsym(fn.Func.Nname) fn.Nbody.Set(r) funcbody(fn) Curfn = fn fn = typecheck(fn, Etop) typecheckslice(r, Etop) Curfn = nil funccompile(fn) }