Home | History | Annotate | Download | only in gc
      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 package gc
      6 
      7 //	case OADD:
      8 //		if(n->right->op == OLITERAL) {
      9 //			v = n->right->vconst;
     10 //			naddr(n->left, a, canemitcode);
     11 //		} else
     12 //		if(n->left->op == OLITERAL) {
     13 //			v = n->left->vconst;
     14 //			naddr(n->right, a, canemitcode);
     15 //		} else
     16 //			goto bad;
     17 //		a->offset += v;
     18 //		break;
     19 
     20 /*
     21  * a function named init is a special case.
     22  * it is called by the initialization before
     23  * main is run. to make it unique within a
     24  * package and also uncallable, the name,
     25  * normally "pkg.init", is altered to "pkg.init.1".
     26  */
     27 
     28 var renameinit_initgen int
     29 
     30 func renameinit() *Sym {
     31 	renameinit_initgen++
     32 	return Lookupf("init.%d", renameinit_initgen)
     33 }
     34 
     35 /*
     36  * hand-craft the following initialization code
     37  *	var initdone uint8 				(1)
     38  *	func init()					(2)
     39  *		if initdone != 0 {			(3)
     40  *			if initdone == 2		(4)
     41  *				return
     42  *			throw();			(5)
     43  *		}
     44  *		initdone = 1;				(6)
     45  *		// over all matching imported symbols
     46  *			<pkg>.init()			(7)
     47  *		{ <init stmts> }			(8)
     48  *		init.<n>() // if any			(9)
     49  *		initdone = 2;				(10)
     50  *		return					(11)
     51  *	}
     52  */
     53 func anyinit(n *NodeList) bool {
     54 	// are there any interesting init statements
     55 	for l := n; l != nil; l = l.Next {
     56 		switch l.N.Op {
     57 		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
     58 			break
     59 
     60 		case OAS, OASWB:
     61 			if isblank(l.N.Left) && candiscard(l.N.Right) {
     62 				break
     63 			}
     64 			fallthrough
     65 
     66 			// fall through
     67 		default:
     68 			return true
     69 		}
     70 	}
     71 
     72 	// is this main
     73 	if localpkg.Name == "main" {
     74 		return true
     75 	}
     76 
     77 	// is there an explicit init function
     78 	s := Lookup("init.1")
     79 
     80 	if s.Def != nil {
     81 		return true
     82 	}
     83 
     84 	// are there any imported init functions
     85 	for _, s := range initSyms {
     86 		if s.Def != nil {
     87 			return true
     88 		}
     89 	}
     90 
     91 	// then none
     92 	return false
     93 }
     94 
     95 func fninit(n *NodeList) {
     96 	if Debug['A'] != 0 {
     97 		// sys.go or unsafe.go during compiler build
     98 		return
     99 	}
    100 
    101 	n = initfix(n)
    102 	if !anyinit(n) {
    103 		return
    104 	}
    105 
    106 	var r *NodeList
    107 
    108 	// (1)
    109 	gatevar := newname(Lookup("initdone"))
    110 	addvar(gatevar, Types[TUINT8], PEXTERN)
    111 
    112 	// (2)
    113 	Maxarg = 0
    114 
    115 	fn := Nod(ODCLFUNC, nil, nil)
    116 	initsym := Lookup("init")
    117 	fn.Func.Nname = newname(initsym)
    118 	fn.Func.Nname.Name.Defn = fn
    119 	fn.Func.Nname.Name.Param.Ntype = Nod(OTFUNC, nil, nil)
    120 	declare(fn.Func.Nname, PFUNC)
    121 	funchdr(fn)
    122 
    123 	// (3)
    124 	a := Nod(OIF, nil, nil)
    125 
    126 	a.Left = Nod(ONE, gatevar, Nodintconst(0))
    127 	r = list(r, a)
    128 
    129 	// (4)
    130 	b := Nod(OIF, nil, nil)
    131 
    132 	b.Left = Nod(OEQ, gatevar, Nodintconst(2))
    133 	b.Nbody = list1(Nod(ORETURN, nil, nil))
    134 	a.Nbody = list1(b)
    135 
    136 	// (5)
    137 	b = syslook("throwinit", 0)
    138 
    139 	b = Nod(OCALL, b, nil)
    140 	a.Nbody = list(a.Nbody, b)
    141 
    142 	// (6)
    143 	a = Nod(OAS, gatevar, Nodintconst(1))
    144 
    145 	r = list(r, a)
    146 
    147 	// (7)
    148 	for _, s := range initSyms {
    149 		if s.Def != nil && s != initsym {
    150 			// could check that it is fn of no args/returns
    151 			a = Nod(OCALL, s.Def, nil)
    152 			r = list(r, a)
    153 		}
    154 	}
    155 
    156 	// (8)
    157 	r = concat(r, n)
    158 
    159 	// (9)
    160 	// could check that it is fn of no args/returns
    161 	for i := 1; ; i++ {
    162 		s := Lookupf("init.%d", i)
    163 		if s.Def == nil {
    164 			break
    165 		}
    166 		a = Nod(OCALL, s.Def, nil)
    167 		r = list(r, a)
    168 	}
    169 
    170 	// (10)
    171 	a = Nod(OAS, gatevar, Nodintconst(2))
    172 
    173 	r = list(r, a)
    174 
    175 	// (11)
    176 	a = Nod(ORETURN, nil, nil)
    177 
    178 	r = list(r, a)
    179 	exportsym(fn.Func.Nname)
    180 
    181 	fn.Nbody = r
    182 	funcbody(fn)
    183 
    184 	Curfn = fn
    185 	typecheck(&fn, Etop)
    186 	typechecklist(r, Etop)
    187 	Curfn = nil
    188 	funccompile(fn)
    189 }
    190