diff options
Diffstat (limited to 'src/pkg/gob/encode.go')
-rw-r--r-- | src/pkg/gob/encode.go | 148 |
1 files changed, 89 insertions, 59 deletions
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go index 9190d9203..36bde08aa 100644 --- a/src/pkg/gob/encode.go +++ b/src/pkg/gob/encode.go @@ -6,9 +6,7 @@ package gob import ( "bytes" - "io" "math" - "os" "reflect" "unsafe" ) @@ -25,10 +23,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 @@ -92,11 +106,14 @@ func (state *encoderState) update(instr *encInstr) { } } -// Each encoder is responsible for handling any indirections associated -// with the data structure. If any pointer so reached is nil, no bytes are written. -// If the data item is zero, no bytes are written. -// Otherwise, the output (for a scalar) is the field number, as an encoded integer, -// followed by the field data in its appropriate format. +// Each encoder for a composite is responsible for handling any +// indirections associated with the elements of the data structure. +// If any pointer so reached is nil, no bytes are written. If the +// data item is zero, no bytes are written. Single values - ints, +// strings etc. - are indirected before calling their encoders. +// Otherwise, the output (for a scalar) is the field number, as an +// encoded integer, followed by the field data in its appropriate +// format. // encIndirect dereferences p indir times and returns the result. func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer { @@ -301,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) } } @@ -323,7 +340,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. @@ -336,11 +353,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] @@ -352,11 +370,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)) @@ -372,14 +391,15 @@ 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. func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) { - for i := 0; i < indir && v != nil; i++ { + for i := 0; i < indir && v.IsValid(); i++ { v = reflect.Indirect(v) } - if v == nil { + if !v.IsValid() { errorf("gob: encodeReflectValue: nil element") } op(nil, state, unsafe.Pointer(v.UnsafeAddr())) @@ -388,16 +408,17 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in // encodeMap encodes a map as unsigned count followed by key:value pairs. // 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) +func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) { + state := enc.newEncoderState(b) state.fieldnum = -1 state.sendZero = true - keys := mv.Keys() + keys := mv.MapKeys() state.encodeUint(uint64(len(keys))) for _, key := range keys { encodeReflectValue(state, key, keyOp, keyIndir) - encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir) + encodeReflectValue(state, mv.MapIndex(key), elemOp, elemIndir) } + enc.freeEncoderState(state) } // encodeInterface encodes the interface value iv. @@ -405,8 +426,8 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elem // by the type identifier (which might require defining that type right now), followed // 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) +func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) { + state := enc.newEncoderState(b) state.fieldnum = -1 state.sendZero = true if iv.IsNil() { @@ -421,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) } @@ -433,15 +454,16 @@ 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) if enc.err != nil { error(err) } + enc.freeEncoderState(state) } // encGobEncoder encodes a value that implements the GobEncoder interface. @@ -453,10 +475,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{ @@ -502,8 +525,8 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp if op == nil { inProgress[rt] = &op // Special cases - switch t := typ.(type) { - case *reflect.SliceType: + switch t := typ; t.Kind() { + case reflect.Slice: if t.Elem().Kind() == reflect.Uint8 { op = encUint8Array break @@ -518,14 +541,14 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp state.update(i) state.enc.encodeArray(state.b, slice.Data, *elemOp, t.Elem().Size(), indir, int(slice.Len)) } - case *reflect.ArrayType: + case reflect.Array: // True arrays have size in the type. elemOp, indir := enc.encOpFor(t.Elem(), inProgress) op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { state.update(i) state.enc.encodeArray(state.b, uintptr(p), *elemOp, t.Elem().Size(), indir, t.Len()) } - case *reflect.MapType: + case reflect.Map: keyOp, keyIndir := enc.encOpFor(t.Key(), inProgress) elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress) op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { @@ -533,14 +556,14 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp // that slices etc. can. We must recover a full reflection value for // the iteration. v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer(p))) - mv := reflect.Indirect(v).(*reflect.MapValue) + mv := reflect.Indirect(v) if !state.sendZero && mv.Len() == 0 { return } state.update(i) state.enc.encodeMap(state.b, mv, *keyOp, *elemOp, keyIndir, elemIndir) } - case *reflect.StructType: + case reflect.Struct: // Generate a closure that calls out to the engine for the nested type. enc.getEncEngine(userType(typ)) info := mustGetTypeInfo(typ) @@ -549,13 +572,13 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp // indirect through info to delay evaluation for recursive structs state.enc.encodeStruct(state.b, info.encoder, uintptr(p)) } - case *reflect.InterfaceType: + case reflect.Interface: op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { // Interfaces transmit the name and contents of the concrete // value they contain. v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer(p))) - iv := reflect.Indirect(v).(*reflect.InterfaceValue) - if !state.sendZero && (iv == nil || iv.IsNil()) { + iv := reflect.Indirect(v) + if !state.sendZero && (!iv.IsValid() || iv.IsNil()) { return } state.update(i) @@ -569,43 +592,54 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp return &op, indir } +// methodIndex returns which method of rt implements the method. +func methodIndex(rt reflect.Type, method string) int { + for i := 0; i < rt.NumMethod(); i++ { + if rt.Method(i).Name == method { + return i + } + } + errorf("gob: internal error: can't find method %s", method) + return 0 +} + // gobEncodeOpFor returns the op for a type that is known to implement // GobEncoder. func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) { rt := ut.user - if ut.encIndir != 0 { - errorf("gob: TODO: can't handle indirection to reach GobEncoder") - } - index := -1 - for i := 0; i < rt.NumMethod(); i++ { - if rt.Method(i).Name == gobEncodeMethodName { - index = i - break + if ut.encIndir == -1 { + rt = reflect.PtrTo(rt) + } else if ut.encIndir > 0 { + for i := int8(0); i < ut.encIndir; i++ { + rt = rt.Elem() } } - if index < 0 { - panic("can't find GobEncode method") - } var op encOp op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { - // TODO: this will need fixing when ut.encIndr != 0. - v := reflect.NewValue(unsafe.Unreflect(rt, p)) + var v reflect.Value + if ut.encIndir == -1 { + // Need to climb up one level to turn value into pointer. + v = reflect.NewValue(unsafe.Unreflect(rt, unsafe.Pointer(&p))) + } else { + v = reflect.NewValue(unsafe.Unreflect(rt, p)) + } state.update(i) - state.enc.encodeGobEncoder(state.b, v, index) + state.enc.encodeGobEncoder(state.b, v, methodIndex(rt, gobEncodeMethodName)) } - return &op, int(ut.encIndir) + return &op, int(ut.encIndir) // encIndir: op will get called with p == address of receiver. } // compileEnc returns the engine to compile the type. func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine { - srt, isStruct := ut.base.(*reflect.StructType) + srt := ut.base engine := new(encEngine) seen := make(map[reflect.Type]*encOp) rt := ut.base if ut.isGobEncoder { rt = ut.user } - if !ut.isGobEncoder && isStruct { + if !ut.isGobEncoder && + srt.Kind() == reflect.Struct { for fieldNum, wireFieldNum := 0, 0; fieldNum < srt.NumField(); fieldNum++ { f := srt.Field(fieldNum) if !isExported(f.Name) { @@ -616,7 +650,7 @@ func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine { wireFieldNum++ } if srt.NumField() > 0 && len(engine.instr) == 0 { - errorf("type %s has no exported fields", rt) + errorf("gob: type %s has no exported fields", rt) } engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, 0, 0}) } else { @@ -650,15 +684,12 @@ 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 { indir = int(ut.encIndir) - if indir != 0 { - errorf("TODO: can't handle indirection in GobEncoder value") - } } for i := 0; i < indir; i++ { value = reflect.Indirect(value) @@ -668,5 +699,4 @@ func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInf } else { enc.encodeSingle(b, engine, value.UnsafeAddr()) } - return nil } |