1
0
mirror of https://github.com/golang/go synced 2024-11-20 07:54:39 -07:00

gob: compute information about a user's type once.

Other than maybe cleaning the code up a bit, this has
little practical effect for now, but lays the foundation
for remembering the method set of a type, which can
be expensive.

R=rsc
CC=golang-dev
https://golang.org/cl/4193041
This commit is contained in:
Rob Pike 2011-02-22 12:31:57 -08:00
parent 556506e869
commit 14b6a47748
5 changed files with 101 additions and 57 deletions

View File

@ -984,7 +984,7 @@ func TestInvalidField(t *testing.T) {
var bad0 Bad0
bad0.ch = make(chan int)
b := new(bytes.Buffer)
err := nilEncoder.encode(b, reflect.NewValue(&bad0))
err := nilEncoder.encode(b, reflect.NewValue(&bad0), userType(reflect.Typeof(&bad0)))
if err == nil {
t.Error("expected error; got none")
} else if strings.Index(err.String(), "type") < 0 {

View File

@ -409,9 +409,9 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
return *(*uintptr)(up)
}
func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, p uintptr, indir int) (err os.Error) {
func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr) (err os.Error) {
defer catchError(&err)
p = allocate(rtyp, p, indir)
p = allocate(ut.base, p, ut.indir)
state := newDecodeState(dec, &dec.buf)
state.fieldnum = singletonField
basep := p
@ -428,9 +428,13 @@ func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, p uintptr
return nil
}
func (dec *Decoder) decodeStruct(engine *decEngine, rtyp *reflect.StructType, p uintptr, indir int) (err os.Error) {
// Indir is for the value, not the type. At the time of the call it may
// differ from ut.indir, which was computed when the engine was built.
// This state cannot arise for decodeSingle, which is called directly
// from the user's value, not from the innards of an engine.
func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr, indir int) (err os.Error) {
defer catchError(&err)
p = allocate(rtyp, p, indir)
p = allocate(ut.base.(*reflect.StructType), p, indir)
state := newDecodeState(dec, &dec.buf)
state.fieldnum = -1
basep := p
@ -702,7 +706,9 @@ var decIgnoreOpMap = map[typeId]decOp{
// Return the decoding op for the base type under rt and
// the indirection count to reach it.
func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp, int) {
typ, indir := indirect(rt)
ut := userType(rt)
typ := ut.base
indir := ut.indir
var op decOp
k := typ.Kind()
if int(k) < len(decOpMap) {
@ -757,8 +763,8 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
error(err)
}
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
// indirect through enginePtr to delay evaluation for recursive structs
err = dec.decodeStruct(*enginePtr, t, uintptr(p), i.indir)
// indirect through enginePtr to delay evaluation for recursive structs.
err = dec.decodeStruct(*enginePtr, userType(typ), uintptr(p), i.indir)
if err != nil {
error(err)
}
@ -837,7 +843,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
// Answers the question for basic types, arrays, and slices.
// Structs are considered ok; fields will be checked later.
func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
fr, _ = indirect(fr)
fr = userType(fr).base
switch t := fr.(type) {
default:
// map, chan, etc: cannot handle.
@ -882,7 +888,7 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
} else {
sw = dec.wireType[fw].SliceT
}
elem, _ := indirect(t.Elem())
elem := userType(t.Elem()).base
return sw != nil && dec.compatibleType(elem, sw.Elem)
case *reflect.StructType:
return true
@ -1026,20 +1032,22 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) os.Error {
return dec.decodeIgnoredValue(wireId)
}
// Dereference down to the underlying struct type.
rt, indir := indirect(val.Type())
enginePtr, err := dec.getDecEnginePtr(wireId, rt)
ut := userType(val.Type())
base := ut.base
indir := ut.indir
enginePtr, err := dec.getDecEnginePtr(wireId, base)
if err != nil {
return err
}
engine := *enginePtr
if st, ok := rt.(*reflect.StructType); ok {
if st, ok := base.(*reflect.StructType); ok {
if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
name := rt.Name()
name := base.Name()
return os.ErrorString("gob: type mismatch: no fields matched compiling decoder for " + name)
}
return dec.decodeStruct(engine, st, uintptr(val.Addr()), indir)
return dec.decodeStruct(engine, ut, uintptr(val.Addr()), indir)
}
return dec.decodeSingle(engine, rt, uintptr(val.Addr()), indir)
return dec.decodeSingle(engine, ut, uintptr(val.Addr()))
}
func (dec *Decoder) decodeIgnoredValue(wireId typeId) os.Error {

View File

@ -384,10 +384,10 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue)
return
}
typ, _ := indirect(iv.Elem().Type())
name, ok := concreteTypeToName[typ]
ut := userType(iv.Elem().Type())
name, ok := concreteTypeToName[ut.base]
if !ok {
errorf("gob: type not registered for interface: %s", typ)
errorf("gob: type not registered for interface: %s", ut.base)
}
// Send the name.
state.encodeUint(uint64(len(name)))
@ -396,14 +396,14 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue)
error(err)
}
// Define the type id if necessary.
enc.sendTypeDescriptor(enc.writer(), state, typ)
enc.sendTypeDescriptor(enc.writer(), state, ut)
// Send the type id.
enc.sendTypeId(state, typ)
enc.sendTypeId(state, ut)
// Encode the value into a new buffer. Any nested type definitions
// should be written to b, before the encoded value.
enc.pushWriter(b)
data := new(bytes.Buffer)
err = enc.encode(data, iv.Elem())
err = enc.encode(data, iv.Elem(), ut)
if err != nil {
error(err)
}
@ -437,7 +437,9 @@ var encOpMap = []encOp{
// Return the encoding op for the base type under rt and
// the indirection count to reach it.
func (enc *Encoder) encOpFor(rt reflect.Type) (encOp, int) {
typ, indir := indirect(rt)
ut := userType(rt)
typ := ut.base
indir := ut.indir
var op encOp
k := typ.Kind()
if int(k) < len(encOpMap) {
@ -559,14 +561,12 @@ func (enc *Encoder) lockAndGetEncEngine(rt reflect.Type) *encEngine {
return enc.getEncEngine(rt)
}
func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value) (err os.Error) {
func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) (err os.Error) {
defer catchError(&err)
// Dereference down to the underlying object.
rt, indir := indirect(value.Type())
for i := 0; i < indir; i++ {
for i := 0; i < ut.indir; i++ {
value = reflect.Indirect(value)
}
engine := enc.lockAndGetEncEngine(rt)
engine := enc.lockAndGetEncEngine(ut.base)
if value.Type().Kind() == reflect.Struct {
enc.encodeStruct(b, engine, value.Addr())
} else {

View File

@ -80,7 +80,8 @@ func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Type) (sent bool) {
// Drill down to the base type.
rt, _ := indirect(origt)
ut := userType(origt)
rt := ut.base
switch rt := rt.(type) {
default:
@ -125,7 +126,7 @@ func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Typ
// Id:
state.encodeInt(-int64(info.id))
// Type:
enc.encode(state.b, reflect.NewValue(info.wire))
enc.encode(state.b, reflect.NewValue(info.wire), wireTypeUserInfo)
enc.writeMessage(w, state.b)
if enc.err != nil {
return
@ -153,15 +154,16 @@ func (enc *Encoder) Encode(e interface{}) os.Error {
return enc.EncodeValue(reflect.NewValue(e))
}
// sendTypeId makes sure the remote side knows about this type.
// sendTypeDescriptor makes sure the remote side knows about this type.
// It will send a descriptor if this is the first time the type has been
// sent.
func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, rt reflect.Type) {
func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *userTypeInfo) {
// Make sure the type is known to the other side.
// First, have we already sent this type?
if _, alreadySent := enc.sent[rt]; !alreadySent {
// First, have we already sent this (base) type?
base := ut.base
if _, alreadySent := enc.sent[base]; !alreadySent {
// No, so send it.
sent := enc.sendType(w, state, rt)
sent := enc.sendType(w, state, base)
if enc.err != nil {
return
}
@ -170,21 +172,21 @@ func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, rt refl
// need to send the type info but we do need to update enc.sent.
if !sent {
typeLock.Lock()
info, err := getTypeInfo(rt)
info, err := getTypeInfo(base)
typeLock.Unlock()
if err != nil {
enc.setError(err)
return
}
enc.sent[rt] = info.id
enc.sent[base] = info.id
}
}
}
// sendTypeId sends the id, which must have already been defined.
func (enc *Encoder) sendTypeId(state *encoderState, rt reflect.Type) {
func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
// Identify the type of this top-level value.
state.encodeInt(int64(enc.sent[rt]))
state.encodeInt(int64(enc.sent[ut.base]))
}
// EncodeValue transmits the data item represented by the reflection value,
@ -199,18 +201,18 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
enc.w = enc.w[0:1]
enc.err = nil
rt, _ := indirect(value.Type())
ut := userType(value.Type())
state := newEncoderState(enc, new(bytes.Buffer))
enc.sendTypeDescriptor(enc.writer(), state, rt)
enc.sendTypeId(state, rt)
enc.sendTypeDescriptor(enc.writer(), state, ut)
enc.sendTypeId(state, ut)
if enc.err != nil {
return enc.err
}
// Encode the object.
err := enc.encode(state.b, value)
err := enc.encode(state.b, value, ut)
if err != nil {
enc.setError(err)
} else {

View File

@ -11,12 +11,43 @@ import (
"sync"
)
// Reflection types are themselves interface values holding structs
// describing the type. Each type has a different struct so that struct can
// be the kind. For example, if typ is the reflect type for an int8, typ is
// a pointer to a reflect.Int8Type struct; if typ is the reflect type for a
// function, typ is a pointer to a reflect.FuncType struct; we use the type
// of that pointer as the kind.
// userTypeInfo stores the information associated with a type the user has handed
// to the package. It's computed once and stored in a map keyed by reflection
// type.
type userTypeInfo struct {
user reflect.Type // the type the user handed us
base reflect.Type // the base type after all indirections
indir int // number of indirections to reach the base type
}
var (
// Protected by an RWMutex because we read it a lot and write
// it only when we see a new type, typically when compiling.
userTypeLock sync.RWMutex
userTypeCache = make(map[reflect.Type]*userTypeInfo)
)
// userType returns, and saves, the information associated with user-provided type rt
func userType(rt reflect.Type) *userTypeInfo {
userTypeLock.RLock()
ut := userTypeCache[rt]
userTypeLock.RUnlock()
if ut != nil {
return ut
}
// Now set the value under the write lock.
userTypeLock.Lock()
defer userTypeLock.Unlock()
if ut = userTypeCache[rt]; ut != nil {
// Lost the race; not a problem.
return ut
}
ut = new(userTypeInfo)
ut.user = rt
ut.base, ut.indir = indirect(rt)
userTypeCache[rt] = ut
return ut
}
// A typeId represents a gob Type as an integer that can be passed on the wire.
// Internally, typeIds are used as keys to a map to recover the underlying type info.
@ -110,6 +141,7 @@ var (
// Predefined because it's needed by the Decoder
var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
var wireTypeUserInfo *userTypeInfo // userTypeInfo of (*wireType)
func init() {
// Some magic numbers to make sure there are no surprises.
@ -133,6 +165,7 @@ func init() {
}
nextId = firstUserId
registerBasics()
wireTypeUserInfo = userType(reflect.Typeof((*wireType)(nil)))
}
// Array type
@ -317,10 +350,10 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
field := make([]*fieldType, t.NumField())
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
typ, _ := indirect(f.Type)
typ := userType(f.Type).base
tname := typ.Name()
if tname == "" {
t, _ := indirect(f.Type)
t := userType(f.Type).base
tname = t.String()
}
gt, err := getType(tname, f.Type)
@ -341,7 +374,7 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
// getType returns the Gob type describing the given reflect.Type.
// typeLock must be held.
func getType(name string, rt reflect.Type) (gobType, os.Error) {
rt, _ = indirect(rt)
rt = userType(rt).base
typ, present := types[rt]
if present {
return typ, nil
@ -371,6 +404,7 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
types[rt] = typ
setTypeId(typ)
checkId(expect, nextId)
userType(rt) // might as well cache it now
return nextId
}
@ -473,18 +507,18 @@ func RegisterName(name string, value interface{}) {
// reserved for nil
panic("attempt to register empty name")
}
rt, _ := indirect(reflect.Typeof(value))
base := userType(reflect.Typeof(value)).base
// Check for incompatible duplicates.
if t, ok := nameToConcreteType[name]; ok && t != rt {
if t, ok := nameToConcreteType[name]; ok && t != base {
panic("gob: registering duplicate types for " + name)
}
if n, ok := concreteTypeToName[rt]; ok && n != name {
panic("gob: registering duplicate names for " + rt.String())
if n, ok := concreteTypeToName[base]; ok && n != name {
panic("gob: registering duplicate names for " + base.String())
}
// Store the name and type provided by the user....
nameToConcreteType[name] = reflect.Typeof(value)
// but the flattened type in the type table, since that's what decode needs.
concreteTypeToName[rt] = name
concreteTypeToName[base] = name
}
// Register records a type, identified by a value for that type, under its