aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/walk
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2021-04-02 13:24:35 -0400
committerCherry Zhang <cherryyz@google.com>2021-04-23 21:05:39 +0000
commit142151697397235ba5f30a7a660ed8a159adce0b (patch)
treeeb10ad530ae354ba5304cc4e1ce28f26b12f9399 /src/cmd/compile/internal/walk
parent691e1b84c11d038060807f9c79107996ca2f19ae (diff)
downloadgo-142151697397235ba5f30a7a660ed8a159adce0b.tar.gz
go-142151697397235ba5f30a7a660ed8a159adce0b.zip
cmd/compile, internal/abi: add FuncPCABIxxx intrinsics
When ABI wrappers are used, there are cases where in Go code we need the PC of the defined function instead of the ABI wrapper. Currently we work around this by define such functions as ABIInternal, even if they do not actually follow the internal ABI. This CL introduces internal/abi.FuncPCABIxxx functions as compiler intrinsics, which return the underlying defined function's entry PC if the argument is a direct reference of a function of the expected ABI, and reject it if it is of a different ABI. As a proof of concept, change runtime.goexit back to ABI0 and use internal/abi.FuncPCABI0 to retrieve its PC. Updates #44065. Change-Id: I02286f0f9d99e6a3090f9e8169dbafc6804a2da6 Reviewed-on: https://go-review.googlesource.com/c/go/+/304232 Trust: Cherry Zhang <cherryyz@google.com> Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'src/cmd/compile/internal/walk')
-rw-r--r--src/cmd/compile/internal/walk/expr.go37
-rw-r--r--src/cmd/compile/internal/walk/order.go23
2 files changed, 60 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index a50473db52..5a1a2441bf 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -497,6 +497,43 @@ func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
directClosureCall(n)
}
+ if isFuncPCIntrinsic(n) {
+ // For internal/abi.FuncPCABIxxx(fn), if fn is a defined function, rewrite
+ // it to the address of the function of the ABI fn is defined.
+ name := n.X.(*ir.Name).Sym().Name
+ arg := n.Args[0]
+ var wantABI obj.ABI
+ switch name {
+ case "FuncPCABI0":
+ wantABI = obj.ABI0
+ 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(), "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())
+ e = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, n.Type(), e)
+ 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(n.Pos(), "internal/abi.%s does not accept func expression, which is ABIInternal", name)
+ }
+ arg = walkExpr(arg, init)
+ var e ir.Node = ir.NewUnaryExpr(n.Pos(), ir.OIDATA, arg)
+ e.SetType(n.Type().PtrTo())
+ e = ir.NewStarExpr(n.Pos(), e)
+ e.SetType(n.Type())
+ return e
+ }
+
walkCall1(n, init)
return n
}
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index 99a166119a..b733d3a29f 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -544,6 +544,14 @@ func (o *orderState) call(nn ir.Node) {
n := nn.(*ir.CallExpr)
typecheck.FixVariadicCall(n)
+
+ if isFuncPCIntrinsic(n) && isIfaceOfFunc(n.Args[0]) {
+ // 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.
+ return
+ }
+
n.X = o.expr(n.X, nil)
o.exprList(n.Args)
@@ -1796,3 +1804,18 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) {
// Finally, point the defer statement at the newly generated call.
n.Call = topcall
}
+
+// isFuncPCIntrinsic returns whether n is a direct call of internal/abi.FuncPCABIxxx functions.
+func isFuncPCIntrinsic(n *ir.CallExpr) bool {
+ if n.Op() != ir.OCALLFUNC || n.X.Op() != ir.ONAME {
+ return false
+ }
+ fn := n.X.(*ir.Name).Sym()
+ return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
+ (fn.Pkg.Path == "internal/abi" || fn.Pkg == types.LocalPkg && base.Ctxt.Pkgpath == "internal/abi")
+}
+
+// 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
+}