]> Cypherpunks repositories - gostls13.git/commitdiff
gob: remove a few more allocations.
authorRob Pike <r@golang.org>
Thu, 17 Mar 2011 01:03:13 +0000 (18:03 -0700)
committerRob Pike <r@golang.org>
Thu, 17 Mar 2011 01:03:13 +0000 (18:03 -0700)
- 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

src/pkg/gob/codec_test.go
src/pkg/gob/decode.go
src/pkg/gob/decoder.go
src/pkg/gob/encode.go
src/pkg/gob/encoder.go

index e4364e6fd7a4f501f9c9cd0155654755ad151c27..28042ccaa3a2db8a815eaa9ac079797fd6207eca 100644 (file)
@@ -1004,9 +1004,9 @@ func TestInvalidField(t *testing.T) {
        var bad0 Bad0
        bad0.CH = make(chan int)
        b := new(bytes.Buffer)
-       var nilEncoder *Encoder
-       err := nilEncoder.encode(b, reflect.NewValue(&bad0), userType(reflect.Typeof(&bad0)))
-       if err == nil {
+       dummyEncoder := new(Encoder) // sufficient for this purpose.
+       dummyEncoder.encode(b, reflect.NewValue(&bad0), userType(reflect.Typeof(&bad0)))
+       if err := dummyEncoder.err; err == nil {
                t.Error("expected error; got none")
        } else if strings.Index(err.String(), "type") < 0 {
                t.Error("expected type error; got", err)
index d00ef7cd6573811a453f1dba429c80d6a7d0c05c..f77504d871d45e3d1bd8d1b9102036fb4cdf5463 100644 (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.
 // 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) {
+func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr, indir int) {
        p = allocate(ut.base.(*reflect.StructType), p, indir)
        state := dec.newDecoderState(&dec.buf)
        state.fieldnum = -1
@@ -505,11 +505,10 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr,
                state.fieldnum = fieldnum
        }
        dec.freeDecoderState(state)
-       return nil
 }
 
 // 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.fieldnum = -1
        for state.b.Len() > 0 {
@@ -529,12 +528,11 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) {
                state.fieldnum = fieldnum
        }
        dec.freeDecoderState(state)
-       return nil
 }
 
 // ignoreSingle discards the data for a top-level non-struct value with no
 // 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.fieldnum = singletonField
        delta := int(state.decodeUint())
@@ -544,7 +542,6 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) (err os.Error) {
        instr := &engine.instr[singletonField]
        instr.op(instr, state, unsafe.Pointer(nil))
        dec.freeDecoderState(state)
-       return nil
 }
 
 // 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) {
                                // indirect through enginePtr to delay evaluation for recursive structs.
-                               err = dec.decodeStruct(*enginePtr, userType(typ), uintptr(p), i.indir)
-                               if err != nil {
-                                       error(err)
-                               }
+                               dec.decodeStruct(*enginePtr, userType(typ), uintptr(p), i.indir)
                        }
                case *reflect.InterfaceType:
                        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.
-func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) (err os.Error) {
-       defer catchError(&err)
+func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
+       defer catchError(&dec.err)
        // If the value is nil, it means we should just ignore this item.
        if val == nil {
-               return dec.decodeIgnoredValue(wireId)
+               dec.decodeIgnoredValue(wireId)
+               return
        }
        // Dereference down to the underlying struct type.
        ut := userType(val.Type())
@@ -1198,32 +1193,36 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) (err os.Error)
        if ut.isGobDecoder {
                indir = int(ut.decIndir)
        }
-       enginePtr, err := dec.getDecEnginePtr(wireId, ut)
-       if err != nil {
-               return err
+       var enginePtr **decEngine
+       enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut)
+       if dec.err != nil {
+               return
        }
        engine := *enginePtr
        if st, ok := base.(*reflect.StructType); ok && !ut.isGobDecoder {
                if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
                        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.
-func (dec *Decoder) decodeIgnoredValue(wireId typeId) os.Error {
-       enginePtr, err := dec.getIgnoreEnginePtr(wireId)
-       if err != nil {
-               return err
+func (dec *Decoder) decodeIgnoredValue(wireId typeId) {
+       var enginePtr **decEngine
+       enginePtr, dec.err = dec.getIgnoreEnginePtr(wireId)
+       if dec.err != nil {
+               return
        }
        wire := dec.wireType[wireId]
        if wire != nil && wire.StructT != nil {
-               return dec.ignoreStruct(*enginePtr)
+               dec.ignoreStruct(*enginePtr)
+       } else {
+               dec.ignoreSingle(*enginePtr)
        }
-       return dec.ignoreSingle(*enginePtr)
 }
 
 func init() {
index 5e5afb37b4b5d7a2ae2515f5abc952ab02585d14..34364161aa3bf50ef5caa723aee93ae2df0d7066 100644 (file)
@@ -50,7 +50,7 @@ func (dec *Decoder) recvType(id typeId) {
 
        // Type:
        wire := new(wireType)
-       dec.err = dec.decodeValue(tWireType, reflect.NewValue(wire))
+       dec.decodeValue(tWireType, reflect.NewValue(wire))
        if dec.err != nil {
                return
        }
@@ -185,7 +185,7 @@ func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
        dec.err = nil
        id := dec.decodeTypeSequence(false)
        if dec.err == nil {
-               dec.err = dec.decodeValue(id, value)
+               dec.decodeValue(id, value)
        }
        return dec.err
 }
index 4dbafdddeb7d66587e496dd91d86dc39eabf3d0b..5cfdb583a1804e57848d5aa642458efffab3eba8 100644 (file)
@@ -6,9 +6,7 @@ package gob
 
 import (
        "bytes"
-       "io"
        "math"
-       "os"
        "reflect"
        "unsafe"
 )
@@ -320,7 +318,7 @@ func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
        if len(s) > 0 || state.sendZero {
                state.update(i)
                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.
        state.encodeUint(uint64(len(name)))
-       _, err := io.WriteString(state.b, name)
+       _, err := state.b.WriteString(name)
        if err != nil {
                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.
        enc.pushWriter(b)
        data := new(bytes.Buffer)
-       err = enc.encode(data, iv.Elem(), ut)
-       if err != nil {
-               error(err)
+       enc.encode(data, iv.Elem(), ut)
+       if enc.err != nil {
+               error(enc.err)
        }
        enc.popWriter()
        enc.writeMessage(b, data)
@@ -685,8 +683,8 @@ func (enc *Encoder) lockAndGetEncEngine(ut *userTypeInfo) *encEngine {
        return enc.getEncEngine(ut)
 }
 
-func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) (err os.Error) {
-       defer catchError(&err)
+func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) {
+       defer catchError(&enc.err)
        engine := enc.lockAndGetEncEngine(ut)
        indir := ut.indir
        if ut.isGobEncoder {
@@ -700,5 +698,4 @@ func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInf
        } else {
                enc.encodeSingle(b, engine, value.UnsafeAddr())
        }
-       return nil
 }
index 7045e8e892b0fe64e6ad4416b3060e371b4d5b39..55481a98854f5c0610606f612d03695eaea479eb 100644 (file)
@@ -228,10 +228,8 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
        }
 
        // Encode the object.
-       err = enc.encode(state.b, value, ut)
-       if err != nil {
-               enc.setError(err)
-       } else {
+       enc.encode(state.b, value, ut)
+       if enc.err == nil {
                enc.writeMessage(enc.writer(), state.b)
        }