...

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

Documentation: cmd/compile/internal/ir

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

View as plain text