MM-27456: Use reflect-free serialization for hot structs (#15171)
Automatic Merge
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
32b7d2b5f1
Коммит
91a76b2df9
169
vendor/github.com/tinylib/msgp/parse/inline.go
сгенерированный
поставляемый
Обычный файл
169
vendor/github.com/tinylib/msgp/parse/inline.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,169 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/tinylib/msgp/gen"
|
||||
)
|
||||
|
||||
// This file defines when and how we
|
||||
// propagate type information from
|
||||
// one type declaration to another.
|
||||
// After the processing pass, every
|
||||
// non-primitive type is marshalled/unmarshalled/etc.
|
||||
// through a function call. Here, we propagate
|
||||
// the type information into the caller's type
|
||||
// tree *if* the child type is simple enough.
|
||||
//
|
||||
// For example, types like
|
||||
//
|
||||
// type A [4]int
|
||||
//
|
||||
// will get pushed into parent methods,
|
||||
// whereas types like
|
||||
//
|
||||
// type B [3]map[string]struct{A, B [4]string}
|
||||
//
|
||||
// will not.
|
||||
|
||||
// this is an approximate measure
|
||||
// of the number of children in a node
|
||||
const maxComplex = 5
|
||||
|
||||
// begin recursive search for identities with the
|
||||
// given name and replace them with be
|
||||
func (f *FileSet) findShim(id string, be *gen.BaseElem) {
|
||||
for name, el := range f.Identities {
|
||||
pushstate(name)
|
||||
switch el := el.(type) {
|
||||
case *gen.Struct:
|
||||
for i := range el.Fields {
|
||||
f.nextShim(&el.Fields[i].FieldElem, id, be)
|
||||
}
|
||||
case *gen.Array:
|
||||
f.nextShim(&el.Els, id, be)
|
||||
case *gen.Slice:
|
||||
f.nextShim(&el.Els, id, be)
|
||||
case *gen.Map:
|
||||
f.nextShim(&el.Value, id, be)
|
||||
case *gen.Ptr:
|
||||
f.nextShim(&el.Value, id, be)
|
||||
}
|
||||
popstate()
|
||||
}
|
||||
// we'll need this at the top level as well
|
||||
f.Identities[id] = be
|
||||
}
|
||||
|
||||
func (f *FileSet) nextShim(ref *gen.Elem, id string, be *gen.BaseElem) {
|
||||
if (*ref).TypeName() == id {
|
||||
vn := (*ref).Varname()
|
||||
*ref = be.Copy()
|
||||
(*ref).SetVarname(vn)
|
||||
} else {
|
||||
switch el := (*ref).(type) {
|
||||
case *gen.Struct:
|
||||
for i := range el.Fields {
|
||||
f.nextShim(&el.Fields[i].FieldElem, id, be)
|
||||
}
|
||||
case *gen.Array:
|
||||
f.nextShim(&el.Els, id, be)
|
||||
case *gen.Slice:
|
||||
f.nextShim(&el.Els, id, be)
|
||||
case *gen.Map:
|
||||
f.nextShim(&el.Value, id, be)
|
||||
case *gen.Ptr:
|
||||
f.nextShim(&el.Value, id, be)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// propInline identifies and inlines candidates
|
||||
func (f *FileSet) propInline() {
|
||||
type gelem struct {
|
||||
name string
|
||||
el gen.Elem
|
||||
}
|
||||
|
||||
all := make([]gelem, 0, len(f.Identities))
|
||||
|
||||
for name, el := range f.Identities {
|
||||
all = append(all, gelem{name: name, el: el})
|
||||
}
|
||||
|
||||
// make sure we process inlining determinstically:
|
||||
// start with the least-complex elems;
|
||||
// use identifier names as a tie-breaker
|
||||
sort.Slice(all, func(i, j int) bool {
|
||||
ig, jg := &all[i], &all[j]
|
||||
ic, jc := ig.el.Complexity(), jg.el.Complexity()
|
||||
return ic < jc || (ic == jc && ig.name < jg.name)
|
||||
})
|
||||
|
||||
for i := range all {
|
||||
name := all[i].name
|
||||
pushstate(name)
|
||||
switch el := all[i].el.(type) {
|
||||
case *gen.Struct:
|
||||
for i := range el.Fields {
|
||||
f.nextInline(&el.Fields[i].FieldElem, name)
|
||||
}
|
||||
case *gen.Array:
|
||||
f.nextInline(&el.Els, name)
|
||||
case *gen.Slice:
|
||||
f.nextInline(&el.Els, name)
|
||||
case *gen.Map:
|
||||
f.nextInline(&el.Value, name)
|
||||
case *gen.Ptr:
|
||||
f.nextInline(&el.Value, name)
|
||||
}
|
||||
popstate()
|
||||
}
|
||||
}
|
||||
|
||||
const fatalloop = `detected infinite recursion in inlining loop!
|
||||
Please file a bug at github.com/tinylib/msgp/issues!
|
||||
Thanks!
|
||||
`
|
||||
|
||||
func (f *FileSet) nextInline(ref *gen.Elem, root string) {
|
||||
switch el := (*ref).(type) {
|
||||
case *gen.BaseElem:
|
||||
// ensure that we're not inlining
|
||||
// a type into itself
|
||||
typ := el.TypeName()
|
||||
if el.Value == gen.IDENT && typ != root {
|
||||
if node, ok := f.Identities[typ]; ok && node.Complexity() < maxComplex {
|
||||
infof("inlining %s\n", typ)
|
||||
|
||||
// This should never happen; it will cause
|
||||
// infinite recursion.
|
||||
if node == *ref {
|
||||
panic(fatalloop)
|
||||
}
|
||||
|
||||
*ref = node.Copy()
|
||||
f.nextInline(ref, node.TypeName())
|
||||
} else if !ok && !el.Resolved() {
|
||||
// this is the point at which we're sure that
|
||||
// we've got a type that isn't a primitive,
|
||||
// a library builtin, or a processed type
|
||||
warnf("unresolved identifier: %s\n", typ)
|
||||
}
|
||||
}
|
||||
case *gen.Struct:
|
||||
for i := range el.Fields {
|
||||
f.nextInline(&el.Fields[i].FieldElem, root)
|
||||
}
|
||||
case *gen.Array:
|
||||
f.nextInline(&el.Els, root)
|
||||
case *gen.Slice:
|
||||
f.nextInline(&el.Els, root)
|
||||
case *gen.Map:
|
||||
f.nextInline(&el.Value, root)
|
||||
case *gen.Ptr:
|
||||
f.nextInline(&el.Value, root)
|
||||
default:
|
||||
panic("bad elem type")
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user