summaryrefslogtreecommitdiff
path: root/src/cmd/gc/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/init.c')
-rw-r--r--src/cmd/gc/init.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
new file mode 100644
index 000000000..5fc7f8bbc
--- /dev/null
+++ b/src/cmd/gc/init.c
@@ -0,0 +1,193 @@
+// 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·filename".
+ */
+Node*
+renameinit(Node *n)
+{
+ Sym *s;
+
+ s = n->sym;
+ if(s == S)
+ return n;
+ if(strcmp(s->name, "init") != 0)
+ return n;
+
+ snprint(namebuf, sizeof(namebuf), "init·%s", filename);
+ s = lookup(namebuf);
+ return newname(s);
+}
+
+/*
+ * hand-craft the following initialization code
+ * var initdone·<file> uint8 (1)
+ * func Init·<file>() (2)
+ * if initdone·<file> { (3)
+ * if initdone·<file> == 2 (4)
+ * return
+ * throw(); (5)
+ * }
+ * initdone.<file>++; (6)
+ * // over all matching imported symbols
+ * <pkg>.init·<file>() (7)
+ * { <init stmts> } (8)
+ * init·<file>() // if any (9)
+ * initdone.<file>++; (10)
+ * return (11)
+ * }
+ */
+int
+anyinit(NodeList *n)
+{
+ uint32 h;
+ Sym *s;
+
+ // are there any init statements
+ if(n != nil)
+ return 1;
+
+ // is this main
+ if(strcmp(package, "main") == 0)
+ return 1;
+
+ // is there an explicit init function
+ snprint(namebuf, sizeof(namebuf), "init·%s", filename);
+ 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' || strncmp(s->name, "Init·", 6) != 0)
+ continue;
+ if(s->def == N)
+ continue;
+ return 1;
+ }
+
+ // then none
+ return 0;
+}
+
+void
+fninit(NodeList *n)
+{
+ 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;
+ }
+
+ if(!anyinit(n))
+ return;
+
+ r = nil;
+
+ // (1)
+ snprint(namebuf, sizeof(namebuf), "initdone·%s", filename);
+ gatevar = newname(lookup(namebuf));
+ addvar(gatevar, types[TUINT8], PEXTERN);
+
+ // (2)
+
+ maxarg = 0;
+ stksize = initstksize;
+
+ snprint(namebuf, sizeof(namebuf), "Init·%s", filename);
+
+ // 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->type = functype(N, nil, nil);
+ 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(OASOP, gatevar, nodintconst(1));
+ a->etype = OADD;
+ 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' || 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, initfix(n));
+
+ // (9)
+ // could check that it is fn of no args/returns
+ snprint(namebuf, sizeof(namebuf), "init·%s", filename);
+ s = lookup(namebuf);
+ if(s->def != N) {
+ a = nod(OCALL, s->def, N);
+ r = list(r, a);
+ }
+
+ // (10)
+ a = nod(OASOP, gatevar, nodintconst(1));
+ a->etype = OADD;
+ r = list(r, a);
+
+ // (11)
+ a = nod(ORETURN, N, N);
+ r = list(r, a);
+
+ exportsym(fn->nname->sym);
+
+ fn->nbody = r;
+//dump("b", fn);
+//dump("r", fn->nbody);
+
+ popdcl();
+ initflag = 1; // flag for loader static initialization
+ compile(fn);
+ initflag = 0;
+}
+
+