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