github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/ir/func.go (about) 1 // Copyright 2020 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 ir 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 10 "github.com/bir3/gocompiler/src/cmd/internal/obj" 11 "github.com/bir3/gocompiler/src/cmd/internal/src" 12 "fmt" 13 ) 14 15 // A Func corresponds to a single function in a Go program 16 // (and vice versa: each function is denoted by exactly one *Func). 17 // 18 // There are multiple nodes that represent a Func in the IR. 19 // 20 // The ONAME node (Func.Nname) is used for plain references to it. 21 // The ODCLFUNC node (the Func itself) is used for its declaration code. 22 // The OCLOSURE node (Func.OClosure) is used for a reference to a 23 // function literal. 24 // 25 // An imported function will have an ONAME node which points to a Func 26 // with an empty body. 27 // A declared function or method has an ODCLFUNC (the Func itself) and an ONAME. 28 // A function literal is represented directly by an OCLOSURE, but it also 29 // has an ODCLFUNC (and a matching ONAME) representing the compiled 30 // underlying form of the closure, which accesses the captured variables 31 // using a special data structure passed in a register. 32 // 33 // A method declaration is represented like functions, except f.Sym 34 // will be the qualified method name (e.g., "T.m"). 35 // 36 // A method expression (T.M) is represented as an OMETHEXPR node, 37 // in which n.Left and n.Right point to the type and method, respectively. 38 // Each distinct mention of a method expression in the source code 39 // constructs a fresh node. 40 // 41 // A method value (t.M) is represented by ODOTMETH/ODOTINTER 42 // when it is called directly and by OMETHVALUE otherwise. 43 // These are like method expressions, except that for ODOTMETH/ODOTINTER, 44 // the method name is stored in Sym instead of Right. 45 // Each OMETHVALUE ends up being implemented as a new 46 // function, a bit like a closure, with its own ODCLFUNC. 47 // The OMETHVALUE uses n.Func to record the linkage to 48 // the generated ODCLFUNC, but there is no 49 // pointer from the Func back to the OMETHVALUE. 50 type Func struct { 51 miniNode 52 Body Nodes 53 54 Nname *Name // ONAME node 55 OClosure *ClosureExpr // OCLOSURE node 56 57 // Extra entry code for the function. For example, allocate and initialize 58 // memory for escaping parameters. 59 Enter Nodes 60 Exit Nodes 61 62 // ONAME nodes for all params/locals for this func/closure, does NOT 63 // include closurevars until transforming closures during walk. 64 // Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs, 65 // with PPARAMs and PPARAMOUTs in order corresponding to the function signature. 66 // However, as anonymous or blank PPARAMs are not actually declared, 67 // they are omitted from Dcl. 68 // Anonymous and blank PPARAMOUTs are declared as ~rNN and ~bNN Names, respectively. 69 Dcl []*Name 70 71 // ClosureVars lists the free variables that are used within a 72 // function literal, but formally declared in an enclosing 73 // function. The variables in this slice are the closure function's 74 // own copy of the variables, which are used within its function 75 // body. They will also each have IsClosureVar set, and will have 76 // Byval set if they're captured by value. 77 ClosureVars []*Name 78 79 // Enclosed functions that need to be compiled. 80 // Populated during walk. 81 Closures []*Func 82 83 // Parents records the parent scope of each scope within a 84 // function. The root scope (0) has no parent, so the i'th 85 // scope's parent is stored at Parents[i-1]. 86 Parents []ScopeID 87 88 // Marks records scope boundary changes. 89 Marks []Mark 90 91 FieldTrack map[*obj.LSym]struct{} 92 DebugInfo interface{} 93 LSym *obj.LSym // Linker object in this function's native ABI (Func.ABI) 94 95 Inl *Inline 96 97 // Closgen tracks how many closures have been generated within 98 // this function. Used by closurename for creating unique 99 // function names. 100 Closgen int32 101 102 Label int32 // largest auto-generated label in this function 103 104 Endlineno src.XPos 105 WBPos src.XPos // position of first write barrier; see SetWBPos 106 107 Pragma PragmaFlag // go:xxx function annotations 108 109 flags bitset16 110 111 // ABI is a function's "definition" ABI. This is the ABI that 112 // this function's generated code is expecting to be called by. 113 // 114 // For most functions, this will be obj.ABIInternal. It may be 115 // a different ABI for functions defined in assembly or ABI wrappers. 116 // 117 // This is included in the export data and tracked across packages. 118 ABI obj.ABI 119 // ABIRefs is the set of ABIs by which this function is referenced. 120 // For ABIs other than this function's definition ABI, the 121 // compiler generates ABI wrapper functions. This is only tracked 122 // within a package. 123 ABIRefs obj.ABISet 124 125 NumDefers int32 // number of defer calls in the function 126 NumReturns int32 // number of explicit returns in the function 127 128 // nwbrCalls records the LSyms of functions called by this 129 // function for go:nowritebarrierrec analysis. Only filled in 130 // if nowritebarrierrecCheck != nil. 131 NWBRCalls *[]SymAndPos 132 133 // For wrapper functions, WrappedFunc point to the original Func. 134 // Currently only used for go/defer wrappers. 135 WrappedFunc *Func 136 } 137 138 func NewFunc(pos src.XPos) *Func { 139 f := new(Func) 140 f.pos = pos 141 f.op = ODCLFUNC 142 // Most functions are ABIInternal. The importer or symabis 143 // pass may override this. 144 f.ABI = obj.ABIInternal 145 return f 146 } 147 148 func (f *Func) isStmt() {} 149 150 func (n *Func) copy() Node { panic(n.no("copy")) } 151 func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) } 152 func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) } 153 func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) } 154 155 func (f *Func) Type() *types.Type { return f.Nname.Type() } 156 func (f *Func) Sym() *types.Sym { return f.Nname.Sym() } 157 func (f *Func) Linksym() *obj.LSym { return f.Nname.Linksym() } 158 func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) } 159 160 // An Inline holds fields used for function bodies that can be inlined. 161 type Inline struct { 162 Cost int32 // heuristic cost of inlining this function 163 164 // Copies of Func.Dcl and Func.Body for use during inlining. Copies are 165 // needed because the function's dcl/body may be changed by later compiler 166 // transformations. These fields are also populated when a function from 167 // another package is imported. 168 Dcl []*Name 169 Body []Node 170 171 // CanDelayResults reports whether it's safe for the inliner to delay 172 // initializing the result parameters until immediately before the 173 // "return" statement. 174 CanDelayResults bool 175 } 176 177 // A Mark represents a scope boundary. 178 type Mark struct { 179 // Pos is the position of the token that marks the scope 180 // change. 181 Pos src.XPos 182 183 // Scope identifies the innermost scope to the right of Pos. 184 Scope ScopeID 185 } 186 187 // A ScopeID represents a lexical scope within a function. 188 type ScopeID int32 189 190 const ( 191 funcDupok = 1 << iota // duplicate definitions ok 192 funcWrapper // hide frame from users (elide in tracebacks, don't count as a frame for recover()) 193 funcABIWrapper // is an ABI wrapper (also set flagWrapper) 194 funcNeedctxt // function uses context register (has closure variables) 195 funcReflectMethod // function calls reflect.Type.Method or MethodByName 196 // true if closure inside a function; false if a simple function or a 197 // closure in a global variable initialization 198 funcIsHiddenClosure 199 funcIsDeadcodeClosure // true if closure is deadcode 200 funcHasDefer // contains a defer statement 201 funcNilCheckDisabled // disable nil checks when compiling this function 202 funcInlinabilityChecked // inliner has already determined whether the function is inlinable 203 funcExportInline // include inline body in export data 204 funcInstrumentBody // add race/msan/asan instrumentation during SSA construction 205 funcOpenCodedDeferDisallowed // can't do open-coded defers 206 funcClosureCalled // closure is only immediately called; used by escape analysis 207 ) 208 209 type SymAndPos struct { 210 Sym *obj.LSym // LSym of callee 211 Pos src.XPos // line of call 212 } 213 214 func (f *Func) Dupok() bool { return f.flags&funcDupok != 0 } 215 func (f *Func) Wrapper() bool { return f.flags&funcWrapper != 0 } 216 func (f *Func) ABIWrapper() bool { return f.flags&funcABIWrapper != 0 } 217 func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 } 218 func (f *Func) ReflectMethod() bool { return f.flags&funcReflectMethod != 0 } 219 func (f *Func) IsHiddenClosure() bool { return f.flags&funcIsHiddenClosure != 0 } 220 func (f *Func) IsDeadcodeClosure() bool { return f.flags&funcIsDeadcodeClosure != 0 } 221 func (f *Func) HasDefer() bool { return f.flags&funcHasDefer != 0 } 222 func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 } 223 func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 } 224 func (f *Func) ExportInline() bool { return f.flags&funcExportInline != 0 } 225 func (f *Func) InstrumentBody() bool { return f.flags&funcInstrumentBody != 0 } 226 func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 } 227 func (f *Func) ClosureCalled() bool { return f.flags&funcClosureCalled != 0 } 228 229 func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) } 230 func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) } 231 func (f *Func) SetABIWrapper(b bool) { f.flags.set(funcABIWrapper, b) } 232 func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) } 233 func (f *Func) SetReflectMethod(b bool) { f.flags.set(funcReflectMethod, b) } 234 func (f *Func) SetIsHiddenClosure(b bool) { f.flags.set(funcIsHiddenClosure, b) } 235 func (f *Func) SetIsDeadcodeClosure(b bool) { f.flags.set(funcIsDeadcodeClosure, b) } 236 func (f *Func) SetHasDefer(b bool) { f.flags.set(funcHasDefer, b) } 237 func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) } 238 func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) } 239 func (f *Func) SetExportInline(b bool) { f.flags.set(funcExportInline, b) } 240 func (f *Func) SetInstrumentBody(b bool) { f.flags.set(funcInstrumentBody, b) } 241 func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) } 242 func (f *Func) SetClosureCalled(b bool) { f.flags.set(funcClosureCalled, b) } 243 244 func (f *Func) SetWBPos(pos src.XPos) { 245 if base.Debug.WB != 0 { 246 base.WarnfAt(pos, "write barrier") 247 } 248 if !f.WBPos.IsKnown() { 249 f.WBPos = pos 250 } 251 } 252 253 // FuncName returns the name (without the package) of the function n. 254 func FuncName(f *Func) string { 255 if f == nil || f.Nname == nil { 256 return "<nil>" 257 } 258 return f.Sym().Name 259 } 260 261 // PkgFuncName returns the name of the function referenced by n, with package prepended. 262 // This differs from the compiler's internal convention where local functions lack a package 263 // because the ultimate consumer of this is a human looking at an IDE; package is only empty 264 // if the compilation package is actually the empty string. 265 func PkgFuncName(f *Func) string { 266 if f == nil || f.Nname == nil { 267 return "<nil>" 268 } 269 s := f.Sym() 270 pkg := s.Pkg 271 272 return pkg.Path + "." + s.Name 273 } 274 275 var CurFunc *Func 276 277 // WithFunc invokes do with CurFunc and base.Pos set to curfn and 278 // curfn.Pos(), respectively, and then restores their previous values 279 // before returning. 280 func WithFunc(curfn *Func, do func()) { 281 oldfn, oldpos := CurFunc, base.Pos 282 defer func() { CurFunc, base.Pos = oldfn, oldpos }() 283 284 CurFunc, base.Pos = curfn, curfn.Pos() 285 do() 286 } 287 288 func FuncSymName(s *types.Sym) string { 289 return s.Name + "·f" 290 } 291 292 // MarkFunc marks a node as a function. 293 func MarkFunc(n *Name) { 294 if n.Op() != ONAME || n.Class != Pxxx { 295 base.FatalfAt(n.Pos(), "expected ONAME/Pxxx node, got %v (%v/%v)", n, n.Op(), n.Class) 296 } 297 298 n.Class = PFUNC 299 n.Sym().SetFunc(true) 300 } 301 302 // ClosureDebugRuntimeCheck applies boilerplate checks for debug flags 303 // and compiling runtime. 304 func ClosureDebugRuntimeCheck(clo *ClosureExpr) { 305 if base.Debug.Closure > 0 { 306 if clo.Esc() == EscHeap { 307 base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars) 308 } else { 309 base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars) 310 } 311 } 312 if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap { 313 base.ErrorfAt(clo.Pos(), "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func)) 314 } 315 } 316 317 // IsTrivialClosure reports whether closure clo has an 318 // empty list of captured vars. 319 func IsTrivialClosure(clo *ClosureExpr) bool { 320 return len(clo.Func.ClosureVars) == 0 321 } 322 323 // globClosgen is like Func.Closgen, but for the global scope. 324 var globClosgen int32 325 326 // closureName generates a new unique name for a closure within outerfn. 327 func closureName(outerfn *Func) *types.Sym { 328 pkg := types.LocalPkg 329 outer := "glob." 330 prefix := "func" 331 gen := &globClosgen 332 333 if outerfn != nil { 334 if outerfn.OClosure != nil { 335 prefix = "" 336 } 337 338 pkg = outerfn.Sym().Pkg 339 outer = FuncName(outerfn) 340 341 // There may be multiple functions named "_". In those 342 // cases, we can't use their individual Closgens as it 343 // would lead to name clashes. 344 if !IsBlank(outerfn.Nname) { 345 gen = &outerfn.Closgen 346 } 347 } 348 349 *gen++ 350 return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen)) 351 } 352 353 // NewClosureFunc creates a new Func to represent a function literal. 354 // If hidden is true, then the closure is marked hidden (i.e., as a 355 // function literal contained within another function, rather than a 356 // package-scope variable initialization expression). 357 func NewClosureFunc(pos src.XPos, hidden bool) *Func { 358 fn := NewFunc(pos) 359 fn.SetIsHiddenClosure(hidden) 360 361 fn.Nname = NewNameAt(pos, BlankNode.Sym()) 362 fn.Nname.Func = fn 363 fn.Nname.Defn = fn 364 365 fn.OClosure = &ClosureExpr{Func: fn} 366 fn.OClosure.op = OCLOSURE 367 fn.OClosure.pos = pos 368 369 return fn 370 } 371 372 // NameClosure generates a unique for the given function literal, 373 // which must have appeared within outerfn. 374 func NameClosure(clo *ClosureExpr, outerfn *Func) { 375 fn := clo.Func 376 if fn.IsHiddenClosure() != (outerfn != nil) { 377 base.FatalfAt(clo.Pos(), "closure naming inconsistency: hidden %v, but outer %v", fn.IsHiddenClosure(), outerfn) 378 } 379 380 name := fn.Nname 381 if !IsBlank(name) { 382 base.FatalfAt(clo.Pos(), "closure already named: %v", name) 383 } 384 385 name.SetSym(closureName(outerfn)) 386 MarkFunc(name) 387 } 388 389 // UseClosure checks that the ginen function literal has been setup 390 // correctly, and then returns it as an expression. 391 // It must be called after clo.Func.ClosureVars has been set. 392 func UseClosure(clo *ClosureExpr, pkg *Package) Node { 393 fn := clo.Func 394 name := fn.Nname 395 396 if IsBlank(name) { 397 base.FatalfAt(fn.Pos(), "unnamed closure func: %v", fn) 398 } 399 // Caution: clo.Typecheck() is still 0 when UseClosure is called by 400 // tcClosure. 401 if fn.Typecheck() != 1 || name.Typecheck() != 1 { 402 base.FatalfAt(fn.Pos(), "missed typecheck: %v", fn) 403 } 404 if clo.Type() == nil || name.Type() == nil { 405 base.FatalfAt(fn.Pos(), "missing types: %v", fn) 406 } 407 if !types.Identical(clo.Type(), name.Type()) { 408 base.FatalfAt(fn.Pos(), "mismatched types: %v", fn) 409 } 410 411 if base.Flag.W > 1 { 412 s := fmt.Sprintf("new closure func: %v", fn) 413 Dump(s, fn) 414 } 415 416 if pkg != nil { 417 pkg.Decls = append(pkg.Decls, fn) 418 } 419 420 if false && IsTrivialClosure(clo) { 421 // TODO(mdempsky): Investigate if we can/should optimize this 422 // case. walkClosure already handles it later, but it could be 423 // useful to recognize earlier (e.g., it might allow multiple 424 // inlined calls to a function to share a common trivial closure 425 // func, rather than cloning it for each inlined call). 426 } 427 428 return clo 429 }