Source file src/cmd/compile/internal/ir/func.go

     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  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/types"
    10  	"cmd/internal/hash"
    11  	"cmd/internal/obj"
    12  	"cmd/internal/objabi"
    13  	"cmd/internal/src"
    14  	"encoding/base64"
    15  	"fmt"
    16  	"unicode/utf8"
    17  )
    18  
    19  // A Func corresponds to a single function in a Go program
    20  // (and vice versa: each function is denoted by exactly one *Func).
    21  //
    22  // There are multiple nodes that represent a Func in the IR.
    23  //
    24  // The ONAME node (Func.Nname) is used for plain references to it.
    25  // The ODCLFUNC node (the Func itself) is used for its declaration code.
    26  // The OCLOSURE node (Func.OClosure) is used for a reference to a
    27  // function literal.
    28  //
    29  // An imported function will have an ONAME node which points to a Func
    30  // with an empty body.
    31  // A declared function or method has an ODCLFUNC (the Func itself) and an ONAME.
    32  // A function literal is represented directly by an OCLOSURE, but it also
    33  // has an ODCLFUNC (and a matching ONAME) representing the compiled
    34  // underlying form of the closure, which accesses the captured variables
    35  // using a special data structure passed in a register.
    36  //
    37  // A method declaration is represented like functions, except f.Sym
    38  // will be the qualified method name (e.g., "T.m").
    39  //
    40  // A method expression (T.M) is represented as an OMETHEXPR node,
    41  // in which n.Left and n.Right point to the type and method, respectively.
    42  // Each distinct mention of a method expression in the source code
    43  // constructs a fresh node.
    44  //
    45  // A method value (t.M) is represented by ODOTMETH/ODOTINTER
    46  // when it is called directly and by OMETHVALUE otherwise.
    47  // These are like method expressions, except that for ODOTMETH/ODOTINTER,
    48  // the method name is stored in Sym instead of Right.
    49  // Each OMETHVALUE ends up being implemented as a new
    50  // function, a bit like a closure, with its own ODCLFUNC.
    51  // The OMETHVALUE uses n.Func to record the linkage to
    52  // the generated ODCLFUNC, but there is no
    53  // pointer from the Func back to the OMETHVALUE.
    54  type Func struct {
    55  	// if you add or remove a field, don't forget to update sizeof_test.go
    56  
    57  	miniNode
    58  	Body Nodes
    59  
    60  	Nname    *Name        // ONAME node
    61  	OClosure *ClosureExpr // OCLOSURE node
    62  
    63  	// ONAME nodes for all params/locals for this func/closure, does NOT
    64  	// include closurevars until transforming closures during walk.
    65  	// Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
    66  	// with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
    67  	// Anonymous and blank params are declared as ~pNN (for PPARAMs) and ~rNN (for PPARAMOUTs).
    68  	Dcl []*Name
    69  
    70  	// ClosureVars lists the free variables that are used within a
    71  	// function literal, but formally declared in an enclosing
    72  	// function. The variables in this slice are the closure function's
    73  	// own copy of the variables, which are used within its function
    74  	// body. They will also each have IsClosureVar set, and will have
    75  	// Byval set if they're captured by value.
    76  	ClosureVars []*Name
    77  
    78  	// Enclosed functions that need to be compiled.
    79  	// Populated during walk.
    80  	Closures []*Func
    81  
    82  	// Parent of a closure
    83  	ClosureParent *Func
    84  
    85  	// Parents records the parent scope of each scope within a
    86  	// function. The root scope (0) has no parent, so the i'th
    87  	// scope's parent is stored at Parents[i-1].
    88  	Parents []ScopeID
    89  
    90  	// Marks records scope boundary changes.
    91  	Marks []Mark
    92  
    93  	FieldTrack map[*obj.LSym]struct{}
    94  	DebugInfo  any
    95  	LSym       *obj.LSym // Linker object in this function's native ABI (Func.ABI)
    96  
    97  	Inl *Inline
    98  
    99  	// RangeParent, if non-nil, is the first non-range body function containing
   100  	// the closure for the body of a range function.
   101  	RangeParent *Func
   102  
   103  	// funcLitGen, rangeLitGen and goDeferGen track how many closures have been
   104  	// created in this function for function literals, range-over-func loops,
   105  	// and go/defer wrappers, respectively. Used by closureName for creating
   106  	// unique function names.
   107  	// Tracking goDeferGen separately avoids wrappers throwing off
   108  	// function literal numbering (e.g., runtime/trace_test.TestTraceSymbolize.func11).
   109  	funcLitGen  int32
   110  	rangeLitGen int32
   111  	goDeferGen  int32
   112  
   113  	Label int32 // largest auto-generated label in this function
   114  
   115  	Endlineno src.XPos
   116  	WBPos     src.XPos // position of first write barrier; see SetWBPos
   117  
   118  	Pragma PragmaFlag // go:xxx function annotations
   119  
   120  	flags bitset16
   121  
   122  	// ABI is a function's "definition" ABI. This is the ABI that
   123  	// this function's generated code is expecting to be called by.
   124  	//
   125  	// For most functions, this will be obj.ABIInternal. It may be
   126  	// a different ABI for functions defined in assembly or ABI wrappers.
   127  	//
   128  	// This is included in the export data and tracked across packages.
   129  	ABI obj.ABI
   130  	// ABIRefs is the set of ABIs by which this function is referenced.
   131  	// For ABIs other than this function's definition ABI, the
   132  	// compiler generates ABI wrapper functions. This is only tracked
   133  	// within a package.
   134  	ABIRefs obj.ABISet
   135  
   136  	NumDefers  int32 // number of defer calls in the function
   137  	NumReturns int32 // number of explicit returns in the function
   138  
   139  	// NWBRCalls records the LSyms of functions called by this
   140  	// function for go:nowritebarrierrec analysis. Only filled in
   141  	// if nowritebarrierrecCheck != nil.
   142  	NWBRCalls *[]SymAndPos
   143  
   144  	// For wrapper functions, WrappedFunc point to the original Func.
   145  	// Currently only used for go/defer wrappers.
   146  	WrappedFunc *Func
   147  
   148  	// WasmImport is used by the //go:wasmimport directive to store info about
   149  	// a WebAssembly function import.
   150  	WasmImport *WasmImport
   151  	// WasmExport is used by the //go:wasmexport directive to store info about
   152  	// a WebAssembly function export.
   153  	WasmExport *WasmExport
   154  }
   155  
   156  // WasmImport stores metadata associated with the //go:wasmimport pragma.
   157  type WasmImport struct {
   158  	Module string
   159  	Name   string
   160  }
   161  
   162  // WasmExport stores metadata associated with the //go:wasmexport pragma.
   163  type WasmExport struct {
   164  	Name string
   165  }
   166  
   167  // NewFunc returns a new Func with the given name and type.
   168  //
   169  // fpos is the position of the "func" token, and npos is the position
   170  // of the name identifier.
   171  //
   172  // TODO(mdempsky): I suspect there's no need for separate fpos and
   173  // npos.
   174  func NewFunc(fpos, npos src.XPos, sym *types.Sym, typ *types.Type) *Func {
   175  	name := NewNameAt(npos, sym, typ)
   176  	name.Class = PFUNC
   177  	sym.SetFunc(true)
   178  
   179  	fn := &Func{Nname: name}
   180  	fn.pos = fpos
   181  	fn.op = ODCLFUNC
   182  	// Most functions are ABIInternal. The importer or symabis
   183  	// pass may override this.
   184  	fn.ABI = obj.ABIInternal
   185  	fn.SetTypecheck(1)
   186  
   187  	name.Func = fn
   188  
   189  	return fn
   190  }
   191  
   192  func (f *Func) isStmt() {}
   193  
   194  func (n *Func) copy() Node                                   { panic(n.no("copy")) }
   195  func (n *Func) doChildren(do func(Node) bool) bool           { return doNodes(n.Body, do) }
   196  func (n *Func) doChildrenWithHidden(do func(Node) bool) bool { return doNodes(n.Body, do) }
   197  func (n *Func) editChildren(edit func(Node) Node)            { editNodes(n.Body, edit) }
   198  func (n *Func) editChildrenWithHidden(edit func(Node) Node)  { editNodes(n.Body, edit) }
   199  
   200  func (f *Func) Type() *types.Type                { return f.Nname.Type() }
   201  func (f *Func) Sym() *types.Sym                  { return f.Nname.Sym() }
   202  func (f *Func) Linksym() *obj.LSym               { return f.Nname.Linksym() }
   203  func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) }
   204  
   205  // An Inline holds fields used for function bodies that can be inlined.
   206  type Inline struct {
   207  	Cost int32 // heuristic cost of inlining this function
   208  
   209  	// Copy of Func.Dcl for use during inlining. This copy is needed
   210  	// because the function's Dcl may change from later compiler
   211  	// transformations. This field is also populated when a function
   212  	// from another package is imported and inlined.
   213  	Dcl     []*Name
   214  	HaveDcl bool // whether we've loaded Dcl
   215  
   216  	// Function properties, encoded as a string (these are used for
   217  	// making inlining decisions). See cmd/compile/internal/inline/inlheur.
   218  	Properties string
   219  
   220  	// CanDelayResults reports whether it's safe for the inliner to delay
   221  	// initializing the result parameters until immediately before the
   222  	// "return" statement.
   223  	CanDelayResults bool
   224  }
   225  
   226  // A Mark represents a scope boundary.
   227  type Mark struct {
   228  	// Pos is the position of the token that marks the scope
   229  	// change.
   230  	Pos src.XPos
   231  
   232  	// Scope identifies the innermost scope to the right of Pos.
   233  	Scope ScopeID
   234  }
   235  
   236  // A ScopeID represents a lexical scope within a function.
   237  type ScopeID int32
   238  
   239  const (
   240  	funcDupok                    = 1 << iota // duplicate definitions ok
   241  	funcWrapper                              // hide frame from users (elide in tracebacks, don't count as a frame for recover())
   242  	funcABIWrapper                           // is an ABI wrapper (also set flagWrapper)
   243  	funcNeedctxt                             // function uses context register (has closure variables)
   244  	funcHasDefer                             // contains a defer statement
   245  	funcNilCheckDisabled                     // disable nil checks when compiling this function
   246  	funcInlinabilityChecked                  // inliner has already determined whether the function is inlinable
   247  	funcNeverReturns                         // function never returns (in most cases calls panic(), os.Exit(), or equivalent)
   248  	funcOpenCodedDeferDisallowed             // can't do open-coded defers
   249  	funcClosureResultsLost                   // closure is called indirectly and we lost track of its results; used by escape analysis
   250  	funcPackageInit                          // compiler emitted .init func for package
   251  )
   252  
   253  type SymAndPos struct {
   254  	Sym *obj.LSym // LSym of callee
   255  	Pos src.XPos  // line of call
   256  }
   257  
   258  func (f *Func) Dupok() bool                    { return f.flags&funcDupok != 0 }
   259  func (f *Func) Wrapper() bool                  { return f.flags&funcWrapper != 0 }
   260  func (f *Func) ABIWrapper() bool               { return f.flags&funcABIWrapper != 0 }
   261  func (f *Func) Needctxt() bool                 { return f.flags&funcNeedctxt != 0 }
   262  func (f *Func) HasDefer() bool                 { return f.flags&funcHasDefer != 0 }
   263  func (f *Func) NilCheckDisabled() bool         { return f.flags&funcNilCheckDisabled != 0 }
   264  func (f *Func) InlinabilityChecked() bool      { return f.flags&funcInlinabilityChecked != 0 }
   265  func (f *Func) NeverReturns() bool             { return f.flags&funcNeverReturns != 0 }
   266  func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
   267  func (f *Func) ClosureResultsLost() bool       { return f.flags&funcClosureResultsLost != 0 }
   268  func (f *Func) IsPackageInit() bool            { return f.flags&funcPackageInit != 0 }
   269  
   270  func (f *Func) SetDupok(b bool)                    { f.flags.set(funcDupok, b) }
   271  func (f *Func) SetWrapper(b bool)                  { f.flags.set(funcWrapper, b) }
   272  func (f *Func) SetABIWrapper(b bool)               { f.flags.set(funcABIWrapper, b) }
   273  func (f *Func) SetNeedctxt(b bool)                 { f.flags.set(funcNeedctxt, b) }
   274  func (f *Func) SetHasDefer(b bool)                 { f.flags.set(funcHasDefer, b) }
   275  func (f *Func) SetNilCheckDisabled(b bool)         { f.flags.set(funcNilCheckDisabled, b) }
   276  func (f *Func) SetInlinabilityChecked(b bool)      { f.flags.set(funcInlinabilityChecked, b) }
   277  func (f *Func) SetNeverReturns(b bool)             { f.flags.set(funcNeverReturns, b) }
   278  func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
   279  func (f *Func) SetClosureResultsLost(b bool)       { f.flags.set(funcClosureResultsLost, b) }
   280  func (f *Func) SetIsPackageInit(b bool)            { f.flags.set(funcPackageInit, b) }
   281  
   282  func (f *Func) SetWBPos(pos src.XPos) {
   283  	if base.Debug.WB != 0 {
   284  		base.WarnfAt(pos, "write barrier")
   285  	}
   286  	if !f.WBPos.IsKnown() {
   287  		f.WBPos = pos
   288  	}
   289  }
   290  
   291  // IsClosure reports whether f is a function literal that captures at least one value.
   292  func (f *Func) IsClosure() bool {
   293  	if f.OClosure == nil {
   294  		return false
   295  	}
   296  	return len(f.ClosureVars) > 0
   297  }
   298  
   299  // FuncName returns the name (without the package) of the function f.
   300  func FuncName(f *Func) string {
   301  	if f == nil || f.Nname == nil {
   302  		return "<nil>"
   303  	}
   304  	return f.Sym().Name
   305  }
   306  
   307  // PkgFuncName returns the name of the function referenced by f, with package
   308  // prepended.
   309  //
   310  // This differs from the compiler's internal convention where local functions
   311  // lack a package. This is primarily useful when the ultimate consumer of this
   312  // is a human looking at message.
   313  func PkgFuncName(f *Func) string {
   314  	if f == nil || f.Nname == nil {
   315  		return "<nil>"
   316  	}
   317  	s := f.Sym()
   318  	pkg := s.Pkg
   319  	if pkg == nil {
   320  		return "<nil>." + s.Name
   321  	}
   322  	return pkg.Path + "." + s.Name
   323  }
   324  
   325  // LinkFuncName returns the name of the function f, as it will appear in the
   326  // symbol table of the final linked binary.
   327  func LinkFuncName(f *Func) string {
   328  	if f == nil || f.Nname == nil {
   329  		return "<nil>"
   330  	}
   331  	s := f.Sym()
   332  	pkg := s.Pkg
   333  
   334  	return objabi.PathToPrefix(pkg.Path) + "." + s.Name
   335  }
   336  
   337  // ParseLinkFuncName parsers a symbol name (as returned from LinkFuncName) back
   338  // to the package path and local symbol name.
   339  func ParseLinkFuncName(name string) (pkg, sym string, err error) {
   340  	pkg, sym = splitPkg(name)
   341  	if pkg == "" {
   342  		return "", "", fmt.Errorf("no package path in name")
   343  	}
   344  
   345  	pkg, err = objabi.PrefixToPath(pkg) // unescape
   346  	if err != nil {
   347  		return "", "", fmt.Errorf("malformed package path: %v", err)
   348  	}
   349  
   350  	return pkg, sym, nil
   351  }
   352  
   353  // Borrowed from x/mod.
   354  func modPathOK(r rune) bool {
   355  	if r < utf8.RuneSelf {
   356  		return r == '-' || r == '.' || r == '_' || r == '~' ||
   357  			'0' <= r && r <= '9' ||
   358  			'A' <= r && r <= 'Z' ||
   359  			'a' <= r && r <= 'z'
   360  	}
   361  	return false
   362  }
   363  
   364  func escapedImportPathOK(r rune) bool {
   365  	return modPathOK(r) || r == '+' || r == '/' || r == '%'
   366  }
   367  
   368  // splitPkg splits the full linker symbol name into package and local symbol
   369  // name.
   370  func splitPkg(name string) (pkgpath, sym string) {
   371  	// package-sym split is at first dot after last the / that comes before
   372  	// any characters illegal in a package path.
   373  
   374  	lastSlashIdx := 0
   375  	for i, r := range name {
   376  		// Catches cases like:
   377  		// * example.foo[sync/atomic.Uint64].
   378  		// * example%2ecom.foo[sync/atomic.Uint64].
   379  		//
   380  		// Note that name is still escaped; unescape occurs after splitPkg.
   381  		if !escapedImportPathOK(r) {
   382  			break
   383  		}
   384  		if r == '/' {
   385  			lastSlashIdx = i
   386  		}
   387  	}
   388  	for i := lastSlashIdx; i < len(name); i++ {
   389  		r := name[i]
   390  		if r == '.' {
   391  			return name[:i], name[i+1:]
   392  		}
   393  	}
   394  
   395  	return "", name
   396  }
   397  
   398  var CurFunc *Func
   399  
   400  // WithFunc invokes do with CurFunc and base.Pos set to curfn and
   401  // curfn.Pos(), respectively, and then restores their previous values
   402  // before returning.
   403  func WithFunc(curfn *Func, do func()) {
   404  	oldfn, oldpos := CurFunc, base.Pos
   405  	defer func() { CurFunc, base.Pos = oldfn, oldpos }()
   406  
   407  	CurFunc, base.Pos = curfn, curfn.Pos()
   408  	do()
   409  }
   410  
   411  func FuncSymName(s *types.Sym) string {
   412  	return s.Name + "·f"
   413  }
   414  
   415  // ClosureDebugRuntimeCheck applies boilerplate checks for debug flags
   416  // and compiling runtime.
   417  func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
   418  	if base.Debug.Closure > 0 {
   419  		if clo.Esc() == EscHeap {
   420  			base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
   421  		} else {
   422  			base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
   423  		}
   424  	}
   425  	if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap {
   426  		base.ErrorfAt(clo.Pos(), 0, "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func))
   427  	}
   428  }
   429  
   430  // globClosgen is like Func.Closgen, but for the global scope.
   431  var globClosgen int32
   432  
   433  // closureName generates a new unique name for a closure within outerfn at pos.
   434  // gen is an optional counter for the closure name. If it is 0, the counter
   435  // will be computed based on outerfn.
   436  func closureName(outerfn *Func, pos src.XPos, why Op, gen int) *types.Sym {
   437  	pkg := types.LocalPkg
   438  	outer := "glob."
   439  	var suffix string = "."
   440  	switch why {
   441  	default:
   442  		base.FatalfAt(pos, "closureName: bad Op: %v", why)
   443  	case OCLOSURE:
   444  		if outerfn.OClosure == nil {
   445  			suffix = ".func"
   446  		}
   447  	case ORANGE:
   448  		suffix = "-range"
   449  	case OGO:
   450  		suffix = ".gowrap"
   451  	case ODEFER:
   452  		suffix = ".deferwrap"
   453  	}
   454  
   455  	// There may be multiple functions named "_". In those
   456  	// cases, we can't use their individual Closgens as it
   457  	// would lead to name clashes.
   458  	if !IsBlank(outerfn.Nname) {
   459  		pkg = outerfn.Sym().Pkg
   460  		outer = FuncName(outerfn)
   461  	}
   462  
   463  	// If this closure was created due to inlining, find the original
   464  	// outer function's name for the closure (#60324).
   465  	var inlHash string
   466  	if inlIndex := base.Ctxt.InnermostPos(pos).Base().InliningIndex(); inlIndex >= 0 {
   467  		// The compiler doesn't like multiple symbols with the same
   468  		// name. We make a unique suffix temporarily for the
   469  		// compiler, and strip it during object file writing, so
   470  		// it will not be the linker symbol name. For linking,
   471  		// we use a content hash to disambiguate instead.
   472  		// We choose the suffix as a hash of the inline call stack.
   473  		h := hash.New32()
   474  		fmt.Fprint(h, inlIndex)
   475  		base.Ctxt.InlTree.AllParents(inlIndex, func(call obj.InlinedCall) {
   476  			if call.Parent >= 0 {
   477  				fmt.Fprint(h, " ", call.Parent)
   478  			}
   479  		})
   480  		inlHash = base64.StdEncoding.EncodeToString(h.Sum(nil)[:8])
   481  
   482  		outer = base.Ctxt.InlTree.InlinedFuncName(inlIndex)
   483  		if pkgPath := base.Ctxt.InlTree.InlinedFuncPkg(inlIndex); pkgPath != "" {
   484  			pkg = types.NewPkg(pkgPath, "")
   485  		}
   486  	}
   487  
   488  	if gen == 0 {
   489  		p := &globClosgen
   490  		if !IsBlank(outerfn.Nname) {
   491  			switch why {
   492  			case OCLOSURE:
   493  				p = &outerfn.funcLitGen
   494  			case ORANGE:
   495  				p = &outerfn.rangeLitGen
   496  			default:
   497  				p = &outerfn.goDeferGen
   498  			}
   499  		}
   500  		*p++
   501  		gen = int(*p)
   502  	}
   503  
   504  	name := fmt.Sprintf("%s%s%d", outer, suffix, gen)
   505  	if inlHash != "" {
   506  		// Attach the inline hash (see the comment above).
   507  		// If it already has a hash, trim it, so we don't include
   508  		// two hashes for nested closures. The new hash should be
   509  		// enough to disambiguate.
   510  		name = obj.TrimInlineHash(name) + "#" + inlHash + "#"
   511  	}
   512  
   513  	return pkg.Lookup(name)
   514  }
   515  
   516  // NewClosureFunc creates a new Func to represent a function literal
   517  // with the given type.
   518  //
   519  // fpos the position used for the underlying ODCLFUNC and ONAME,
   520  // whereas cpos is the position used for the OCLOSURE. They're
   521  // separate because in the presence of inlining, the OCLOSURE node
   522  // should have an inline-adjusted position, whereas the ODCLFUNC and
   523  // ONAME must not.
   524  //
   525  // outerfn is the enclosing function. The returned function is
   526  // appending to pkg.Funcs.
   527  //
   528  // why is the reason we're generating this Func. It can be OCLOSURE
   529  // (for a normal function literal) or OGO or ODEFER (for wrapping a
   530  // call expression that has parameters or results).
   531  //
   532  // gen is an optional counter for the closure name. If it is 0,
   533  // the counter will be computed based on outerfn.
   534  func NewClosureFunc(fpos, cpos src.XPos, why Op, typ *types.Type, outerfn *Func, pkg *Package, gen int) *Func {
   535  	if outerfn == nil {
   536  		base.FatalfAt(fpos, "outerfn is nil")
   537  	}
   538  
   539  	fn := NewFunc(fpos, fpos, closureName(outerfn, cpos, why, gen), typ)
   540  	fn.SetDupok(outerfn.Dupok()) // if the outer function is dupok, so is the closure
   541  
   542  	fn.Linksym().Set(obj.AttrContentAddressable, true)
   543  
   544  	clo := &ClosureExpr{Func: fn}
   545  	clo.op = OCLOSURE
   546  	clo.pos = cpos
   547  	clo.SetType(typ)
   548  	clo.SetTypecheck(1)
   549  	if why == ORANGE {
   550  		clo.Func.RangeParent = outerfn
   551  		if outerfn.OClosure != nil && outerfn.OClosure.Func.RangeParent != nil {
   552  			clo.Func.RangeParent = outerfn.OClosure.Func.RangeParent
   553  		}
   554  	}
   555  	fn.OClosure = clo
   556  
   557  	fn.Nname.Defn = fn
   558  	pkg.Funcs = append(pkg.Funcs, fn)
   559  	fn.ClosureParent = outerfn
   560  
   561  	return fn
   562  }
   563  
   564  // IsFuncPCIntrinsic returns whether n is a direct call of internal/abi.FuncPCABIxxx functions.
   565  func IsFuncPCIntrinsic(n *CallExpr) bool {
   566  	if n.Op() != OCALLFUNC || n.Fun.Op() != ONAME {
   567  		return false
   568  	}
   569  	fn := n.Fun.(*Name).Sym()
   570  	return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
   571  		fn.Pkg.Path == "internal/abi"
   572  }
   573  
   574  // IsIfaceOfFunc inspects whether n is an interface conversion from a direct
   575  // reference of a func. If so, it returns referenced Func; otherwise nil.
   576  //
   577  // This is only usable before walk.walkConvertInterface, which converts to an
   578  // OMAKEFACE.
   579  func IsIfaceOfFunc(n Node) *Func {
   580  	if n, ok := n.(*ConvExpr); ok && n.Op() == OCONVIFACE {
   581  		if name, ok := n.X.(*Name); ok && name.Op() == ONAME && name.Class == PFUNC {
   582  			return name.Func
   583  		}
   584  	}
   585  	return nil
   586  }
   587  
   588  // FuncPC returns a uintptr-typed expression that evaluates to the PC of a
   589  // function as uintptr, as returned by internal/abi.FuncPC{ABI0,ABIInternal}.
   590  //
   591  // n should be a Node of an interface type, as is passed to
   592  // internal/abi.FuncPC{ABI0,ABIInternal}.
   593  //
   594  // TODO(prattmic): Since n is simply an interface{} there is no assertion that
   595  // it is actually a function at all. Perhaps we should emit a runtime type
   596  // assertion?
   597  func FuncPC(pos src.XPos, n Node, wantABI obj.ABI) Node {
   598  	if !n.Type().IsInterface() {
   599  		base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an interface value, got %v", wantABI, n.Type())
   600  	}
   601  
   602  	if fn := IsIfaceOfFunc(n); fn != nil {
   603  		name := fn.Nname
   604  		abi := fn.ABI
   605  		if abi != wantABI {
   606  			base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an %v function, %s is defined as %v", wantABI, wantABI, name.Sym().Name, abi)
   607  		}
   608  		var e Node = NewLinksymExpr(pos, name.LinksymABI(abi), types.Types[types.TUINTPTR])
   609  		e = NewAddrExpr(pos, e)
   610  		e.SetType(types.Types[types.TUINTPTR].PtrTo())
   611  		e = NewConvExpr(pos, OCONVNOP, types.Types[types.TUINTPTR], e)
   612  		e.SetTypecheck(1)
   613  		return e
   614  	}
   615  	// fn is not a defined function. It must be ABIInternal.
   616  	// Read the address from func value, i.e. *(*uintptr)(idata(fn)).
   617  	if wantABI != obj.ABIInternal {
   618  		base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s does not accept func expression, which is ABIInternal", wantABI)
   619  	}
   620  	var e Node = NewUnaryExpr(pos, OIDATA, n)
   621  	e.SetType(types.Types[types.TUINTPTR].PtrTo())
   622  	e.SetTypecheck(1)
   623  	e = NewStarExpr(pos, e)
   624  	e.SetType(types.Types[types.TUINTPTR])
   625  	e.SetTypecheck(1)
   626  	return e
   627  }
   628  
   629  // DeclareParams creates Names for all of the parameters in fn's
   630  // signature and adds them to fn.Dcl.
   631  //
   632  // If setNname is true, then it also sets types.Field.Nname for each
   633  // parameter.
   634  func (fn *Func) DeclareParams(setNname bool) {
   635  	if fn.Dcl != nil {
   636  		base.FatalfAt(fn.Pos(), "%v already has Dcl", fn)
   637  	}
   638  
   639  	declareParams := func(params []*types.Field, ctxt Class, prefix string, offset int) {
   640  		for i, param := range params {
   641  			sym := param.Sym
   642  			if sym == nil || sym.IsBlank() {
   643  				sym = fn.Sym().Pkg.LookupNum(prefix, i)
   644  			}
   645  
   646  			name := NewNameAt(param.Pos, sym, param.Type)
   647  			name.Class = ctxt
   648  			name.Curfn = fn
   649  			fn.Dcl[offset+i] = name
   650  
   651  			if setNname {
   652  				param.Nname = name
   653  			}
   654  		}
   655  	}
   656  
   657  	sig := fn.Type()
   658  	params := sig.RecvParams()
   659  	results := sig.Results()
   660  
   661  	fn.Dcl = make([]*Name, len(params)+len(results))
   662  	declareParams(params, PPARAM, "~p", 0)
   663  	declareParams(results, PPARAMOUT, "~r", len(params))
   664  }
   665  
   666  // ContainsClosure reports whether c is a closure contained within f.
   667  func ContainsClosure(f, c *Func) bool {
   668  	// Common cases.
   669  	if f == c || c.OClosure == nil {
   670  		return false
   671  	}
   672  
   673  	for p := c.ClosureParent; p != nil; p = p.ClosureParent {
   674  		if p == f {
   675  			return true
   676  		}
   677  	}
   678  	return false
   679  }
   680  

View as plain text