diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go index 4562e19309..e4364e6fd7 100644 --- a/src/pkg/gob/codec_test.go +++ b/src/pkg/gob/codec_test.go @@ -50,7 +50,7 @@ func testError(t *testing.T) { func TestUintCodec(t *testing.T) { defer testError(t) b := new(bytes.Buffer) - encState := newEncoderState(nil, b) + encState := newEncoderState(b) for _, tt := range encodeT { b.Reset() encState.encodeUint(tt.x) @@ -58,7 +58,7 @@ func TestUintCodec(t *testing.T) { t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes()) } } - decState := newDecodeState(nil, b) + decState := newDecodeState(b) for u := uint64(0); ; u = (u + 1) * 7 { b.Reset() encState.encodeUint(u) @@ -75,9 +75,9 @@ func TestUintCodec(t *testing.T) { func verifyInt(i int64, t *testing.T) { defer testError(t) var b = new(bytes.Buffer) - encState := newEncoderState(nil, b) + encState := newEncoderState(b) encState.encodeInt(i) - decState := newDecodeState(nil, b) + decState := newDecodeState(b) decState.buf = make([]byte, 8) j := decState.decodeInt() if i != j { @@ -111,9 +111,16 @@ var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40} // The result of encoding "hello" with field number 7 var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'} -func newencoderState(b *bytes.Buffer) *encoderState { +func newDecodeState(buf *bytes.Buffer) *decoderState { + d := new(decoderState) + d.b = buf + d.buf = make([]byte, uint64Size) + return d +} + +func newEncoderState(b *bytes.Buffer) *encoderState { b.Reset() - state := newEncoderState(nil, b) + state := &encoderState{enc: nil, b: b} state.fieldnum = -1 return state } @@ -127,7 +134,7 @@ func TestScalarEncInstructions(t *testing.T) { { data := struct{ a bool }{true} instr := &encInstr{encBool, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(boolResult, b.Bytes()) { t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes()) @@ -139,7 +146,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a int }{17} instr := &encInstr{encInt, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(signedResult, b.Bytes()) { t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes()) @@ -151,7 +158,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a uint }{17} instr := &encInstr{encUint, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(unsignedResult, b.Bytes()) { t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes()) @@ -163,7 +170,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a int8 }{17} instr := &encInstr{encInt8, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(signedResult, b.Bytes()) { t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes()) @@ -175,7 +182,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a uint8 }{17} instr := &encInstr{encUint8, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(unsignedResult, b.Bytes()) { t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes()) @@ -187,7 +194,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a int16 }{17} instr := &encInstr{encInt16, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(signedResult, b.Bytes()) { t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes()) @@ -199,7 +206,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a uint16 }{17} instr := &encInstr{encUint16, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(unsignedResult, b.Bytes()) { t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes()) @@ -211,7 +218,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a int32 }{17} instr := &encInstr{encInt32, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(signedResult, b.Bytes()) { t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes()) @@ -223,7 +230,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a uint32 }{17} instr := &encInstr{encUint32, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(unsignedResult, b.Bytes()) { t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes()) @@ -235,7 +242,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a int64 }{17} instr := &encInstr{encInt64, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(signedResult, b.Bytes()) { t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes()) @@ -247,7 +254,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a uint64 }{17} instr := &encInstr{encUint64, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(unsignedResult, b.Bytes()) { t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes()) @@ -259,7 +266,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a float32 }{17} instr := &encInstr{encFloat32, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(floatResult, b.Bytes()) { t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes()) @@ -271,7 +278,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a float64 }{17} instr := &encInstr{encFloat64, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(floatResult, b.Bytes()) { t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes()) @@ -283,7 +290,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a []byte }{[]byte("hello")} instr := &encInstr{encUint8Array, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(bytesResult, b.Bytes()) { t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes()) @@ -295,7 +302,7 @@ func TestScalarEncInstructions(t *testing.T) { b.Reset() data := struct{ a string }{"hello"} instr := &encInstr{encString, 6, 0, 0} - state := newencoderState(b) + state := newEncoderState(b) instr.op(instr, state, unsafe.Pointer(&data)) if !bytes.Equal(bytesResult, b.Bytes()) { t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes()) @@ -315,7 +322,7 @@ func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, p u func newDecodeStateFromData(data []byte) *decoderState { b := bytes.NewBuffer(data) - state := newDecodeState(nil, b) + state := newDecodeState(b) state.fieldnum = -1 return state } diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go index c47fea1a70..d00ef7cd65 100644 --- a/src/pkg/gob/decode.go +++ b/src/pkg/gob/decode.go @@ -31,18 +31,29 @@ type decoderState struct { b *bytes.Buffer fieldnum int // the last field number read. buf []byte + next *decoderState // for free list } // We pass the bytes.Buffer separately for easier testing of the infrastructure // without requiring a full Decoder. -func newDecodeState(dec *Decoder, buf *bytes.Buffer) *decoderState { - d := new(decoderState) - d.dec = dec +func (dec *Decoder) newDecoderState(buf *bytes.Buffer) *decoderState { + d := dec.freeList + if d == nil { + d = new(decoderState) + d.dec = dec + } else { + dec.freeList = d.next + } d.b = buf d.buf = make([]byte, uint64Size) return d } +func (dec *Decoder) freeDecoderState(d *decoderState) { + d.next = dec.freeList + dec.freeList = d +} + func overflow(name string) os.ErrorString { return os.ErrorString(`value for "` + name + `" out of range`) } @@ -445,7 +456,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr) indir = int(ut.decIndir) } p = allocate(ut.base, p, indir) - state := newDecodeState(dec, &dec.buf) + state := dec.newDecoderState(&dec.buf) state.fieldnum = singletonField basep := p delta := int(state.decodeUint()) @@ -458,6 +469,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr) ptr = decIndirect(ptr, instr.indir) } instr.op(instr, state, ptr) + dec.freeDecoderState(state) return nil } @@ -468,7 +480,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr) // 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) { p = allocate(ut.base.(*reflect.StructType), p, indir) - state := newDecodeState(dec, &dec.buf) + state := dec.newDecoderState(&dec.buf) state.fieldnum = -1 basep := p for state.b.Len() > 0 { @@ -492,12 +504,13 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr, instr.op(instr, state, p) 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) { - state := newDecodeState(dec, &dec.buf) + state := dec.newDecoderState(&dec.buf) state.fieldnum = -1 for state.b.Len() > 0 { delta := int(state.decodeUint()) @@ -515,13 +528,14 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) { instr.op(instr, state, unsafe.Pointer(nil)) 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) { - state := newDecodeState(dec, &dec.buf) + state := dec.newDecoderState(&dec.buf) state.fieldnum = singletonField delta := int(state.decodeUint()) if delta != 0 { @@ -529,6 +543,7 @@ 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 } diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go index 0c5fbbd7ea..5e5afb37b4 100644 --- a/src/pkg/gob/decoder.go +++ b/src/pkg/gob/decoder.go @@ -22,7 +22,7 @@ type Decoder struct { wireType map[typeId]*wireType // map from remote ID to local description decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines ignorerCache map[typeId]**decEngine // ditto for ignored objects - countState *decoderState // reads counts from wire + freeList *decoderState // list of free decoderStates; avoids reallocation countBuf []byte // used for decoding integers while parsing messages tmp []byte // temporary storage for i/o; saves reallocating err os.Error diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go index adaf958e78..4dbafdddeb 100644 --- a/src/pkg/gob/encode.go +++ b/src/pkg/gob/encode.go @@ -25,10 +25,26 @@ type encoderState struct { sendZero bool // encoding an array element or map key/value pair; send zero values fieldnum int // the last field number written. buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation. + next *encoderState // for free list } -func newEncoderState(enc *Encoder, b *bytes.Buffer) *encoderState { - return &encoderState{enc: enc, b: b} +func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState { + e := enc.freeList + if e == nil { + e = new(encoderState) + e.enc = enc + } else { + enc.freeList = e.next + } + e.sendZero = false + e.fieldnum = 0 + e.b = b + return e +} + +func (enc *Encoder) freeEncoderState(e *encoderState) { + e.next = enc.freeList + enc.freeList = e } // Unsigned integers have a two-state encoding. If the number is less @@ -326,7 +342,7 @@ const singletonField = 0 // encodeSingle encodes a single top-level non-struct value. func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintptr) { - state := newEncoderState(enc, b) + state := enc.newEncoderState(b) state.fieldnum = singletonField // There is no surrounding struct to frame the transmission, so we must // generate data even if the item is zero. To do this, set sendZero. @@ -339,11 +355,12 @@ func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintp } } instr.op(instr, state, p) + enc.freeEncoderState(state) } // encodeStruct encodes a single struct value. func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintptr) { - state := newEncoderState(enc, b) + state := enc.newEncoderState(b) state.fieldnum = -1 for i := 0; i < len(engine.instr); i++ { instr := &engine.instr[i] @@ -355,11 +372,12 @@ func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintp } instr.op(instr, state, p) } + enc.freeEncoderState(state) } // encodeArray encodes the array whose 0th element is at p. func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) { - state := newEncoderState(enc, b) + state := enc.newEncoderState(b) state.fieldnum = -1 state.sendZero = true state.encodeUint(uint64(length)) @@ -375,6 +393,7 @@ func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid ui op(nil, state, unsafe.Pointer(elemp)) p += uintptr(elemWid) } + enc.freeEncoderState(state) } // encodeReflectValue is a helper for maps. It encodes the value v. @@ -392,7 +411,7 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in // Because map internals are not exposed, we must use reflection rather than // addresses. func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) { - state := newEncoderState(enc, b) + state := enc.newEncoderState(b) state.fieldnum = -1 state.sendZero = true keys := mv.Keys() @@ -401,6 +420,7 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elem encodeReflectValue(state, key, keyOp, keyIndir) encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir) } + enc.freeEncoderState(state) } // encodeInterface encodes the interface value iv. @@ -409,7 +429,7 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elem // by the concrete value. A nil value gets sent as the empty string for the name, // followed by no value. func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) { - state := newEncoderState(enc, b) + state := enc.newEncoderState(b) state.fieldnum = -1 state.sendZero = true if iv.IsNil() { @@ -445,6 +465,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) if enc.err != nil { error(err) } + enc.freeEncoderState(state) } // encGobEncoder encodes a value that implements the GobEncoder interface. @@ -456,10 +477,11 @@ func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value, index int if err != nil { error(err) } - state := newEncoderState(enc, b) + state := enc.newEncoderState(b) state.fieldnum = -1 state.encodeUint(uint64(len(data))) state.b.Write(data) + enc.freeEncoderState(state) } var encOpTable = [...]encOp{ diff --git a/src/pkg/gob/encoder.go b/src/pkg/gob/encoder.go index 228445ff81..7045e8e892 100644 --- a/src/pkg/gob/encoder.go +++ b/src/pkg/gob/encoder.go @@ -19,6 +19,7 @@ type Encoder struct { w []io.Writer // where to send the data sent map[reflect.Type]typeId // which types we've already sent countState *encoderState // stage for writing counts + freeList *encoderState // list of free encoderStates; avoids reallocation buf []byte // for collecting the output. err os.Error } @@ -28,7 +29,7 @@ func NewEncoder(w io.Writer) *Encoder { enc := new(Encoder) enc.w = []io.Writer{w} enc.sent = make(map[reflect.Type]typeId) - enc.countState = newEncoderState(enc, new(bytes.Buffer)) + enc.countState = enc.newEncoderState(new(bytes.Buffer)) return enc } @@ -218,7 +219,7 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error { } enc.err = nil - state := newEncoderState(enc, new(bytes.Buffer)) + state := enc.newEncoderState(new(bytes.Buffer)) enc.sendTypeDescriptor(enc.writer(), state, ut) enc.sendTypeId(state, ut) @@ -234,5 +235,6 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error { enc.writeMessage(enc.writer(), state.b) } + enc.freeEncoderState(state) return enc.err }