Skip to content

cmd/compile: storing zero value into interface should not allocate #71323

@dsnet

Description

@dsnet

Go version

go1.23.5

Output of go env in your module/workspace:

GOARCH=amd64
GOOS=linux

What did you do?

I ran this benchmark:

var sinkAny any

func BenchmarkInterfaceAny(b *testing.B) {
	b.ReportAllocs()
	for range b.N {
		sinkAny = tar.Header{}
	}
}

var sinkValue reflect.Value

func BenchmarkReflectValue(b *testing.B) {
	b.ReportAllocs()
	for range b.N {
		sinkValue = reflect.Zero(reflect.TypeFor[tar.Header]())
	}
}

What did you see happen?

I saw these results:

BenchmarkInterfaceAny    	31895619	        43.36 ns/op	     224 B/op	       1 allocs/op
BenchmarkReflectValue    	401489182	         3.021 ns/op	       0 B/op	       0 allocs/op

What did you expect to see?

I expected to see zero allocations in both cases.

In #33136, we optimized reflect.Zero to use a zero buffer of sufficient size to back the zero value of most types.

It seems to me that we could do the same trick for the non-reflect equivalent of storing a zero value into an interface value, where the data pointer in the interface value points to some shared zero buffer. This can be done in two ways:

  1. Dynamically check whether the value being stored into an interface is the zero value
  2. Statically detect when the value being stored into the interface value is identically equivalent to the zero value

Of course in both cases, you'll need to be careful since we're talking about a stricter definition of "zero" where the memory is equivalent to be all zeros.

Metadata

Metadata

Assignees

Labels

BugReportIssues describing a possible bug in the Go implementation.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Performancecompiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions