internal/impl: refactor fast-path
Move data used by the fast-path implementations into a substructure of
MessageInfo and initialize it separately.
Change-Id: Ib855ee8ea5cb0379528b52ba0e191319aa5e2dff
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/184077
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/impl/message.go b/internal/impl/message.go
index 1226511..e486e9f 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -7,7 +7,6 @@
import (
"fmt"
"reflect"
- "sort"
"strconv"
"strings"
"sync"
@@ -33,11 +32,7 @@
initMu sync.Mutex // protects all unexported fields
initDone uint32
- // Keep a separate slice of fields for efficient field encoding in tag order
- // and because iterating over a slice is substantially faster than a map.
- fields map[pref.FieldNumber]*fieldInfo
- fieldsOrdered []*fieldInfo
-
+ fields map[pref.FieldNumber]*fieldInfo
oneofs map[pref.Name]*oneofInfo
getUnknown func(pointer) pref.RawFields
@@ -45,12 +40,10 @@
extensionMap func(pointer) *extensionMap
+ // Information used by the fast-path methods.
methods piface.Methods
+ coderMessageInfo
- needsInitCheck bool
- sizecacheOffset offset
- extensionOffset offset
- unknownOffset offset
extensionFieldInfosMu sync.RWMutex
extensionFieldInfos map[pref.ExtensionType]*extensionFieldInfo
}
@@ -102,11 +95,10 @@
}
si := mi.makeStructInfo(t.Elem())
- mi.needsInitCheck = needsInitCheck(mi.PBType)
mi.makeKnownFieldsFunc(si)
mi.makeUnknownFieldsFunc(t.Elem())
mi.makeExtensionFieldsFunc(t.Elem())
- mi.makeMethods(t.Elem())
+ mi.makeMethods(t.Elem(), si)
atomic.StoreUint32(&mi.initDone, 1)
}
@@ -123,27 +115,6 @@
extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
)
-func (mi *MessageInfo) makeMethods(t reflect.Type) {
- mi.sizecacheOffset = invalidOffset
- if fx, _ := t.FieldByName("XXX_sizecache"); fx.Type == sizecacheType {
- mi.sizecacheOffset = offsetOf(fx)
- }
- mi.unknownOffset = invalidOffset
- if fx, _ := t.FieldByName("XXX_unrecognized"); fx.Type == unknownFieldsType {
- mi.unknownOffset = offsetOf(fx)
- }
- mi.extensionOffset = invalidOffset
- if fx, _ := t.FieldByName("XXX_InternalExtensions"); fx.Type == extensionFieldsType {
- mi.extensionOffset = offsetOf(fx)
- } else if fx, _ = t.FieldByName("XXX_extensions"); fx.Type == extensionFieldsType {
- mi.extensionOffset = offsetOf(fx)
- }
- mi.methods.Flags = piface.MethodFlagDeterministicMarshal
- mi.methods.MarshalAppend = mi.marshalAppend
- mi.methods.Size = mi.size
- mi.methods.IsInitialized = mi.isInitialized
-}
-
type structInfo struct {
fieldsByNumber map[pref.FieldNumber]reflect.StructField
oneofsByName map[pref.Name]reflect.StructField
@@ -204,7 +175,6 @@
// any discrepancies.
func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
mi.fields = map[pref.FieldNumber]*fieldInfo{}
- mi.fieldsOrdered = make([]*fieldInfo, 0, mi.PBType.Fields().Len())
for i := 0; i < mi.PBType.Descriptor().Fields().Len(); i++ {
fd := mi.PBType.Descriptor().Fields().Get(i)
fs := si.fieldsByNumber[fd.Number()]
@@ -212,16 +182,6 @@
switch {
case fd.ContainingOneof() != nil:
fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], si.oneofWrappersByNumber[fd.Number()])
- // There is one fieldInfo for each proto message field, but only one struct
- // field for all message fields in a oneof. We install the encoder functions
- // on the fieldInfo for the first field in the oneof.
- //
- // A slightly simpler approach would be to have each fieldInfo's encoder
- // handle the case where that field is set, but this would require more
- // checks against the current oneof type than a single map lookup.
- if fd.ContainingOneof().Fields().Get(0).Name() == fd.Name() {
- fi.funcs = makeOneofFieldCoder(si.oneofsByName[fd.ContainingOneof().Name()], fd.ContainingOneof(), si.fieldsByNumber, si.oneofWrappersByNumber)
- }
case fd.IsMap():
fi = fieldInfoForMap(fd, fs)
case fd.IsList():
@@ -231,13 +191,8 @@
default:
fi = fieldInfoForScalar(fd, fs)
}
- fi.num = fd.Number()
mi.fields[fd.Number()] = &fi
- mi.fieldsOrdered = append(mi.fieldsOrdered, &fi)
}
- sort.Slice(mi.fieldsOrdered, func(i, j int) bool {
- return mi.fieldsOrdered[i].num < mi.fieldsOrdered[j].num
- })
mi.oneofs = map[pref.Name]*oneofInfo{}
for i := 0; i < mi.PBType.Descriptor().Oneofs().Len(); i++ {