| // 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. | |
| #include <u.h> | |
| #include <libc.h> | |
| #include "go.h" | |
| /* | |
| * 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". | |
| */ | |
| Node* | |
| renameinit(Node *n) | |
| { | |
| Sym *s; | |
| static int initgen; | |
| s = n->sym; | |
| if(s == S) | |
| return n; | |
| if(strcmp(s->name, "init") != 0) | |
| return n; | |
| snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen); | |
| s = lookup(namebuf); | |
| return newname(s); | |
| } | |
| /* | |
| * 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) | |
| * } | |
| */ | |
| static int | |
| anyinit(NodeList *n) | |
| { | |
| uint32 h; | |
| Sym *s; | |
| NodeList *l; | |
| // are there any interesting init statements | |
| for(l=n; l; l=l->next) { | |
| switch(l->n->op) { | |
| case ODCLFUNC: | |
| case ODCLCONST: | |
| case ODCLTYPE: | |
| case OEMPTY: | |
| break; | |
| default: | |
| return 1; | |
| } | |
| } | |
| // is this main | |
| if(strcmp(localpkg->name, "main") == 0) | |
| return 1; | |
| // is there an explicit init function | |
| snprint(namebuf, sizeof(namebuf), "init·1"); | |
| s = lookup(namebuf); | |
| if(s->def != N) | |
| return 1; | |
| // are there any imported init functions | |
| for(h=0; h<NHASH; h++) | |
| for(s = hash[h]; s != S; s = s->link) { | |
| if(s->name[0] != 'i' || strcmp(s->name, "init") != 0) | |
| continue; | |
| if(s->def == N) | |
| continue; | |
| return 1; | |
| } | |
| // then none | |
| return 0; | |
| } | |
| void | |
| fninit(NodeList *n) | |
| { | |
| int i; | |
| Node *gatevar; | |
| Node *a, *b, *fn; | |
| NodeList *r; | |
| uint32 h; | |
| Sym *s, *initsym; | |
| if(debug['A']) { | |
| // sys.go or unsafe.go during compiler build | |
| return; | |
| } | |
| n = initfix(n); | |
| if(!anyinit(n)) | |
| return; | |
| r = nil; | |
| // (1) | |
| snprint(namebuf, sizeof(namebuf), "initdone·"); | |
| gatevar = newname(lookup(namebuf)); | |
| addvar(gatevar, types[TUINT8], PEXTERN); | |
| // (2) | |
| maxarg = 0; | |
| snprint(namebuf, sizeof(namebuf), "init"); | |
| fn = nod(ODCLFUNC, N, N); | |
| initsym = lookup(namebuf); | |
| fn->nname = newname(initsym); | |
| fn->nname->ntype = nod(OTFUNC, N, N); | |
| funchdr(fn); | |
| // (3) | |
| a = nod(OIF, N, N); | |
| a->ntest = nod(ONE, gatevar, nodintconst(0)); | |
| r = list(r, a); | |
| // (4) | |
| b = nod(OIF, N, N); | |
| b->ntest = nod(OEQ, gatevar, nodintconst(2)); | |
| b->nbody = list1(nod(ORETURN, N, N)); | |
| a->nbody = list1(b); | |
| // (5) | |
| b = syslook("throwinit", 0); | |
| b = nod(OCALL, b, N); | |
| a->nbody = list(a->nbody, b); | |
| // (6) | |
| a = nod(OAS, gatevar, nodintconst(1)); | |
| r = list(r, a); | |
| // (7) | |
| for(h=0; h<NHASH; h++) | |
| for(s = hash[h]; s != S; s = s->link) { | |
| if(s->name[0] != 'i' || strcmp(s->name, "init") != 0) | |
| continue; | |
| if(s->def == N) | |
| continue; | |
| if(s == initsym) | |
| continue; | |
| // could check that it is fn of no args/returns | |
| a = nod(OCALL, s->def, N); | |
| r = list(r, a); | |
| } | |
| // (8) | |
| r = concat(r, n); | |
| // (9) | |
| // could check that it is fn of no args/returns | |
| for(i=1;; i++) { | |
| snprint(namebuf, sizeof(namebuf), "init·%d", i); | |
| s = lookup(namebuf); | |
| if(s->def == N) | |
| break; | |
| a = nod(OCALL, s->def, N); | |
| r = list(r, a); | |
| } | |
| // (10) | |
| a = nod(OAS, gatevar, nodintconst(2)); | |
| r = list(r, a); | |
| // (11) | |
| a = nod(ORETURN, N, N); | |
| r = list(r, a); | |
| exportsym(fn->nname); | |
| fn->nbody = r; | |
| funcbody(fn); | |
| curfn = fn; | |
| typecheck(&fn, Etop); | |
| typechecklist(r, Etop); | |
| curfn = nil; | |
| funccompile(fn, 0); | |
| } |