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

View as plain text