// 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 * .init·() (7) * { } (8) * init·() // if any (9) * initdone. += 1; (10) * return (11) * } * note that this code cannot have an assignment * statement or, because of the initflag, it will * be converted into a data statement. */ 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(package, "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; hlink) { if(s->name[0] != 'I' || strncmp(s->name, "Init·", 6) != 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(strcmp(package, "PACKAGE") == 0) { // 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·"); // this is a botch since we need a known name to // call the top level init function out of rt0 if(strcmp(package, "main") == 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; hlink) { if(s->name[0] != 'I' || strncmp(s->name, "Init·", 6) != 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); typecheck(&fn, Etop); funccompile(fn); }