github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 (
     8  	"cmd/compile/internal/types"
     9  )
    10  
    11  // A function named init is a special case.
    12  // It is called by the initialization before main is run.
    13  // To make it unique within a package and also uncallable,
    14  // the name, normally "pkg.init", is altered to "pkg.init.0".
    15  var renameinitgen int
    16  
    17  func renameinit() *types.Sym {
    18  	s := lookupN("init.", renameinitgen)
    19  	renameinitgen++
    20  	return s
    21  }
    22  
    23  // anyinit reports whether there any interesting init statements.
    24  func anyinit(n []*Node) bool {
    25  	for _, ln := range n {
    26  		switch ln.Op {
    27  		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
    28  		case OAS:
    29  			if !ln.Left.isBlank() || !candiscard(ln.Right) {
    30  				return true
    31  			}
    32  		default:
    33  			return true
    34  		}
    35  	}
    36  
    37  	// is this main
    38  	if localpkg.Name == "main" {
    39  		return true
    40  	}
    41  
    42  	// is there an explicit init function
    43  	if renameinitgen > 0 {
    44  		return true
    45  	}
    46  
    47  	// are there any imported init functions
    48  	for _, s := range types.InitSyms {
    49  		if s.Def != nil {
    50  			return true
    51  		}
    52  	}
    53  
    54  	// then none
    55  	return false
    56  }
    57  
    58  // fninit hand-crafts package initialization code.
    59  //
    60  //      func init.ializers() {                          (0)
    61  //              <init stmts>
    62  //      }
    63  //      var initdone· uint8                             (1)
    64  //      func init() {                                   (2)
    65  //              if initdone· > 1 {                      (3)
    66  //                      return                          (3a)
    67  //              }
    68  //              if initdone· == 1 {                     (4)
    69  //                      throw()                         (4a)
    70  //              }
    71  //              initdone· = 1                           (5)
    72  //              // over all matching imported symbols
    73  //                      <pkg>.init()                    (6)
    74  //              init.ializers()                         (7)
    75  //              init.<n>() // if any                    (8)
    76  //              initdone· = 2                           (9)
    77  //              return                                  (10)
    78  //      }
    79  func fninit(n []*Node) {
    80  	lineno = autogeneratedPos
    81  	nf := initfix(n)
    82  	if !anyinit(nf) {
    83  		return
    84  	}
    85  
    86  	// (0)
    87  	// Make a function that contains all the initialization statements.
    88  	// This is a separate function because we want it to appear in
    89  	// stack traces, where the init function itself does not.
    90  	var initializers *types.Sym
    91  	if len(nf) > 0 {
    92  		lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt
    93  		initializers = lookup("init.ializers")
    94  		disableExport(initializers)
    95  		fn := dclfunc(initializers, nod(OTFUNC, nil, nil))
    96  		fn.Nbody.Set(nf)
    97  		funcbody()
    98  
    99  		fn = typecheck(fn, ctxStmt)
   100  		Curfn = fn
   101  		typecheckslice(nf, ctxStmt)
   102  		Curfn = nil
   103  		funccompile(fn)
   104  		lineno = autogeneratedPos
   105  	}
   106  
   107  	var r []*Node
   108  
   109  	// (1)
   110  	gatevar := newname(lookup("initdone·"))
   111  	addvar(gatevar, types.Types[TUINT8], PEXTERN)
   112  
   113  	// (2)
   114  	initsym := lookup("init")
   115  	fn := dclfunc(initsym, nod(OTFUNC, nil, nil))
   116  
   117  	// (3)
   118  	a := nod(OIF, nil, nil)
   119  	a.Left = nod(OGT, gatevar, nodintconst(1))
   120  	a.SetLikely(true)
   121  	r = append(r, a)
   122  	// (3a)
   123  	a.Nbody.Set1(nod(ORETURN, nil, nil))
   124  
   125  	// (4)
   126  	b := nod(OIF, nil, nil)
   127  	b.Left = nod(OEQ, gatevar, nodintconst(1))
   128  	// this actually isn't likely, but code layout is better
   129  	// like this: no JMP needed after the call.
   130  	b.SetLikely(true)
   131  	r = append(r, b)
   132  	// (4a)
   133  	b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil))
   134  
   135  	// (5)
   136  	a = nod(OAS, gatevar, nodintconst(1))
   137  
   138  	r = append(r, a)
   139  
   140  	// (6)
   141  	for _, s := range types.InitSyms {
   142  		if s == initsym {
   143  			continue
   144  		}
   145  		n := resolve(oldname(s))
   146  		if n.Op == ONONAME {
   147  			// No package-scope init function; just a
   148  			// local variable, field name, or something.
   149  			continue
   150  		}
   151  		n.checkInitFuncSignature()
   152  		a = nod(OCALL, n, nil)
   153  		r = append(r, a)
   154  	}
   155  
   156  	// (7)
   157  	if initializers != nil {
   158  		n := newname(initializers)
   159  		addvar(n, functype(nil, nil, nil), PFUNC)
   160  		r = append(r, nod(OCALL, n, nil))
   161  	}
   162  
   163  	// (8)
   164  
   165  	// maxInlineInitCalls is the threshold at which we switch
   166  	// from generating calls inline to generating a static array
   167  	// of functions and calling them in a loop.
   168  	// See CL 41500 for more discussion.
   169  	const maxInlineInitCalls = 500
   170  
   171  	if renameinitgen < maxInlineInitCalls {
   172  		// Not many init functions. Just call them all directly.
   173  		for i := 0; i < renameinitgen; i++ {
   174  			s := lookupN("init.", i)
   175  			n := asNode(s.Def)
   176  			n.checkInitFuncSignature()
   177  			a = nod(OCALL, n, nil)
   178  			r = append(r, a)
   179  		}
   180  	} else {
   181  		// Lots of init functions.
   182  		// Set up an array of functions and loop to call them.
   183  		// This is faster to compile and similar at runtime.
   184  
   185  		// Build type [renameinitgen]func().
   186  		typ := types.NewArray(functype(nil, nil, nil), int64(renameinitgen))
   187  
   188  		// Make and fill array.
   189  		fnarr := staticname(typ)
   190  		fnarr.Name.SetReadonly(true)
   191  		for i := 0; i < renameinitgen; i++ {
   192  			s := lookupN("init.", i)
   193  			lhs := nod(OINDEX, fnarr, nodintconst(int64(i)))
   194  			rhs := asNode(s.Def)
   195  			rhs.checkInitFuncSignature()
   196  			as := nod(OAS, lhs, rhs)
   197  			as = typecheck(as, ctxStmt)
   198  			genAsStatic(as)
   199  		}
   200  
   201  		// Generate a loop that calls each function in turn.
   202  		// for i := 0; i < renameinitgen; i++ {
   203  		//   fnarr[i]()
   204  		// }
   205  		i := temp(types.Types[TINT])
   206  		fnidx := nod(OINDEX, fnarr, i)
   207  		fnidx.SetBounded(true)
   208  
   209  		zero := nod(OAS, i, nodintconst(0))
   210  		cond := nod(OLT, i, nodintconst(int64(renameinitgen)))
   211  		incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
   212  		body := nod(OCALL, fnidx, nil)
   213  
   214  		loop := nod(OFOR, cond, incr)
   215  		loop.Nbody.Set1(body)
   216  		loop.Ninit.Set1(zero)
   217  
   218  		loop = typecheck(loop, ctxStmt)
   219  		r = append(r, loop)
   220  	}
   221  
   222  	// (9)
   223  	a = nod(OAS, gatevar, nodintconst(2))
   224  
   225  	r = append(r, a)
   226  
   227  	// (10)
   228  	a = nod(ORETURN, nil, nil)
   229  
   230  	r = append(r, a)
   231  	exportsym(fn.Func.Nname)
   232  
   233  	fn.Nbody.Set(r)
   234  	funcbody()
   235  
   236  	Curfn = fn
   237  	fn = typecheck(fn, ctxStmt)
   238  	typecheckslice(r, ctxStmt)
   239  	Curfn = nil
   240  	funccompile(fn)
   241  }
   242  
   243  func (n *Node) checkInitFuncSignature() {
   244  	if n.Type.NumRecvs()+n.Type.NumParams()+n.Type.NumResults() > 0 {
   245  		Fatalf("init function cannot have receiver, params, or results: %v (%v)", n, n.Type)
   246  	}
   247  }