gocore: expand bigslice test to test deconstructed values on the stack
Change-Id: Ie525b23748a53fffd9876515ebf2caa93744f523
Reviewed-on: https://go-review.googlesource.com/c/debug/+/659796
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nicolas Hillegeer <aktau@google.com>
diff --git a/internal/gocore/gocore_test.go b/internal/gocore/gocore_test.go
index ffb9bd4..6899f78 100644
--- a/internal/gocore/gocore_test.go
+++ b/internal/gocore/gocore_test.go
@@ -296,13 +296,15 @@
}
return true
})
- if largeObjects != 1 {
- t.Errorf("expected exactly one object larger than %d, found %d", largeObjectThreshold, largeObjects)
+ if largeObjects != 3 {
+ t.Errorf("expected exactly three object larger than %d, found %d", largeObjectThreshold, largeObjects)
}
// Check object counts.
+ //
+ // TODO(mknyszek): Support typing roots in pieces.
if want := 32 << 10; bigSliceElemObjects != want {
- t.Errorf("expected exactly %d main.globalBigSliceInt objects, found %d", want, bigSliceElemObjects)
+ t.Errorf("expected exactly %d main.bigSliceElem objects, found %d", want, bigSliceElemObjects)
}
})
t.Run("large.go", func(t *testing.T) {
diff --git a/internal/gocore/testdata/testprogs/bigslice.go b/internal/gocore/testdata/testprogs/bigslice.go
index d383fea..322913f 100644
--- a/internal/gocore/testdata/testprogs/bigslice.go
+++ b/internal/gocore/testdata/testprogs/bigslice.go
@@ -10,6 +10,7 @@
import (
"os"
+ "runtime"
"golang.org/x/debug/internal/testenv"
)
@@ -19,13 +20,42 @@
}
var globalBigSlice []*bigSliceElem
+var block chan struct{}
func main() {
testenv.RunThenCrash(os.Getenv("GO_DEBUG_TEST_COREDUMP_FILTER"), func() any {
- globalBigSlice = make([]*bigSliceElem, 32<<10)
- for i := range globalBigSlice {
- globalBigSlice[i] = &bigSliceElem{float64(i), float64(i) - 0.5, float64(i * 124)}
- }
+ globalBigSlice = *makeBigSlice()
+ ready := make(chan []*bigSliceElem)
+ go func() {
+ // This funny incantation exists to force the bs0 and bs1 slice
+ // headers to be deconstructed by the compiler and stored in pieces
+ // on the stack. This tests whether gocore can piece it back
+ // together.
+ bsp0 := makeBigSlice()
+ bsp1 := makeBigSlice()
+ bs0 := *bsp0
+ bs1 := *bsp1
+ runtime.GC()
+ ready <- bs0
+ ready <- bs1
+ runtime.KeepAlive(bs0)
+ runtime.KeepAlive(bs1)
+ }()
+ <-ready
+
return nil
})
}
+
+// This function signature looks weird, returning a pointer to a slice, but it's
+// to try and force deconstruction of the slice value by the compiler in the caller.
+// See callers of makeBigSlice.
+//
+//go:noinline
+func makeBigSlice() *[]*bigSliceElem {
+ bs := make([]*bigSliceElem, 32<<10)
+ for i := range bs {
+ bs[i] = &bigSliceElem{float64(i), float64(i) - 0.5, float64(i * 124)}
+ }
+ return &bs
+}