mirror of
https://github.com/golang/go
synced 2024-11-25 16:17:56 -07:00
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
This commit is contained in:
parent
4d27f64863
commit
a479a45548
@ -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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
|||||||
}
|
}
|
||||||
}{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 {
|
|||||||
|
|
||||||
// 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) {
|
|||||||
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) {
|
|||||||
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:
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
// 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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user