Skip to content

Commit e323e7d

Browse files
prattmicgopherbot
authored andcommitted
cmd/compile: move FuncPC intrinsic handling to common helper
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 <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Auto-Submit: Michael Pratt <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 505dff4 commit e323e7d

File tree

3 files changed

+60
-29
lines changed

3 files changed

+60
-29
lines changed

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

+55
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,61 @@ func IsFuncPCIntrinsic(n *CallExpr) bool {
505505
fn.Pkg.Path == "internal/abi"
506506
}
507507

508+
// IsIfaceOfFunc inspects whether n is an interface conversion from a direct
509+
// reference of a func. If so, it returns referenced Func; otherwise nil.
510+
//
511+
// This is only usable before walk.walkConvertInterface, which converts to an
512+
// OMAKEFACE.
513+
func IsIfaceOfFunc(n Node) *Func {
514+
if n, ok := n.(*ConvExpr); ok && n.Op() == OCONVIFACE {
515+
if name, ok := n.X.(*Name); ok && name.Op() == ONAME && name.Class == PFUNC {
516+
return name.Func
517+
}
518+
}
519+
return nil
520+
}
521+
522+
// FuncPC returns a uintptr-typed expression that evaluates to the PC of a
523+
// function as uintptr, as returned by internal/abi.FuncPC{ABI0,ABIInternal}.
524+
//
525+
// n should be a Node of an interface type, as is passed to
526+
// internal/abi.FuncPC{ABI0,ABIInternal}.
527+
//
528+
// TODO(prattmic): Since n is simply an interface{} there is no assertion that
529+
// it is actually a function at all. Perhaps we should emit a runtime type
530+
// assertion?
531+
func FuncPC(pos src.XPos, n Node, wantABI obj.ABI) Node {
532+
if !n.Type().IsInterface() {
533+
base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an interface value, got %v", wantABI, n.Type())
534+
}
535+
536+
if fn := IsIfaceOfFunc(n); fn != nil {
537+
name := fn.Nname
538+
abi := fn.ABI
539+
if abi != wantABI {
540+
base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an %v function, %s is defined as %v", wantABI, wantABI, name.Sym().Name, abi)
541+
}
542+
var e Node = NewLinksymExpr(pos, name.Sym().LinksymABI(abi), types.Types[types.TUINTPTR])
543+
e = NewAddrExpr(pos, e)
544+
e.SetType(types.Types[types.TUINTPTR].PtrTo())
545+
e = NewConvExpr(pos, OCONVNOP, types.Types[types.TUINTPTR], e)
546+
e.SetTypecheck(1)
547+
return e
548+
}
549+
// fn is not a defined function. It must be ABIInternal.
550+
// Read the address from func value, i.e. *(*uintptr)(idata(fn)).
551+
if wantABI != obj.ABIInternal {
552+
base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s does not accept func expression, which is ABIInternal", wantABI)
553+
}
554+
var e Node = NewUnaryExpr(pos, OIDATA, n)
555+
e.SetType(types.Types[types.TUINTPTR].PtrTo())
556+
e.SetTypecheck(1)
557+
e = NewStarExpr(pos, e)
558+
e.SetType(types.Types[types.TUINTPTR])
559+
e.SetTypecheck(1)
560+
return e
561+
}
562+
508563
// DeclareParams creates Names for all of the parameters in fn's
509564
// signature and adds them to fn.Dcl.
510565
//

src/cmd/compile/internal/walk/expr.go

+4-23
Original file line numberDiff line numberDiff line change
@@ -559,30 +559,11 @@ func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
559559
case "FuncPCABIInternal":
560560
wantABI = obj.ABIInternal
561561
}
562-
if isIfaceOfFunc(arg) {
563-
fn := arg.(*ir.ConvExpr).X.(*ir.Name)
564-
abi := fn.Func.ABI
565-
if abi != wantABI {
566-
base.ErrorfAt(n.Pos(), 0, "internal/abi.%s expects an %v function, %s is defined as %v", name, wantABI, fn.Sym().Name, abi)
567-
}
568-
var e ir.Node = ir.NewLinksymExpr(n.Pos(), fn.Sym().LinksymABI(abi), types.Types[types.TUINTPTR])
569-
e = ir.NewAddrExpr(n.Pos(), e)
570-
e.SetType(types.Types[types.TUINTPTR].PtrTo())
571-
return typecheck.Expr(ir.NewConvExpr(n.Pos(), ir.OCONVNOP, n.Type(), e))
572-
}
573-
// fn is not a defined function. It must be ABIInternal.
574-
// Read the address from func value, i.e. *(*uintptr)(idata(fn)).
575-
if wantABI != obj.ABIInternal {
576-
base.ErrorfAt(n.Pos(), 0, "internal/abi.%s does not accept func expression, which is ABIInternal", name)
562+
if n.Type() != types.Types[types.TUINTPTR] {
563+
base.FatalfAt(n.Pos(), "FuncPC intrinsic should return uintptr, got %v", n.Type()) // as expected by typecheck.FuncPC.
577564
}
578-
arg = walkExpr(arg, init)
579-
var e ir.Node = ir.NewUnaryExpr(n.Pos(), ir.OIDATA, arg)
580-
e.SetType(n.Type().PtrTo())
581-
e.SetTypecheck(1)
582-
e = ir.NewStarExpr(n.Pos(), e)
583-
e.SetType(n.Type())
584-
e.SetTypecheck(1)
585-
return e
565+
n := ir.FuncPC(n.Pos(), arg, wantABI)
566+
return walkExpr(n, init)
586567
}
587568

588569
if name, ok := n.Fun.(*ir.Name); ok {

src/cmd/compile/internal/walk/order.go

+1-6
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ func (o *orderState) call(nn ir.Node) {
538538
n := nn.(*ir.CallExpr)
539539
typecheck.AssertFixedCall(n)
540540

541-
if ir.IsFuncPCIntrinsic(n) && isIfaceOfFunc(n.Args[0]) {
541+
if ir.IsFuncPCIntrinsic(n) && ir.IsIfaceOfFunc(n.Args[0]) != nil {
542542
// For internal/abi.FuncPCABIxxx(fn), if fn is a defined function,
543543
// do not introduce temporaries here, so it is easier to rewrite it
544544
// to symbol address reference later in walk.
@@ -1502,8 +1502,3 @@ func (o *orderState) as2ok(n *ir.AssignListStmt) {
15021502
o.out = append(o.out, n)
15031503
o.stmt(typecheck.Stmt(as))
15041504
}
1505-
1506-
// isIfaceOfFunc returns whether n is an interface conversion from a direct reference of a func.
1507-
func isIfaceOfFunc(n ir.Node) bool {
1508-
return n.Op() == ir.OCONVIFACE && n.(*ir.ConvExpr).X.Op() == ir.ONAME && n.(*ir.ConvExpr).X.(*ir.Name).Class == ir.PFUNC
1509-
}

0 commit comments

Comments
 (0)