aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/debug_test.go
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2021-04-10 00:05:07 +0000
committerMichael Knyszek <mknyszek@google.com>2021-04-14 19:54:26 +0000
commita89ace106f820a4f3b129c81ba0bcf0c48b5b7cd (patch)
tree57f8b82d0e3d9215334fc3cd939293c96e8a2014 /src/runtime/debug_test.go
parentde7a87ef066d726eddcc47a018a2bc8fbd3793af (diff)
downloadgo-a89ace106f820a4f3b129c81ba0bcf0c48b5b7cd.tar.gz
go-a89ace106f820a4f3b129c81ba0bcf0c48b5b7cd.zip
runtime: update debug call protocol for register ABI
The debug call tests currently assume that the target Go function is ABI0; this is clearly no longer true when we switch to the new ABI, so make the tests set up argument register state in the debug call handler and copy back results returned in registers. A small snag in calling a Go function that follows the new ABI is that the debug call protocol depends on the AX register being set to a specific value as it bounces in and out of the handler, but this register is part of the new register ABI, so results end up being clobbered. Use R12 instead. Next, the new desugaring behavior for "go" statements means that newosproc1 must always call a function with no frame; if it takes any arguments, it closes over them and they're passed in the context register. Currently when debugCallWrap creates a new goroutine, it uses newosproc1 directly and passes a non-zero-sized frame, so that needs to be updated. To fix this, briefly use the g's param field which is otherwise only used for channels to pass an explicitly allocated object containing the "closed over" variables. While we could manually do the desugaring ourselves (we cannot do so automatically because the Go compiler prevents heap-allocated closures in the runtime), that bakes in more ABI details in a place that really doesn't need to care about them. Finally, there's an old bug here where the context register was set up in CX, so technically closure calls never worked. Oops. It was otherwise harmless for other types of calls before, but now CX is an argument register, so now that interferes with regular calls, too. For #40724. Change-Id: I652c25ed56a25741bb04c24cfb603063c099edde Reviewed-on: https://go-review.googlesource.com/c/go/+/309169 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Alessandro Arzilli <alessandro.arzilli@gmail.com> TryBot-Result: Go Bot <gobot@golang.org>
Diffstat (limited to 'src/runtime/debug_test.go')
-rw-r--r--src/runtime/debug_test.go67
1 files changed, 47 insertions, 20 deletions
diff --git a/src/runtime/debug_test.go b/src/runtime/debug_test.go
index 7f9e460303..f74383457f 100644
--- a/src/runtime/debug_test.go
+++ b/src/runtime/debug_test.go
@@ -9,17 +9,16 @@
// spends all of its time in the race runtime, which isn't a safe
// point.
-// TODO(register args): We skip this under GOEXPERIMENT=regabidefer
-// because debugCallWrap passes a non-empty frame to newproc1,
-// triggering a panic.
-
-//go:build amd64 && linux && !race && !goexperiment.regabidefer
-// +build amd64,linux,!race,!goexperiment.regabidefer
+//go:build amd64 && linux && !race
+// +build amd64,linux,!race
package runtime_test
import (
"fmt"
+ "internal/abi"
+ "internal/goexperiment"
+ "math"
"os"
"regexp"
"runtime"
@@ -119,21 +118,49 @@ func TestDebugCall(t *testing.T) {
g, after := startDebugCallWorker(t)
defer after()
+ type stackArgs struct {
+ x0 int
+ x1 float64
+ y0Ret int
+ y1Ret float64
+ }
+
// Inject a call into the debugCallWorker goroutine and test
// basic argument and result passing.
- var args struct {
- x int
- yRet int
+ fn := func(x int, y float64) (y0Ret int, y1Ret float64) {
+ return x + 1, y + 1.0
}
- fn := func(x int) (yRet int) {
- return x + 1
+ var args *stackArgs
+ var regs abi.RegArgs
+ intRegs := regs.Ints[:]
+ floatRegs := regs.Floats[:]
+ fval := float64(42.0)
+ if goexperiment.RegabiArgs {
+ intRegs[0] = 42
+ floatRegs[0] = math.Float64bits(fval)
+ } else {
+ args = &stackArgs{
+ x0: 42,
+ x1: 42.0,
+ }
}
- args.x = 42
- if _, err := runtime.InjectDebugCall(g, fn, &args, debugCallTKill, false); err != nil {
+ if _, err := runtime.InjectDebugCall(g, fn, &regs, args, debugCallTKill, false); err != nil {
t.Fatal(err)
}
- if args.yRet != 43 {
- t.Fatalf("want 43, got %d", args.yRet)
+ var result0 int
+ var result1 float64
+ if goexperiment.RegabiArgs {
+ result0 = int(intRegs[0])
+ result1 = math.Float64frombits(floatRegs[0])
+ } else {
+ result0 = args.y0Ret
+ result1 = args.y1Ret
+ }
+ if result0 != 43 {
+ t.Errorf("want 43, got %d", result0)
+ }
+ if result1 != fval+1 {
+ t.Errorf("want 43, got %f", result1)
}
}
@@ -158,7 +185,7 @@ func TestDebugCallLarge(t *testing.T) {
args.in[i] = i
want[i] = i + 1
}
- if _, err := runtime.InjectDebugCall(g, fn, &args, debugCallTKill, false); err != nil {
+ if _, err := runtime.InjectDebugCall(g, fn, nil, &args, debugCallTKill, false); err != nil {
t.Fatal(err)
}
if want != args.out {
@@ -171,7 +198,7 @@ func TestDebugCallGC(t *testing.T) {
defer after()
// Inject a call that performs a GC.
- if _, err := runtime.InjectDebugCall(g, runtime.GC, nil, debugCallTKill, false); err != nil {
+ if _, err := runtime.InjectDebugCall(g, runtime.GC, nil, nil, debugCallTKill, false); err != nil {
t.Fatal(err)
}
}
@@ -182,7 +209,7 @@ func TestDebugCallGrowStack(t *testing.T) {
// Inject a call that grows the stack. debugCallWorker checks
// for stack pointer breakage.
- if _, err := runtime.InjectDebugCall(g, func() { growStack(nil) }, nil, debugCallTKill, false); err != nil {
+ if _, err := runtime.InjectDebugCall(g, func() { growStack(nil) }, nil, nil, debugCallTKill, false); err != nil {
t.Fatal(err)
}
}
@@ -218,7 +245,7 @@ func TestDebugCallUnsafePoint(t *testing.T) {
runtime.Gosched()
}
- _, err := runtime.InjectDebugCall(g, func() {}, nil, debugCallTKill, true)
+ _, err := runtime.InjectDebugCall(g, func() {}, nil, nil, debugCallTKill, true)
if msg := "call not at safe point"; err == nil || err.Error() != msg {
t.Fatalf("want %q, got %s", msg, err)
}
@@ -242,7 +269,7 @@ func TestDebugCallPanic(t *testing.T) {
}()
g := <-ready
- p, err := runtime.InjectDebugCall(g, func() { panic("test") }, nil, debugCallTKill, false)
+ p, err := runtime.InjectDebugCall(g, func() { panic("test") }, nil, nil, debugCallTKill, false)
if err != nil {
t.Fatal(err)
}