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.
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/types"
18 // A Func corresponds to a single function in a Go program
19 // (and vice versa: each function is denoted by exactly one *Func).
21 // There are multiple nodes that represent a Func in the IR.
23 // The ONAME node (Func.Nname) is used for plain references to it.
24 // The ODCLFUNC node (the Func itself) is used for its declaration code.
25 // The OCLOSURE node (Func.OClosure) is used for a reference to a
28 // An imported function will have an ONAME node which points to a Func
29 // with an empty body.
30 // A declared function or method has an ODCLFUNC (the Func itself) and an ONAME.
31 // A function literal is represented directly by an OCLOSURE, but it also
32 // has an ODCLFUNC (and a matching ONAME) representing the compiled
33 // underlying form of the closure, which accesses the captured variables
34 // using a special data structure passed in a register.
36 // A method declaration is represented like functions, except f.Sym
37 // will be the qualified method name (e.g., "T.m").
39 // A method expression (T.M) is represented as an OMETHEXPR node,
40 // in which n.Left and n.Right point to the type and method, respectively.
41 // Each distinct mention of a method expression in the source code
42 // constructs a fresh node.
44 // A method value (t.M) is represented by ODOTMETH/ODOTINTER
45 // when it is called directly and by OMETHVALUE otherwise.
46 // These are like method expressions, except that for ODOTMETH/ODOTINTER,
47 // the method name is stored in Sym instead of Right.
48 // Each OMETHVALUE ends up being implemented as a new
49 // function, a bit like a closure, with its own ODCLFUNC.
50 // The OMETHVALUE uses n.Func to record the linkage to
51 // the generated ODCLFUNC, but there is no
52 // pointer from the Func back to the OMETHVALUE.
57 Nname *Name // ONAME node
58 OClosure *ClosureExpr // OCLOSURE node
60 // ONAME nodes for all params/locals for this func/closure, does NOT
61 // include closurevars until transforming closures during walk.
62 // Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
63 // with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
64 // Anonymous and blank params are declared as ~pNN (for PPARAMs) and ~rNN (for PPARAMOUTs).
67 // ClosureVars lists the free variables that are used within a
68 // function literal, but formally declared in an enclosing
69 // function. The variables in this slice are the closure function's
70 // own copy of the variables, which are used within its function
71 // body. They will also each have IsClosureVar set, and will have
72 // Byval set if they're captured by value.
75 // Enclosed functions that need to be compiled.
76 // Populated during walk.
79 // Parents records the parent scope of each scope within a
80 // function. The root scope (0) has no parent, so the i'th
81 // scope's parent is stored at Parents[i-1].
84 // Marks records scope boundary changes.
87 FieldTrack map[*obj.LSym]struct{}
89 LSym *obj.LSym // Linker object in this function's native ABI (Func.ABI)
93 // funcLitGen and goDeferGen track how many closures have been
94 // created in this function for function literals and go/defer
95 // wrappers, respectively. Used by closureName for creating unique
98 // Tracking goDeferGen separately avoids wrappers throwing off
99 // function literal numbering (e.g., runtime/trace_test.TestTraceSymbolize.func11).
103 Label int32 // largest auto-generated label in this function
106 WBPos src.XPos // position of first write barrier; see SetWBPos
108 Pragma PragmaFlag // go:xxx function annotations
112 // ABI is a function's "definition" ABI. This is the ABI that
113 // this function's generated code is expecting to be called by.
115 // For most functions, this will be obj.ABIInternal. It may be
116 // a different ABI for functions defined in assembly or ABI wrappers.
118 // This is included in the export data and tracked across packages.
120 // ABIRefs is the set of ABIs by which this function is referenced.
121 // For ABIs other than this function's definition ABI, the
122 // compiler generates ABI wrapper functions. This is only tracked
126 NumDefers int32 // number of defer calls in the function
127 NumReturns int32 // number of explicit returns in the function
129 // nwbrCalls records the LSyms of functions called by this
130 // function for go:nowritebarrierrec analysis. Only filled in
131 // if nowritebarrierrecCheck != nil.
132 NWBRCalls *[]SymAndPos
134 // For wrapper functions, WrappedFunc point to the original Func.
135 // Currently only used for go/defer wrappers.
138 // WasmImport is used by the //go:wasmimport directive to store info about
139 // a WebAssembly function import.
140 WasmImport *WasmImport
143 // WasmImport stores metadata associated with the //go:wasmimport pragma.
144 type WasmImport struct {
149 // NewFunc returns a new Func with the given name and type.
151 // fpos is the position of the "func" token, and npos is the position
152 // of the name identifier.
154 // TODO(mdempsky): I suspect there's no need for separate fpos and
156 func NewFunc(fpos, npos src.XPos, sym *types.Sym, typ *types.Type) *Func {
157 name := NewNameAt(npos, sym, typ)
161 fn := &Func{Nname: name}
164 // Most functions are ABIInternal. The importer or symabis
165 // pass may override this.
166 fn.ABI = obj.ABIInternal
174 func (f *Func) isStmt() {}
176 func (n *Func) copy() Node { panic(n.no("copy")) }
177 func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
178 func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
179 func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
181 func (f *Func) Type() *types.Type { return f.Nname.Type() }
182 func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
183 func (f *Func) Linksym() *obj.LSym { return f.Nname.Linksym() }
184 func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) }
186 // An Inline holds fields used for function bodies that can be inlined.
188 Cost int32 // heuristic cost of inlining this function
190 // Copy of Func.Dcl for use during inlining. This copy is needed
191 // because the function's Dcl may change from later compiler
192 // transformations. This field is also populated when a function
193 // from another package is imported and inlined.
195 HaveDcl bool // whether we've loaded Dcl
197 // Function properties, encoded as a string (these are used for
198 // making inlining decisions). See cmd/compile/internal/inline/inlheur.
201 // CanDelayResults reports whether it's safe for the inliner to delay
202 // initializing the result parameters until immediately before the
203 // "return" statement.
207 // A Mark represents a scope boundary.
209 // Pos is the position of the token that marks the scope
213 // Scope identifies the innermost scope to the right of Pos.
217 // A ScopeID represents a lexical scope within a function.
221 funcDupok = 1 << iota // duplicate definitions ok
222 funcWrapper // hide frame from users (elide in tracebacks, don't count as a frame for recover())
223 funcABIWrapper // is an ABI wrapper (also set flagWrapper)
224 funcNeedctxt // function uses context register (has closure variables)
225 // true if closure inside a function; false if a simple function or a
226 // closure in a global variable initialization
228 funcIsDeadcodeClosure // true if closure is deadcode
229 funcHasDefer // contains a defer statement
230 funcNilCheckDisabled // disable nil checks when compiling this function
231 funcInlinabilityChecked // inliner has already determined whether the function is inlinable
232 funcNeverReturns // function never returns (in most cases calls panic(), os.Exit(), or equivalent)
233 funcOpenCodedDeferDisallowed // can't do open-coded defers
234 funcClosureResultsLost // closure is called indirectly and we lost track of its results; used by escape analysis
235 funcPackageInit // compiler emitted .init func for package
238 type SymAndPos struct {
239 Sym *obj.LSym // LSym of callee
240 Pos src.XPos // line of call
243 func (f *Func) Dupok() bool { return f.flags&funcDupok != 0 }
244 func (f *Func) Wrapper() bool { return f.flags&funcWrapper != 0 }
245 func (f *Func) ABIWrapper() bool { return f.flags&funcABIWrapper != 0 }
246 func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 }
247 func (f *Func) IsHiddenClosure() bool { return f.flags&funcIsHiddenClosure != 0 }
248 func (f *Func) IsDeadcodeClosure() bool { return f.flags&funcIsDeadcodeClosure != 0 }
249 func (f *Func) HasDefer() bool { return f.flags&funcHasDefer != 0 }
250 func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 }
251 func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 }
252 func (f *Func) NeverReturns() bool { return f.flags&funcNeverReturns != 0 }
253 func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
254 func (f *Func) ClosureResultsLost() bool { return f.flags&funcClosureResultsLost != 0 }
255 func (f *Func) IsPackageInit() bool { return f.flags&funcPackageInit != 0 }
257 func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) }
258 func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) }
259 func (f *Func) SetABIWrapper(b bool) { f.flags.set(funcABIWrapper, b) }
260 func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) }
261 func (f *Func) SetIsHiddenClosure(b bool) { f.flags.set(funcIsHiddenClosure, b) }
262 func (f *Func) SetIsDeadcodeClosure(b bool) { f.flags.set(funcIsDeadcodeClosure, b) }
263 func (f *Func) SetHasDefer(b bool) { f.flags.set(funcHasDefer, b) }
264 func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) }
265 func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) }
266 func (f *Func) SetNeverReturns(b bool) { f.flags.set(funcNeverReturns, b) }
267 func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
268 func (f *Func) SetClosureResultsLost(b bool) { f.flags.set(funcClosureResultsLost, b) }
269 func (f *Func) SetIsPackageInit(b bool) { f.flags.set(funcPackageInit, b) }
271 func (f *Func) SetWBPos(pos src.XPos) {
272 if base.Debug.WB != 0 {
273 base.WarnfAt(pos, "write barrier")
275 if !f.WBPos.IsKnown() {
280 // FuncName returns the name (without the package) of the function f.
281 func FuncName(f *Func) string {
282 if f == nil || f.Nname == nil {
288 // PkgFuncName returns the name of the function referenced by f, with package
291 // This differs from the compiler's internal convention where local functions
292 // lack a package. This is primarily useful when the ultimate consumer of this
293 // is a human looking at message.
294 func PkgFuncName(f *Func) string {
295 if f == nil || f.Nname == nil {
301 return pkg.Path + "." + s.Name
304 // LinkFuncName returns the name of the function f, as it will appear in the
305 // symbol table of the final linked binary.
306 func LinkFuncName(f *Func) string {
307 if f == nil || f.Nname == nil {
313 return objabi.PathToPrefix(pkg.Path) + "." + s.Name
316 // ParseLinkFuncName parsers a symbol name (as returned from LinkFuncName) back
317 // to the package path and local symbol name.
318 func ParseLinkFuncName(name string) (pkg, sym string, err error) {
319 pkg, sym = splitPkg(name)
321 return "", "", fmt.Errorf("no package path in name")
324 pkg, err = objabi.PrefixToPath(pkg) // unescape
326 return "", "", fmt.Errorf("malformed package path: %v", err)
332 // Borrowed from x/mod.
333 func modPathOK(r rune) bool {
334 if r < utf8.RuneSelf {
335 return r == '-' || r == '.' || r == '_' || r == '~' ||
336 '0' <= r && r <= '9' ||
337 'A' <= r && r <= 'Z' ||
343 func escapedImportPathOK(r rune) bool {
344 return modPathOK(r) || r == '+' || r == '/' || r == '%'
347 // splitPkg splits the full linker symbol name into package and local symbol
349 func splitPkg(name string) (pkgpath, sym string) {
350 // package-sym split is at first dot after last the / that comes before
351 // any characters illegal in a package path.
354 for i, r := range name {
355 // Catches cases like:
356 // * example.foo[sync/atomic.Uint64].
357 // * example%2ecom.foo[sync/atomic.Uint64].
359 // Note that name is still escaped; unescape occurs after splitPkg.
360 if !escapedImportPathOK(r) {
367 for i := lastSlashIdx; i < len(name); i++ {
370 return name[:i], name[i+1:]
379 // WithFunc invokes do with CurFunc and base.Pos set to curfn and
380 // curfn.Pos(), respectively, and then restores their previous values
382 func WithFunc(curfn *Func, do func()) {
383 oldfn, oldpos := CurFunc, base.Pos
384 defer func() { CurFunc, base.Pos = oldfn, oldpos }()
386 CurFunc, base.Pos = curfn, curfn.Pos()
390 func FuncSymName(s *types.Sym) string {
394 // ClosureDebugRuntimeCheck applies boilerplate checks for debug flags
395 // and compiling runtime.
396 func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
397 if base.Debug.Closure > 0 {
398 if clo.Esc() == EscHeap {
399 base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
401 base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
404 if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap {
405 base.ErrorfAt(clo.Pos(), 0, "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func))
409 // IsTrivialClosure reports whether closure clo has an
410 // empty list of captured vars.
411 func IsTrivialClosure(clo *ClosureExpr) bool {
412 return len(clo.Func.ClosureVars) == 0
415 // globClosgen is like Func.Closgen, but for the global scope.
416 var globClosgen int32
418 // closureName generates a new unique name for a closure within outerfn at pos.
419 func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
420 pkg := types.LocalPkg
425 base.FatalfAt(pos, "closureName: bad Op: %v", why)
427 if outerfn == nil || outerfn.OClosure == nil {
437 // There may be multiple functions named "_". In those
438 // cases, we can't use their individual Closgens as it
439 // would lead to name clashes.
440 if outerfn != nil && !IsBlank(outerfn.Nname) {
441 pkg = outerfn.Sym().Pkg
442 outer = FuncName(outerfn)
445 gen = &outerfn.funcLitGen
447 gen = &outerfn.goDeferGen
451 // If this closure was created due to inlining, then incorporate any
452 // inlined functions' names into the closure's linker symbol name
454 if inlIndex := base.Ctxt.InnermostPos(pos).Base().InliningIndex(); inlIndex >= 0 {
455 names := []string{outer}
456 base.Ctxt.InlTree.AllParents(inlIndex, func(call obj.InlinedCall) {
457 names = append(names, call.Name)
459 outer = strings.Join(names, ".")
463 return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
466 // NewClosureFunc creates a new Func to represent a function literal
467 // with the given type.
469 // fpos the position used for the underlying ODCLFUNC and ONAME,
470 // whereas cpos is the position used for the OCLOSURE. They're
471 // separate because in the presence of inlining, the OCLOSURE node
472 // should have an inline-adjusted position, whereas the ODCLFUNC and
475 // outerfn is the enclosing function, if any. The returned function is
476 // appending to pkg.Funcs.
478 // why is the reason we're generating this Func. It can be OCLOSURE
479 // (for a normal function literal) or OGO or ODEFER (for wrapping a
480 // call expression that has parameters or results).
481 func NewClosureFunc(fpos, cpos src.XPos, why Op, typ *types.Type, outerfn *Func, pkg *Package) *Func {
482 fn := NewFunc(fpos, fpos, closureName(outerfn, cpos, why), typ)
483 fn.SetIsHiddenClosure(outerfn != nil)
485 clo := &ClosureExpr{Func: fn}
493 pkg.Funcs = append(pkg.Funcs, fn)
498 // IsFuncPCIntrinsic returns whether n is a direct call of internal/abi.FuncPCABIxxx functions.
499 func IsFuncPCIntrinsic(n *CallExpr) bool {
500 if n.Op() != OCALLFUNC || n.Fun.Op() != ONAME {
503 fn := n.Fun.(*Name).Sym()
504 return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
505 fn.Pkg.Path == "internal/abi"
508 // IsIfaceOfFunc inspects whether n is an interface conversion from a direct
509 // reference of a func. If so, it returns referenced Func; otherwise nil.
511 // This is only usable before walk.walkConvertInterface, which converts to an
513 func IsIfaceOfFunc(n Node) *Func {
514 if n, ok := n.(*ConvExpr); ok && n.Op() == OCONVIFACE {
515 if name, ok := n.X.(*Name); ok && name.Op() == ONAME && name.Class == PFUNC {
522 // FuncPC returns a uintptr-typed expression that evaluates to the PC of a
523 // function as uintptr, as returned by internal/abi.FuncPC{ABI0,ABIInternal}.
525 // n should be a Node of an interface type, as is passed to
526 // internal/abi.FuncPC{ABI0,ABIInternal}.
528 // TODO(prattmic): Since n is simply an interface{} there is no assertion that
529 // it is actually a function at all. Perhaps we should emit a runtime type
531 func FuncPC(pos src.XPos, n Node, wantABI obj.ABI) Node {
532 if !n.Type().IsInterface() {
533 base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an interface value, got %v", wantABI, n.Type())
536 if fn := IsIfaceOfFunc(n); fn != nil {
540 base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an %v function, %s is defined as %v", wantABI, wantABI, name.Sym().Name, abi)
542 var e Node = NewLinksymExpr(pos, name.Sym().LinksymABI(abi), types.Types[types.TUINTPTR])
543 e = NewAddrExpr(pos, e)
544 e.SetType(types.Types[types.TUINTPTR].PtrTo())
545 e = NewConvExpr(pos, OCONVNOP, types.Types[types.TUINTPTR], e)
549 // fn is not a defined function. It must be ABIInternal.
550 // Read the address from func value, i.e. *(*uintptr)(idata(fn)).
551 if wantABI != obj.ABIInternal {
552 base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s does not accept func expression, which is ABIInternal", wantABI)
554 var e Node = NewUnaryExpr(pos, OIDATA, n)
555 e.SetType(types.Types[types.TUINTPTR].PtrTo())
557 e = NewStarExpr(pos, e)
558 e.SetType(types.Types[types.TUINTPTR])
563 // DeclareParams creates Names for all of the parameters in fn's
564 // signature and adds them to fn.Dcl.
566 // If setNname is true, then it also sets types.Field.Nname for each
568 func (fn *Func) DeclareParams(setNname bool) {
570 base.FatalfAt(fn.Pos(), "%v already has Dcl", fn)
573 declareParams := func(params []*types.Field, ctxt Class, prefix string, offset int) {
574 for i, param := range params {
576 if sym == nil || sym.IsBlank() {
577 sym = fn.Sym().Pkg.LookupNum(prefix, i)
580 name := NewNameAt(param.Pos, sym, param.Type)
583 fn.Dcl[offset+i] = name
592 params := sig.RecvParams()
593 results := sig.Results()
595 fn.Dcl = make([]*Name, len(params)+len(results))
596 declareParams(params, PPARAM, "~p", 0)
597 declareParams(results, PPARAMOUT, "~r", len(params))