aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2021-01-28 15:23:05 +0000
committerMichael Knyszek <mknyszek@google.com>2021-04-02 16:53:18 +0000
commit28c5fed5576483cc696db233d7f6fffecd2833a2 (patch)
tree00109d3e508e63bbfff7c5c73f2b54ea321c402c /src/runtime
parent6996bae5d1d34ea9e2ab6399f70adb402697ed94 (diff)
downloadgo-28c5fed5576483cc696db233d7f6fffecd2833a2.tar.xz
reflect: add register ABI support for makeFuncStub and methodValueCall
This change finishes off functionality register ABI for the reflect package. Specifically, it implements a call on a MakeFunc'd value by performing the reverse process that reflect.Value.Call does, using the same ABI steps. It implements a call on a method value created by reflect by translating between the method value's ABI to the method's ABI. Tests are added for both cases. For #40724. Change-Id: I302820b61fc0a8f94c5525a002bc02776aef41af Reviewed-on: https://go-review.googlesource.com/c/go/+/298670 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/asm_amd64.s12
-rw-r--r--src/runtime/stack.go42
-rw-r--r--src/runtime/stubs_amd64.go7
-rw-r--r--src/runtime/traceback.go2
4 files changed, 45 insertions, 18 deletions
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 193d8f00bb..dbe7f7f381 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -473,7 +473,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
#ifdef GOEXPERIMENT_REGABI_REFLECT
// spillArgs stores return values from registers to a *internal/abi.RegArgs in R12.
-TEXT spillArgs<>(SB),NOSPLIT,$0-0
+TEXT ·spillArgs<ABIInternal>(SB),NOSPLIT,$0-0
MOVQ AX, 0(R12)
MOVQ BX, 8(R12)
MOVQ CX, 16(R12)
@@ -501,7 +501,7 @@ TEXT spillArgs<>(SB),NOSPLIT,$0-0
RET
// unspillArgs loads args into registers from a *internal/abi.RegArgs in R12.
-TEXT unspillArgs<>(SB),NOSPLIT,$0-0
+TEXT ·unspillArgs<ABIInternal>(SB),NOSPLIT,$0-0
MOVQ 0(R12), AX
MOVQ 8(R12), BX
MOVQ 16(R12), CX
@@ -529,11 +529,11 @@ TEXT unspillArgs<>(SB),NOSPLIT,$0-0
RET
#else
// spillArgs stores return values from registers to a pointer in R12.
-TEXT spillArgs<>(SB),NOSPLIT,$0-0
+TEXT ·spillArgs<ABIInternal>(SB),NOSPLIT,$0-0
RET
// unspillArgs loads args into registers from a pointer in R12.
-TEXT unspillArgs<>(SB),NOSPLIT,$0-0
+TEXT ·unspillArgs<ABIInternal>(SB),NOSPLIT,$0-0
RET
#endif
@@ -592,7 +592,7 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \
REP;MOVSB; \
/* set up argument registers */ \
MOVQ regArgs+40(FP), R12; \
- CALL unspillArgs<>(SB); \
+ CALL ·unspillArgs<ABIInternal>(SB); \
/* call function */ \
MOVQ f+8(FP), DX; \
PCDATA $PCDATA_StackMapIndex, $0; \
@@ -600,7 +600,7 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-48; \
CALL R12; \
/* copy register return values back */ \
MOVQ regArgs+40(FP), R12; \
- CALL spillArgs<>(SB); \
+ CALL ·spillArgs<ABIInternal>(SB); \
MOVLQZX stackArgsSize+24(FP), CX; \
MOVLQZX stackRetOffset+28(FP), BX; \
MOVQ stackArgs+16(FP), DI; \
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 5c7fadc2d2..cdccdcc2c5 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -5,6 +5,7 @@
package runtime
import (
+ "internal/abi"
"internal/cpu"
"runtime/internal/atomic"
"runtime/internal/sys"
@@ -1312,23 +1313,42 @@ func getStackMap(frame *stkframe, cache *pcvalueCache, debug bool) (locals, args
}
// stack objects.
- p := funcdata(f, _FUNCDATA_StackObjects)
- if p != nil {
- n := *(*uintptr)(p)
- p = add(p, sys.PtrSize)
- *(*slice)(unsafe.Pointer(&objs)) = slice{array: noescape(p), len: int(n), cap: int(n)}
- // Note: the noescape above is needed to keep
- // getStackMap from "leaking param content:
- // frame". That leak propagates up to getgcmask, then
- // GCMask, then verifyGCInfo, which converts the stack
- // gcinfo tests into heap gcinfo tests :(
+ if GOARCH == "amd64" && unsafe.Sizeof(abi.RegArgs{}) > 0 && frame.argmap != nil {
+ // argmap is set when the function is reflect.makeFuncStub or reflect.methodValueCall.
+ // We don't actually use argmap in this case, but we need to fake the stack object
+ // record for these frames which contain an internal/abi.RegArgs at a hard-coded offset
+ // on amd64.
+ objs = methodValueCallFrameObjs
+ } else {
+ p := funcdata(f, _FUNCDATA_StackObjects)
+ if p != nil {
+ n := *(*uintptr)(p)
+ p = add(p, sys.PtrSize)
+ *(*slice)(unsafe.Pointer(&objs)) = slice{array: noescape(p), len: int(n), cap: int(n)}
+ // Note: the noescape above is needed to keep
+ // getStackMap from "leaking param content:
+ // frame". That leak propagates up to getgcmask, then
+ // GCMask, then verifyGCInfo, which converts the stack
+ // gcinfo tests into heap gcinfo tests :(
+ }
}
return
}
+var (
+ abiRegArgsEface interface{} = abi.RegArgs{}
+ abiRegArgsType *_type = efaceOf(&abiRegArgsEface)._type
+ methodValueCallFrameObjs = []stackObjectRecord{
+ {
+ off: -int(alignUp(abiRegArgsType.size, 8)), // It's always the highest address local.
+ typ: abiRegArgsType,
+ },
+ }
+)
+
// A stackObjectRecord is generated by the compiler for each stack object in a stack frame.
-// This record must match the generator code in cmd/compile/internal/gc/ssa.go:emitStackObjects.
+// This record must match the generator code in cmd/compile/internal/liveness/plive.go:emitStackObjects.
type stackObjectRecord struct {
// offset in frame
// if negative, offset from varp
diff --git a/src/runtime/stubs_amd64.go b/src/runtime/stubs_amd64.go
index bf98493e9d..687a506cdd 100644
--- a/src/runtime/stubs_amd64.go
+++ b/src/runtime/stubs_amd64.go
@@ -40,3 +40,10 @@ func retpolineR15()
//go:noescape
func asmcgocall_no_g(fn, arg unsafe.Pointer)
+
+// Used by reflectcall and the reflect package.
+//
+// Spills/loads arguments in registers to/from an internal/abi.RegArgs
+// respectively. Does not follow the Go ABI.
+func spillArgs()
+func unspillArgs()
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index f8cda83098..0969af1a21 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -630,7 +630,7 @@ func getArgInfo(frame *stkframe, f funcInfo, needArgMap bool, ctxt *funcval) (ar
// Figure out whether the return values are valid.
// Reflect will update this value after it copies
// in the return values.
- retValid = *(*bool)(unsafe.Pointer(arg0 + 3*sys.PtrSize))
+ retValid = *(*bool)(unsafe.Pointer(arg0 + 4*sys.PtrSize))
}
if mv.fn != f.entry {
print("runtime: confused by ", funcname(f), "\n")