Commit a479a455 authored by Russ Cox's avatar Russ Cox

reflect: make Value an opaque struct

Making Value opaque means we can drop the interface kludges
in favor of a significantly simpler and faster representation.
v.Kind() will be a prime candidate for inlining too.

On a Thinkpad X201s using -benchtime 10:

benchmark                           old ns/op    new ns/op    delta
json.BenchmarkCodeEncoder           284391780    157415960  -44.65%
json.BenchmarkCodeMarshal           286979140    158992020  -44.60%
json.BenchmarkCodeDecoder           717175800    388288220  -45.86%
json.BenchmarkCodeUnmarshal         734470500    404548520  -44.92%
json.BenchmarkCodeUnmarshalReuse    707172280    385258720  -45.52%
json.BenchmarkSkipValue              24630036     18557062  -24.66%

benchmark                            old MB/s     new MB/s  speedup
json.BenchmarkCodeEncoder                6.82        12.33    1.81x
json.BenchmarkCodeMarshal                6.76        12.20    1.80x
json.BenchmarkCodeDecoder                2.71         5.00    1.85x
json.BenchmarkCodeUnmarshal              2.64         4.80    1.82x
json.BenchmarkCodeUnmarshalReuse         2.74         5.04    1.84x
json.BenchmarkSkipValue                 77.92       103.42    1.33x

I cannot explain why BenchmarkSkipValue gets faster.
Maybe it is one of those code alignment things.

R=iant, r, gri, r
CC=golang-dev
https://golang.org/cl/5373101
parent 4d27f648
...@@ -16,6 +16,13 @@ import ( ...@@ -16,6 +16,13 @@ import (
"unsafe" "unsafe"
) )
func TestBool(t *testing.T) {
v := ValueOf(true)
if v.Bool() != true {
t.Fatal("ValueOf(true).Bool() = false")
}
}
type integer int type integer int
type T struct { type T struct {
a int a int
...@@ -215,7 +222,8 @@ func TestTypes(t *testing.T) { ...@@ -215,7 +222,8 @@ func TestTypes(t *testing.T) {
func TestSet(t *testing.T) { func TestSet(t *testing.T) {
for i, tt := range valueTests { for i, tt := range valueTests {
v := ValueOf(tt.i).Elem() v := ValueOf(tt.i)
v = v.Elem()
switch v.Kind() { switch v.Kind() {
case Int: case Int:
v.SetInt(132) v.SetInt(132)
...@@ -1100,21 +1108,38 @@ func TestMethod(t *testing.T) { ...@@ -1100,21 +1108,38 @@ func TestMethod(t *testing.T) {
} }
// Curried method of value. // Curried method of value.
i = ValueOf(p).Method(1).Call([]Value{ValueOf(10)})[0].Int() tfunc := TypeOf(func(int) int(nil))
v := ValueOf(p).Method(1)
if tt := v.Type(); tt != tfunc {
t.Errorf("Value Method Type is %s; want %s", tt, tfunc)
}
i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 { if i != 250 {
t.Errorf("Value Method returned %d; want 250", i) t.Errorf("Value Method returned %d; want 250", i)
} }
i = ValueOf(p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int() v = ValueOf(p).MethodByName("Dist")
if tt := v.Type(); tt != tfunc {
t.Errorf("Value MethodByName Type is %s; want %s", tt, tfunc)
}
i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 { if i != 250 {
t.Errorf("Value MethodByName returned %d; want 250", i) t.Errorf("Value MethodByName returned %d; want 250", i)
} }
// Curried method of pointer. // Curried method of pointer.
i = ValueOf(&p).Method(1).Call([]Value{ValueOf(10)})[0].Int() v = ValueOf(&p).Method(1)
if tt := v.Type(); tt != tfunc {
t.Errorf("Pointer Value Method Type is %s; want %s", tt, tfunc)
}
i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 { if i != 250 {
t.Errorf("Pointer Value Method returned %d; want 250", i) t.Errorf("Pointer Value Method returned %d; want 250", i)
} }
i = ValueOf(&p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int() v = ValueOf(&p).MethodByName("Dist")
if tt := v.Type(); tt != tfunc {
t.Errorf("Pointer Value MethodByName Type is %s; want %s", tt, tfunc)
}
i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 { if i != 250 {
t.Errorf("Pointer Value MethodByName returned %d; want 250", i) t.Errorf("Pointer Value MethodByName returned %d; want 250", i)
} }
...@@ -1129,11 +1154,19 @@ func TestMethod(t *testing.T) { ...@@ -1129,11 +1154,19 @@ func TestMethod(t *testing.T) {
} }
}{p} }{p}
pv := ValueOf(s).Field(0) pv := ValueOf(s).Field(0)
i = pv.Method(0).Call([]Value{ValueOf(10)})[0].Int() v = pv.Method(0)
if tt := v.Type(); tt != tfunc {
t.Errorf("Interface Method Type is %s; want %s", tt, tfunc)
}
i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 { if i != 250 {
t.Errorf("Interface Method returned %d; want 250", i) t.Errorf("Interface Method returned %d; want 250", i)
} }
i = pv.MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int() v = pv.MethodByName("Dist")
if tt := v.Type(); tt != tfunc {
t.Errorf("Interface MethodByName Type is %s; want %s", tt, tfunc)
}
i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 { if i != 250 {
t.Errorf("Interface MethodByName returned %d; want 250", i) t.Errorf("Interface MethodByName returned %d; want 250", i)
} }
......
...@@ -188,7 +188,7 @@ type Type interface { ...@@ -188,7 +188,7 @@ type Type interface {
// A Kind represents the specific kind of type that a Type represents. // A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind. // The zero Kind is not a valid kind.
type Kind uint8 type Kind uint
const ( const (
Invalid Kind = iota Invalid Kind = iota
...@@ -455,14 +455,15 @@ func (t *uncommonType) Method(i int) (m Method) { ...@@ -455,14 +455,15 @@ func (t *uncommonType) Method(i int) (m Method) {
if p.name != nil { if p.name != nil {
m.Name = *p.name m.Name = *p.name
} }
flag := uint32(0) fl := flag(Func) << flagKindShift
if p.pkgPath != nil { if p.pkgPath != nil {
m.PkgPath = *p.pkgPath m.PkgPath = *p.pkgPath
flag |= flagRO fl |= flagRO
} }
m.Type = toType(p.typ) mt := toCommonType(p.typ)
m.Type = mt
fn := p.tfn fn := p.tfn
m.Func = valueFromIword(flag, m.Type, iword(fn)) m.Func = Value{mt, fn, fl}
m.Index = i m.Index = i
return return
} }
...@@ -768,7 +769,7 @@ func (t *structType) Field(i int) (f StructField) { ...@@ -768,7 +769,7 @@ func (t *structType) Field(i int) (f StructField) {
if i < 0 || i >= len(t.fields) { if i < 0 || i >= len(t.fields) {
return return
} }
p := t.fields[i] p := &t.fields[i]
f.Type = toType(p.typ) f.Type = toType(p.typ)
if p.name != nil { if p.name != nil {
f.Name = *p.name f.Name = *p.name
...@@ -867,10 +868,12 @@ L: ...@@ -867,10 +868,12 @@ L:
if n == 1 { if n == 1 {
// Found matching field. // Found matching field.
if len(ff.Index) <= depth { if depth >= len(ff.Index) {
ff.Index = make([]int, depth+1) ff.Index = make([]int, depth+1)
} }
if len(ff.Index) > 1 {
ff.Index[depth] = fi ff.Index[depth] = fi
}
} else { } else {
// None or more than one matching field found. // None or more than one matching field found.
fd = inf fd = inf
...@@ -906,9 +909,6 @@ func toCommonType(p *runtime.Type) *commonType { ...@@ -906,9 +909,6 @@ func toCommonType(p *runtime.Type) *commonType {
t commonType t commonType
} }
x := unsafe.Pointer(p) x := unsafe.Pointer(p)
if uintptr(x)&reflectFlags != 0 {
panic("reflect: invalid interface value")
}
return &(*hdr)(x).t return &(*hdr)(x).t
} }
...@@ -944,10 +944,12 @@ func (t *commonType) runtimeType() *runtime.Type { ...@@ -944,10 +944,12 @@ func (t *commonType) runtimeType() *runtime.Type {
// PtrTo returns the pointer type with element t. // PtrTo returns the pointer type with element t.
// For example, if t represents type Foo, PtrTo(t) represents *Foo. // For example, if t represents type Foo, PtrTo(t) represents *Foo.
func PtrTo(t Type) Type { func PtrTo(t Type) Type {
// If t records its pointer-to type, use it. return t.(*commonType).ptrTo()
ct := t.(*commonType) }
func (ct *commonType) ptrTo() *commonType {
if p := ct.ptrToThis; p != nil { if p := ct.ptrToThis; p != nil {
return toType(p) return toCommonType(p)
} }
// Otherwise, synthesize one. // Otherwise, synthesize one.
...@@ -959,7 +961,7 @@ func PtrTo(t Type) Type { ...@@ -959,7 +961,7 @@ func PtrTo(t Type) Type {
if m := ptrMap.m; m != nil { if m := ptrMap.m; m != nil {
if p := m[ct]; p != nil { if p := m[ct]; p != nil {
ptrMap.RUnlock() ptrMap.RUnlock()
return p.commonType.toType() return &p.commonType
} }
} }
ptrMap.RUnlock() ptrMap.RUnlock()
...@@ -971,7 +973,7 @@ func PtrTo(t Type) Type { ...@@ -971,7 +973,7 @@ func PtrTo(t Type) Type {
if p != nil { if p != nil {
// some other goroutine won the race and created it // some other goroutine won the race and created it
ptrMap.Unlock() ptrMap.Unlock()
return p return &p.commonType
} }
var rt struct { var rt struct {
...@@ -1003,7 +1005,7 @@ func PtrTo(t Type) Type { ...@@ -1003,7 +1005,7 @@ func PtrTo(t Type) Type {
ptrMap.m[ct] = p ptrMap.m[ct] = p
ptrMap.Unlock() ptrMap.Unlock()
return p.commonType.toType() return &p.commonType
} }
func (t *commonType) Implements(u Type) bool { func (t *commonType) Implements(u Type) bool {
......
This diff is collapsed.
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