| // 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) | |
| } |