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

View as plain text