Commit 3050a0a7 authored by Rob Pike's avatar Rob Pike

encoding/gob: remove unsafe, use reflection.

This removes a major unsafe thorn in our side, a perennial obstacle
to clean garbage collection.
Not coincidentally: In cleaning this up, several bugs were found,
including code that reached inside by-value interfaces to create
pointers for pointer-receiver methods. Unsafe code is just as
advertised.

Performance of course suffers, but not too badly. The Pipe number
is more indicative, since it's doing I/O that simulates a network
connection. Plus these are end-to-end, so each end suffers
only half of this pain.

The edit is pretty much a line-by-line conversion, with a few
simplifications and a couple of new tests. There may be more
performance to gain.

BenchmarkEndToEndByteBuffer     2493          3033          +21.66%
BenchmarkEndToEndPipe           4953          5597          +13.00%

Fixes #5159.

LGTM=rsc
R=rsc
CC=golang-codereviews, khr
https://golang.org/cl/102680045
parent 3e692bec
...@@ -14,7 +14,6 @@ import ( ...@@ -14,7 +14,6 @@ import (
"strings" "strings"
"testing" "testing"
"time" "time"
"unsafe"
) )
var doFuzzTests = flag.Bool("gob.fuzz", false, "run the fuzz tests, which are large and very slow") var doFuzzTests = flag.Bool("gob.fuzz", false, "run the fuzz tests, which are large and very slow")
...@@ -140,10 +139,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -140,10 +139,10 @@ func TestScalarEncInstructions(t *testing.T) {
// bool // bool
{ {
data := struct{ a bool }{true} var data bool = true
instr := &encInstr{encBool, 6, 0, 0} instr := &encInstr{encBool, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(boolResult, b.Bytes()) { if !bytes.Equal(boolResult, b.Bytes()) {
t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes()) t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes())
} }
...@@ -152,10 +151,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -152,10 +151,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int // int
{ {
b.Reset() b.Reset()
data := struct{ a int }{17} var data int = 17
instr := &encInstr{encInt, 6, 0, 0} instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) { if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes()) t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes())
} }
...@@ -164,10 +163,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -164,10 +163,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint // uint
{ {
b.Reset() b.Reset()
data := struct{ a uint }{17} var data uint = 17
instr := &encInstr{encUint, 6, 0, 0} instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) { if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes()) t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes())
} }
...@@ -176,10 +175,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -176,10 +175,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int8 // int8
{ {
b.Reset() b.Reset()
data := struct{ a int8 }{17} var data int8 = 17
instr := &encInstr{encInt8, 6, 0, 0} instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) { if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes()) t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes())
} }
...@@ -188,10 +187,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -188,10 +187,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint8 // uint8
{ {
b.Reset() b.Reset()
data := struct{ a uint8 }{17} var data uint8 = 17
instr := &encInstr{encUint8, 6, 0, 0} instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) { if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes()) t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
} }
...@@ -200,10 +199,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -200,10 +199,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int16 // int16
{ {
b.Reset() b.Reset()
data := struct{ a int16 }{17} var data int16 = 17
instr := &encInstr{encInt16, 6, 0, 0} instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) { if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes()) t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes())
} }
...@@ -212,10 +211,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -212,10 +211,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint16 // uint16
{ {
b.Reset() b.Reset()
data := struct{ a uint16 }{17} var data uint16 = 17
instr := &encInstr{encUint16, 6, 0, 0} instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) { if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes()) t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
} }
...@@ -224,10 +223,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -224,10 +223,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int32 // int32
{ {
b.Reset() b.Reset()
data := struct{ a int32 }{17} var data int32 = 17
instr := &encInstr{encInt32, 6, 0, 0} instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) { if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes()) t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes())
} }
...@@ -236,10 +235,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -236,10 +235,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint32 // uint32
{ {
b.Reset() b.Reset()
data := struct{ a uint32 }{17} var data uint32 = 17
instr := &encInstr{encUint32, 6, 0, 0} instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) { if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes()) t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
} }
...@@ -248,10 +247,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -248,10 +247,10 @@ func TestScalarEncInstructions(t *testing.T) {
// int64 // int64
{ {
b.Reset() b.Reset()
data := struct{ a int64 }{17} var data int64 = 17
instr := &encInstr{encInt64, 6, 0, 0} instr := &encInstr{encInt, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(signedResult, b.Bytes()) { if !bytes.Equal(signedResult, b.Bytes()) {
t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes()) t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes())
} }
...@@ -260,10 +259,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -260,10 +259,10 @@ func TestScalarEncInstructions(t *testing.T) {
// uint64 // uint64
{ {
b.Reset() b.Reset()
data := struct{ a uint64 }{17} var data uint64 = 17
instr := &encInstr{encUint64, 6, 0, 0} instr := &encInstr{encUint, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(unsignedResult, b.Bytes()) { if !bytes.Equal(unsignedResult, b.Bytes()) {
t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes()) t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
} }
...@@ -272,10 +271,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -272,10 +271,10 @@ func TestScalarEncInstructions(t *testing.T) {
// float32 // float32
{ {
b.Reset() b.Reset()
data := struct{ a float32 }{17} var data float32 = 17
instr := &encInstr{encFloat32, 6, 0, 0} instr := &encInstr{encFloat, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(floatResult, b.Bytes()) { if !bytes.Equal(floatResult, b.Bytes()) {
t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes()) t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes())
} }
...@@ -284,10 +283,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -284,10 +283,10 @@ func TestScalarEncInstructions(t *testing.T) {
// float64 // float64
{ {
b.Reset() b.Reset()
data := struct{ a float64 }{17} var data float64 = 17
instr := &encInstr{encFloat64, 6, 0, 0} instr := &encInstr{encFloat, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(floatResult, b.Bytes()) { if !bytes.Equal(floatResult, b.Bytes()) {
t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes()) t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes())
} }
...@@ -296,10 +295,10 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -296,10 +295,10 @@ func TestScalarEncInstructions(t *testing.T) {
// bytes == []uint8 // bytes == []uint8
{ {
b.Reset() b.Reset()
data := struct{ a []byte }{[]byte("hello")} data := []byte("hello")
instr := &encInstr{encUint8Array, 6, 0, 0} instr := &encInstr{encUint8Array, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(bytesResult, b.Bytes()) { if !bytes.Equal(bytesResult, b.Bytes()) {
t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes()) t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes())
} }
...@@ -308,23 +307,23 @@ func TestScalarEncInstructions(t *testing.T) { ...@@ -308,23 +307,23 @@ func TestScalarEncInstructions(t *testing.T) {
// string // string
{ {
b.Reset() b.Reset()
data := struct{ a string }{"hello"} var data string = "hello"
instr := &encInstr{encString, 6, 0, 0} instr := &encInstr{encString, 6, nil, 0}
state := newEncoderState(b) state := newEncoderState(b)
instr.op(instr, state, unsafe.Pointer(&data)) instr.op(instr, state, reflect.ValueOf(data))
if !bytes.Equal(bytesResult, b.Bytes()) { if !bytes.Equal(bytesResult, b.Bytes()) {
t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes()) t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes())
} }
} }
} }
func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, p unsafe.Pointer) { func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, value reflect.Value) {
defer testError(t) defer testError(t)
v := int(state.decodeUint()) v := int(state.decodeUint())
if v+state.fieldnum != 6 { if v+state.fieldnum != 6 {
t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum) t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum)
} }
instr.op(instr, state, decIndirect(p, instr.indir)) instr.op(instr, state, decIndirect(value, instr.indir))
state.fieldnum = 6 state.fieldnum = 6
} }
...@@ -342,234 +341,198 @@ func TestScalarDecInstructions(t *testing.T) { ...@@ -342,234 +341,198 @@ func TestScalarDecInstructions(t *testing.T) {
// bool // bool
{ {
var data struct { var data bool
a bool instr := &decInstr{decBool, 6, nil, 1, ovfl}
}
instr := &decInstr{decBool, 6, 0, 0, ovfl}
state := newDecodeStateFromData(boolResult) state := newDecodeStateFromData(boolResult)
execDec("bool", instr, state, t, unsafe.Pointer(&data)) execDec("bool", instr, state, t, reflect.ValueOf(&data))
if data.a != true { if data != true {
t.Errorf("bool a = %v not true", data.a) t.Errorf("bool a = %v not true", data)
} }
} }
// int // int
{ {
var data struct { var data int
a int instr := &decInstr{decOpTable[reflect.Int], 6, nil, 1, ovfl}
}
instr := &decInstr{decOpTable[reflect.Int], 6, 0, 0, ovfl}
state := newDecodeStateFromData(signedResult) state := newDecodeStateFromData(signedResult)
execDec("int", instr, state, t, unsafe.Pointer(&data)) execDec("int", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("int a = %v not 17", data.a) t.Errorf("int a = %v not 17", data)
} }
} }
// uint // uint
{ {
var data struct { var data uint
a uint instr := &decInstr{decOpTable[reflect.Uint], 6, nil, 1, ovfl}
}
instr := &decInstr{decOpTable[reflect.Uint], 6, 0, 0, ovfl}
state := newDecodeStateFromData(unsignedResult) state := newDecodeStateFromData(unsignedResult)
execDec("uint", instr, state, t, unsafe.Pointer(&data)) execDec("uint", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("uint a = %v not 17", data.a) t.Errorf("uint a = %v not 17", data)
} }
} }
// int8 // int8
{ {
var data struct { var data int8
a int8 instr := &decInstr{decInt8, 6, nil, 1, ovfl}
}
instr := &decInstr{decInt8, 6, 0, 0, ovfl}
state := newDecodeStateFromData(signedResult) state := newDecodeStateFromData(signedResult)
execDec("int8", instr, state, t, unsafe.Pointer(&data)) execDec("int8", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("int8 a = %v not 17", data.a) t.Errorf("int8 a = %v not 17", data)
} }
} }
// uint8 // uint8
{ {
var data struct { var data uint8
a uint8 instr := &decInstr{decUint8, 6, nil, 1, ovfl}
}
instr := &decInstr{decUint8, 6, 0, 0, ovfl}
state := newDecodeStateFromData(unsignedResult) state := newDecodeStateFromData(unsignedResult)
execDec("uint8", instr, state, t, unsafe.Pointer(&data)) execDec("uint8", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("uint8 a = %v not 17", data.a) t.Errorf("uint8 a = %v not 17", data)
} }
} }
// int16 // int16
{ {
var data struct { var data int16
a int16 instr := &decInstr{decInt16, 6, nil, 1, ovfl}
}
instr := &decInstr{decInt16, 6, 0, 0, ovfl}
state := newDecodeStateFromData(signedResult) state := newDecodeStateFromData(signedResult)
execDec("int16", instr, state, t, unsafe.Pointer(&data)) execDec("int16", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("int16 a = %v not 17", data.a) t.Errorf("int16 a = %v not 17", data)
} }
} }
// uint16 // uint16
{ {
var data struct { var data uint16
a uint16 instr := &decInstr{decUint16, 6, nil, 1, ovfl}
}
instr := &decInstr{decUint16, 6, 0, 0, ovfl}
state := newDecodeStateFromData(unsignedResult) state := newDecodeStateFromData(unsignedResult)
execDec("uint16", instr, state, t, unsafe.Pointer(&data)) execDec("uint16", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("uint16 a = %v not 17", data.a) t.Errorf("uint16 a = %v not 17", data)
} }
} }
// int32 // int32
{ {
var data struct { var data int32
a int32 instr := &decInstr{decInt32, 6, nil, 1, ovfl}
}
instr := &decInstr{decInt32, 6, 0, 0, ovfl}
state := newDecodeStateFromData(signedResult) state := newDecodeStateFromData(signedResult)
execDec("int32", instr, state, t, unsafe.Pointer(&data)) execDec("int32", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("int32 a = %v not 17", data.a) t.Errorf("int32 a = %v not 17", data)
} }
} }
// uint32 // uint32
{ {
var data struct { var data uint32
a uint32 instr := &decInstr{decUint32, 6, nil, 1, ovfl}
}
instr := &decInstr{decUint32, 6, 0, 0, ovfl}
state := newDecodeStateFromData(unsignedResult) state := newDecodeStateFromData(unsignedResult)
execDec("uint32", instr, state, t, unsafe.Pointer(&data)) execDec("uint32", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("uint32 a = %v not 17", data.a) t.Errorf("uint32 a = %v not 17", data)
} }
} }
// uintptr // uintptr
{ {
var data struct { var data uintptr
a uintptr instr := &decInstr{decOpTable[reflect.Uintptr], 6, nil, 1, ovfl}
}
instr := &decInstr{decOpTable[reflect.Uintptr], 6, 0, 0, ovfl}
state := newDecodeStateFromData(unsignedResult) state := newDecodeStateFromData(unsignedResult)
execDec("uintptr", instr, state, t, unsafe.Pointer(&data)) execDec("uintptr", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("uintptr a = %v not 17", data.a) t.Errorf("uintptr a = %v not 17", data)
} }
} }
// int64 // int64
{ {
var data struct { var data int64
a int64 instr := &decInstr{decInt64, 6, nil, 1, ovfl}
}
instr := &decInstr{decInt64, 6, 0, 0, ovfl}
state := newDecodeStateFromData(signedResult) state := newDecodeStateFromData(signedResult)
execDec("int64", instr, state, t, unsafe.Pointer(&data)) execDec("int64", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("int64 a = %v not 17", data.a) t.Errorf("int64 a = %v not 17", data)
} }
} }
// uint64 // uint64
{ {
var data struct { var data uint64
a uint64 instr := &decInstr{decUint64, 6, nil, 1, ovfl}
}
instr := &decInstr{decUint64, 6, 0, 0, ovfl}
state := newDecodeStateFromData(unsignedResult) state := newDecodeStateFromData(unsignedResult)
execDec("uint64", instr, state, t, unsafe.Pointer(&data)) execDec("uint64", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("uint64 a = %v not 17", data.a) t.Errorf("uint64 a = %v not 17", data)
} }
} }
// float32 // float32
{ {
var data struct { var data float32
a float32 instr := &decInstr{decFloat32, 6, nil, 1, ovfl}
}
instr := &decInstr{decFloat32, 6, 0, 0, ovfl}
state := newDecodeStateFromData(floatResult) state := newDecodeStateFromData(floatResult)
execDec("float32", instr, state, t, unsafe.Pointer(&data)) execDec("float32", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("float32 a = %v not 17", data.a) t.Errorf("float32 a = %v not 17", data)
} }
} }
// float64 // float64
{ {
var data struct { var data float64
a float64 instr := &decInstr{decFloat64, 6, nil, 1, ovfl}
}
instr := &decInstr{decFloat64, 6, 0, 0, ovfl}
state := newDecodeStateFromData(floatResult) state := newDecodeStateFromData(floatResult)
execDec("float64", instr, state, t, unsafe.Pointer(&data)) execDec("float64", instr, state, t, reflect.ValueOf(&data))
if data.a != 17 { if data != 17 {
t.Errorf("float64 a = %v not 17", data.a) t.Errorf("float64 a = %v not 17", data)
} }
} }
// complex64 // complex64
{ {
var data struct { var data complex64
a complex64 instr := &decInstr{decOpTable[reflect.Complex64], 6, nil, 1, ovfl}
}
instr := &decInstr{decOpTable[reflect.Complex64], 6, 0, 0, ovfl}
state := newDecodeStateFromData(complexResult) state := newDecodeStateFromData(complexResult)
execDec("complex", instr, state, t, unsafe.Pointer(&data)) execDec("complex", instr, state, t, reflect.ValueOf(&data))
if data.a != 17+19i { if data != 17+19i {
t.Errorf("complex a = %v not 17+19i", data.a) t.Errorf("complex a = %v not 17+19i", data)
} }
} }
// complex128 // complex128
{ {
var data struct { var data complex128
a complex128 instr := &decInstr{decOpTable[reflect.Complex128], 6, nil, 1, ovfl}
}
instr := &decInstr{decOpTable[reflect.Complex128], 6, 0, 0, ovfl}
state := newDecodeStateFromData(complexResult) state := newDecodeStateFromData(complexResult)
execDec("complex", instr, state, t, unsafe.Pointer(&data)) execDec("complex", instr, state, t, reflect.ValueOf(&data))
if data.a != 17+19i { if data != 17+19i {
t.Errorf("complex a = %v not 17+19i", data.a) t.Errorf("complex a = %v not 17+19i", data)
} }
} }
// bytes == []uint8 // bytes == []uint8
{ {
var data struct { var data []byte
a []byte instr := &decInstr{decUint8Slice, 6, nil, 1, ovfl}
}
instr := &decInstr{decUint8Slice, 6, 0, 0, ovfl}
state := newDecodeStateFromData(bytesResult) state := newDecodeStateFromData(bytesResult)
execDec("bytes", instr, state, t, unsafe.Pointer(&data)) execDec("bytes", instr, state, t, reflect.ValueOf(&data))
if string(data.a) != "hello" { if string(data) != "hello" {
t.Errorf(`bytes a = %q not "hello"`, string(data.a)) t.Errorf(`bytes a = %q not "hello"`, string(data))
} }
} }
// string // string
{ {
var data struct { var data string
a string instr := &decInstr{decString, 6, nil, 1, ovfl}
}
instr := &decInstr{decString, 6, 0, 0, ovfl}
state := newDecodeStateFromData(bytesResult) state := newDecodeStateFromData(bytesResult)
execDec("bytes", instr, state, t, unsafe.Pointer(&data)) execDec("bytes", instr, state, t, reflect.ValueOf(&data))
if data.a != "hello" { if data != "hello" {
t.Errorf(`bytes a = %q not "hello"`, data.a) t.Errorf(`bytes a = %q not "hello"`, data)
} }
} }
} }
......
...@@ -306,7 +306,7 @@ func (deb *debugger) common() CommonType { ...@@ -306,7 +306,7 @@ func (deb *debugger) common() CommonType {
// Id typeId // Id typeId
id = deb.typeId() id = deb.typeId()
default: default:
errorf("corrupted CommonType") errorf("corrupted CommonType, delta is %d fieldNum is %d", delta, fieldNum)
} }
} }
return CommonType{name, id} return CommonType{name, id}
...@@ -598,11 +598,11 @@ func (deb *debugger) printBuiltin(indent tab, id typeId) { ...@@ -598,11 +598,11 @@ func (deb *debugger) printBuiltin(indent tab, id typeId) {
fmt.Fprintf(os.Stderr, "%s%d\n", indent, x) fmt.Fprintf(os.Stderr, "%s%d\n", indent, x)
case tFloat: case tFloat:
x := deb.uint64() x := deb.uint64()
fmt.Fprintf(os.Stderr, "%s%g\n", indent, floatFromBits(x)) fmt.Fprintf(os.Stderr, "%s%g\n", indent, float64FromBits(x))
case tComplex: case tComplex:
r := deb.uint64() r := deb.uint64()
i := deb.uint64() i := deb.uint64()
fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, floatFromBits(r), floatFromBits(i)) fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, float64FromBits(r), float64FromBits(i))
case tBytes: case tBytes:
x := int(deb.uint64()) x := int(deb.uint64())
b := make([]byte, x) b := make([]byte, x)
......
...@@ -4,9 +4,6 @@ ...@@ -4,9 +4,6 @@
package gob package gob
// TODO(rsc): When garbage collector changes, revisit
// the allocations in this file that use unsafe.Pointer.
import ( import (
"bytes" "bytes"
"encoding" "encoding"
...@@ -14,7 +11,6 @@ import ( ...@@ -14,7 +11,6 @@ import (
"io" "io"
"math" "math"
"reflect" "reflect"
"unsafe"
) )
var ( var (
...@@ -128,15 +124,15 @@ func (state *decoderState) decodeInt() int64 { ...@@ -128,15 +124,15 @@ func (state *decoderState) decodeInt() int64 {
} }
// decOp is the signature of a decoding operator for a given type. // decOp is the signature of a decoding operator for a given type.
type decOp func(i *decInstr, state *decoderState, p unsafe.Pointer) type decOp func(i *decInstr, state *decoderState, v reflect.Value)
// The 'instructions' of the decoding machine // The 'instructions' of the decoding machine
type decInstr struct { type decInstr struct {
op decOp op decOp
field int // field number of the wire type field int // field number of the wire type
indir int // how many pointer indirections to reach the value in the struct index []int // field access indices for destination type
offset uintptr // offset in the structure of the field to encode 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) 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 // Since the encoder writes no zeros, if we arrive at a decoder we have
...@@ -146,157 +142,112 @@ type decInstr struct { ...@@ -146,157 +142,112 @@ type decInstr struct {
// with the data structure. If any pointer so reached is nil, allocation must // with the data structure. If any pointer so reached is nil, allocation must
// be done. // be done.
// Walk the pointer hierarchy, allocating if we find a nil. Stop one before the end. // decIndirect walks the pointer hierarchy, allocating if we find a nil. Stop one before the end.
func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer { func decIndirect(pv reflect.Value, indir int) reflect.Value {
for ; indir > 1; indir-- { for ; indir > 1; indir-- {
if *(*unsafe.Pointer)(p) == nil { if pv.IsNil() {
// Allocation required // Allocation required
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(unsafe.Pointer)) pv.Set(reflect.New(pv.Type().Elem())) // New will always allocate a pointer here.
} }
p = *(*unsafe.Pointer)(p) pv = pv.Elem()
} }
return p return pv
} }
// ignoreUint discards a uint value with no destination. // ignoreUint discards a uint value with no destination.
func ignoreUint(i *decInstr, state *decoderState, p unsafe.Pointer) { func ignoreUint(i *decInstr, state *decoderState, v reflect.Value) {
state.decodeUint() state.decodeUint()
} }
// ignoreTwoUints discards a uint value with no destination. It's used to skip // ignoreTwoUints discards a uint value with no destination. It's used to skip
// complex values. // complex values.
func ignoreTwoUints(i *decInstr, state *decoderState, p unsafe.Pointer) { func ignoreTwoUints(i *decInstr, state *decoderState, v reflect.Value) {
state.decodeUint() state.decodeUint()
state.decodeUint() state.decodeUint()
} }
// decBool decodes a uint and stores it as a boolean through p. // decAlloc takes a value and returns a settable value that can
func decBool(i *decInstr, state *decoderState, p unsafe.Pointer) { // 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 { if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil { if v.IsNil() {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(bool)) v.Set(reflect.New(v.Type().Elem()))
} }
p = *(*unsafe.Pointer)(p) v = v.Elem()
} }
*(*bool)(p) = state.decodeUint() != 0 return v
} }
// decInt8 decodes an integer and stores it as an int8 through p. // decBool decodes a uint and stores it as a boolean in value.
func decInt8(i *decInstr, state *decoderState, p unsafe.Pointer) { func decBool(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { i.decAlloc(value).SetBool(state.decodeUint() != 0)
if *(*unsafe.Pointer)(p) == nil { }
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int8))
} // decInt8 decodes an integer and stores it as an int8 in value.
p = *(*unsafe.Pointer)(p) func decInt8(i *decInstr, state *decoderState, value reflect.Value) {
}
v := state.decodeInt() v := state.decodeInt()
if v < math.MinInt8 || math.MaxInt8 < v { if v < math.MinInt8 || math.MaxInt8 < v {
error_(i.ovfl) error_(i.ovfl)
} else {
*(*int8)(p) = int8(v)
} }
i.decAlloc(value).SetInt(v)
} }
// decUint8 decodes an unsigned integer and stores it as a uint8 through p. // decUint8 decodes an unsigned integer and stores it as a uint8 in value.
func decUint8(i *decInstr, state *decoderState, p unsafe.Pointer) { func decUint8(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint8))
}
p = *(*unsafe.Pointer)(p)
}
v := state.decodeUint() v := state.decodeUint()
if math.MaxUint8 < v { if math.MaxUint8 < v {
error_(i.ovfl) error_(i.ovfl)
} else {
*(*uint8)(p) = uint8(v)
} }
i.decAlloc(value).SetUint(v)
} }
// decInt16 decodes an integer and stores it as an int16 through p. // decInt16 decodes an integer and stores it as an int16 in value.
func decInt16(i *decInstr, state *decoderState, p unsafe.Pointer) { func decInt16(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int16))
}
p = *(*unsafe.Pointer)(p)
}
v := state.decodeInt() v := state.decodeInt()
if v < math.MinInt16 || math.MaxInt16 < v { if v < math.MinInt16 || math.MaxInt16 < v {
error_(i.ovfl) error_(i.ovfl)
} else {
*(*int16)(p) = int16(v)
} }
i.decAlloc(value).SetInt(v)
} }
// decUint16 decodes an unsigned integer and stores it as a uint16 through p. // decUint16 decodes an unsigned integer and stores it as a uint16 in value.
func decUint16(i *decInstr, state *decoderState, p unsafe.Pointer) { func decUint16(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint16))
}
p = *(*unsafe.Pointer)(p)
}
v := state.decodeUint() v := state.decodeUint()
if math.MaxUint16 < v { if math.MaxUint16 < v {
error_(i.ovfl) error_(i.ovfl)
} else {
*(*uint16)(p) = uint16(v)
} }
i.decAlloc(value).SetUint(v)
} }
// decInt32 decodes an integer and stores it as an int32 through p. // decInt32 decodes an integer and stores it as an int32 in value.
func decInt32(i *decInstr, state *decoderState, p unsafe.Pointer) { func decInt32(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int32))
}
p = *(*unsafe.Pointer)(p)
}
v := state.decodeInt() v := state.decodeInt()
if v < math.MinInt32 || math.MaxInt32 < v { if v < math.MinInt32 || math.MaxInt32 < v {
error_(i.ovfl) error_(i.ovfl)
} else {
*(*int32)(p) = int32(v)
} }
i.decAlloc(value).SetInt(v)
} }
// decUint32 decodes an unsigned integer and stores it as a uint32 through p. // decUint32 decodes an unsigned integer and stores it as a uint32 in value.
func decUint32(i *decInstr, state *decoderState, p unsafe.Pointer) { func decUint32(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint32))
}
p = *(*unsafe.Pointer)(p)
}
v := state.decodeUint() v := state.decodeUint()
if math.MaxUint32 < v { if math.MaxUint32 < v {
error_(i.ovfl) error_(i.ovfl)
} else {
*(*uint32)(p) = uint32(v)
} }
i.decAlloc(value).SetUint(v)
} }
// decInt64 decodes an integer and stores it as an int64 through p. // decInt64 decodes an integer and stores it as an int64 in value.
func decInt64(i *decInstr, state *decoderState, p unsafe.Pointer) { func decInt64(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { v := state.decodeInt()
if *(*unsafe.Pointer)(p) == nil { i.decAlloc(value).SetInt(v)
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(int64))
}
p = *(*unsafe.Pointer)(p)
}
*(*int64)(p) = int64(state.decodeInt())
} }
// decUint64 decodes an unsigned integer and stores it as a uint64 through p. // decUint64 decodes an unsigned integer and stores it as a uint64 in value.
func decUint64(i *decInstr, state *decoderState, p unsafe.Pointer) { func decUint64(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { v := state.decodeUint()
if *(*unsafe.Pointer)(p) == nil { i.decAlloc(value).SetUint(v)
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(uint64))
}
p = *(*unsafe.Pointer)(p)
}
*(*uint64)(p) = uint64(state.decodeUint())
} }
// Floating-point numbers are transmitted as uint64s holding the bits // Floating-point numbers are transmitted as uint64s holding the bits
...@@ -304,7 +255,7 @@ func decUint64(i *decInstr, state *decoderState, p unsafe.Pointer) { ...@@ -304,7 +255,7 @@ func decUint64(i *decInstr, state *decoderState, p unsafe.Pointer) {
// the exponent end coming out first, so integer floating point numbers // the exponent end coming out first, so integer floating point numbers
// (for example) transmit more compactly. This routine does the // (for example) transmit more compactly. This routine does the
// unswizzling. // unswizzling.
func floatFromBits(u uint64) float64 { func float64FromBits(u uint64) float64 {
var v uint64 var v uint64
for i := 0; i < 8; i++ { for i := 0; i < 8; i++ {
v <<= 8 v <<= 8
...@@ -314,10 +265,12 @@ func floatFromBits(u uint64) float64 { ...@@ -314,10 +265,12 @@ func floatFromBits(u uint64) float64 {
return math.Float64frombits(v) return math.Float64frombits(v)
} }
// storeFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point // float32FromBits decodes an unsigned integer, treats it as a 32-bit floating-point
// number, and stores it through p. It's a helper function for float32 and complex64. // number, and returns it. It's a helper function for float32 and complex64.
func storeFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) { // It returns a float64 because that's what reflection needs, but its return
v := floatFromBits(state.decodeUint()) // value is known to be accurately representable in a float32.
func float32FromBits(i *decInstr, u uint64) float64 {
v := float64FromBits(u)
av := v av := v
if av < 0 { if av < 0 {
av = -av av = -av
...@@ -325,117 +278,105 @@ func storeFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) { ...@@ -325,117 +278,105 @@ func storeFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) {
// +Inf is OK in both 32- and 64-bit floats. Underflow is always OK. // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
if math.MaxFloat32 < av && av <= math.MaxFloat64 { if math.MaxFloat32 < av && av <= math.MaxFloat64 {
error_(i.ovfl) error_(i.ovfl)
} else {
*(*float32)(p) = float32(v)
} }
return v
} }
// decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point // decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point
// number, and stores it through p. // number, and stores it in value.
func decFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) { func decFloat32(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { i.decAlloc(value).SetFloat(float32FromBits(i, state.decodeUint()))
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(float32))
}
p = *(*unsafe.Pointer)(p)
}
storeFloat32(i, state, p)
} }
// decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point // decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point
// number, and stores it through p. // number, and stores it in value.
func decFloat64(i *decInstr, state *decoderState, p unsafe.Pointer) { func decFloat64(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { i.decAlloc(value).SetFloat(float64FromBits(state.decodeUint()))
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(float64))
}
p = *(*unsafe.Pointer)(p)
}
*(*float64)(p) = floatFromBits(uint64(state.decodeUint()))
} }
// decComplex64 decodes a pair of unsigned integers, treats them as a // decComplex64 decodes a pair of unsigned integers, treats them as a
// pair of floating point numbers, and stores them as a complex64 through p. // pair of floating point numbers, and stores them as a complex64 through v.
// The real part comes first. // The real part comes first.
func decComplex64(i *decInstr, state *decoderState, p unsafe.Pointer) { func decComplex64(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { real := float32FromBits(i, state.decodeUint())
if *(*unsafe.Pointer)(p) == nil { imag := float32FromBits(i, state.decodeUint())
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex64)) i.decAlloc(value).SetComplex(complex(real, imag))
}
p = *(*unsafe.Pointer)(p)
}
storeFloat32(i, state, p)
storeFloat32(i, state, unsafe.Pointer(uintptr(p)+unsafe.Sizeof(float32(0))))
} }
// decComplex128 decodes a pair of unsigned integers, treats them as a // decComplex128 decodes a pair of unsigned integers, treats them as a
// pair of floating point numbers, and stores them as a complex128 through p. // pair of floating point numbers, and stores them as a complex128 through v.
// The real part comes first. // The real part comes first.
func decComplex128(i *decInstr, state *decoderState, p unsafe.Pointer) { func decComplex128(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { real := float64FromBits(state.decodeUint())
if *(*unsafe.Pointer)(p) == nil { imag := float64FromBits(state.decodeUint())
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(complex128)) i.decAlloc(value).SetComplex(complex(real, imag))
}
p = *(*unsafe.Pointer)(p)
}
real := floatFromBits(uint64(state.decodeUint()))
imag := floatFromBits(uint64(state.decodeUint()))
*(*complex128)(p) = complex(real, imag)
} }
// decUint8Slice decodes a byte slice and stores through p a slice header // decUint8Slice decodes a byte slice and stores through v a slice header
// describing the data. // describing the data.
// uint8 slices are encoded as an unsigned count followed by the raw bytes. // uint8 slices are encoded as an unsigned count followed by the raw bytes.
func decUint8Slice(i *decInstr, state *decoderState, p unsafe.Pointer) { func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { u := state.decodeUint()
if *(*unsafe.Pointer)(p) == nil { n := int(u)
*(*unsafe.Pointer)(p) = unsafe.Pointer(new([]uint8)) if n < 0 {
errorf("negative slice length: %d", n)
}
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))
} }
p = *(*unsafe.Pointer)(p) case reflect.Ptr:
} for typ.Elem().Kind() == reflect.Ptr {
n := state.decodeUint() if value.IsNil() {
if n > uint64(state.b.Len()) { value.Set(reflect.New(typ.Elem()))
errorf("length of []byte exceeds input size (%d bytes)", n) }
} value = value.Elem()
slice := (*[]uint8)(p) typ = typ.Elem()
if uint64(cap(*slice)) < n { }
*slice = make([]uint8, n) // Value is now a pointer to a slice header.
} else { // It might be nil. If so, allocate the header.
*slice = (*slice)[0:n] 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()
} }
if _, err := state.b.Read(*slice); err != nil { if _, err := state.b.Read(value.Bytes()); err != nil {
errorf("error decoding []byte: %s", err) errorf("error decoding []byte: %s", err)
} }
} }
// decString decodes byte array and stores through p a string header // decString decodes byte array and stores through v a string header
// describing the data. // describing the data.
// Strings are encoded as an unsigned count followed by the raw bytes. // Strings are encoded as an unsigned count followed by the raw bytes.
func decString(i *decInstr, state *decoderState, p unsafe.Pointer) { func decString(i *decInstr, state *decoderState, value reflect.Value) {
if i.indir > 0 { u := state.decodeUint()
if *(*unsafe.Pointer)(p) == nil { n := int(u)
*(*unsafe.Pointer)(p) = unsafe.Pointer(new(string)) if n < 0 || uint64(n) < u || n > state.b.Len() {
} errorf("length of string exceeds input size (%d bytes)", n)
p = *(*unsafe.Pointer)(p)
} }
n := state.decodeUint() // Read the data.
if n > uint64(state.b.Len()) { data := make([]byte, n)
errorf("string length exceeds input size (%d bytes)", n) if _, err := state.b.Read(data); err != nil {
errorf("error decoding string: %s", err)
} }
b := make([]byte, n) i.decAlloc(value).SetString(string(data))
state.b.Read(b)
// It would be a shame to do the obvious thing here,
// *(*string)(p) = string(b)
// because we've already allocated the storage and this would
// allocate again and copy. So we do this ugly hack, which is even
// even more unsafe than it looks as it depends the memory
// representation of a string matching the beginning of the memory
// representation of a byte slice (a byte slice is longer).
*(*string)(p) = *(*string)(unsafe.Pointer(&b))
} }
// ignoreUint8Array skips over the data for a byte slice value with no destination. // ignoreUint8Array skips over the data for a byte slice value with no destination.
func ignoreUint8Array(i *decInstr, state *decoderState, p unsafe.Pointer) { func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) {
b := make([]byte, state.decodeUint()) b := make([]byte, state.decodeUint())
state.b.Read(b) state.b.Read(b)
} }
...@@ -451,53 +392,50 @@ type decEngine struct { ...@@ -451,53 +392,50 @@ type decEngine struct {
// allocate makes sure storage is available for an object of underlying type rtyp // allocate makes sure storage is available for an object of underlying type rtyp
// that is indir levels of indirection through p. // that is indir levels of indirection through p.
func allocate(rtyp reflect.Type, p unsafe.Pointer, indir int) unsafe.Pointer { func allocate(rtyp reflect.Type, v reflect.Value, indir int) reflect.Value {
if indir == 0 { if indir == 0 {
return p return v
} }
up := p
if indir > 1 { if indir > 1 {
up = decIndirect(up, indir) v = decIndirect(v, indir)
} }
if *(*unsafe.Pointer)(up) == nil { if v.IsNil() {
// Allocate object. // Allocate object.
*(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.New(rtyp).Pointer()) v.Set(reflect.New(v.Type().Elem()))
} }
return *(*unsafe.Pointer)(up) return v.Elem()
} }
// decodeSingle decodes a top-level value that is not a struct and stores it through p. // 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 // Such values are preceded by a zero, making them have the memory layout of a
// struct field (although with an illegal field number). // struct field (although with an illegal field number).
func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep unsafe.Pointer) { func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, value reflect.Value) {
state := dec.newDecoderState(&dec.buf) state := dec.newDecoderState(&dec.buf)
defer dec.freeDecoderState(state)
state.fieldnum = singletonField state.fieldnum = singletonField
delta := int(state.decodeUint()) if state.decodeUint() != 0 {
if delta != 0 {
errorf("decode: corrupted data: non-zero delta for singleton") errorf("decode: corrupted data: non-zero delta for singleton")
} }
instr := &engine.instr[singletonField] instr := &engine.instr[singletonField]
if instr.indir != ut.indir { if instr.indir != ut.indir {
errorf("internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir) errorf("internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir)
} }
ptr := basep // offset will be zero
if instr.indir > 1 { if instr.indir > 1 {
ptr = decIndirect(ptr, instr.indir) value = decIndirect(value, instr.indir)
} }
instr.op(instr, state, ptr) instr.op(instr, state, value)
dec.freeDecoderState(state)
} }
// decodeStruct decodes a top-level struct and stores it through p. // decodeStruct decodes a top-level struct and stores it in value.
// Indir is for the value, not the type. At the time of the call it may // Indir is for the value, not the type. At the time of the call it may
// 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 unsafe.Pointer, indir int) { func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, value reflect.Value, indir int) {
p = allocate(ut.base, p, indir) value = allocate(ut.base, value, indir)
state := dec.newDecoderState(&dec.buf) state := dec.newDecoderState(&dec.buf)
defer dec.freeDecoderState(state)
state.fieldnum = -1 state.fieldnum = -1
basep := p
for state.b.Len() > 0 { for state.b.Len() > 0 {
delta := int(state.decodeUint()) delta := int(state.decodeUint())
if delta < 0 { if delta < 0 {
...@@ -512,19 +450,25 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p unsafe.P ...@@ -512,19 +450,25 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p unsafe.P
break break
} }
instr := &engine.instr[fieldnum] instr := &engine.instr[fieldnum]
p := unsafe.Pointer(uintptr(basep) + instr.offset) var field reflect.Value
if instr.indir > 1 { if instr.index != nil {
p = decIndirect(p, instr.indir) // 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, p) instr.op(instr, state, field)
state.fieldnum = fieldnum state.fieldnum = fieldnum
} }
dec.freeDecoderState(state)
} }
var zeroValue reflect.Value
// 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) { func (dec *Decoder) ignoreStruct(engine *decEngine) {
state := dec.newDecoderState(&dec.buf) state := dec.newDecoderState(&dec.buf)
defer dec.freeDecoderState(state)
state.fieldnum = -1 state.fieldnum = -1
for state.b.Len() > 0 { for state.b.Len() > 0 {
delta := int(state.decodeUint()) delta := int(state.decodeUint())
...@@ -539,97 +483,88 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) { ...@@ -539,97 +483,88 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) {
error_(errRange) error_(errRange)
} }
instr := &engine.instr[fieldnum] instr := &engine.instr[fieldnum]
instr.op(instr, state, unsafe.Pointer(nil)) instr.op(instr, state, zeroValue)
state.fieldnum = fieldnum state.fieldnum = fieldnum
} }
dec.freeDecoderState(state)
} }
// 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) { func (dec *Decoder) ignoreSingle(engine *decEngine) {
state := dec.newDecoderState(&dec.buf) state := dec.newDecoderState(&dec.buf)
defer dec.freeDecoderState(state)
state.fieldnum = singletonField state.fieldnum = singletonField
delta := int(state.decodeUint()) delta := int(state.decodeUint())
if delta != 0 { if delta != 0 {
errorf("decode: corrupted data: non-zero delta for singleton") errorf("decode: corrupted data: non-zero delta for singleton")
} }
instr := &engine.instr[singletonField] instr := &engine.instr[singletonField]
instr.op(instr, state, unsafe.Pointer(nil)) instr.op(instr, state, zeroValue)
dec.freeDecoderState(state)
} }
// decodeArrayHelper does the work for decoding arrays and slices. // decodeArrayHelper does the work for decoding arrays and slices.
func (dec *Decoder) decodeArrayHelper(state *decoderState, p unsafe.Pointer, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl error) { func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length, elemIndir int, ovfl error) {
instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl} instr := &decInstr{elemOp, 0, nil, elemIndir, ovfl}
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
if state.b.Len() == 0 { if state.b.Len() == 0 {
errorf("decoding array or slice: length exceeds input size (%d elements)", length) errorf("decoding array or slice: length exceeds input size (%d elements)", length)
} }
up := p elem := value.Index(i)
if elemIndir > 1 { if elemIndir > 1 {
up = decIndirect(up, elemIndir) elem = decIndirect(elem, elemIndir)
} }
elemOp(instr, state, up) elemOp(instr, state, elem)
p = unsafe.Pointer(uintptr(p) + elemWid)
} }
} }
// decodeArray decodes an array and stores it through p, that is, p points to the zeroth element. // decodeArray decodes an array and stores it in value.
// The length is an unsigned integer preceding the elements. Even though the length is redundant // 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. // (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, p unsafe.Pointer, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl error) { func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length, indir, elemIndir int, ovfl error) {
if indir > 0 { if indir > 0 {
p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect value = allocate(atyp, value, 1) // All but the last level has been allocated by dec.Indirect
} }
if n := state.decodeUint(); n != uint64(length) { if n := state.decodeUint(); n != uint64(length) {
errorf("length mismatch in decodeArray") errorf("length mismatch in decodeArray")
} }
dec.decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl) dec.decodeArrayHelper(state, value, elemOp, length, elemIndir, ovfl)
} }
// decodeIntoValue is a helper for map decoding. Since maps are decoded using reflection, // decodeIntoValue is a helper for map decoding.
// unlike the other items we can't use a pointer directly. func decodeIntoValue(state *decoderState, op decOp, indir int, value reflect.Value, ovfl error) reflect.Value {
func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl error) reflect.Value { instr := &decInstr{op, 0, nil, indir, ovfl}
instr := &decInstr{op, 0, indir, 0, ovfl}
up := unsafeAddr(v)
if indir > 1 { if indir > 1 {
up = decIndirect(up, indir) value = decIndirect(value, indir)
} }
op(instr, state, up) op(instr, state, value)
return v return value
} }
// decodeMap decodes a map and stores its header through p. // decodeMap decodes a map and stores it in value.
// Maps are encoded as a length followed by key:value pairs. // Maps are encoded as a length followed by key:value pairs.
// Because the internals of maps are not visible to us, we must // Because the internals of maps are not visible to us, we must
// use reflection rather than pointer magic. // use reflection rather than pointer magic.
func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p unsafe.Pointer, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl error) { func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value reflect.Value, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl error) {
if indir > 0 { if indir > 0 {
p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect value = allocate(mtyp, value, 1) // All but the last level has been allocated by dec.Indirect
} }
up := unsafe.Pointer(p) if value.IsNil() {
if *(*unsafe.Pointer)(up) == nil { // maps are represented as a pointer in the runtime
// Allocate map. // Allocate map.
*(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.MakeMap(mtyp).Pointer()) value.Set(reflect.MakeMap(mtyp))
} }
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
v := reflect.NewAt(mtyp, unsafe.Pointer(p)).Elem()
n := int(state.decodeUint()) n := int(state.decodeUint())
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
key := decodeIntoValue(state, keyOp, keyIndir, allocValue(mtyp.Key()), ovfl) key := decodeIntoValue(state, keyOp, keyIndir, allocValue(mtyp.Key()), ovfl)
elem := decodeIntoValue(state, elemOp, elemIndir, allocValue(mtyp.Elem()), ovfl) elem := decodeIntoValue(state, elemOp, elemIndir, allocValue(mtyp.Elem()), ovfl)
v.SetMapIndex(key, elem) value.SetMapIndex(key, elem)
} }
} }
// ignoreArrayHelper does the work for discarding arrays and slices. // ignoreArrayHelper does the work for discarding arrays and slices.
func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) { func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
instr := &decInstr{elemOp, 0, 0, 0, errors.New("no error")} instr := &decInstr{elemOp, 0, nil, 0, errors.New("no error")}
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
elemOp(instr, state, nil) elemOp(instr, state, zeroValue)
} }
} }
...@@ -644,36 +579,52 @@ func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) { ...@@ -644,36 +579,52 @@ func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) {
// ignoreMap discards the data for a map value with no destination. // ignoreMap discards the data for a map value with no destination.
func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) { func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
n := int(state.decodeUint()) n := int(state.decodeUint())
keyInstr := &decInstr{keyOp, 0, 0, 0, errors.New("no error")} keyInstr := &decInstr{keyOp, 0, nil, 0, errors.New("no error")}
elemInstr := &decInstr{elemOp, 0, 0, 0, errors.New("no error")} elemInstr := &decInstr{elemOp, 0, nil, 0, errors.New("no error")}
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
keyOp(keyInstr, state, nil) keyOp(keyInstr, state, zeroValue)
elemOp(elemInstr, state, nil) elemOp(elemInstr, state, zeroValue)
} }
} }
// decodeSlice decodes a slice and stores the slice header through p. // decodeSlice decodes a slice and stores it in value.
// Slices are encoded as an unsigned length followed by the elements. // Slices are encoded as an unsigned length followed by the elements.
func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p unsafe.Pointer, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) { func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, indir, elemIndir int, ovfl error) {
nr := state.decodeUint() u := state.decodeUint()
n := int(nr) n := int(u)
if indir > 0 { if n < 0 {
if *(*unsafe.Pointer)(p) == nil { errorf("negative slice length: %d", n)
// Allocate the slice header. }
*(*unsafe.Pointer)(p) = unsafe.Pointer(new([]unsafe.Pointer)) // 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))
} }
p = *(*unsafe.Pointer)(p) case reflect.Ptr:
} for typ.Elem().Kind() == reflect.Ptr {
// Allocate storage for the slice elements, that is, the underlying array, if value.IsNil() {
// if the existing slice does not have the capacity. value.Set(reflect.New(typ.Elem()))
// Always write a header at p. }
hdrp := (*reflect.SliceHeader)(p) value = value.Elem()
if hdrp.Cap < n { typ = typ.Elem()
hdrp.Data = reflect.MakeSlice(atyp, n, n).Pointer() }
hdrp.Cap = n // 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()
} }
hdrp.Len = n dec.decodeArrayHelper(state, value, elemOp, n, elemIndir, ovfl)
dec.decodeArrayHelper(state, unsafe.Pointer(hdrp.Data), elemOp, elemWid, n, elemIndir, ovfl)
} }
// ignoreSlice skips over the data for a slice value with no destination. // ignoreSlice skips over the data for a slice value with no destination.
...@@ -690,10 +641,10 @@ func setInterfaceValue(ivalue reflect.Value, value reflect.Value) { ...@@ -690,10 +641,10 @@ func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
ivalue.Set(value) ivalue.Set(value)
} }
// decodeInterface decodes an interface value and stores it through p. // decodeInterface decodes an interface value and stores it in value.
// Interfaces are encoded as the name of a concrete type followed by a 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. // If the name is empty, the value is nil and no value is sent.
func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p unsafe.Pointer, indir int) { 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. // Create a writable interface reflect.Value. We need one even for the nil case.
ivalue := allocValue(ityp) ivalue := allocValue(ityp)
// Read the name of the concrete type. // Read the name of the concrete type.
...@@ -708,12 +659,11 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un ...@@ -708,12 +659,11 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un
state.b.Read(b) state.b.Read(b)
name := string(b) name := string(b)
if name == "" { if name == "" {
// Copy the representation of the nil interface value to the target. // Copy the nil interface value to the target.
// This is horribly unsafe and special.
if indir > 0 { if indir > 0 {
p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect v = allocate(ityp, v, 1) // All but the last level has been allocated by dec.Indirect
} }
*(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.InterfaceData() v.Set(ivalue)
return return
} }
if len(name) > 1024 { if len(name) > 1024 {
...@@ -742,14 +692,13 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un ...@@ -742,14 +692,13 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un
} }
// Allocate the destination interface value. // Allocate the destination interface value.
if indir > 0 { if indir > 0 {
p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect v = allocate(ityp, v, 1) // All but the last level has been allocated by dec.Indirect
} }
// Assign the concrete value to the interface. // Assign the concrete value to the interface.
// Tread carefully; it might not satisfy the interface. // Tread carefully; it might not satisfy the interface.
setInterfaceValue(ivalue, value) setInterfaceValue(ivalue, value)
// Copy the representation of the interface value to the target. // Copy the interface value to the target.
// This is horribly unsafe and special. v.Set(value)
*(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.InterfaceData()
} }
// ignoreInterface discards the data for an interface value with no destination. // ignoreInterface discards the data for an interface value with no destination.
...@@ -860,8 +809,8 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg ...@@ -860,8 +809,8 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
elemId := dec.wireType[wireId].ArrayT.Elem elemId := dec.wireType[wireId].ArrayT.Elem
elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress) elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name) ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.decodeArray(t, state, p, *elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl) state.dec.decodeArray(t, state, value, *elemOp, t.Len(), i.indir, elemIndir, ovfl)
} }
case reflect.Map: case reflect.Map:
...@@ -870,8 +819,8 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg ...@@ -870,8 +819,8 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress) keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress)
elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress) elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress)
ovfl := overflow(name) ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.decodeMap(t, state, p, *keyOp, *elemOp, i.indir, keyIndir, elemIndir, ovfl) state.dec.decodeMap(t, state, value, *keyOp, *elemOp, i.indir, keyIndir, elemIndir, ovfl)
} }
case reflect.Slice: case reflect.Slice:
...@@ -888,8 +837,8 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg ...@@ -888,8 +837,8 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
} }
elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress) elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name) ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.decodeSlice(t, state, p, *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl) state.dec.decodeSlice(state, value, *elemOp, i.indir, elemIndir, ovfl)
} }
case reflect.Struct: case reflect.Struct:
...@@ -898,13 +847,13 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg ...@@ -898,13 +847,13 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
if err != nil { if err != nil {
error_(err) error_(err)
} }
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
// indirect through enginePtr to delay evaluation for recursive structs. // indirect through enginePtr to delay evaluation for recursive structs.
dec.decodeStruct(*enginePtr, userType(typ), p, i.indir) dec.decodeStruct(*enginePtr, userType(typ), value, i.indir)
} }
case reflect.Interface: case reflect.Interface:
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.decodeInterface(t, state, p, i.indir) state.dec.decodeInterface(t, state, value, i.indir)
} }
} }
} }
...@@ -921,7 +870,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { ...@@ -921,7 +870,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
if wireId == tInterface { if wireId == tInterface {
// Special case because it's a method: the ignored item might // Special case because it's a method: the ignored item might
// define types and we need to record their state in the decoder. // define types and we need to record their state in the decoder.
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreInterface(state) state.dec.ignoreInterface(state)
} }
return op return op
...@@ -934,7 +883,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { ...@@ -934,7 +883,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
case wire.ArrayT != nil: case wire.ArrayT != nil:
elemId := wire.ArrayT.Elem elemId := wire.ArrayT.Elem
elemOp := dec.decIgnoreOpFor(elemId) elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len) state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len)
} }
...@@ -943,14 +892,14 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { ...@@ -943,14 +892,14 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
elemId := dec.wireType[wireId].MapT.Elem elemId := dec.wireType[wireId].MapT.Elem
keyOp := dec.decIgnoreOpFor(keyId) keyOp := dec.decIgnoreOpFor(keyId)
elemOp := dec.decIgnoreOpFor(elemId) elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreMap(state, keyOp, elemOp) state.dec.ignoreMap(state, keyOp, elemOp)
} }
case wire.SliceT != nil: case wire.SliceT != nil:
elemId := wire.SliceT.Elem elemId := wire.SliceT.Elem
elemOp := dec.decIgnoreOpFor(elemId) elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreSlice(state, elemOp) state.dec.ignoreSlice(state, elemOp)
} }
...@@ -960,13 +909,13 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { ...@@ -960,13 +909,13 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
if err != nil { if err != nil {
error_(err) error_(err)
} }
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
// indirect through enginePtr to delay evaluation for recursive structs // indirect through enginePtr to delay evaluation for recursive structs
state.dec.ignoreStruct(*enginePtr) state.dec.ignoreStruct(*enginePtr)
} }
case wire.GobEncoderT != nil, wire.BinaryMarshalerT != nil, wire.TextMarshalerT != nil: case wire.GobEncoderT != nil, wire.BinaryMarshalerT != nil, wire.TextMarshalerT != nil:
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
state.dec.ignoreGobDecoder(state) state.dec.ignoreGobDecoder(state)
} }
} }
...@@ -989,25 +938,21 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) { ...@@ -989,25 +938,21 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
} }
} }
var op decOp var op decOp
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { op = func(i *decInstr, state *decoderState, value reflect.Value) {
// Caller has gotten us to within one indirection of our value. // Caller has gotten us to within one indirection of our value.
if i.indir > 0 { if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil { if value.IsNil() {
*(*unsafe.Pointer)(p) = unsafe.Pointer(reflect.New(ut.base).Pointer()) value.Set(reflect.New(ut.base))
} }
} }
// Now p is a pointer to the base type. Do we need to climb out to // Now value is a pointer to the base type. Do we need to climb out to
// get to the receiver type? // get to the receiver type?
var v reflect.Value
if ut.decIndir == -1 { if ut.decIndir == -1 {
v = reflect.NewAt(rcvrType, unsafe.Pointer(&p)).Elem() value = value.Addr()
} else {
v = reflect.NewAt(rcvrType, p).Elem()
} }
state.dec.decodeGobDecoder(ut, state, v) state.dec.decodeGobDecoder(ut, state, value)
} }
return &op, int(ut.indir) return &op, int(ut.indir)
} }
// compatibleType asks: Are these two gob Types compatible? // compatibleType asks: Are these two gob Types compatible?
...@@ -1110,7 +1055,7 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de ...@@ -1110,7 +1055,7 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
} }
op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp)) op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
ovfl := errors.New(`value for "` + name + `" out of range`) ovfl := errors.New(`value for "` + name + `" out of range`)
engine.instr[singletonField] = decInstr{*op, singletonField, indir, 0, ovfl} engine.instr[singletonField] = decInstr{*op, singletonField, nil, indir, ovfl}
engine.numInstr = 1 engine.numInstr = 1
return return
} }
...@@ -1121,7 +1066,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err ...@@ -1121,7 +1066,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err
engine.instr = make([]decInstr, 1) // one item engine.instr = make([]decInstr, 1) // one item
op := dec.decIgnoreOpFor(remoteId) op := dec.decIgnoreOpFor(remoteId)
ovfl := overflow(dec.typeString(remoteId)) ovfl := overflow(dec.typeString(remoteId))
engine.instr[0] = decInstr{op, 0, 0, 0, ovfl} engine.instr[0] = decInstr{op, 0, nil, 0, ovfl}
engine.numInstr = 1 engine.numInstr = 1
return return
} }
...@@ -1164,14 +1109,14 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn ...@@ -1164,14 +1109,14 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
// TODO(r): anonymous names // TODO(r): anonymous names
if !present || !isExported(wireField.Name) { if !present || !isExported(wireField.Name) {
op := dec.decIgnoreOpFor(wireField.Id) op := dec.decIgnoreOpFor(wireField.Id)
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl} engine.instr[fieldnum] = decInstr{op, fieldnum, nil, 0, ovfl}
continue continue
} }
if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) { 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) 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) op, indir := dec.decOpFor(wireField.Id, localField.Type, localField.Name, seen)
engine.instr[fieldnum] = decInstr{*op, fieldnum, indir, uintptr(localField.Offset), ovfl} engine.instr[fieldnum] = decInstr{*op, fieldnum, localField.Index, indir, ovfl}
engine.numInstr++ engine.numInstr++
} }
return return
...@@ -1222,16 +1167,16 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er ...@@ -1222,16 +1167,16 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er
return return
} }
// 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 value.
func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) { func (dec *Decoder) decodeValue(wireId typeId, value reflect.Value) {
defer catchError(&dec.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.IsValid() { if !value.IsValid() {
dec.decodeIgnoredValue(wireId) dec.decodeIgnoredValue(wireId)
return return
} }
// Dereference down to the underlying type. // Dereference down to the underlying type.
ut := userType(val.Type()) ut := userType(value.Type())
base := ut.base base := ut.base
var enginePtr **decEngine var enginePtr **decEngine
enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut) enginePtr, dec.err = dec.getDecEnginePtr(wireId, ut)
...@@ -1245,9 +1190,9 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) { ...@@ -1245,9 +1190,9 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
name := base.Name() name := base.Name()
errorf("type mismatch: no fields matched compiling decoder for %s", name) errorf("type mismatch: no fields matched compiling decoder for %s", name)
} }
dec.decodeStruct(engine, ut, unsafeAddr(val), ut.indir) dec.decodeStruct(engine, ut, value, ut.indir)
} else { } else {
dec.decodeSingle(engine, ut, unsafeAddr(val)) dec.decodeSingle(engine, ut, value)
} }
} }
...@@ -1293,21 +1238,6 @@ func init() { ...@@ -1293,21 +1238,6 @@ func init() {
decOpTable[reflect.Uintptr] = uop decOpTable[reflect.Uintptr] = uop
} }
// Gob assumes it can call UnsafeAddr on any Value
// in order to get a pointer it can copy data from.
// Values that have just been created and do not point
// into existing structs or slices cannot be addressed,
// so simulate it by returning a pointer to a copy.
// Each call allocates once.
func unsafeAddr(v reflect.Value) unsafe.Pointer {
if v.CanAddr() {
return unsafe.Pointer(v.UnsafeAddr())
}
x := reflect.New(v.Type()).Elem()
x.Set(v)
return unsafe.Pointer(x.UnsafeAddr())
}
// Gob depends on being able to take the address // Gob depends on being able to take the address
// of zeroed Values it creates, so use this wrapper instead // of zeroed Values it creates, so use this wrapper instead
// of the standard reflect.Zero. // of the standard reflect.Zero.
......
...@@ -9,10 +9,9 @@ import ( ...@@ -9,10 +9,9 @@ import (
"encoding" "encoding"
"math" "math"
"reflect" "reflect"
"unsafe"
) )
const uint64Size = int(unsafe.Sizeof(uint64(0))) const uint64Size = 8
// encoderState is the global execution state of an instance of the encoder. // encoderState is the global execution state of an instance of the encoder.
// Field numbers are delta encoded and always increase. The field // Field numbers are delta encoded and always increase. The field
...@@ -87,14 +86,14 @@ func (state *encoderState) encodeInt(i int64) { ...@@ -87,14 +86,14 @@ func (state *encoderState) encodeInt(i int64) {
} }
// encOp is the signature of an encoding operator for a given type. // encOp is the signature of an encoding operator for a given type.
type encOp func(i *encInstr, state *encoderState, p unsafe.Pointer) type encOp func(i *encInstr, state *encoderState, v reflect.Value)
// The 'instructions' of the encoding machine // The 'instructions' of the encoding machine
type encInstr struct { type encInstr struct {
op encOp op encOp
field int // field number field int // field number in input
indir int // how many pointer indirections to reach the value in the struct index []int // struct index
offset uintptr // offset in the structure of the field to encode indir int // how many pointer indirections to reach the value in the struct
} }
// update emits a field number and updates the state to record its value for delta encoding. // update emits a field number and updates the state to record its value for delta encoding.
...@@ -115,20 +114,20 @@ func (state *encoderState) update(instr *encInstr) { ...@@ -115,20 +114,20 @@ func (state *encoderState) update(instr *encInstr) {
// encoded integer, followed by the field data in its appropriate // encoded integer, followed by the field data in its appropriate
// format. // format.
// encIndirect dereferences p indir times and returns the result. // encIndirect dereferences pv indir times and returns the result.
func encIndirect(p unsafe.Pointer, indir int) unsafe.Pointer { func encIndirect(pv reflect.Value, indir int) reflect.Value {
for ; indir > 0; indir-- { for ; indir > 0; indir-- {
p = *(*unsafe.Pointer)(p) if pv.IsNil() {
if p == nil { break
return unsafe.Pointer(nil)
} }
pv = pv.Elem()
} }
return p return pv
} }
// encBool encodes the bool with address p as an unsigned 0 or 1. // encBool encodes the bool referenced by v as an unsigned 0 or 1.
func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) { func encBool(i *encInstr, state *encoderState, v reflect.Value) {
b := *(*bool)(p) b := v.Bool()
if b || state.sendZero { if b || state.sendZero {
state.update(i) state.update(i)
if b { if b {
...@@ -139,102 +138,21 @@ func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) { ...@@ -139,102 +138,21 @@ func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
} }
} }
// encInt encodes the int with address p. // encInt encodes the signed integer (int int8 int16 int32 int64) referenced by v.
func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) { func encInt(i *encInstr, state *encoderState, v reflect.Value) {
v := int64(*(*int)(p)) value := v.Int()
if v != 0 || state.sendZero { if value != 0 || state.sendZero {
state.update(i) state.update(i)
state.encodeInt(v) state.encodeInt(value)
} }
} }
// encUint encodes the uint with address p. // encUint encodes the unsigned integer (uint uint8 uint16 uint32 uint64 uintptr) referenced by v.
func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUint(i *encInstr, state *encoderState, v reflect.Value) {
v := uint64(*(*uint)(p)) value := v.Uint()
if v != 0 || state.sendZero { if value != 0 || state.sendZero {
state.update(i) state.update(i)
state.encodeUint(v) state.encodeUint(value)
}
}
// encInt8 encodes the int8 with address p.
func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int8)(p))
if v != 0 || state.sendZero {
state.update(i)
state.encodeInt(v)
}
}
// encUint8 encodes the uint8 with address p.
func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint8)(p))
if v != 0 || state.sendZero {
state.update(i)
state.encodeUint(v)
}
}
// encInt16 encodes the int16 with address p.
func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int16)(p))
if v != 0 || state.sendZero {
state.update(i)
state.encodeInt(v)
}
}
// encUint16 encodes the uint16 with address p.
func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint16)(p))
if v != 0 || state.sendZero {
state.update(i)
state.encodeUint(v)
}
}
// encInt32 encodes the int32 with address p.
func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int32)(p))
if v != 0 || state.sendZero {
state.update(i)
state.encodeInt(v)
}
}
// encUint encodes the uint32 with address p.
func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint32)(p))
if v != 0 || state.sendZero {
state.update(i)
state.encodeUint(v)
}
}
// encInt64 encodes the int64 with address p.
func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := *(*int64)(p)
if v != 0 || state.sendZero {
state.update(i)
state.encodeInt(v)
}
}
// encInt64 encodes the uint64 with address p.
func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := *(*uint64)(p)
if v != 0 || state.sendZero {
state.update(i)
state.encodeUint(v)
}
}
// encUintptr encodes the uintptr with address p.
func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uintptr)(p))
if v != 0 || state.sendZero {
state.update(i)
state.encodeUint(v)
} }
} }
...@@ -255,42 +173,20 @@ func floatBits(f float64) uint64 { ...@@ -255,42 +173,20 @@ func floatBits(f float64) uint64 {
return v return v
} }
// encFloat32 encodes the float32 with address p. // encFloat encodes the floating point value (float32 float64) referenced by v.
func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) { func encFloat(i *encInstr, state *encoderState, v reflect.Value) {
f := *(*float32)(p) f := v.Float()
if f != 0 || state.sendZero {
v := floatBits(float64(f))
state.update(i)
state.encodeUint(v)
}
}
// encFloat64 encodes the float64 with address p.
func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
f := *(*float64)(p)
if f != 0 || state.sendZero { if f != 0 || state.sendZero {
bits := floatBits(f)
state.update(i) state.update(i)
v := floatBits(f) state.encodeUint(bits)
state.encodeUint(v)
} }
} }
// encComplex64 encodes the complex64 with address p. // encComplex encodes the complex value (complex64 complex128) referenced by v.
// Complex numbers are just a pair of floating-point numbers, real part first. // Complex numbers are just a pair of floating-point numbers, real part first.
func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) { func encComplex(i *encInstr, state *encoderState, v reflect.Value) {
c := *(*complex64)(p) c := v.Complex()
if c != 0+0i || state.sendZero {
rpart := floatBits(float64(real(c)))
ipart := floatBits(float64(imag(c)))
state.update(i)
state.encodeUint(rpart)
state.encodeUint(ipart)
}
}
// encComplex128 encodes the complex128 with address p.
func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
c := *(*complex128)(p)
if c != 0+0i || state.sendZero { if c != 0+0i || state.sendZero {
rpart := floatBits(real(c)) rpart := floatBits(real(c))
ipart := floatBits(imag(c)) ipart := floatBits(imag(c))
...@@ -300,10 +196,10 @@ func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) { ...@@ -300,10 +196,10 @@ func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
} }
} }
// encUint8Array encodes the byte slice whose header has address p. // encUint8Array encodes the byte array referenced by v.
// Byte arrays are encoded as an unsigned count followed by the raw bytes. // Byte arrays are encoded as an unsigned count followed by the raw bytes.
func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) { func encUint8Array(i *encInstr, state *encoderState, v reflect.Value) {
b := *(*[]byte)(p) b := v.Bytes()
if len(b) > 0 || state.sendZero { if len(b) > 0 || state.sendZero {
state.update(i) state.update(i)
state.encodeUint(uint64(len(b))) state.encodeUint(uint64(len(b)))
...@@ -311,10 +207,10 @@ func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) { ...@@ -311,10 +207,10 @@ func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
} }
} }
// encString encodes the string whose header has address p. // encString encodes the string referenced by v.
// Strings are encoded as an unsigned count followed by the raw bytes. // Strings are encoded as an unsigned count followed by the raw bytes.
func encString(i *encInstr, state *encoderState, p unsafe.Pointer) { func encString(i *encInstr, state *encoderState, v reflect.Value) {
s := *(*string)(p) s := v.String()
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)))
...@@ -324,7 +220,7 @@ func encString(i *encInstr, state *encoderState, p unsafe.Pointer) { ...@@ -324,7 +220,7 @@ func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
// encStructTerminator encodes the end of an encoded struct // encStructTerminator encodes the end of an encoded struct
// as delta field number of 0. // as delta field number of 0.
func encStructTerminator(i *encInstr, state *encoderState, p unsafe.Pointer) { func encStructTerminator(i *encInstr, state *encoderState, v reflect.Value) {
state.encodeUint(0) state.encodeUint(0)
} }
...@@ -338,60 +234,78 @@ type encEngine struct { ...@@ -338,60 +234,78 @@ type encEngine struct {
const singletonField = 0 const singletonField = 0
// valid reports whether the value is valid and a non-nil pointer.
// (Slices, maps, and chans take care of themselves.)
func valid(v reflect.Value) bool {
switch v.Kind() {
case reflect.Invalid:
return false
case reflect.Ptr:
return !v.IsNil()
}
return true
}
// encodeSingle encodes a single top-level non-struct value. // encodeSingle encodes a single top-level non-struct value.
func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep unsafe.Pointer) { func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, value reflect.Value) {
state := enc.newEncoderState(b) state := enc.newEncoderState(b)
defer enc.freeEncoderState(state)
state.fieldnum = singletonField state.fieldnum = singletonField
// There is no surrounding struct to frame the transmission, so we must // 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. // generate data even if the item is zero. To do this, set sendZero.
state.sendZero = true state.sendZero = true
instr := &engine.instr[singletonField] instr := &engine.instr[singletonField]
p := basep // offset will be zero
if instr.indir > 0 { if instr.indir > 0 {
if p = encIndirect(p, instr.indir); p == nil { value = encIndirect(value, instr.indir)
return }
} if valid(value) {
instr.op(instr, state, value)
} }
instr.op(instr, state, p)
enc.freeEncoderState(state)
} }
// encodeStruct encodes a single struct value. // encodeStruct encodes a single struct value.
func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep unsafe.Pointer) { func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value reflect.Value) {
if !valid(value) {
return
}
state := enc.newEncoderState(b) state := enc.newEncoderState(b)
defer enc.freeEncoderState(state)
state.fieldnum = -1 state.fieldnum = -1
for i := 0; i < len(engine.instr); i++ { for i := 0; i < len(engine.instr); i++ {
instr := &engine.instr[i] instr := &engine.instr[i]
p := unsafe.Pointer(uintptr(basep) + instr.offset) if i >= value.NumField() {
// encStructTerminator
instr.op(instr, state, reflect.Value{})
break
}
field := value.FieldByIndex(instr.index)
if instr.indir > 0 { if instr.indir > 0 {
if p = encIndirect(p, instr.indir); p == nil { field = encIndirect(field, instr.indir)
continue }
} if !valid(field) {
continue
} }
instr.op(instr, state, p) instr.op(instr, state, field)
} }
enc.freeEncoderState(state)
} }
// encodeArray encodes the array whose 0th element is at p. // encodeArray encodes the array whose 0th element is at p.
func (enc *Encoder) encodeArray(b *bytes.Buffer, p unsafe.Pointer, op encOp, elemWid uintptr, elemIndir int, length int) { func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int) {
state := enc.newEncoderState(b) state := enc.newEncoderState(b)
defer enc.freeEncoderState(state)
state.fieldnum = -1 state.fieldnum = -1
state.sendZero = true state.sendZero = true
state.encodeUint(uint64(length)) state.encodeUint(uint64(length))
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
elemp := p elem := value.Index(i)
if elemIndir > 0 { if elemIndir > 0 {
up := encIndirect(elemp, elemIndir) elem = encIndirect(elem, elemIndir)
if up == nil { if !valid(elem) {
errorf("encodeArray: nil element") errorf("encodeArray: nil element")
} }
elemp = up
} }
op(nil, state, elemp) op(nil, state, elem)
p = unsafe.Pointer(uintptr(p) + elemWid)
} }
enc.freeEncoderState(state)
} }
// encodeReflectValue is a helper for maps. It encodes the value v. // encodeReflectValue is a helper for maps. It encodes the value v.
...@@ -402,12 +316,10 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in ...@@ -402,12 +316,10 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in
if !v.IsValid() { if !v.IsValid() {
errorf("encodeReflectValue: nil element") errorf("encodeReflectValue: nil element")
} }
op(nil, state, unsafeAddr(v)) op(nil, state, v)
} }
// encodeMap encodes a map as unsigned count followed by key:value pairs. // 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.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) { func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) {
state := enc.newEncoderState(b) state := enc.newEncoderState(b)
state.fieldnum = -1 state.fieldnum = -1
...@@ -539,20 +451,20 @@ func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, ut *userTypeInfo, v reflec ...@@ -539,20 +451,20 @@ func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, ut *userTypeInfo, v reflec
var encOpTable = [...]encOp{ var encOpTable = [...]encOp{
reflect.Bool: encBool, reflect.Bool: encBool,
reflect.Int: encInt, reflect.Int: encInt,
reflect.Int8: encInt8, reflect.Int8: encInt,
reflect.Int16: encInt16, reflect.Int16: encInt,
reflect.Int32: encInt32, reflect.Int32: encInt,
reflect.Int64: encInt64, reflect.Int64: encInt,
reflect.Uint: encUint, reflect.Uint: encUint,
reflect.Uint8: encUint8, reflect.Uint8: encUint,
reflect.Uint16: encUint16, reflect.Uint16: encUint,
reflect.Uint32: encUint32, reflect.Uint32: encUint,
reflect.Uint64: encUint64, reflect.Uint64: encUint,
reflect.Uintptr: encUintptr, reflect.Uintptr: encUint,
reflect.Float32: encFloat32, reflect.Float32: encFloat,
reflect.Float64: encFloat64, reflect.Float64: encFloat,
reflect.Complex64: encComplex64, reflect.Complex64: encComplex,
reflect.Complex128: encComplex128, reflect.Complex128: encComplex,
reflect.String: encString, reflect.String: encString,
} }
...@@ -587,30 +499,24 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp ...@@ -587,30 +499,24 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
} }
// Slices have a header; we decode it to find the underlying array. // Slices have a header; we decode it to find the underlying array.
elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress) elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress)
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { op = func(i *encInstr, state *encoderState, slice reflect.Value) {
slice := (*reflect.SliceHeader)(p) if !state.sendZero && slice.Len() == 0 {
if !state.sendZero && slice.Len == 0 {
return return
} }
state.update(i) state.update(i)
state.enc.encodeArray(state.b, unsafe.Pointer(slice.Data), *elemOp, t.Elem().Size(), elemIndir, int(slice.Len)) state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len())
} }
case reflect.Array: case reflect.Array:
// True arrays have size in the type. // True arrays have size in the type.
elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress) elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress)
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { op = func(i *encInstr, state *encoderState, array reflect.Value) {
state.update(i) state.update(i)
state.enc.encodeArray(state.b, p, *elemOp, t.Elem().Size(), elemIndir, t.Len()) state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len())
} }
case reflect.Map: case reflect.Map:
keyOp, keyIndir := enc.encOpFor(t.Key(), inProgress) keyOp, keyIndir := enc.encOpFor(t.Key(), inProgress)
elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress) elemOp, elemIndir := enc.encOpFor(t.Elem(), inProgress)
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { op = func(i *encInstr, state *encoderState, mv reflect.Value) {
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
v := reflect.NewAt(t, unsafe.Pointer(p)).Elem()
mv := reflect.Indirect(v)
// We send zero-length (but non-nil) maps because the // We send zero-length (but non-nil) maps because the
// receiver might want to use the map. (Maps don't use append.) // receiver might want to use the map. (Maps don't use append.)
if !state.sendZero && mv.IsNil() { if !state.sendZero && mv.IsNil() {
...@@ -623,17 +529,13 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp ...@@ -623,17 +529,13 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
// Generate a closure that calls out to the engine for the nested type. // Generate a closure that calls out to the engine for the nested type.
enc.getEncEngine(userType(typ)) enc.getEncEngine(userType(typ))
info := mustGetTypeInfo(typ) info := mustGetTypeInfo(typ)
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { op = func(i *encInstr, state *encoderState, sv reflect.Value) {
state.update(i) state.update(i)
// indirect through info to delay evaluation for recursive structs // indirect through info to delay evaluation for recursive structs
state.enc.encodeStruct(state.b, info.encoder, p) state.enc.encodeStruct(state.b, info.encoder, sv)
} }
case reflect.Interface: case reflect.Interface:
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { op = func(i *encInstr, state *encoderState, iv reflect.Value) {
// Interfaces transmit the name and contents of the concrete
// value they contain.
v := reflect.NewAt(t, unsafe.Pointer(p)).Elem()
iv := reflect.Indirect(v)
if !state.sendZero && (!iv.IsValid() || iv.IsNil()) { if !state.sendZero && (!iv.IsValid() || iv.IsNil()) {
return return
} }
...@@ -660,13 +562,13 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) { ...@@ -660,13 +562,13 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
} }
} }
var op encOp var op encOp
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) { op = func(i *encInstr, state *encoderState, v reflect.Value) {
var v reflect.Value
if ut.encIndir == -1 { if ut.encIndir == -1 {
// Need to climb up one level to turn value into pointer. // Need to climb up one level to turn value into pointer.
v = reflect.NewAt(rt, unsafe.Pointer(&p)).Elem() if !v.CanAddr() {
} else { errorf("unaddressable value of type %s", rt)
v = reflect.NewAt(rt, p).Elem() }
v = v.Addr()
} }
if !state.sendZero && isZero(v) { if !state.sendZero && isZero(v) {
return return
...@@ -693,17 +595,17 @@ func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine { ...@@ -693,17 +595,17 @@ func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine {
continue continue
} }
op, indir := enc.encOpFor(f.Type, seen) op, indir := enc.encOpFor(f.Type, seen)
engine.instr = append(engine.instr, encInstr{*op, wireFieldNum, indir, uintptr(f.Offset)}) engine.instr = append(engine.instr, encInstr{*op, wireFieldNum, f.Index, indir})
wireFieldNum++ wireFieldNum++
} }
if srt.NumField() > 0 && len(engine.instr) == 0 { if srt.NumField() > 0 && len(engine.instr) == 0 {
errorf("type %s has no exported fields", rt) errorf("type %s has no exported fields", rt)
} }
engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, 0, 0}) engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, nil, 0})
} else { } else {
engine.instr = make([]encInstr, 1) engine.instr = make([]encInstr, 1)
op, indir := enc.encOpFor(rt, seen) op, indir := enc.encOpFor(rt, seen)
engine.instr[0] = encInstr{*op, singletonField, indir, 0} // offset is zero engine.instr[0] = encInstr{*op, singletonField, nil, indir}
} }
return engine return engine
} }
...@@ -753,8 +655,8 @@ func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInf ...@@ -753,8 +655,8 @@ func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInf
value = reflect.Indirect(value) value = reflect.Indirect(value)
} }
if ut.externalEnc == 0 && value.Type().Kind() == reflect.Struct { if ut.externalEnc == 0 && value.Type().Kind() == reflect.Struct {
enc.encodeStruct(b, engine, unsafeAddr(value)) enc.encodeStruct(b, engine, value)
} else { } else {
enc.encodeSingle(b, engine, unsafeAddr(value)) enc.encodeSingle(b, engine, value)
} }
} }
...@@ -13,6 +13,52 @@ import ( ...@@ -13,6 +13,52 @@ import (
"testing" "testing"
) )
// Test basic operations in a safe manner.
func TestBasicEncoderDecoder(t *testing.T) {
var values = []interface{}{
true,
int(123),
int8(123),
int16(-12345),
int32(123456),
int64(-1234567),
uint(123),
uint8(123),
uint16(12345),
uint32(123456),
uint64(1234567),
uintptr(12345678),
float32(1.2345),
float64(1.2345678),
complex64(1.2345 + 2.3456i),
complex128(1.2345678 + 2.3456789i),
[]byte("hello"),
string("hello"),
}
for _, value := range values {
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode(value)
if err != nil {
t.Error("encoder fail:", err)
}
dec := NewDecoder(b)
result := reflect.New(reflect.TypeOf(value))
err = dec.Decode(result.Interface())
if err != nil {
t.Fatalf("error decoding %T: %v:", reflect.TypeOf(value), err)
}
if !reflect.DeepEqual(value, result.Elem().Interface()) {
t.Fatalf("%T: expected %v got %v", value, value, result.Elem().Interface())
}
}
}
type ET0 struct {
A int
B string
}
type ET2 struct { type ET2 struct {
X string X string
} }
...@@ -40,14 +86,40 @@ type ET4 struct { ...@@ -40,14 +86,40 @@ type ET4 struct {
func TestEncoderDecoder(t *testing.T) { func TestEncoderDecoder(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
enc := NewEncoder(b) enc := NewEncoder(b)
et0 := new(ET0)
et0.A = 7
et0.B = "gobs of fun"
err := enc.Encode(et0)
if err != nil {
t.Error("encoder fail:", err)
}
//fmt.Printf("% x %q\n", b, b)
//Debug(b)
dec := NewDecoder(b)
newEt0 := new(ET0)
err = dec.Decode(newEt0)
if err != nil {
t.Fatal("error decoding ET0:", err)
}
if !reflect.DeepEqual(et0, newEt0) {
t.Fatalf("invalid data for et0: expected %+v; got %+v", *et0, *newEt0)
}
if b.Len() != 0 {
t.Error("not at eof;", b.Len(), "bytes left")
}
// t.FailNow()
b = new(bytes.Buffer)
enc = NewEncoder(b)
et1 := new(ET1) et1 := new(ET1)
et1.A = 7 et1.A = 7
et1.Et2 = new(ET2) et1.Et2 = new(ET2)
err := enc.Encode(et1) err = enc.Encode(et1)
if err != nil { if err != nil {
t.Error("encoder fail:", err) t.Error("encoder fail:", err)
} }
dec := NewDecoder(b) dec = NewDecoder(b)
newEt1 := new(ET1) newEt1 := new(ET1)
err = dec.Decode(newEt1) err = dec.Decode(newEt1)
if err != nil { if err != nil {
......
...@@ -279,7 +279,7 @@ func TestGobEncoderValueField(t *testing.T) { ...@@ -279,7 +279,7 @@ func TestGobEncoderValueField(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
// First a field that's a structure. // First a field that's a structure.
enc := NewEncoder(b) enc := NewEncoder(b)
err := enc.Encode(GobTestValueEncDec{17, StringStruct{"HIJKL"}}) err := enc.Encode(&GobTestValueEncDec{17, StringStruct{"HIJKL"}})
if err != nil { if err != nil {
t.Fatal("encode error:", err) t.Fatal("encode error:", err)
} }
...@@ -326,7 +326,7 @@ func TestGobEncoderArrayField(t *testing.T) { ...@@ -326,7 +326,7 @@ func TestGobEncoderArrayField(t *testing.T) {
for i := range a.A.a { for i := range a.A.a {
a.A.a[i] = byte(i) a.A.a[i] = byte(i)
} }
err := enc.Encode(a) err := enc.Encode(&a)
if err != nil { if err != nil {
t.Fatal("encode error:", err) t.Fatal("encode error:", err)
} }
...@@ -589,7 +589,8 @@ func TestGobEncoderStructSingleton(t *testing.T) { ...@@ -589,7 +589,8 @@ func TestGobEncoderStructSingleton(t *testing.T) {
func TestGobEncoderNonStructSingleton(t *testing.T) { func TestGobEncoderNonStructSingleton(t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
enc := NewEncoder(b) enc := NewEncoder(b)
err := enc.Encode(Gobber(1234)) var g Gobber = 1234
err := enc.Encode(&g)
if err != nil { if err != nil {
t.Fatal("encode error:", err) t.Fatal("encode error:", err)
} }
......
...@@ -23,7 +23,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) { ...@@ -23,7 +23,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) {
b.StopTimer() b.StopTimer()
enc := NewEncoder(w) enc := NewEncoder(w)
dec := NewDecoder(r) dec := NewDecoder(r)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")} bench := &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
b.StartTimer() b.StartTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if enc.Encode(bench) != nil { if enc.Encode(bench) != nil {
...@@ -103,7 +103,7 @@ func TestCountDecodeMallocs(t *testing.T) { ...@@ -103,7 +103,7 @@ func TestCountDecodeMallocs(t *testing.T) {
t.Fatal("decode:", err) t.Fatal("decode:", err)
} }
}) })
if allocs != 3 { if allocs != 4 {
t.Fatalf("mallocs per decode of type Bench: %v; wanted 3\n", allocs) t.Fatalf("mallocs per decode of type Bench: %v; wanted 4\n", allocs)
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment