github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/pkginit/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 pkginit
     6  
     7  import (
     8  	"github.com/bir3/gocompiler/src/cmd/compile/internal/base"
     9  	"github.com/bir3/gocompiler/src/cmd/compile/internal/ir"
    10  	"github.com/bir3/gocompiler/src/cmd/compile/internal/noder"
    11  	"github.com/bir3/gocompiler/src/cmd/compile/internal/objw"
    12  	"github.com/bir3/gocompiler/src/cmd/compile/internal/staticinit"
    13  	"github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck"
    14  	"github.com/bir3/gocompiler/src/cmd/compile/internal/types"
    15  	"github.com/bir3/gocompiler/src/cmd/internal/obj"
    16  	"github.com/bir3/gocompiler/src/cmd/internal/src"
    17  )
    18  
    19  // MakeInit creates a synthetic init function to handle any
    20  // package-scope initialization statements.
    21  //
    22  // TODO(mdempsky): Move into noder, so that the types2-based frontends
    23  // can use Info.InitOrder instead.
    24  func MakeInit() {
    25  	nf := initOrder(typecheck.Target.Decls)
    26  	if len(nf) == 0 {
    27  		return
    28  	}
    29  
    30  	// Make a function that contains all the initialization statements.
    31  	base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
    32  	initializers := typecheck.Lookup("init")
    33  	fn := typecheck.DeclFunc(initializers, nil, nil, nil)
    34  	for _, dcl := range typecheck.InitTodoFunc.Dcl {
    35  		dcl.Curfn = fn
    36  	}
    37  	fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
    38  	typecheck.InitTodoFunc.Dcl = nil
    39  
    40  	// Suppress useless "can inline" diagnostics.
    41  	// Init functions are only called dynamically.
    42  	fn.SetInlinabilityChecked(true)
    43  
    44  	fn.Body = nf
    45  	typecheck.FinishFuncBody()
    46  
    47  	typecheck.Func(fn)
    48  	ir.WithFunc(fn, func() {
    49  		typecheck.Stmts(nf)
    50  	})
    51  	typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
    52  
    53  	// Prepend to Inits, so it runs first, before any user-declared init
    54  	// functions.
    55  	typecheck.Target.Inits = append([]*ir.Func{fn}, typecheck.Target.Inits...)
    56  
    57  	if typecheck.InitTodoFunc.Dcl != nil {
    58  		// We only generate temps using InitTodoFunc if there
    59  		// are package-scope initialization statements, so
    60  		// something's weird if we get here.
    61  		base.Fatalf("InitTodoFunc still has declarations")
    62  	}
    63  	typecheck.InitTodoFunc = nil
    64  }
    65  
    66  // Task makes and returns an initialization record for the package.
    67  // See runtime/proc.go:initTask for its layout.
    68  // The 3 tasks for initialization are:
    69  //  1. Initialize all of the packages the current package depends on.
    70  //  2. Initialize all the variables that have initializers.
    71  //  3. Run any init functions.
    72  func Task() *ir.Name {
    73  	var deps []*obj.LSym // initTask records for packages the current package depends on
    74  	var fns []*obj.LSym  // functions to call for package initialization
    75  
    76  	// Find imported packages with init tasks.
    77  	for _, pkg := range typecheck.Target.Imports {
    78  		n := typecheck.Resolve(ir.NewIdent(base.Pos, pkg.Lookup(".inittask")))
    79  		if n.Op() == ir.ONONAME {
    80  			continue
    81  		}
    82  		if n.Op() != ir.ONAME || n.(*ir.Name).Class != ir.PEXTERN {
    83  			base.Fatalf("bad inittask: %v", n)
    84  		}
    85  		deps = append(deps, n.(*ir.Name).Linksym())
    86  	}
    87  	if base.Flag.ASan {
    88  		// Make an initialization function to call runtime.asanregisterglobals to register an
    89  		// array of instrumented global variables when -asan is enabled. An instrumented global
    90  		// variable is described by a structure.
    91  		// See the _asan_global structure declared in src/runtime/asan/asan.go.
    92  		//
    93  		// func init {
    94  		// 		var globals []_asan_global {...}
    95  		// 		asanregisterglobals(&globals[0], len(globals))
    96  		// }
    97  		for _, n := range typecheck.Target.Externs {
    98  			if canInstrumentGlobal(n) {
    99  				name := n.Sym().Name
   100  				InstrumentGlobalsMap[name] = n
   101  				InstrumentGlobalsSlice = append(InstrumentGlobalsSlice, n)
   102  			}
   103  		}
   104  		ni := len(InstrumentGlobalsMap)
   105  		if ni != 0 {
   106  			// Make an init._ function.
   107  			base.Pos = base.AutogeneratedPos
   108  			typecheck.DeclContext = ir.PEXTERN
   109  			name := noder.Renameinit()
   110  			fnInit := typecheck.DeclFunc(name, nil, nil, nil)
   111  
   112  			// Get an array of intrumented global variables.
   113  			globals := instrumentGlobals(fnInit)
   114  
   115  			// Call runtime.asanregisterglobals function to poison redzones.
   116  			// runtime.asanregisterglobals(unsafe.Pointer(&globals[0]), ni)
   117  			asanf := typecheck.NewName(ir.Pkgs.Runtime.Lookup("asanregisterglobals"))
   118  			ir.MarkFunc(asanf)
   119  			asanf.SetType(types.NewSignature(types.NoPkg, nil, nil, []*types.Field{
   120  				types.NewField(base.Pos, nil, types.Types[types.TUNSAFEPTR]),
   121  				types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
   122  			}, nil))
   123  			asancall := ir.NewCallExpr(base.Pos, ir.OCALL, asanf, nil)
   124  			asancall.Args.Append(typecheck.ConvNop(typecheck.NodAddr(
   125  				ir.NewIndexExpr(base.Pos, globals, ir.NewInt(0))), types.Types[types.TUNSAFEPTR]))
   126  			asancall.Args.Append(typecheck.ConvNop(ir.NewInt(int64(ni)), types.Types[types.TUINTPTR]))
   127  
   128  			fnInit.Body.Append(asancall)
   129  			typecheck.FinishFuncBody()
   130  			typecheck.Func(fnInit)
   131  			ir.CurFunc = fnInit
   132  			typecheck.Stmts(fnInit.Body)
   133  			ir.CurFunc = nil
   134  
   135  			typecheck.Target.Decls = append(typecheck.Target.Decls, fnInit)
   136  			typecheck.Target.Inits = append(typecheck.Target.Inits, fnInit)
   137  		}
   138  	}
   139  
   140  	// Record user init functions.
   141  	for _, fn := range typecheck.Target.Inits {
   142  		if fn.Sym().Name == "init" {
   143  			// Synthetic init function for initialization of package-scope
   144  			// variables. We can use staticinit to optimize away static
   145  			// assignments.
   146  			s := staticinit.Schedule{
   147  				Plans: make(map[ir.Node]*staticinit.Plan),
   148  				Temps: make(map[ir.Node]*ir.Name),
   149  			}
   150  			for _, n := range fn.Body {
   151  				s.StaticInit(n)
   152  			}
   153  			fn.Body = s.Out
   154  			ir.WithFunc(fn, func() {
   155  				typecheck.Stmts(fn.Body)
   156  			})
   157  
   158  			if len(fn.Body) == 0 {
   159  				fn.Body = []ir.Node{ir.NewBlockStmt(src.NoXPos, nil)}
   160  			}
   161  		}
   162  
   163  		// Skip init functions with empty bodies.
   164  		if len(fn.Body) == 1 {
   165  			if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
   166  				continue
   167  			}
   168  		}
   169  		fns = append(fns, fn.Nname.Linksym())
   170  	}
   171  
   172  	if len(deps) == 0 && len(fns) == 0 && types.LocalPkg.Path != "main" && types.LocalPkg.Path != "runtime" {
   173  		return nil // nothing to initialize
   174  	}
   175  
   176  	// Make an .inittask structure.
   177  	sym := typecheck.Lookup(".inittask")
   178  	task := typecheck.NewName(sym)
   179  	task.SetType(types.Types[types.TUINT8]) // fake type
   180  	task.Class = ir.PEXTERN
   181  	sym.Def = task
   182  	lsym := task.Linksym()
   183  	ot := 0
   184  	ot = objw.Uintptr(lsym, ot, 0) // state: not initialized yet
   185  	ot = objw.Uintptr(lsym, ot, uint64(len(deps)))
   186  	ot = objw.Uintptr(lsym, ot, uint64(len(fns)))
   187  	for _, d := range deps {
   188  		ot = objw.SymPtr(lsym, ot, d, 0)
   189  	}
   190  	for _, f := range fns {
   191  		ot = objw.SymPtr(lsym, ot, f, 0)
   192  	}
   193  	// An initTask has pointers, but none into the Go heap.
   194  	// It's not quite read only, the state field must be modifiable.
   195  	objw.Global(lsym, int32(ot), obj.NOPTR)
   196  	return task
   197  }
   198  
   199  // initRequiredForCoverage returns TRUE if we need to force creation
   200  // of an init function for the package so as to insert a coverage
   201  // runtime registration call.
   202  func initRequiredForCoverage(l []ir.Node) bool {
   203  	if base.Flag.Cfg.CoverageInfo == nil {
   204  		return false
   205  	}
   206  	for _, n := range l {
   207  		if n.Op() == ir.ODCLFUNC {
   208  			return true
   209  		}
   210  	}
   211  	return false
   212  }