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