github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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  /*
    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  }