diff options
Diffstat (limited to 'src/cmd/gc/init.c')
-rw-r--r-- | src/cmd/gc/init.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c new file mode 100644 index 000000000..8818db08c --- /dev/null +++ b/src/cmd/gc/init.c @@ -0,0 +1,195 @@ +// 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 "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); +} |