internal/impl: add MessageState to every generated message
We define MessageState, which is essentially an atomically set *MessageInfo.
By nesting this as the first field in every generated message, we can
implement the reflective methods on a *MessageState when obtained by
unsafe casting a concrete message pointer as a *MessageState.
The MessageInfo held by MessageState provides additional Go type information
to interpret the memory that comes after the contents of the MessageState.
Since we are nesting a MessageState in every message,
the memory use of every message instance grows by 8B.
On average, the body of ProtoReflect grows from 133B to 202B (+50%).
However, this is offset by XXX_Methods, which is 108B and
will be removed in a future CL. Taking into account the eventual removal
of XXX_Methods, this is a net reduction of 25%.
name old time/op new time/op delta
Name/Value-4 70.3ns ± 2% 17.5ns ± 6% -75.08% (p=0.000 n=10+10)
Name/Nil-4 70.6ns ± 3% 33.4ns ± 2% -52.66% (p=0.000 n=10+10)
name old alloc/op new alloc/op delta
Name/Value-4 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10)
Name/Nil-4 16.0B ± 0% 0.0B -100.00% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
Name/Value-4 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10)
Name/Nil-4 1.00 ± 0% 0.00 -100.00% (p=0.000 n=10+10)
Change-Id: I92bd58dc681c57c92612fd5ba7fc066aea34e95a
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/185460
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/pointer_reflect.go b/internal/impl/pointer_reflect.go
index 0a9c53e..020af8e 100644
--- a/internal/impl/pointer_reflect.go
+++ b/internal/impl/pointer_reflect.go
@@ -9,10 +9,14 @@
import (
"fmt"
"reflect"
+ "sync"
)
const UnsafeEnabled = false
+// Pointer is an opaque pointer type.
+type Pointer interface{}
+
// offset represents the offset to a struct field, accessible from a pointer.
// The offset is the field index into a struct.
type offset struct {
@@ -46,6 +50,11 @@
// pointer is an abstract representation of a pointer to a struct or field.
type pointer struct{ v reflect.Value }
+// pointerOf returns p as a pointer.
+func pointerOf(p Pointer) pointer {
+ return pointerOfIface(p)
+}
+
// pointerOfValue returns v as a pointer.
func pointerOfValue(v reflect.Value) pointer {
return pointer{v: v}
@@ -146,3 +155,21 @@
func (p pointer) SetPointer(v pointer) {
p.v.Elem().Set(v.v)
}
+
+func (Export) MessageStateOf(p Pointer) *messageState { panic("not supported") }
+func (ms *messageState) pointer() pointer { panic("not supported") }
+func (ms *messageState) LoadMessageInfo() *MessageInfo { panic("not supported") }
+func (ms *messageState) StoreMessageInfo(mi *MessageInfo) { panic("not supported") }
+
+type atomicNilMessage struct {
+ once sync.Once
+ m messageReflectWrapper
+}
+
+func (m *atomicNilMessage) Init(mi *MessageInfo) *messageReflectWrapper {
+ m.once.Do(func() {
+ m.m.p = pointerOfIface(reflect.Zero(mi.GoType).Interface())
+ m.m.mi = mi
+ })
+ return &m.m
+}