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