The Go Programming Language

Text file src/cmd/gc/init.c

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	#include "go.h"
     6	
     7	/*
     8	 * a function named init is a special case.
     9	 * it is called by the initialization before
    10	 * main is run. to make it unique within a
    11	 * package and also uncallable, the name,
    12	 * normally "pkg.init", is altered to "pkg.init·1".
    13	 */
    14	Node*
    15	renameinit(Node *n)
    16	{
    17		Sym *s;
    18		static int initgen;
    19	
    20		s = n->sym;
    21		if(s == S)
    22			return n;
    23		if(strcmp(s->name, "init") != 0)
    24			return n;
    25	
    26		snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
    27		s = lookup(namebuf);
    28		return newname(s);
    29	}
    30	
    31	/*
    32	 * hand-craft the following initialization code
    33	 *	var initdone· uint8 				(1)
    34	 *	func init()					(2)
    35	 *		if initdone· != 0 {			(3)
    36	 *			if initdone· == 2		(4)
    37	 *				return
    38	 *			throw();			(5)
    39	 *		}
    40	 *		initdone· = 1;				(6)
    41	 *		// over all matching imported symbols
    42	 *			<pkg>.init()			(7)
    43	 *		{ <init stmts> }			(8)
    44	 *		init·<n>() // if any			(9)
    45	 *		initdone· = 2;				(10)
    46	 *		return					(11)
    47	 *	}
    48	 */
    49	static int
    50	anyinit(NodeList *n)
    51	{
    52		uint32 h;
    53		Sym *s;
    54		NodeList *l;
    55	
    56		// are there any interesting init statements
    57		for(l=n; l; l=l->next) {
    58			switch(l->n->op) {
    59			case ODCLFUNC:
    60			case ODCLCONST:
    61			case ODCLTYPE:
    62			case OEMPTY:
    63				break;
    64			default:
    65				return 1;
    66			}
    67		}
    68	
    69		// is this main
    70		if(strcmp(localpkg->name, "main") == 0)
    71			return 1;
    72	
    73		// is there an explicit init function
    74		snprint(namebuf, sizeof(namebuf), "init·1");
    75		s = lookup(namebuf);
    76		if(s->def != N)
    77			return 1;
    78	
    79		// are there any imported init functions
    80		for(h=0; h<NHASH; h++)
    81		for(s = hash[h]; s != S; s = s->link) {
    82			if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
    83				continue;
    84			if(s->def == N)
    85				continue;
    86			return 1;
    87		}
    88	
    89		// then none
    90		return 0;
    91	}
    92	
    93	void
    94	fninit(NodeList *n)
    95	{
    96		int i;
    97		Node *gatevar;
    98		Node *a, *b, *fn;
    99		NodeList *r;
   100		uint32 h;
   101		Sym *s, *initsym;
   102	
   103		if(debug['A']) {
   104			// sys.go or unsafe.go during compiler build
   105			return;
   106		}
   107	
   108		n = initfix(n);
   109		if(!anyinit(n))
   110			return;
   111	
   112		r = nil;
   113	
   114		// (1)
   115		snprint(namebuf, sizeof(namebuf), "initdone·");
   116		gatevar = newname(lookup(namebuf));
   117		addvar(gatevar, types[TUINT8], PEXTERN);
   118	
   119		// (2)
   120		maxarg = 0;
   121		snprint(namebuf, sizeof(namebuf), "init");
   122	
   123		fn = nod(ODCLFUNC, N, N);
   124		initsym = lookup(namebuf);
   125		fn->nname = newname(initsym);
   126		fn->nname->ntype = nod(OTFUNC, N, N);
   127		funchdr(fn);
   128	
   129		// (3)
   130		a = nod(OIF, N, N);
   131		a->ntest = nod(ONE, gatevar, nodintconst(0));
   132		r = list(r, a);
   133	
   134		// (4)
   135		b = nod(OIF, N, N);
   136		b->ntest = nod(OEQ, gatevar, nodintconst(2));
   137		b->nbody = list1(nod(ORETURN, N, N));
   138		a->nbody = list1(b);
   139	
   140		// (5)
   141		b = syslook("throwinit", 0);
   142		b = nod(OCALL, b, N);
   143		a->nbody = list(a->nbody, b);
   144	
   145		// (6)
   146		a = nod(OAS, gatevar, nodintconst(1));
   147		r = list(r, a);
   148	
   149		// (7)
   150		for(h=0; h<NHASH; h++)
   151		for(s = hash[h]; s != S; s = s->link) {
   152			if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
   153				continue;
   154			if(s->def == N)
   155				continue;
   156			if(s == initsym)
   157				continue;
   158	
   159			// could check that it is fn of no args/returns
   160			a = nod(OCALL, s->def, N);
   161			r = list(r, a);
   162		}
   163	
   164		// (8)
   165		r = concat(r, n);
   166	
   167		// (9)
   168		// could check that it is fn of no args/returns
   169		for(i=1;; i++) {
   170			snprint(namebuf, sizeof(namebuf), "init·%d", i);
   171			s = lookup(namebuf);
   172			if(s->def == N)
   173				break;
   174			a = nod(OCALL, s->def, N);
   175			r = list(r, a);
   176		}
   177	
   178		// (10)
   179		a = nod(OAS, gatevar, nodintconst(2));
   180		r = list(r, a);
   181	
   182		// (11)
   183		a = nod(ORETURN, N, N);
   184		r = list(r, a);
   185		exportsym(fn->nname);
   186	
   187		fn->nbody = r;
   188		funcbody(fn);
   189	
   190		curfn = fn;
   191		typecheck(&fn, Etop);
   192		typechecklist(r, Etop);
   193		curfn = nil;
   194		funccompile(fn, 0);
   195	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.