// 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 // case OADD: // if(n->right->op == OLITERAL) { // v = n->right->vconst; // naddr(n->left, a, canemitcode); // } else // if(n->left->op == OLITERAL) { // v = n->left->vconst; // naddr(n->right, a, canemitcode); // } else // goto bad; // a->offset += v; // break; /* * 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 Lookupf("init.%d", renameinit_initgen) } /* * hand-craft the following initialization code * var initdone· uint8 (1) * func init() (2) * if initdone· != 0 { (3) * if initdone· == 2 (4) * return * throw(); (5) * } * initdone· = 1; (6) * // over all matching imported symbols * <pkg>.init() (7) * { <init stmts> } (8) * init.<n>() // if any (9) * initdone· = 2; (10) * return (11) * } */ func anyinit(n *NodeList) bool { // are there any interesting init statements for l := n; l != nil; l = l.Next { switch l.N.Op { case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY: break case OAS, OASWB: if isblank(l.N.Left) && candiscard(l.N.Right) { break } fallthrough // fall through 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 *NodeList) { if Debug['A'] != 0 { // sys.go or unsafe.go during compiler build return } n = initfix(n) if !anyinit(n) { return } var r *NodeList // (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(ONE, gatevar, Nodintconst(0)) r = list(r, a) // (4) b := Nod(OIF, nil, nil) b.Left = Nod(OEQ, gatevar, Nodintconst(2)) b.Nbody = list1(Nod(ORETURN, nil, nil)) a.Nbody = list1(b) // (5) b = syslook("throwinit", 0) b = Nod(OCALL, b, nil) a.Nbody = list(a.Nbody, b) // (6) a = Nod(OAS, gatevar, Nodintconst(1)) r = list(r, a) // (7) 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 = list(r, a) } } // (8) r = concat(r, n) // (9) // could check that it is fn of no args/returns for i := 1; ; i++ { s := Lookupf("init.%d", i) if s.Def == nil { break } a = Nod(OCALL, s.Def, nil) r = list(r, a) } // (10) a = Nod(OAS, gatevar, Nodintconst(2)) r = list(r, a) // (11) a = Nod(ORETURN, nil, nil) r = list(r, a) exportsym(fn.Func.Nname) fn.Nbody = r funcbody(fn) Curfn = fn typecheck(&fn, Etop) typechecklist(r, Etop) Curfn = nil funccompile(fn) }