]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: move FuncPC intrinsic handling to common helper
authorMichael Pratt <mpratt@google.com>
Fri, 3 Nov 2023 20:00:40 +0000 (16:00 -0400)
committerGopher Robot <gobot@golang.org>
Fri, 10 Nov 2023 20:33:58 +0000 (20:33 +0000)
CL 539699 will need to do the equivalent of
internal/abi.FuncPCABIInternal to get the PC of a function value for the
runtime devirtualization check.

Move the FuncPC expression creation from the depths of walk to a
typecheck helper so it can be reused in both places.

For #61577.

Change-Id: I76f333157cf0e5fd867b41bfffcdaf6f45254707
Reviewed-on: https://go-review.googlesource.com/c/go/+/539698
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/compile/internal/ir/func.go
src/cmd/compile/internal/walk/expr.go
src/cmd/compile/internal/walk/order.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.
 //
index 6c3d9fcd37aa7a85e9ffdcc00bf0c4a1cb05fa25..64d20b555e41e849ae99cdb7598d08541c672d81 100644 (file)
@@ -559,30 +559,11 @@ func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
                case "FuncPCABIInternal":
                        wantABI = obj.ABIInternal
                }
-               if isIfaceOfFunc(arg) {
-                       fn := arg.(*ir.ConvExpr).X.(*ir.Name)
-                       abi := fn.Func.ABI
-                       if abi != wantABI {
-                               base.ErrorfAt(n.Pos(), 0, "internal/abi.%s expects an %v function, %s is defined as %v", name, wantABI, fn.Sym().Name, abi)
-                       }
-                       var e ir.Node = ir.NewLinksymExpr(n.Pos(), fn.Sym().LinksymABI(abi), types.Types[types.TUINTPTR])
-                       e = ir.NewAddrExpr(n.Pos(), e)
-                       e.SetType(types.Types[types.TUINTPTR].PtrTo())
-                       return typecheck.Expr(ir.NewConvExpr(n.Pos(), ir.OCONVNOP, n.Type(), 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(n.Pos(), 0, "internal/abi.%s does not accept func expression, which is ABIInternal", name)
+               if n.Type() != types.Types[types.TUINTPTR] {
+                       base.FatalfAt(n.Pos(), "FuncPC intrinsic should return uintptr, got %v", n.Type()) // as expected by typecheck.FuncPC.
                }
-               arg = walkExpr(arg, init)
-               var e ir.Node = ir.NewUnaryExpr(n.Pos(), ir.OIDATA, arg)
-               e.SetType(n.Type().PtrTo())
-               e.SetTypecheck(1)
-               e = ir.NewStarExpr(n.Pos(), e)
-               e.SetType(n.Type())
-               e.SetTypecheck(1)
-               return e
+               n := ir.FuncPC(n.Pos(), arg, wantABI)
+               return walkExpr(n, init)
        }
 
        if name, ok := n.Fun.(*ir.Name); ok {
index 828a1537e229f1d672cc772421da2e2916252b06..4d9b2fbee566ef79128cd1c61b4e9ed884b5e6e1 100644 (file)
@@ -538,7 +538,7 @@ func (o *orderState) call(nn ir.Node) {
        n := nn.(*ir.CallExpr)
        typecheck.AssertFixedCall(n)
 
-       if ir.IsFuncPCIntrinsic(n) && isIfaceOfFunc(n.Args[0]) {
+       if ir.IsFuncPCIntrinsic(n) && ir.IsIfaceOfFunc(n.Args[0]) != nil {
                // For internal/abi.FuncPCABIxxx(fn), if fn is a defined function,
                // do not introduce temporaries here, so it is easier to rewrite it
                // to symbol address reference later in walk.
@@ -1502,8 +1502,3 @@ func (o *orderState) as2ok(n *ir.AssignListStmt) {
        o.out = append(o.out, n)
        o.stmt(typecheck.Stmt(as))
 }
-
-// isIfaceOfFunc returns whether n is an interface conversion from a direct reference of a func.
-func isIfaceOfFunc(n ir.Node) bool {
-       return n.Op() == ir.OCONVIFACE && n.(*ir.ConvExpr).X.Op() == ir.ONAME && n.(*ir.ConvExpr).X.(*ir.Name).Class == ir.PFUNC
-}