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 }