]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/ir/func.go
cmd/compile: move FuncPC intrinsic handling to common helper
[gostls13.git] / src / cmd / compile / internal / ir / func.go
index a4a31f314deda2cb23fab45cb6a124c2bf3b1f40..c28761255f3839a42b74a66350343a1da975e96e 100644 (file)
@@ -505,6 +505,61 @@ func IsFuncPCIntrinsic(n *CallExpr) bool {
                fn.Pkg.Path == "internal/abi"
 }
 
+// IsIfaceOfFunc inspects whether n is an interface conversion from a direct
+// reference of a func. If so, it returns referenced Func; otherwise nil.
+//
+// This is only usable before walk.walkConvertInterface, which converts to an
+// OMAKEFACE.
+func IsIfaceOfFunc(n Node) *Func {
+       if n, ok := n.(*ConvExpr); ok && n.Op() == OCONVIFACE {
+               if name, ok := n.X.(*Name); ok && name.Op() == ONAME && name.Class == PFUNC {
+                       return name.Func
+               }
+       }
+       return nil
+}
+
+// FuncPC returns a uintptr-typed expression that evaluates to the PC of a
+// function as uintptr, as returned by internal/abi.FuncPC{ABI0,ABIInternal}.
+//
+// n should be a Node of an interface type, as is passed to
+// internal/abi.FuncPC{ABI0,ABIInternal}.
+//
+// TODO(prattmic): Since n is simply an interface{} there is no assertion that
+// it is actually a function at all. Perhaps we should emit a runtime type
+// assertion?
+func FuncPC(pos src.XPos, n Node, wantABI obj.ABI) Node {
+       if !n.Type().IsInterface() {
+               base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an interface value, got %v", wantABI, n.Type())
+       }
+
+       if fn := IsIfaceOfFunc(n); fn != nil {
+               name := fn.Nname
+               abi := fn.ABI
+               if abi != wantABI {
+                       base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an %v function, %s is defined as %v", wantABI, wantABI, name.Sym().Name, abi)
+               }
+               var e Node = NewLinksymExpr(pos, name.Sym().LinksymABI(abi), types.Types[types.TUINTPTR])
+               e = NewAddrExpr(pos, e)
+               e.SetType(types.Types[types.TUINTPTR].PtrTo())
+               e = NewConvExpr(pos, OCONVNOP, types.Types[types.TUINTPTR], e)
+               e.SetTypecheck(1)
+               return e
+       }
+       // fn is not a defined function. It must be ABIInternal.
+       // Read the address from func value, i.e. *(*uintptr)(idata(fn)).
+       if wantABI != obj.ABIInternal {
+               base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s does not accept func expression, which is ABIInternal", wantABI)
+       }
+       var e Node = NewUnaryExpr(pos, OIDATA, n)
+       e.SetType(types.Types[types.TUINTPTR].PtrTo())
+       e.SetTypecheck(1)
+       e = NewStarExpr(pos, e)
+       e.SetType(types.Types[types.TUINTPTR])
+       e.SetTypecheck(1)
+       return e
+}
+
 // DeclareParams creates Names for all of the parameters in fn's
 // signature and adds them to fn.Dcl.
 //