| // Copyright 2025 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package test | |
| import ( | |
| "internal/testenv" | |
| "testing" | |
| "unsafe" | |
| ) | |
| // Stack allocation size for variable-sized allocations. | |
| // Matches constant of the same name in ../walk/builtin.go:walkMakeSlice. | |
| const maxStackSize = 32 | |
| //go:noinline | |
| func genericUse[T any](s []T) { | |
| // Doesn't escape s. | |
| } | |
| func TestStackAllocation(t *testing.T) { | |
| testenv.SkipIfOptimizationOff(t) | |
| type testCase struct { | |
| f func(int) | |
| elemSize uintptr | |
| } | |
| for _, tc := range []testCase{ | |
| { | |
| f: func(n int) { | |
| genericUse(make([]int, n)) | |
| }, | |
| elemSize: unsafe.Sizeof(int(0)), | |
| }, | |
| { | |
| f: func(n int) { | |
| genericUse(make([]*byte, n)) | |
| }, | |
| elemSize: unsafe.Sizeof((*byte)(nil)), | |
| }, | |
| { | |
| f: func(n int) { | |
| genericUse(make([]string, n)) | |
| }, | |
| elemSize: unsafe.Sizeof(""), | |
| }, | |
| } { | |
| max := maxStackSize / int(tc.elemSize) | |
| if n := testing.AllocsPerRun(10, func() { | |
| tc.f(max) | |
| }); n != 0 { | |
| t.Fatalf("unexpected allocation: %f", n) | |
| } | |
| if n := testing.AllocsPerRun(10, func() { | |
| tc.f(max + 1) | |
| }); n != 1 { | |
| t.Fatalf("unexpected allocation: %f", n) | |
| } | |
| } | |
| } | |