github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/gc/init.c (about)

     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 <u.h>
     6  #include <libc.h>
     7  #include "go.h"
     8  
     9  /*
    10   * a function named init is a special case.
    11   * it is called by the initialization before
    12   * main is run. to make it unique within a
    13   * package and also uncallable, the name,
    14   * normally "pkg.init", is altered to "pkg.init·1".
    15   */
    16  Sym*
    17  renameinit(void)
    18  {
    19  	static int initgen;
    20  
    21  	snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
    22  	return lookup(namebuf);
    23  }
    24  
    25  /*
    26   * hand-craft the following initialization code
    27   *	var initdone· uint8 				(1)
    28   *	func init()					(2)
    29   *		if initdone· != 0 {			(3)
    30   *			if initdone· == 2		(4)
    31   *				return
    32   *			throw();			(5)
    33   *		}
    34   *		initdone· = 1;				(6)
    35   *		// over all matching imported symbols
    36   *			<pkg>.init()			(7)
    37   *		{ <init stmts> }			(8)
    38   *		init·<n>() // if any			(9)
    39   *		initdone· = 2;				(10)
    40   *		return					(11)
    41   *	}
    42   */
    43  static int
    44  anyinit(NodeList *n)
    45  {
    46  	uint32 h;
    47  	Sym *s;
    48  	NodeList *l;
    49  
    50  	// are there any interesting init statements
    51  	for(l=n; l; l=l->next) {
    52  		switch(l->n->op) {
    53  		case ODCLFUNC:
    54  		case ODCLCONST:
    55  		case ODCLTYPE:
    56  		case OEMPTY:
    57  			break;
    58  		case OAS:
    59  			if(isblank(l->n->left) && candiscard(l->n->right))
    60  				break;
    61  			// fall through
    62  		default:
    63  			return 1;
    64  		}
    65  	}
    66  
    67  	// is this main
    68  	if(strcmp(localpkg->name, "main") == 0)
    69  		return 1;
    70  
    71  	// is there an explicit init function
    72  	snprint(namebuf, sizeof(namebuf), "init·1");
    73  	s = lookup(namebuf);
    74  	if(s->def != N)
    75  		return 1;
    76  
    77  	// are there any imported init functions
    78  	for(h=0; h<NHASH; h++)
    79  	for(s = hash[h]; s != S; s = s->link) {
    80  		if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
    81  			continue;
    82  		if(s->def == N)
    83  			continue;
    84  		return 1;
    85  	}
    86  
    87  	// then none
    88  	return 0;
    89  }
    90  
    91  void
    92  fninit(NodeList *n)
    93  {
    94  	int i;
    95  	Node *gatevar;
    96  	Node *a, *b, *fn;
    97  	NodeList *r;
    98  	uint32 h;
    99  	Sym *s, *initsym;
   100  
   101  	if(debug['A']) {
   102  		// sys.go or unsafe.go during compiler build
   103  		return;
   104  	}
   105  
   106  	n = initfix(n);
   107  	if(!anyinit(n))
   108  		return;
   109  
   110  	r = nil;
   111  
   112  	// (1)
   113  	snprint(namebuf, sizeof(namebuf), "initdone·");
   114  	gatevar = newname(lookup(namebuf));
   115  	addvar(gatevar, types[TUINT8], PEXTERN);
   116  
   117  	// (2)
   118  	maxarg = 0;
   119  	snprint(namebuf, sizeof(namebuf), "init");
   120  
   121  	fn = nod(ODCLFUNC, N, N);
   122  	initsym = lookup(namebuf);
   123  	fn->nname = newname(initsym);
   124  	fn->nname->defn = fn;
   125  	fn->nname->ntype = nod(OTFUNC, N, N);
   126  	declare(fn->nname, PFUNC);
   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  }