github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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  import "cmd/compile/internal/types"
     8  
     9  // a function named init is a special case.
    10  // it is called by the initialization before
    11  // main is run. to make it unique within a
    12  // package and also uncallable, the name,
    13  // normally "pkg.init", is altered to "pkg.init.1".
    14  
    15  var renameinit_initgen int
    16  
    17  func renameinit() *types.Sym {
    18  	renameinit_initgen++
    19  	return lookupN("init.", renameinit_initgen)
    20  }
    21  
    22  // anyinit reports whether there any interesting init statements.
    23  func anyinit(n []*Node) bool {
    24  	for _, ln := range n {
    25  		switch ln.Op {
    26  		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
    27  		case OAS:
    28  			if !isblank(ln.Left) || !candiscard(ln.Right) {
    29  				return true
    30  			}
    31  		default:
    32  			return true
    33  		}
    34  	}
    35  
    36  	// is this main
    37  	if localpkg.Name == "main" {
    38  		return true
    39  	}
    40  
    41  	// is there an explicit init function
    42  	if s := lookup("init.1"); s.Def != nil {
    43  		return true
    44  	}
    45  
    46  	// are there any imported init functions
    47  	for _, s := range types.InitSyms {
    48  		if s.Def != nil {
    49  			return true
    50  		}
    51  	}
    52  
    53  	// then none
    54  	return false
    55  }
    56  
    57  // fninit hand-crafts package initialization code.
    58  //
    59  //      var initdone· uint8                             (1)
    60  //      func init() {                                   (2)
    61  //              if initdone· > 1 {                      (3)
    62  //                      return                          (3a)
    63  //              }
    64  //              if initdone· == 1 {                     (4)
    65  //                      throw()                         (4a)
    66  //              }
    67  //              initdone· = 1                           (5)
    68  //              // over all matching imported symbols
    69  //                      <pkg>.init()                    (6)
    70  //              { <init stmts> }                        (7)
    71  //              init.<n>() // if any                    (8)
    72  //              initdone· = 2                           (9)
    73  //              return                                  (10)
    74  //      }
    75  func fninit(n []*Node) {
    76  	lineno = autogeneratedPos
    77  	nf := initfix(n)
    78  	if !anyinit(nf) {
    79  		return
    80  	}
    81  
    82  	var r []*Node
    83  
    84  	// (1)
    85  	gatevar := newname(lookup("initdone·"))
    86  	addvar(gatevar, types.Types[TUINT8], PEXTERN)
    87  
    88  	// (2)
    89  	initsym := lookup("init")
    90  	fn := dclfunc(initsym, nod(OTFUNC, nil, nil))
    91  
    92  	// (3)
    93  	a := nod(OIF, nil, nil)
    94  	a.Left = nod(OGT, gatevar, nodintconst(1))
    95  	a.Likely = 1
    96  	r = append(r, a)
    97  	// (3a)
    98  	a.Nbody.Set1(nod(ORETURN, nil, nil))
    99  
   100  	// (4)
   101  	b := nod(OIF, nil, nil)
   102  	b.Left = nod(OEQ, gatevar, nodintconst(1))
   103  	// this actually isn't likely, but code layout is better
   104  	// like this: no JMP needed after the call.
   105  	b.Likely = 1
   106  	r = append(r, b)
   107  	// (4a)
   108  	b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil))
   109  
   110  	// (5)
   111  	a = nod(OAS, gatevar, nodintconst(1))
   112  
   113  	r = append(r, a)
   114  
   115  	// (6)
   116  	for _, s := range types.InitSyms {
   117  		if s.Def != nil && s != initsym {
   118  			// could check that it is fn of no args/returns
   119  			a = nod(OCALL, asNode(s.Def), nil)
   120  			r = append(r, a)
   121  		}
   122  	}
   123  
   124  	// (7)
   125  	r = append(r, nf...)
   126  
   127  	// (8)
   128  	// could check that it is fn of no args/returns
   129  	for i := 1; ; i++ {
   130  		s := lookupN("init.", i)
   131  		if s.Def == nil {
   132  			break
   133  		}
   134  		a = nod(OCALL, asNode(s.Def), nil)
   135  		r = append(r, a)
   136  	}
   137  
   138  	// (9)
   139  	a = nod(OAS, gatevar, nodintconst(2))
   140  
   141  	r = append(r, a)
   142  
   143  	// (10)
   144  	a = nod(ORETURN, nil, nil)
   145  
   146  	r = append(r, a)
   147  	exportsym(fn.Func.Nname)
   148  
   149  	fn.Nbody.Set(r)
   150  	funcbody(fn)
   151  
   152  	Curfn = fn
   153  	fn = typecheck(fn, Etop)
   154  	typecheckslice(r, Etop)
   155  	Curfn = nil
   156  	funccompile(fn)
   157  }