package escapelab import "testing" // intSink defeats dead-code elimination for results we would otherwise discard. // b.Loop (Go 1.24+) already keeps the loop body live, but an explicit sink // makes the intent obvious and is harmless. var intSink int // --- Claim 2: any-boxing allocates ------------------------------------------- // // We feed an input larger than 255 on purpose. The runtime keeps a static // table of boxed small integers (0..255), so boxing a small int can read as // "0 allocs/op" and hide the effect. Using a large value forces a real // allocation and shows the true cost of interface boxing. func BenchmarkSquareQuiet(b *testing.B) { n := 1 << 20 for b.Loop() { intSink = SquareQuiet(n) } } func BenchmarkSquareLogged(b *testing.B) { n := 1 << 20 for b.Loop() { intSink = SquareLogged(n) } } func TestLocalInterfaceConversionDoesNotAllocate(t *testing.T) { if got := testing.AllocsPerRun(1000, func() { intSink = BoxLocal(1 << 20) }); got != 0 { t.Fatalf("local interface conversion allocated: got %v allocs", got) } } // --- Claim 1: pointer return escapes, value return does not ------------------- func BenchmarkNewPointVal(b *testing.B) { for b.Loop() { p := NewPointVal(1, 2) intSink = p.X } } func BenchmarkNewPointPtr(b *testing.B) { for b.Loop() { p := NewPointPtr(1, 2) intSink = p.X } } // --- Claim 3: escaping closure allocates, local closure does not -------------- func BenchmarkClosureEscape(b *testing.B) { for b.Loop() { c := MakeCounter() intSink = c() } } func BenchmarkClosureLocal(b *testing.B) { nums := []int{1, 2, 3, 4, 5} for b.Loop() { intSink = SumLocally(nums) } } // --- Claim 5: package-level assignment escapes -------------------------------- func BenchmarkStashGlobal(b *testing.B) { for b.Loop() { StashGlobal(1, 2) } }