1
0
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:
Rob Pike 2011-03-16 18:03:13 -07:00
parent 3d1afb7680
commit 90f3f91786
5 changed files with 38 additions and 44 deletions

View File

@ -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)

View File

@ -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() {

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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)
} }