github.com/euank/go@v0.0.0-20160829210321-495514729181/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 LookupN("init.", renameinit_initgen)
    31  }
    32  
    33  // hand-craft the following initialization code
    34  //      var initdone· uint8                             (1)
    35  //      func init() {                                   (2)
    36  //              if initdone· > 1 {                      (3)
    37  //                      return                          (3a)
    38  //              }
    39  //              if initdone· == 1 {                     (4)
    40  //                      throw()                         (4a)
    41  //              }
    42  //              initdone· = 1                           (5)
    43  //              // over all matching imported symbols
    44  //                      <pkg>.init()                    (6)
    45  //              { <init stmts> }                        (7)
    46  //              init.<n>() // if any                    (8)
    47  //              initdone· = 2                           (9)
    48  //              return                                  (10)
    49  //      }
    50  func anyinit(n []*Node) bool {
    51  	// are there any interesting init statements
    52  	for _, ln := range n {
    53  		switch ln.Op {
    54  		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
    55  			break
    56  
    57  		case OAS, OASWB:
    58  			if isblank(ln.Left) && candiscard(ln.Right) {
    59  				break
    60  			}
    61  			fallthrough
    62  		default:
    63  			return true
    64  		}
    65  	}
    66  
    67  	// is this main
    68  	if localpkg.Name == "main" {
    69  		return true
    70  	}
    71  
    72  	// is there an explicit init function
    73  	s := Lookup("init.1")
    74  
    75  	if s.Def != nil {
    76  		return true
    77  	}
    78  
    79  	// are there any imported init functions
    80  	for _, s := range initSyms {
    81  		if s.Def != nil {
    82  			return true
    83  		}
    84  	}
    85  
    86  	// then none
    87  	return false
    88  }
    89  
    90  func fninit(n []*Node) {
    91  	if Debug['A'] != 0 {
    92  		// sys.go or unsafe.go during compiler build
    93  		return
    94  	}
    95  
    96  	nf := initfix(n)
    97  	if !anyinit(nf) {
    98  		return
    99  	}
   100  
   101  	var r []*Node
   102  
   103  	// (1)
   104  	gatevar := newname(Lookup("initdone·"))
   105  	addvar(gatevar, Types[TUINT8], PEXTERN)
   106  
   107  	// (2)
   108  	Maxarg = 0
   109  
   110  	fn := Nod(ODCLFUNC, nil, nil)
   111  	initsym := Lookup("init")
   112  	fn.Func.Nname = newname(initsym)
   113  	fn.Func.Nname.Name.Defn = fn
   114  	fn.Func.Nname.Name.Param.Ntype = Nod(OTFUNC, nil, nil)
   115  	declare(fn.Func.Nname, PFUNC)
   116  	funchdr(fn)
   117  
   118  	// (3)
   119  	a := Nod(OIF, nil, nil)
   120  	a.Left = Nod(OGT, gatevar, Nodintconst(1))
   121  	a.Likely = 1
   122  	r = append(r, a)
   123  	// (3a)
   124  	a.Nbody.Set1(Nod(ORETURN, nil, nil))
   125  
   126  	// (4)
   127  	b := Nod(OIF, nil, nil)
   128  	b.Left = Nod(OEQ, gatevar, Nodintconst(1))
   129  	// this actually isn't likely, but code layout is better
   130  	// like this: no JMP needed after the call.
   131  	b.Likely = 1
   132  	r = append(r, b)
   133  	// (4a)
   134  	b.Nbody.Set1(Nod(OCALL, syslook("throwinit"), nil))
   135  
   136  	// (5)
   137  	a = Nod(OAS, gatevar, Nodintconst(1))
   138  
   139  	r = append(r, a)
   140  
   141  	// (6)
   142  	for _, s := range initSyms {
   143  		if s.Def != nil && s != initsym {
   144  			// could check that it is fn of no args/returns
   145  			a = Nod(OCALL, s.Def, nil)
   146  			r = append(r, a)
   147  		}
   148  	}
   149  
   150  	// (7)
   151  	r = append(r, nf...)
   152  
   153  	// (8)
   154  	// could check that it is fn of no args/returns
   155  	for i := 1; ; i++ {
   156  		s := LookupN("init.", i)
   157  		if s.Def == nil {
   158  			break
   159  		}
   160  		a = Nod(OCALL, s.Def, nil)
   161  		r = append(r, a)
   162  	}
   163  
   164  	// (9)
   165  	a = Nod(OAS, gatevar, Nodintconst(2))
   166  
   167  	r = append(r, a)
   168  
   169  	// (10)
   170  	a = Nod(ORETURN, nil, nil)
   171  
   172  	r = append(r, a)
   173  	exportsym(fn.Func.Nname)
   174  
   175  	fn.Nbody.Set(r)
   176  	funcbody(fn)
   177  
   178  	Curfn = fn
   179  	fn = typecheck(fn, Etop)
   180  	typecheckslice(r, Etop)
   181  	Curfn = nil
   182  	funccompile(fn)
   183  }