mirror of
https://github.com/golang/go
synced 2024-11-25 20:07:56 -07:00
gob: remove a few more allocations.
- use enc.err and dec.err instead of return values in deferred error catcher - replace io.WriteString with buffer.WriteString now at: mallocs per encode of type Bench: 7 mallocs per decode of type Bench: 8 R=rsc CC=golang-dev https://golang.org/cl/4277057
This commit is contained in:
parent
3d1afb7680
commit
90f3f91786
@ -1004,9 +1004,9 @@ func TestInvalidField(t *testing.T) {
|
|||||||
var bad0 Bad0
|
var bad0 Bad0
|
||||||
bad0.CH = make(chan int)
|
bad0.CH = make(chan int)
|
||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
var nilEncoder *Encoder
|
dummyEncoder := new(Encoder) // sufficient for this purpose.
|
||||||
err := nilEncoder.encode(b, reflect.NewValue(&bad0), userType(reflect.Typeof(&bad0)))
|
dummyEncoder.encode(b, reflect.NewValue(&bad0), userType(reflect.Typeof(&bad0)))
|
||||||
if err == nil {
|
if err := dummyEncoder.err; err == nil {
|
||||||
t.Error("expected error; got none")
|
t.Error("expected error; got none")
|
||||||
} else if strings.Index(err.String(), "type") < 0 {
|
} else if strings.Index(err.String(), "type") < 0 {
|
||||||
t.Error("expected type error; got", err)
|
t.Error("expected type error; got", err)
|
||||||
|
@ -478,7 +478,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr)
|
|||||||
// differ from ut.indir, which was computed when the engine was built.
|
// differ from ut.indir, which was computed when the engine was built.
|
||||||
// This state cannot arise for decodeSingle, which is called directly
|
// This state cannot arise for decodeSingle, which is called directly
|
||||||
// from the user's value, not from the innards of an engine.
|
// 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) {
|
func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr, indir int) {
|
||||||
p = allocate(ut.base.(*reflect.StructType), p, indir)
|
p = allocate(ut.base.(*reflect.StructType), p, indir)
|
||||||
state := dec.newDecoderState(&dec.buf)
|
state := dec.newDecoderState(&dec.buf)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
@ -505,11 +505,10 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr,
|
|||||||
state.fieldnum = fieldnum
|
state.fieldnum = fieldnum
|
||||||
}
|
}
|
||||||
dec.freeDecoderState(state)
|
dec.freeDecoderState(state)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignoreStruct discards the data for a struct with no destination.
|
// ignoreStruct discards the data for a struct with no destination.
|
||||||
func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) {
|
func (dec *Decoder) ignoreStruct(engine *decEngine) {
|
||||||
state := dec.newDecoderState(&dec.buf)
|
state := dec.newDecoderState(&dec.buf)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
for state.b.Len() > 0 {
|
for state.b.Len() > 0 {
|
||||||
@ -529,12 +528,11 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) {
|
|||||||
state.fieldnum = fieldnum
|
state.fieldnum = fieldnum
|
||||||
}
|
}
|
||||||
dec.freeDecoderState(state)
|
dec.freeDecoderState(state)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignoreSingle discards the data for a top-level non-struct value with no
|
// ignoreSingle discards the data for a top-level non-struct value with no
|
||||||
// destination. It's used when calling Decode with a nil value.
|
// destination. It's used when calling Decode with a nil value.
|
||||||
func (dec *Decoder) ignoreSingle(engine *decEngine) (err os.Error) {
|
func (dec *Decoder) ignoreSingle(engine *decEngine) {
|
||||||
state := dec.newDecoderState(&dec.buf)
|
state := dec.newDecoderState(&dec.buf)
|
||||||
state.fieldnum = singletonField
|
state.fieldnum = singletonField
|
||||||
delta := int(state.decodeUint())
|
delta := int(state.decodeUint())
|
||||||
@ -544,7 +542,6 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) (err os.Error) {
|
|||||||
instr := &engine.instr[singletonField]
|
instr := &engine.instr[singletonField]
|
||||||
instr.op(instr, state, unsafe.Pointer(nil))
|
instr.op(instr, state, unsafe.Pointer(nil))
|
||||||
dec.freeDecoderState(state)
|
dec.freeDecoderState(state)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeArrayHelper does the work for decoding arrays and slices.
|
// decodeArrayHelper does the work for decoding arrays and slices.
|
||||||
@ -867,10 +864,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
|
|||||||
}
|
}
|
||||||
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
|
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
|
||||||
// indirect through enginePtr to delay evaluation for recursive structs.
|
// indirect through enginePtr to delay evaluation for recursive structs.
|
||||||
err = dec.decodeStruct(*enginePtr, userType(typ), uintptr(p), i.indir)
|
dec.decodeStruct(*enginePtr, userType(typ), uintptr(p), i.indir)
|
||||||
if err != nil {
|
|
||||||
error(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case *reflect.InterfaceType:
|
case *reflect.InterfaceType:
|
||||||
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
|
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
|
||||||
@ -1185,11 +1179,12 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// decodeValue decodes the data stream representing a value and stores it in val.
|
// decodeValue decodes the data stream representing a value and stores it in val.
|
||||||
func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) (err os.Error) {
|
func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
|
||||||
defer catchError(&err)
|
defer catchError(&dec.err)
|
||||||
// If the value is nil, it means we should just ignore this item.
|
// If the value is nil, it means we should just ignore this item.
|
||||||
if val == nil {
|
if val == nil {
|
||||||
return dec.decodeIgnoredValue(wireId)
|
dec.decodeIgnoredValue(wireId)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// Dereference down to the underlying struct type.
|
// Dereference down to the underlying struct type.
|
||||||
ut := userType(val.Type())
|
ut := userType(val.Type())
|
||||||
@ -1198,32 +1193,36 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) (err os.Error)
|
|||||||
if ut.isGobDecoder {
|
if ut.isGobDecoder {
|
||||||
indir = int(ut.decIndir)
|
indir = int(ut.decIndir)
|
||||||
}
|
}
|
||||||
enginePtr, err := dec.getDecEnginePtr(wireId, ut)
|
var enginePtr **decEngine
|
||||||
if err != nil {
|
enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut)
|
||||||
return err
|
if dec.err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
engine := *enginePtr
|
engine := *enginePtr
|
||||||
if st, ok := base.(*reflect.StructType); ok && !ut.isGobDecoder {
|
if st, ok := base.(*reflect.StructType); ok && !ut.isGobDecoder {
|
||||||
if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
|
if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
|
||||||
name := base.Name()
|
name := base.Name()
|
||||||
return os.ErrorString("gob: type mismatch: no fields matched compiling decoder for " + name)
|
errorf("gob: type mismatch: no fields matched compiling decoder for %s", name)
|
||||||
}
|
}
|
||||||
return dec.decodeStruct(engine, ut, uintptr(val.UnsafeAddr()), indir)
|
dec.decodeStruct(engine, ut, uintptr(val.UnsafeAddr()), indir)
|
||||||
|
} else {
|
||||||
|
dec.decodeSingle(engine, ut, uintptr(val.UnsafeAddr()))
|
||||||
}
|
}
|
||||||
return dec.decodeSingle(engine, ut, uintptr(val.UnsafeAddr()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeIgnoredValue decodes the data stream representing a value of the specified type and discards it.
|
// decodeIgnoredValue decodes the data stream representing a value of the specified type and discards it.
|
||||||
func (dec *Decoder) decodeIgnoredValue(wireId typeId) os.Error {
|
func (dec *Decoder) decodeIgnoredValue(wireId typeId) {
|
||||||
enginePtr, err := dec.getIgnoreEnginePtr(wireId)
|
var enginePtr **decEngine
|
||||||
if err != nil {
|
enginePtr, dec.err = dec.getIgnoreEnginePtr(wireId)
|
||||||
return err
|
if dec.err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
wire := dec.wireType[wireId]
|
wire := dec.wireType[wireId]
|
||||||
if wire != nil && wire.StructT != nil {
|
if wire != nil && wire.StructT != nil {
|
||||||
return dec.ignoreStruct(*enginePtr)
|
dec.ignoreStruct(*enginePtr)
|
||||||
|
} else {
|
||||||
|
dec.ignoreSingle(*enginePtr)
|
||||||
}
|
}
|
||||||
return dec.ignoreSingle(*enginePtr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -50,7 +50,7 @@ func (dec *Decoder) recvType(id typeId) {
|
|||||||
|
|
||||||
// Type:
|
// Type:
|
||||||
wire := new(wireType)
|
wire := new(wireType)
|
||||||
dec.err = dec.decodeValue(tWireType, reflect.NewValue(wire))
|
dec.decodeValue(tWireType, reflect.NewValue(wire))
|
||||||
if dec.err != nil {
|
if dec.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -185,7 +185,7 @@ func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
|
|||||||
dec.err = nil
|
dec.err = nil
|
||||||
id := dec.decodeTypeSequence(false)
|
id := dec.decodeTypeSequence(false)
|
||||||
if dec.err == nil {
|
if dec.err == nil {
|
||||||
dec.err = dec.decodeValue(id, value)
|
dec.decodeValue(id, value)
|
||||||
}
|
}
|
||||||
return dec.err
|
return dec.err
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,7 @@ package gob
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
|
||||||
"math"
|
"math"
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -320,7 +318,7 @@ func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
|
|||||||
if len(s) > 0 || state.sendZero {
|
if len(s) > 0 || state.sendZero {
|
||||||
state.update(i)
|
state.update(i)
|
||||||
state.encodeUint(uint64(len(s)))
|
state.encodeUint(uint64(len(s)))
|
||||||
io.WriteString(state.b, s)
|
state.b.WriteString(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,7 +442,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue)
|
|||||||
}
|
}
|
||||||
// Send the name.
|
// Send the name.
|
||||||
state.encodeUint(uint64(len(name)))
|
state.encodeUint(uint64(len(name)))
|
||||||
_, err := io.WriteString(state.b, name)
|
_, err := state.b.WriteString(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
error(err)
|
error(err)
|
||||||
}
|
}
|
||||||
@ -456,9 +454,9 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue)
|
|||||||
// should be written to b, before the encoded value.
|
// should be written to b, before the encoded value.
|
||||||
enc.pushWriter(b)
|
enc.pushWriter(b)
|
||||||
data := new(bytes.Buffer)
|
data := new(bytes.Buffer)
|
||||||
err = enc.encode(data, iv.Elem(), ut)
|
enc.encode(data, iv.Elem(), ut)
|
||||||
if err != nil {
|
if enc.err != nil {
|
||||||
error(err)
|
error(enc.err)
|
||||||
}
|
}
|
||||||
enc.popWriter()
|
enc.popWriter()
|
||||||
enc.writeMessage(b, data)
|
enc.writeMessage(b, data)
|
||||||
@ -685,8 +683,8 @@ func (enc *Encoder) lockAndGetEncEngine(ut *userTypeInfo) *encEngine {
|
|||||||
return enc.getEncEngine(ut)
|
return enc.getEncEngine(ut)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) (err os.Error) {
|
func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) {
|
||||||
defer catchError(&err)
|
defer catchError(&enc.err)
|
||||||
engine := enc.lockAndGetEncEngine(ut)
|
engine := enc.lockAndGetEncEngine(ut)
|
||||||
indir := ut.indir
|
indir := ut.indir
|
||||||
if ut.isGobEncoder {
|
if ut.isGobEncoder {
|
||||||
@ -700,5 +698,4 @@ func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInf
|
|||||||
} else {
|
} else {
|
||||||
enc.encodeSingle(b, engine, value.UnsafeAddr())
|
enc.encodeSingle(b, engine, value.UnsafeAddr())
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -228,10 +228,8 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encode the object.
|
// Encode the object.
|
||||||
err = enc.encode(state.b, value, ut)
|
enc.encode(state.b, value, ut)
|
||||||
if err != nil {
|
if enc.err == nil {
|
||||||
enc.setError(err)
|
|
||||||
} else {
|
|
||||||
enc.writeMessage(enc.writer(), state.b)
|
enc.writeMessage(enc.writer(), state.b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user