encoding/gob: simplify allocation in decode.
The old code's structure needed to track indirections because of the
use of unsafe. That is no longer necessary, so we can remove all
that tracking. The code cleans up considerably but is a little slower.
We may be able to recover that performance drop. I believe the
code quality improvement is worthwhile regardless.
BenchmarkEndToEndPipe 5610 5780 +3.03%
BenchmarkEndToEndByteBuffer 3156 3222 +2.09%
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/103700043
diff --git a/src/pkg/encoding/gob/codec_test.go b/src/pkg/encoding/gob/codec_test.go
index a6012f5..c7b2567 100644
--- a/src/pkg/encoding/gob/codec_test.go
+++ b/src/pkg/encoding/gob/codec_test.go
@@ -323,7 +323,7 @@
if v+state.fieldnum != 6 {
t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum)
}
- instr.op(instr, state, decIndirect(value, instr.indir))
+ instr.op(instr, state, value)
state.fieldnum = 6
}
@@ -342,7 +342,7 @@
// bool
{
var data bool
- instr := &decInstr{decBool, 6, nil, 1, ovfl}
+ instr := &decInstr{decBool, 6, nil, ovfl}
state := newDecodeStateFromData(boolResult)
execDec("bool", instr, state, t, reflect.ValueOf(&data))
if data != true {
@@ -352,7 +352,7 @@
// int
{
var data int
- instr := &decInstr{decOpTable[reflect.Int], 6, nil, 1, ovfl}
+ instr := &decInstr{decOpTable[reflect.Int], 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
execDec("int", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -363,7 +363,7 @@
// uint
{
var data uint
- instr := &decInstr{decOpTable[reflect.Uint], 6, nil, 1, ovfl}
+ instr := &decInstr{decOpTable[reflect.Uint], 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
execDec("uint", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -374,7 +374,7 @@
// int8
{
var data int8
- instr := &decInstr{decInt8, 6, nil, 1, ovfl}
+ instr := &decInstr{decInt8, 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
execDec("int8", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -385,7 +385,7 @@
// uint8
{
var data uint8
- instr := &decInstr{decUint8, 6, nil, 1, ovfl}
+ instr := &decInstr{decUint8, 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
execDec("uint8", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -396,7 +396,7 @@
// int16
{
var data int16
- instr := &decInstr{decInt16, 6, nil, 1, ovfl}
+ instr := &decInstr{decInt16, 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
execDec("int16", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -407,7 +407,7 @@
// uint16
{
var data uint16
- instr := &decInstr{decUint16, 6, nil, 1, ovfl}
+ instr := &decInstr{decUint16, 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
execDec("uint16", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -418,7 +418,7 @@
// int32
{
var data int32
- instr := &decInstr{decInt32, 6, nil, 1, ovfl}
+ instr := &decInstr{decInt32, 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
execDec("int32", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -429,7 +429,7 @@
// uint32
{
var data uint32
- instr := &decInstr{decUint32, 6, nil, 1, ovfl}
+ instr := &decInstr{decUint32, 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
execDec("uint32", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -440,7 +440,7 @@
// uintptr
{
var data uintptr
- instr := &decInstr{decOpTable[reflect.Uintptr], 6, nil, 1, ovfl}
+ instr := &decInstr{decOpTable[reflect.Uintptr], 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
execDec("uintptr", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -451,7 +451,7 @@
// int64
{
var data int64
- instr := &decInstr{decInt64, 6, nil, 1, ovfl}
+ instr := &decInstr{decInt64, 6, nil, ovfl}
state := newDecodeStateFromData(signedResult)
execDec("int64", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -462,7 +462,7 @@
// uint64
{
var data uint64
- instr := &decInstr{decUint64, 6, nil, 1, ovfl}
+ instr := &decInstr{decUint64, 6, nil, ovfl}
state := newDecodeStateFromData(unsignedResult)
execDec("uint64", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -473,7 +473,7 @@
// float32
{
var data float32
- instr := &decInstr{decFloat32, 6, nil, 1, ovfl}
+ instr := &decInstr{decFloat32, 6, nil, ovfl}
state := newDecodeStateFromData(floatResult)
execDec("float32", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -484,7 +484,7 @@
// float64
{
var data float64
- instr := &decInstr{decFloat64, 6, nil, 1, ovfl}
+ instr := &decInstr{decFloat64, 6, nil, ovfl}
state := newDecodeStateFromData(floatResult)
execDec("float64", instr, state, t, reflect.ValueOf(&data))
if data != 17 {
@@ -495,7 +495,7 @@
// complex64
{
var data complex64
- instr := &decInstr{decOpTable[reflect.Complex64], 6, nil, 1, ovfl}
+ instr := &decInstr{decOpTable[reflect.Complex64], 6, nil, ovfl}
state := newDecodeStateFromData(complexResult)
execDec("complex", instr, state, t, reflect.ValueOf(&data))
if data != 17+19i {
@@ -506,7 +506,7 @@
// complex128
{
var data complex128
- instr := &decInstr{decOpTable[reflect.Complex128], 6, nil, 1, ovfl}
+ instr := &decInstr{decOpTable[reflect.Complex128], 6, nil, ovfl}
state := newDecodeStateFromData(complexResult)
execDec("complex", instr, state, t, reflect.ValueOf(&data))
if data != 17+19i {
@@ -517,7 +517,7 @@
// bytes == []uint8
{
var data []byte
- instr := &decInstr{decUint8Slice, 6, nil, 1, ovfl}
+ instr := &decInstr{decUint8Slice, 6, nil, ovfl}
state := newDecodeStateFromData(bytesResult)
execDec("bytes", instr, state, t, reflect.ValueOf(&data))
if string(data) != "hello" {
@@ -528,7 +528,7 @@
// string
{
var data string
- instr := &decInstr{decString, 6, nil, 1, ovfl}
+ instr := &decInstr{decString, 6, nil, ovfl}
state := newDecodeStateFromData(bytesResult)
execDec("bytes", instr, state, t, reflect.ValueOf(&data))
if data != "hello" {
diff --git a/src/pkg/encoding/gob/decode.go b/src/pkg/encoding/gob/decode.go
index 14e01ae..feed805 100644
--- a/src/pkg/encoding/gob/decode.go
+++ b/src/pkg/encoding/gob/decode.go
@@ -131,29 +131,9 @@
op decOp
field int // field number of the wire type
index []int // field access indices for destination type
- indir int // how many pointer indirections to reach the value in the struct
ovfl error // error message for overflow/underflow (for arrays, of the elements)
}
-// Since the encoder writes no zeros, if we arrive at a decoder we have
-// a value to extract and store. The field number has already been read
-// (it's how we knew to call this decoder).
-// Each decoder is responsible for handling any indirections associated
-// with the data structure. If any pointer so reached is nil, allocation must
-// be done.
-
-// decIndirect walks the pointer hierarchy, allocating if we find a nil. Stop one before the end.
-func decIndirect(pv reflect.Value, indir int) reflect.Value {
- for ; indir > 1; indir-- {
- if pv.IsNil() {
- // Allocation required
- pv.Set(reflect.New(pv.Type().Elem())) // New will always allocate a pointer here.
- }
- pv = pv.Elem()
- }
- return pv
-}
-
// ignoreUint discards a uint value with no destination.
func ignoreUint(i *decInstr, state *decoderState, v reflect.Value) {
state.decodeUint()
@@ -166,11 +146,17 @@
state.decodeUint()
}
+// Since the encoder writes no zeros, if we arrive at a decoder we have
+// a value to extract and store. The field number has already been read
+// (it's how we knew to call this decoder).
+// Each decoder is responsible for handling any indirections associated
+// with the data structure. If any pointer so reached is nil, allocation must
+// be done.
+
// decAlloc takes a value and returns a settable value that can
-// be assigned to. If the value is a pointer (i.indir is positive),
-// decAlloc guarantees it points to storage.
-func (i *decInstr) decAlloc(v reflect.Value) reflect.Value {
- if i.indir > 0 {
+// be assigned to. If the value is a pointer, decAlloc guarantees it points to storage.
+func decAlloc(v reflect.Value) reflect.Value {
+ for v.Kind() == reflect.Ptr {
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
@@ -181,7 +167,7 @@
// decBool decodes a uint and stores it as a boolean in value.
func decBool(i *decInstr, state *decoderState, value reflect.Value) {
- i.decAlloc(value).SetBool(state.decodeUint() != 0)
+ decAlloc(value).SetBool(state.decodeUint() != 0)
}
// decInt8 decodes an integer and stores it as an int8 in value.
@@ -190,7 +176,7 @@
if v < math.MinInt8 || math.MaxInt8 < v {
error_(i.ovfl)
}
- i.decAlloc(value).SetInt(v)
+ decAlloc(value).SetInt(v)
}
// decUint8 decodes an unsigned integer and stores it as a uint8 in value.
@@ -199,7 +185,7 @@
if math.MaxUint8 < v {
error_(i.ovfl)
}
- i.decAlloc(value).SetUint(v)
+ decAlloc(value).SetUint(v)
}
// decInt16 decodes an integer and stores it as an int16 in value.
@@ -208,7 +194,7 @@
if v < math.MinInt16 || math.MaxInt16 < v {
error_(i.ovfl)
}
- i.decAlloc(value).SetInt(v)
+ decAlloc(value).SetInt(v)
}
// decUint16 decodes an unsigned integer and stores it as a uint16 in value.
@@ -217,7 +203,7 @@
if math.MaxUint16 < v {
error_(i.ovfl)
}
- i.decAlloc(value).SetUint(v)
+ decAlloc(value).SetUint(v)
}
// decInt32 decodes an integer and stores it as an int32 in value.
@@ -226,7 +212,7 @@
if v < math.MinInt32 || math.MaxInt32 < v {
error_(i.ovfl)
}
- i.decAlloc(value).SetInt(v)
+ decAlloc(value).SetInt(v)
}
// decUint32 decodes an unsigned integer and stores it as a uint32 in value.
@@ -235,19 +221,19 @@
if math.MaxUint32 < v {
error_(i.ovfl)
}
- i.decAlloc(value).SetUint(v)
+ decAlloc(value).SetUint(v)
}
// decInt64 decodes an integer and stores it as an int64 in value.
func decInt64(i *decInstr, state *decoderState, value reflect.Value) {
v := state.decodeInt()
- i.decAlloc(value).SetInt(v)
+ decAlloc(value).SetInt(v)
}
// decUint64 decodes an unsigned integer and stores it as a uint64 in value.
func decUint64(i *decInstr, state *decoderState, value reflect.Value) {
v := state.decodeUint()
- i.decAlloc(value).SetUint(v)
+ decAlloc(value).SetUint(v)
}
// Floating-point numbers are transmitted as uint64s holding the bits
@@ -285,94 +271,74 @@
// decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point
// number, and stores it in value.
func decFloat32(i *decInstr, state *decoderState, value reflect.Value) {
- i.decAlloc(value).SetFloat(float32FromBits(i, state.decodeUint()))
+ decAlloc(value).SetFloat(float32FromBits(i, state.decodeUint()))
}
// decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point
// number, and stores it in value.
func decFloat64(i *decInstr, state *decoderState, value reflect.Value) {
- i.decAlloc(value).SetFloat(float64FromBits(state.decodeUint()))
+ decAlloc(value).SetFloat(float64FromBits(state.decodeUint()))
}
// decComplex64 decodes a pair of unsigned integers, treats them as a
-// pair of floating point numbers, and stores them as a complex64 through v.
+// pair of floating point numbers, and stores them as a complex64 in value.
// The real part comes first.
func decComplex64(i *decInstr, state *decoderState, value reflect.Value) {
real := float32FromBits(i, state.decodeUint())
imag := float32FromBits(i, state.decodeUint())
- i.decAlloc(value).SetComplex(complex(real, imag))
+ decAlloc(value).SetComplex(complex(real, imag))
}
// decComplex128 decodes a pair of unsigned integers, treats them as a
-// pair of floating point numbers, and stores them as a complex128 through v.
+// pair of floating point numbers, and stores them as a complex128 in value.
// The real part comes first.
func decComplex128(i *decInstr, state *decoderState, value reflect.Value) {
real := float64FromBits(state.decodeUint())
imag := float64FromBits(state.decodeUint())
- i.decAlloc(value).SetComplex(complex(real, imag))
+ decAlloc(value).SetComplex(complex(real, imag))
}
-// decUint8Slice decodes a byte slice and stores through v a slice header
+// decUint8Slice decodes a byte slice and stores in value a slice header
// describing the data.
// uint8 slices are encoded as an unsigned count followed by the raw bytes.
func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
u := state.decodeUint()
n := int(u)
- if n < 0 {
- errorf("negative slice length: %d", n)
+ if n < 0 || uint64(n) != u {
+ errorf("length of %s exceeds input size (%d bytes)", value.Type(), u)
}
if n > state.b.Len() {
errorf("%s data too long for buffer: %d", value.Type(), n)
}
- // Indirect if necessary until we have a settable slice header with enough storage.
- typ := value.Type()
- switch typ.Kind() {
- default:
- panic("should be slice " + typ.String())
- case reflect.Slice:
- if value.Cap() < n {
- value.Set(reflect.MakeSlice(typ, n, n))
- }
- case reflect.Ptr:
- for typ.Elem().Kind() == reflect.Ptr {
- if value.IsNil() {
- value.Set(reflect.New(typ.Elem()))
- }
- value = value.Elem()
- typ = typ.Elem()
- }
- // Value is now a pointer to a slice header.
- // It might be nil. If so, allocate the header.
- if value.IsNil() {
- value.Set(reflect.New(typ.Elem()))
- }
- if value.Elem().IsNil() || value.Elem().Cap() < n {
- value.Elem().Set(reflect.MakeSlice(typ.Elem(), n, n))
- } else {
- value.Elem().Set(value.Elem().Slice(0, n))
- }
- value = value.Elem()
+ value = decAlloc(value)
+ if value.Cap() < n {
+ value.Set(reflect.MakeSlice(value.Type(), n, n))
+ } else {
+ value.Set(value.Slice(0, n))
}
if _, err := state.b.Read(value.Bytes()); err != nil {
errorf("error decoding []byte: %s", err)
}
}
-// decString decodes byte array and stores through v a string header
+// decString decodes byte array and stores in value a string header
// describing the data.
// Strings are encoded as an unsigned count followed by the raw bytes.
func decString(i *decInstr, state *decoderState, value reflect.Value) {
u := state.decodeUint()
n := int(u)
- if n < 0 || uint64(n) < u || n > state.b.Len() {
- errorf("length of string exceeds input size (%d bytes)", n)
+ if n < 0 || uint64(n) != u || n > state.b.Len() {
+ errorf("length of %s exceeds input size (%d bytes)", value.Type(), u)
+ }
+ if n > state.b.Len() {
+ errorf("%s data too long for buffer: %d", value.Type(), n)
}
// Read the data.
data := make([]byte, n)
if _, err := state.b.Read(data); err != nil {
errorf("error decoding string: %s", err)
}
- i.decAlloc(value).SetString(string(data))
+ decAlloc(value).SetString(string(data))
}
// ignoreUint8Array skips over the data for a byte slice value with no destination.
@@ -390,22 +356,6 @@
numInstr int // the number of active instructions
}
-// allocate makes sure storage is available for an object of underlying type rtyp
-// that is indir levels of indirection through p.
-func allocate(rtyp reflect.Type, v reflect.Value, indir int) reflect.Value {
- if indir == 0 {
- return v
- }
- if indir > 1 {
- v = decIndirect(v, indir)
- }
- if v.IsNil() {
- // Allocate object.
- v.Set(reflect.New(v.Type().Elem()))
- }
- return v.Elem()
-}
-
// decodeSingle decodes a top-level value that is not a struct and stores it in value.
// Such values are preceded by a zero, making them have the memory layout of a
// struct field (although with an illegal field number).
@@ -417,12 +367,6 @@
errorf("decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
- if instr.indir != ut.indir {
- errorf("internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir)
- }
- if instr.indir > 1 {
- value = decIndirect(value, instr.indir)
- }
instr.op(instr, state, value)
}
@@ -431,8 +375,9 @@
// 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, value reflect.Value, indir int) {
- value = allocate(ut.base, value, indir)
+func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, value reflect.Value) {
+ value = decAlloc(value)
+ // println(value.Kind() == reflect.Ptr)
state := dec.newDecoderState(&dec.buf)
defer dec.freeDecoderState(state)
state.fieldnum = -1
@@ -454,16 +399,13 @@
if instr.index != nil {
// Otherwise the field is unknown to us and instr.op is an ignore op.
field = value.FieldByIndex(instr.index)
- if instr.indir > 1 {
- field = decIndirect(field, instr.indir)
- }
}
instr.op(instr, state, field)
state.fieldnum = fieldnum
}
}
-var zeroValue reflect.Value
+var noValue reflect.Value
// ignoreStruct discards the data for a struct with no destination.
func (dec *Decoder) ignoreStruct(engine *decEngine) {
@@ -483,7 +425,7 @@
error_(errRange)
}
instr := &engine.instr[fieldnum]
- instr.op(instr, state, zeroValue)
+ instr.op(instr, state, noValue)
state.fieldnum = fieldnum
}
}
@@ -499,43 +441,34 @@
errorf("decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
- instr.op(instr, state, zeroValue)
+ instr.op(instr, state, noValue)
}
// decodeArrayHelper does the work for decoding arrays and slices.
-func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length, elemIndir int, ovfl error) {
- instr := &decInstr{elemOp, 0, nil, elemIndir, ovfl}
+func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error) {
+ instr := &decInstr{elemOp, 0, nil, ovfl}
for i := 0; i < length; i++ {
if state.b.Len() == 0 {
errorf("decoding array or slice: length exceeds input size (%d elements)", length)
}
- elem := value.Index(i)
- if elemIndir > 1 {
- elem = decIndirect(elem, elemIndir)
- }
- elemOp(instr, state, elem)
+ elemOp(instr, state, value.Index(i))
}
}
// decodeArray decodes an array and stores it in value.
// The length is an unsigned integer preceding the elements. Even though the length is redundant
// (it's part of the type), it's a useful check and is included in the encoding.
-func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length, indir, elemIndir int, ovfl error) {
- if indir > 0 {
- value = allocate(atyp, value, 1) // All but the last level has been allocated by dec.Indirect
- }
+func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error) {
+ value = decAlloc(value)
if n := state.decodeUint(); n != uint64(length) {
errorf("length mismatch in decodeArray")
}
- dec.decodeArrayHelper(state, value, elemOp, length, elemIndir, ovfl)
+ dec.decodeArrayHelper(state, value, elemOp, length, ovfl)
}
// decodeIntoValue is a helper for map decoding.
-func decodeIntoValue(state *decoderState, op decOp, indir int, value reflect.Value, ovfl error) reflect.Value {
- instr := &decInstr{op, 0, nil, indir, ovfl}
- if indir > 1 {
- value = decIndirect(value, indir)
- }
+func decodeIntoValue(state *decoderState, op decOp, value reflect.Value, ovfl error) reflect.Value {
+ instr := &decInstr{op, 0, nil, ovfl}
op(instr, state, value)
return value
}
@@ -544,27 +477,25 @@
// Maps are encoded as a length followed by key:value pairs.
// Because the internals of maps are not visible to us, we must
// use reflection rather than pointer magic.
-func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value reflect.Value, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl error) {
- if indir > 0 {
- value = allocate(mtyp, value, 1) // All but the last level has been allocated by dec.Indirect
- }
+func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value reflect.Value, keyOp, elemOp decOp, ovfl error) {
+ value = decAlloc(value)
if value.IsNil() {
// Allocate map.
value.Set(reflect.MakeMap(mtyp))
}
n := int(state.decodeUint())
for i := 0; i < n; i++ {
- key := decodeIntoValue(state, keyOp, keyIndir, allocValue(mtyp.Key()), ovfl)
- elem := decodeIntoValue(state, elemOp, elemIndir, allocValue(mtyp.Elem()), ovfl)
+ key := decodeIntoValue(state, keyOp, allocValue(mtyp.Key()), ovfl)
+ elem := decodeIntoValue(state, elemOp, allocValue(mtyp.Elem()), ovfl)
value.SetMapIndex(key, elem)
}
}
// ignoreArrayHelper does the work for discarding arrays and slices.
func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
- instr := &decInstr{elemOp, 0, nil, 0, errors.New("no error")}
+ instr := &decInstr{elemOp, 0, nil, errors.New("no error")}
for i := 0; i < length; i++ {
- elemOp(instr, state, zeroValue)
+ elemOp(instr, state, noValue)
}
}
@@ -579,52 +510,31 @@
// ignoreMap discards the data for a map value with no destination.
func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
n := int(state.decodeUint())
- keyInstr := &decInstr{keyOp, 0, nil, 0, errors.New("no error")}
- elemInstr := &decInstr{elemOp, 0, nil, 0, errors.New("no error")}
+ keyInstr := &decInstr{keyOp, 0, nil, errors.New("no error")}
+ elemInstr := &decInstr{elemOp, 0, nil, errors.New("no error")}
for i := 0; i < n; i++ {
- keyOp(keyInstr, state, zeroValue)
- elemOp(elemInstr, state, zeroValue)
+ keyOp(keyInstr, state, noValue)
+ elemOp(elemInstr, state, noValue)
}
}
// decodeSlice decodes a slice and stores it in value.
// Slices are encoded as an unsigned length followed by the elements.
-func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, indir, elemIndir int, ovfl error) {
+func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error) {
u := state.decodeUint()
n := int(u)
- if n < 0 {
- errorf("negative slice length: %d", n)
+ if n < 0 || uint64(n) != u {
+ // We don't check n against buffer length here because if it's a slice
+ // of interfaces, there will be buffer reloads.
+ errorf("length of %s is negative (%d bytes)", value.Type(), u)
}
- // Indirect if necessary until we have a settable slice header with enough storage.
- typ := value.Type()
- switch typ.Kind() {
- default:
- panic("should be slice " + typ.String())
- case reflect.Slice:
- if value.Cap() < n {
- value.Set(reflect.MakeSlice(typ, n, n))
- }
- case reflect.Ptr:
- for typ.Elem().Kind() == reflect.Ptr {
- if value.IsNil() {
- value.Set(reflect.New(typ.Elem()))
- }
- value = value.Elem()
- typ = typ.Elem()
- }
- // Value is now a pointer to a slice header.
- // It might be nil. If so, allocate the header.
- if value.IsNil() {
- value.Set(reflect.New(typ.Elem()))
- }
- if value.Elem().IsNil() || value.Elem().Cap() < n {
- value.Elem().Set(reflect.MakeSlice(typ.Elem(), n, n))
- } else {
- value.Elem().Set(value.Elem().Slice(0, n))
- }
- value = value.Elem()
+ value = decAlloc(value)
+ if value.Cap() < n {
+ value.Set(reflect.MakeSlice(value.Type(), n, n))
+ } else {
+ value.Set(value.Slice(0, n))
}
- dec.decodeArrayHelper(state, value, elemOp, n, elemIndir, ovfl)
+ dec.decodeArrayHelper(state, value, elemOp, n, ovfl)
}
// ignoreSlice skips over the data for a slice value with no destination.
@@ -632,21 +542,10 @@
dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
}
-// setInterfaceValue sets an interface value to a concrete value,
-// but first it checks that the assignment will succeed.
-func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
- if !value.Type().AssignableTo(ivalue.Type()) {
- errorf("%s is not assignable to type %s", value.Type(), ivalue.Type())
- }
- ivalue.Set(value)
-}
-
// decodeInterface decodes an interface value and stores it in value.
// Interfaces are encoded as the name of a concrete type followed by a value.
// If the name is empty, the value is nil and no value is sent.
-func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, v reflect.Value, indir int) {
- // Create a writable interface reflect.Value. We need one even for the nil case.
- ivalue := allocValue(ityp)
+func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, value reflect.Value) {
// Read the name of the concrete type.
nr := state.decodeUint()
if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types
@@ -658,12 +557,11 @@
b := make([]byte, nr)
state.b.Read(b)
name := string(b)
+ // Allocate the destination interface value.
+ value = decAlloc(value)
if name == "" {
// Copy the nil interface value to the target.
- if indir > 0 {
- v = allocate(ityp, v, 1) // All but the last level has been allocated by dec.Indirect
- }
- v.Set(ivalue)
+ value.Set(reflect.Zero(value.Type()))
return
}
if len(name) > 1024 {
@@ -685,20 +583,18 @@
// in case we want to ignore the value by skipping it completely).
state.decodeUint()
// Read the concrete value.
- value := allocValue(typ)
- dec.decodeValue(concreteId, value)
+ v := allocValue(typ)
+ dec.decodeValue(concreteId, v)
if dec.err != nil {
error_(dec.err)
}
- // Allocate the destination interface value.
- if indir > 0 {
- v = allocate(ityp, v, 1) // All but the last level has been allocated by dec.Indirect
- }
// Assign the concrete value to the interface.
// Tread carefully; it might not satisfy the interface.
- setInterfaceValue(ivalue, value)
+ if !typ.AssignableTo(ityp) {
+ errorf("%s is not assignable to type %s", typ, ityp)
+ }
// Copy the interface value to the target.
- v.Set(value)
+ value.Set(v)
}
// ignoreInterface discards the data for an interface value with no destination.
@@ -719,7 +615,7 @@
// decodeGobDecoder decodes something implementing the GobDecoder interface.
// The data is encoded as a byte slice.
-func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, v reflect.Value) {
+func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, value reflect.Value) {
// Read the bytes for the value.
b := make([]byte, state.decodeUint())
_, err := state.b.Read(b)
@@ -729,11 +625,11 @@
// We know it's one of these.
switch ut.externalDec {
case xGob:
- err = v.Interface().(GobDecoder).GobDecode(b)
+ err = value.Interface().(GobDecoder).GobDecode(b)
case xBinary:
- err = v.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b)
+ err = value.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b)
case xText:
- err = v.Interface().(encoding.TextUnmarshaler).UnmarshalText(b)
+ err = value.Interface().(encoding.TextUnmarshaler).UnmarshalText(b)
}
if err != nil {
error_(err)
@@ -781,7 +677,7 @@
// decOpFor returns the decoding op for the base type under rt and
// the indirection count to reach it.
-func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProgress map[reflect.Type]*decOp) (*decOp, int) {
+func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProgress map[reflect.Type]*decOp) *decOp {
ut := userType(rt)
// If the type implements GobEncoder, we handle it without further processing.
if ut.externalDec != 0 {
@@ -791,10 +687,9 @@
// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
// Return the pointer to the op we're already building.
if opPtr := inProgress[rt]; opPtr != nil {
- return opPtr, ut.indir
+ return opPtr
}
typ := ut.base
- indir := ut.indir
var op decOp
k := typ.Kind()
if int(k) < len(decOpTable) {
@@ -807,20 +702,20 @@
case reflect.Array:
name = "element of " + name
elemId := dec.wireType[wireId].ArrayT.Elem
- elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, value reflect.Value) {
- state.dec.decodeArray(t, state, value, *elemOp, t.Len(), i.indir, elemIndir, ovfl)
+ state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl)
}
case reflect.Map:
keyId := dec.wireType[wireId].MapT.Key
elemId := dec.wireType[wireId].MapT.Elem
- keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress)
- elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress)
+ keyOp := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress)
+ elemOp := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress)
ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, value reflect.Value) {
- state.dec.decodeMap(t, state, value, *keyOp, *elemOp, i.indir, keyIndir, elemIndir, ovfl)
+ state.dec.decodeMap(t, state, value, *keyOp, *elemOp, ovfl)
}
case reflect.Slice:
@@ -835,10 +730,10 @@
} else {
elemId = dec.wireType[wireId].SliceT.Elem
}
- elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, value reflect.Value) {
- state.dec.decodeSlice(state, value, *elemOp, i.indir, elemIndir, ovfl)
+ state.dec.decodeSlice(state, value, *elemOp, ovfl)
}
case reflect.Struct:
@@ -849,18 +744,18 @@
}
op = func(i *decInstr, state *decoderState, value reflect.Value) {
// indirect through enginePtr to delay evaluation for recursive structs.
- dec.decodeStruct(*enginePtr, userType(typ), value, i.indir)
+ dec.decodeStruct(*enginePtr, userType(typ), value)
}
case reflect.Interface:
op = func(i *decInstr, state *decoderState, value reflect.Value) {
- state.dec.decodeInterface(t, state, value, i.indir)
+ state.dec.decodeInterface(t, state, value)
}
}
}
if op == nil {
errorf("decode can't handle type %s", rt)
}
- return &op, indir
+ return &op
}
// decIgnoreOpFor returns the decoding op for a field that has no destination.
@@ -928,7 +823,7 @@
// gobDecodeOpFor returns the op for a type that is known to implement
// GobDecoder.
-func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
+func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) *decOp {
rcvrType := ut.user
if ut.decIndir == -1 {
rcvrType = reflect.PtrTo(rcvrType)
@@ -939,20 +834,14 @@
}
var op decOp
op = func(i *decInstr, state *decoderState, value reflect.Value) {
- // Caller has gotten us to within one indirection of our value.
- if i.indir > 0 {
- if value.IsNil() {
- value.Set(reflect.New(ut.base))
- }
- }
- // Now value is a pointer to the base type. Do we need to climb out to
- // get to the receiver type?
- if ut.decIndir == -1 {
+ value = decAlloc(value)
+ // We now have the base type. We need its address if the receiver is a pointer.
+ if value.Kind() != reflect.Ptr && rcvrType.Kind() == reflect.Ptr {
value = value.Addr()
}
state.dec.decodeGobDecoder(ut, state, value)
}
- return &op, int(ut.indir)
+ return &op
}
// compatibleType asks: Are these two gob Types compatible?
@@ -1053,9 +942,9 @@
}
return nil, errors.New("gob: decoding into local type " + name + ", received remote type " + remoteType)
}
- op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
+ op := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
ovfl := errors.New(`value for "` + name + `" out of range`)
- engine.instr[singletonField] = decInstr{*op, singletonField, nil, indir, ovfl}
+ engine.instr[singletonField] = decInstr{*op, singletonField, nil, ovfl}
engine.numInstr = 1
return
}
@@ -1066,7 +955,7 @@
engine.instr = make([]decInstr, 1) // one item
op := dec.decIgnoreOpFor(remoteId)
ovfl := overflow(dec.typeString(remoteId))
- engine.instr[0] = decInstr{op, 0, nil, 0, ovfl}
+ engine.instr[0] = decInstr{op, 0, nil, ovfl}
engine.numInstr = 1
return
}
@@ -1109,14 +998,14 @@
// TODO(r): anonymous names
if !present || !isExported(wireField.Name) {
op := dec.decIgnoreOpFor(wireField.Id)
- engine.instr[fieldnum] = decInstr{op, fieldnum, nil, 0, ovfl}
+ engine.instr[fieldnum] = decInstr{op, fieldnum, nil, ovfl}
continue
}
if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) {
errorf("wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name)
}
- op, indir := dec.decOpFor(wireField.Id, localField.Type, localField.Name, seen)
- engine.instr[fieldnum] = decInstr{*op, fieldnum, localField.Index, indir, ovfl}
+ op := dec.decOpFor(wireField.Id, localField.Type, localField.Name, seen)
+ engine.instr[fieldnum] = decInstr{*op, fieldnum, localField.Index, ovfl}
engine.numInstr++
}
return
@@ -1190,7 +1079,7 @@
name := base.Name()
errorf("type mismatch: no fields matched compiling decoder for %s", name)
}
- dec.decodeStruct(engine, ut, value, ut.indir)
+ dec.decodeStruct(engine, ut, value)
} else {
dec.decodeSingle(engine, ut, value)
}