Repository: go
Issue: reflect: allow stack allocation of underlying value for reflect.Value.Interface
Labels: compiler/runtime,BugReport

### Go version

tip

### What did you do?

Run this simple test ([playground link](https://go.dev/play/p/zDD-8Yl91kk?v=gotip)):

```go
func TestAllocsReflectInterface(t *testing.T) {
	allocs := testing.AllocsPerRun(100, func() {
		v := reflect.ValueOf(Point{x: 1, y: 1})
		_ = v.Interface() // Causes the Point value to escape to heap.
	})
	if allocs != 0 {
		t.Errorf("allocs = %d, want 0", int(allocs))
	}
}
```

### What did you see happen?
```
    prog_test.go:18: allocs = 1, want 0
--- FAIL: TestAllocsReflectInterface (0.00s)
```

### What did you expect to see?

Ideally, zero heap allocations in this test, and ideally reflect.Value.Interface would allow the underlying value to not always be heap allocated. This affects the fmt package and can affect other users of reflect like serialization libraries. This issue is a spin out from https://github.com/golang/go/issues/8618#issuecomment-1720049443.

There are currently two reasons the underlying value escapes to the heap: 

1. reflect.packEface causes reflect.Value.Interface to escape its underlying value: 

```
 parameter v leaks to <heap> for packEface with derefs=0:
   flow: <heap> ← v:
     from v.ptr (dot) at .\value.go:145:13
     from e.word = v.ptr (assign) at ./value.go:145:10
```

2. Within reflect.Value.Interface and its helpers, method values cause conditional allocation of a methodValue struct, which also causes underlying values of other types to also escape: 

```
 parameter v leaks to <heap> for valueInterface with derefs=0:
   flow: {heap} ← v:
     from makeMethodValue("Interface", v) (call parameter) at ./value.go:1492:22
```

I sent https://go.dev/cl/528535 to hopefully address the first reason in reflect.packEface. 

For addressing the second reason above and handling method values, I sent: 

 * https://go.dev/cl/530095, which changes the runtime so that it manually creates the stack map
for reflect.methodValueCall so that a stack-based methodValue can be tracked, including for example to properly update pointers during a stack copy operation.
 * https://go.dev/cl/530097, which updates reflect.Value.Interface to stack allocate a methodValue if needed and pass a pointer to it down the stack. This is done while side-stepping other reasons the *methodValue might escape, while keeping reflect.Value.Interface within the inlining budget so that a caller of reflect.Value.Interface can stack allocate a methodValue (which then ends up avoiding the need to always store all underlying values in the heap, regardless of whether or not they are a method value).
 * https://go.dev/cl/530096, which updates the compiler's escape analysis to recognize more self-assignment patterns. (This was originally used to help squeak past the inlining budget without escaping, but 530096 might end up not being needed for this issue). 

Together, these changes allow the test to pass without heap allocations.

-----

I am hopefully returning to this shortly, and filing this issue to re-summarize the approach and to help with tracking & discussion. (Previously, a short overview was in https://github.com/golang/go/issues/8618#issuecomment-1720049443, in addition to more details in the individual CLs).