diff options
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 162 | ||||
-rw-r--r-- | libgo/go/reflect/deepequal.go | 8 | ||||
-rw-r--r-- | libgo/go/reflect/export_test.go | 2 | ||||
-rw-r--r-- | libgo/go/reflect/set_test.go | 2 | ||||
-rw-r--r-- | libgo/go/reflect/type.go | 566 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 182 |
6 files changed, 673 insertions, 249 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 10f995e..dc2b5b4 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -1332,7 +1332,7 @@ func TestSelect(t *testing.T) { // selectWatch and the selectWatcher are a watchdog mechanism for running Select. // If the selectWatcher notices that the select has been blocked for >1 second, it prints -// an error describing the select and panics the entire test binary. +// an error describing the select and panics the entire test binary. var selectWatch struct { sync.Mutex once sync.Once @@ -1700,6 +1700,20 @@ type S13 struct { S8 } +// The X in S15.S11.S1 and S16.S11.S1 annihilate. +type S14 struct { + S15 + S16 +} + +type S15 struct { + S11 +} + +type S16 struct { + S11 +} + var fieldTests = []FTest{ {struct{}{}, "", nil, 0}, {struct{}{}, "Foo", nil, 0}, @@ -1725,6 +1739,7 @@ var fieldTests = []FTest{ {S5{}, "Y", []int{2, 0, 1}, 0}, {S10{}, "X", nil, 0}, {S10{}, "Y", []int{2, 0, 0, 1}, 0}, + {S14{}, "X", nil, 0}, } func TestFieldByIndex(t *testing.T) { @@ -2046,6 +2061,24 @@ func TestSmallNegativeInt(t *testing.T) { } } +func TestIndex(t *testing.T) { + xs := []byte{1, 2, 3, 4, 5, 6, 7, 8} + v := ValueOf(xs).Index(3).Interface().(byte) + if v != xs[3] { + t.Errorf("xs.Index(3) = %v; expected %v", v, xs[3]) + } + xa := [8]byte{10, 20, 30, 40, 50, 60, 70, 80} + v = ValueOf(xa).Index(2).Interface().(byte) + if v != xa[2] { + t.Errorf("xa.Index(2) = %v; expected %v", v, xa[2]) + } + s := "0123456789" + v = ValueOf(s).Index(3).Interface().(byte) + if v != s[3] { + t.Errorf("s.Index(3) = %v; expected %v", v, s[3]) + } +} + func TestSlice(t *testing.T) { xs := []int{1, 2, 3, 4, 5, 6, 7, 8} v := ValueOf(xs).Slice(3, 5).Interface().([]int) @@ -2058,7 +2091,6 @@ func TestSlice(t *testing.T) { if !DeepEqual(v[0:5], xs[3:]) { t.Errorf("xs.Slice(3, 5)[0:5] = %v", v[0:5]) } - xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80} v = ValueOf(&xa).Elem().Slice(2, 5).Interface().([]int) if len(v) != 3 { @@ -2070,6 +2102,11 @@ func TestSlice(t *testing.T) { if !DeepEqual(v[0:6], xa[2:]) { t.Errorf("xs.Slice(2, 5)[0:6] = %v", v[0:6]) } + s := "0123456789" + vs := ValueOf(s).Slice(3, 5).Interface().(string) + if vs != s[3:5] { + t.Errorf("s.Slice(3, 5) = %q; expected %q", vs, s[3:5]) + } } func TestVariadic(t *testing.T) { @@ -2652,6 +2689,127 @@ func TestConvert(t *testing.T) { } } +func TestOverflow(t *testing.T) { + if ovf := V(float64(0)).OverflowFloat(1e300); ovf { + t.Errorf("%v wrongly overflows float64", 1e300) + } + + maxFloat32 := float64((1<<24 - 1) << (127 - 23)) + if ovf := V(float32(0)).OverflowFloat(maxFloat32); ovf { + t.Errorf("%v wrongly overflows float32", maxFloat32) + } + ovfFloat32 := float64((1<<24-1)<<(127-23) + 1<<(127-52)) + if ovf := V(float32(0)).OverflowFloat(ovfFloat32); !ovf { + t.Errorf("%v should overflow float32", ovfFloat32) + } + if ovf := V(float32(0)).OverflowFloat(-ovfFloat32); !ovf { + t.Errorf("%v should overflow float32", -ovfFloat32) + } + + maxInt32 := int64(0x7fffffff) + if ovf := V(int32(0)).OverflowInt(maxInt32); ovf { + t.Errorf("%v wrongly overflows int32", maxInt32) + } + if ovf := V(int32(0)).OverflowInt(-1 << 31); ovf { + t.Errorf("%v wrongly overflows int32", -int64(1)<<31) + } + ovfInt32 := int64(1 << 31) + if ovf := V(int32(0)).OverflowInt(ovfInt32); !ovf { + t.Errorf("%v should overflow int32", ovfInt32) + } + + maxUint32 := uint64(0xffffffff) + if ovf := V(uint32(0)).OverflowUint(maxUint32); ovf { + t.Errorf("%v wrongly overflows uint32", maxUint32) + } + ovfUint32 := uint64(1 << 32) + if ovf := V(uint32(0)).OverflowUint(ovfUint32); !ovf { + t.Errorf("%v should overflow uint32", ovfUint32) + } +} + +func checkSameType(t *testing.T, x, y interface{}) { + if TypeOf(x) != TypeOf(y) { + t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y)) + } +} + +func TestArrayOf(t *testing.T) { + // check construction and use of type not in binary + type T int + at := ArrayOf(10, TypeOf(T(1))) + v := New(at).Elem() + for i := 0; i < v.Len(); i++ { + v.Index(i).Set(ValueOf(T(i))) + } + s := fmt.Sprint(v.Interface()) + want := "[0 1 2 3 4 5 6 7 8 9]" + if s != want { + t.Errorf("constructed array = %s, want %s", s, want) + } + + // check that type already in binary is found + checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{}) +} + +func TestSliceOf(t *testing.T) { + // check construction and use of type not in binary + type T int + st := SliceOf(TypeOf(T(1))) + v := MakeSlice(st, 10, 10) + for i := 0; i < v.Len(); i++ { + v.Index(i).Set(ValueOf(T(i))) + } + s := fmt.Sprint(v.Interface()) + want := "[0 1 2 3 4 5 6 7 8 9]" + if s != want { + t.Errorf("constructed slice = %s, want %s", s, want) + } + + // check that type already in binary is found + type T1 int + checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{}) +} + +func TestChanOf(t *testing.T) { + // check construction and use of type not in binary + type T string + ct := ChanOf(BothDir, TypeOf(T(""))) + v := MakeChan(ct, 2) + v.Send(ValueOf(T("hello"))) + v.Send(ValueOf(T("world"))) + + sv1, _ := v.Recv() + sv2, _ := v.Recv() + s1 := sv1.String() + s2 := sv2.String() + if s1 != "hello" || s2 != "world" { + t.Errorf("constructed chan: have %q, %q, want %q, %q", s1, s2, "hello", "world") + } + + // check that type already in binary is found + type T1 int + checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil)) +} + +func TestMapOf(t *testing.T) { + // check construction and use of type not in binary + type K string + type V float64 + + v := MakeMap(MapOf(TypeOf(K("")), TypeOf(V(0)))) + v.SetMapIndex(ValueOf(K("a")), ValueOf(V(1))) + + s := fmt.Sprint(v.Interface()) + want := "map[a:1]" + if s != want { + t.Errorf("constructed map = %s, want %s", s, want) + } + + // check that type already in binary is found + checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil)) +} + type B1 struct { X int Y int diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go index cd364dd..db04796 100644 --- a/libgo/go/reflect/deepequal.go +++ b/libgo/go/reflect/deepequal.go @@ -122,9 +122,11 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool panic("Not reached") } -// DeepEqual tests for deep equality. It uses normal == equality where possible -// but will scan members of arrays, slices, maps, and fields of structs. It correctly -// handles recursive types. Functions are equal only if they are both nil. +// DeepEqual tests for deep equality. It uses normal == equality where +// possible but will scan elements of arrays, slices, maps, and fields of +// structs. In maps, keys are compared with == but elements use deep +// equality. DeepEqual correctly handles recursive types. Functions are equal +// only if they are both nil. // An empty slice is not equal to a nil slice. func DeepEqual(a1, a2 interface{}) bool { if a1 == nil || a2 == nil { diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go index 6e0d8a3..cd8cf2c 100644 --- a/libgo/go/reflect/export_test.go +++ b/libgo/go/reflect/export_test.go @@ -14,3 +14,5 @@ func MakeRO(v Value) Value { func IsRO(v Value) bool { return v.flag&flagRO != 0 } + +var ArrayOf = arrayOf diff --git a/libgo/go/reflect/set_test.go b/libgo/go/reflect/set_test.go index 8135a4c..83b6507 100644 --- a/libgo/go/reflect/set_test.go +++ b/libgo/go/reflect/set_test.go @@ -85,7 +85,7 @@ func TestImplicitMapConversion(t *testing.T) { } } { - // convert channel direction + // convert channel direction m := make(map[<-chan int]chan int) mv := ValueOf(m) c1 := make(chan int) diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 60a958a..fb0606d 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -187,8 +187,7 @@ type Type interface { // It panics if i is not in the range [0, NumOut()). Out(i int) Type - runtimeType() *runtimeType - common() *commonType + common() *rtype uncommon() *uncommonType } @@ -232,13 +231,11 @@ const ( UnsafePointer ) -type runtimeType commonType - -// commonType is the common implementation of most values. +// rtype is the common implementation of most values. // It is embedded in other, public struct types, but always // with a unique tag like `reflect:"array"` or `reflect:"ptr"` // so that code cannot convert from, say, *arrayType to *ptrType. -type commonType struct { +type rtype struct { kind uint8 // enumeration for C align int8 // alignment of variable with this type fieldAlign uint8 // alignment of struct field with this type @@ -249,17 +246,17 @@ type commonType struct { hashfn func(unsafe.Pointer, uintptr) // hash function equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) // equality function - string *string // string form; unnecessary but undeniably useful - *uncommonType // (relatively) uncommon fields - ptrToThis *runtimeType // pointer to this type, if used in binary or has methods + string *string // string form; unnecessary but undeniably useful + *uncommonType // (relatively) uncommon fields + ptrToThis *rtype // type for pointer to this type, if used in binary or has methods } // Method on non-interface type type method struct { name *string // name of method pkgPath *string // nil for exported Names; otherwise import path - mtyp *runtimeType // method type (without receiver) - typ *runtimeType // .(*FuncType) underneath (with receiver) + mtyp *rtype // method type (without receiver) + typ *rtype // .(*FuncType) underneath (with receiver) tfn unsafe.Pointer // fn used for normal method call } @@ -284,72 +281,72 @@ const ( // arrayType represents a fixed array type. type arrayType struct { - commonType `reflect:"array"` - elem *runtimeType // array element type - slice *runtimeType // slice type - len uintptr + rtype `reflect:"array"` + elem *rtype // array element type + slice *rtype // slice type + len uintptr } // chanType represents a channel type. type chanType struct { - commonType `reflect:"chan"` - elem *runtimeType // channel element type - dir uintptr // channel direction (ChanDir) + rtype `reflect:"chan"` + elem *rtype // channel element type + dir uintptr // channel direction (ChanDir) } // funcType represents a function type. type funcType struct { - commonType `reflect:"func"` - dotdotdot bool // last input parameter is ... - in []*runtimeType // input parameter types - out []*runtimeType // output parameter types + rtype `reflect:"func"` + dotdotdot bool // last input parameter is ... + in []*rtype // input parameter types + out []*rtype // output parameter types } // imethod represents a method on an interface type type imethod struct { - name *string // name of method - pkgPath *string // nil for exported Names; otherwise import path - typ *runtimeType // .(*FuncType) underneath + name *string // name of method + pkgPath *string // nil for exported Names; otherwise import path + typ *rtype // .(*FuncType) underneath } // interfaceType represents an interface type. type interfaceType struct { - commonType `reflect:"interface"` - methods []imethod // sorted by hash + rtype `reflect:"interface"` + methods []imethod // sorted by hash } // mapType represents a map type. type mapType struct { - commonType `reflect:"map"` - key *runtimeType // map key type - elem *runtimeType // map element (value) type + rtype `reflect:"map"` + key *rtype // map key type + elem *rtype // map element (value) type } // ptrType represents a pointer type. type ptrType struct { - commonType `reflect:"ptr"` - elem *runtimeType // pointer element (pointed at) type + rtype `reflect:"ptr"` + elem *rtype // pointer element (pointed at) type } // sliceType represents a slice type. type sliceType struct { - commonType `reflect:"slice"` - elem *runtimeType // slice element type + rtype `reflect:"slice"` + elem *rtype // slice element type } // Struct field type structField struct { - name *string // nil for embedded fields - pkgPath *string // nil for exported Names; otherwise import path - typ *runtimeType // type of field - tag *string // nil if no tag - offset uintptr // byte offset of field within struct + name *string // nil for embedded fields + pkgPath *string // nil for exported Names; otherwise import path + typ *rtype // type of field + tag *string // nil if no tag + offset uintptr // byte offset of field within struct } // structType represents a struct type. type structType struct { - commonType `reflect:"struct"` - fields []structField // sorted by offset + rtype `reflect:"struct"` + fields []structField // sorted by offset } /* @@ -432,16 +429,9 @@ func (t *uncommonType) Name() string { return *t.name } -func (t *commonType) toType() Type { - if t == nil { - return nil - } - return canonicalize(t) -} - -func (t *commonType) rawString() string { return *t.string } +func (t *rtype) rawString() string { return *t.string } -func (t *commonType) String() string { +func (t *rtype) String() string { // For gccgo, strip out quoted strings. s := *t.string var q bool @@ -458,9 +448,9 @@ func (t *commonType) String() string { return string(r[:j]) } -func (t *commonType) Size() uintptr { return t.size } +func (t *rtype) Size() uintptr { return t.size } -func (t *commonType) Bits() int { +func (t *rtype) Bits() int { if t == nil { panic("reflect: Bits of nil Type") } @@ -471,13 +461,13 @@ func (t *commonType) Bits() int { return int(t.size) * 8 } -func (t *commonType) Align() int { return int(t.align) } +func (t *rtype) Align() int { return int(t.align) } -func (t *commonType) FieldAlign() int { return int(t.fieldAlign) } +func (t *rtype) FieldAlign() int { return int(t.fieldAlign) } -func (t *commonType) Kind() Kind { return Kind(t.kind & kindMask) } +func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) } -func (t *commonType) common() *commonType { return t } +func (t *rtype) common() *rtype { return t } func (t *uncommonType) Method(i int) (m Method) { if t == nil || i < 0 || i >= len(t.methods) { @@ -492,8 +482,8 @@ func (t *uncommonType) Method(i int) (m Method) { m.PkgPath = *p.pkgPath fl |= flagRO } - mt := toCommonType(p.typ) - m.Type = mt.toType() + mt := p.typ + m.Type = toType(mt) x := new(unsafe.Pointer) *x = p.tfn m.Func = Value{mt, unsafe.Pointer(x), fl | flagIndir} @@ -524,8 +514,8 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) { // TODO(rsc): 6g supplies these, but they are not // as efficient as they could be: they have commonType -// as the receiver instead of *commonType. -func (t *commonType) NumMethod() int { +// as the receiver instead of *rtype. +func (t *rtype) NumMethod() int { if t.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.NumMethod() @@ -533,7 +523,7 @@ func (t *commonType) NumMethod() int { return t.uncommonType.NumMethod() } -func (t *commonType) Method(i int) (m Method) { +func (t *rtype) Method(i int) (m Method) { if t.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.Method(i) @@ -541,7 +531,7 @@ func (t *commonType) Method(i int) (m Method) { return t.uncommonType.Method(i) } -func (t *commonType) MethodByName(name string) (m Method, ok bool) { +func (t *rtype) MethodByName(name string) (m Method, ok bool) { if t.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.MethodByName(name) @@ -549,15 +539,15 @@ func (t *commonType) MethodByName(name string) (m Method, ok bool) { return t.uncommonType.MethodByName(name) } -func (t *commonType) PkgPath() string { +func (t *rtype) PkgPath() string { return t.uncommonType.PkgPath() } -func (t *commonType) Name() string { +func (t *rtype) Name() string { return t.uncommonType.Name() } -func (t *commonType) ChanDir() ChanDir { +func (t *rtype) ChanDir() ChanDir { if t.Kind() != Chan { panic("reflect: ChanDir of non-chan type") } @@ -565,7 +555,7 @@ func (t *commonType) ChanDir() ChanDir { return ChanDir(tt.dir) } -func (t *commonType) IsVariadic() bool { +func (t *rtype) IsVariadic() bool { if t.Kind() != Func { panic("reflect: IsVariadic of non-func type") } @@ -573,7 +563,7 @@ func (t *commonType) IsVariadic() bool { return tt.dotdotdot } -func (t *commonType) Elem() Type { +func (t *rtype) Elem() Type { switch t.Kind() { case Array: tt := (*arrayType)(unsafe.Pointer(t)) @@ -594,7 +584,7 @@ func (t *commonType) Elem() Type { panic("reflect: Elem of invalid type") } -func (t *commonType) Field(i int) StructField { +func (t *rtype) Field(i int) StructField { if t.Kind() != Struct { panic("reflect: Field of non-struct type") } @@ -602,7 +592,7 @@ func (t *commonType) Field(i int) StructField { return tt.Field(i) } -func (t *commonType) FieldByIndex(index []int) StructField { +func (t *rtype) FieldByIndex(index []int) StructField { if t.Kind() != Struct { panic("reflect: FieldByIndex of non-struct type") } @@ -610,7 +600,7 @@ func (t *commonType) FieldByIndex(index []int) StructField { return tt.FieldByIndex(index) } -func (t *commonType) FieldByName(name string) (StructField, bool) { +func (t *rtype) FieldByName(name string) (StructField, bool) { if t.Kind() != Struct { panic("reflect: FieldByName of non-struct type") } @@ -618,7 +608,7 @@ func (t *commonType) FieldByName(name string) (StructField, bool) { return tt.FieldByName(name) } -func (t *commonType) FieldByNameFunc(match func(string) bool) (StructField, bool) { +func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) { if t.Kind() != Struct { panic("reflect: FieldByNameFunc of non-struct type") } @@ -626,7 +616,7 @@ func (t *commonType) FieldByNameFunc(match func(string) bool) (StructField, bool return tt.FieldByNameFunc(match) } -func (t *commonType) In(i int) Type { +func (t *rtype) In(i int) Type { if t.Kind() != Func { panic("reflect: In of non-func type") } @@ -634,7 +624,7 @@ func (t *commonType) In(i int) Type { return toType(tt.in[i]) } -func (t *commonType) Key() Type { +func (t *rtype) Key() Type { if t.Kind() != Map { panic("reflect: Key of non-map type") } @@ -642,7 +632,7 @@ func (t *commonType) Key() Type { return toType(tt.key) } -func (t *commonType) Len() int { +func (t *rtype) Len() int { if t.Kind() != Array { panic("reflect: Len of non-array type") } @@ -650,7 +640,7 @@ func (t *commonType) Len() int { return int(tt.len) } -func (t *commonType) NumField() int { +func (t *rtype) NumField() int { if t.Kind() != Struct { panic("reflect: NumField of non-struct type") } @@ -658,7 +648,7 @@ func (t *commonType) NumField() int { return len(tt.fields) } -func (t *commonType) NumIn() int { +func (t *rtype) NumIn() int { if t.Kind() != Func { panic("reflect: NumIn of non-func type") } @@ -666,7 +656,7 @@ func (t *commonType) NumIn() int { return len(tt.in) } -func (t *commonType) NumOut() int { +func (t *rtype) NumOut() int { if t.Kind() != Func { panic("reflect: NumOut of non-func type") } @@ -674,7 +664,7 @@ func (t *commonType) NumOut() int { return len(tt.out) } -func (t *commonType) Out(i int) Type { +func (t *rtype) Out(i int) Type { if t.Kind() != Func { panic("reflect: Out of non-func type") } @@ -844,7 +834,7 @@ func (t *structType) Field(i int) (f StructField) { // FieldByIndex returns the nested field corresponding to index. func (t *structType) FieldByIndex(index []int) (f StructField) { - f.Type = Type(t.toType()) + f.Type = toType(&t.rtype) for i, x := range index { if i > 0 { ft := f.Type @@ -915,13 +905,13 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel f := &t.fields[i] // Find name and type for field f. var fname string - var ntyp *commonType + var ntyp *rtype if f.name != nil { fname = *f.name } else { // Anonymous field of type T or *T. // Name taken from type. - ntyp = toCommonType(f.typ) + ntyp = f.typ if ntyp.Kind() == Ptr { ntyp = ntyp.Elem().common() } @@ -945,19 +935,23 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel // Queue embedded struct fields for processing with next level, // but only if we haven't seen a match yet at this level and only - // if the embedded types haven't alredy been queued. + // if the embedded types haven't already been queued. if ok || ntyp == nil || ntyp.Kind() != Struct { continue } + ntyp = toType(ntyp).common() styp := (*structType)(unsafe.Pointer(ntyp)) if nextCount[styp] > 0 { - nextCount[styp]++ + nextCount[styp] = 2 // exact multiple doesn't matter continue } if nextCount == nil { nextCount = map[*structType]int{} } nextCount[styp] = 1 + if count[t] > 1 { + nextCount[styp] = 2 // exact multiple doesn't matter + } var index []int index = append(index, scan.index...) index = append(index, i) @@ -994,53 +988,6 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) { return t.FieldByNameFunc(func(s string) bool { return s == name }) } -// Convert runtime type to reflect type. -func toCommonType(p *runtimeType) *commonType { - if p == nil { - return nil - } - return (*commonType)(unsafe.Pointer(p)) -} - -// Canonicalize a Type. -var canonicalType = make(map[string]Type) - -var canonicalTypeLock sync.RWMutex - -func canonicalize(t Type) Type { - if t == nil { - return nil - } - u := t.uncommon() - var s string - if u == nil || u.PkgPath() == "" { - s = t.rawString() - } else { - s = u.PkgPath() + "." + u.Name() - } - canonicalTypeLock.RLock() - if r, ok := canonicalType[s]; ok { - canonicalTypeLock.RUnlock() - return r - } - canonicalTypeLock.RUnlock() - canonicalTypeLock.Lock() - if r, ok := canonicalType[s]; ok { - canonicalTypeLock.Unlock() - return r - } - canonicalType[s] = t - canonicalTypeLock.Unlock() - return t -} - -func toType(p *runtimeType) Type { - if p == nil { - return nil - } - return (*commonType)(unsafe.Pointer(p)) -} - // TypeOf returns the reflection Type of the value in the interface{}. // TypeOf(nil) returns nil. func TypeOf(i interface{}) Type { @@ -1051,22 +998,18 @@ func TypeOf(i interface{}) Type { // ptrMap is the cache for PtrTo. var ptrMap struct { sync.RWMutex - m map[*commonType]*ptrType -} - -func (t *commonType) runtimeType() *runtimeType { - return (*runtimeType)(unsafe.Pointer(t)) + m map[*rtype]*ptrType } // PtrTo returns the pointer type with element t. // For example, if t represents type Foo, PtrTo(t) represents *Foo. func PtrTo(t Type) Type { - return t.(*commonType).ptrTo() + return t.(*rtype).ptrTo() } -func (ct *commonType) ptrTo() *commonType { - if p := ct.ptrToThis; p != nil { - return toCommonType(p) +func (t *rtype) ptrTo() *rtype { + if p := t.ptrToThis; p != nil { + return p } // Otherwise, synthesize one. @@ -1076,39 +1019,39 @@ func (ct *commonType) ptrTo() *commonType { // the type structures in read-only memory. ptrMap.RLock() if m := ptrMap.m; m != nil { - if p := m[ct]; p != nil { + if p := m[t]; p != nil { ptrMap.RUnlock() - return &p.commonType + return &p.rtype } } ptrMap.RUnlock() ptrMap.Lock() if ptrMap.m == nil { - ptrMap.m = make(map[*commonType]*ptrType) + ptrMap.m = make(map[*rtype]*ptrType) } - p := ptrMap.m[ct] + p := ptrMap.m[t] if p != nil { // some other goroutine won the race and created it ptrMap.Unlock() - return &p.commonType + return &p.rtype } - s := "*" + *ct.string + s := "*" + *t.string canonicalTypeLock.RLock() r, ok := canonicalType[s] canonicalTypeLock.RUnlock() if ok { - ptrMap.m[ct] = (*ptrType)(unsafe.Pointer(r.(*commonType))) + ptrMap.m[t] = (*ptrType)(unsafe.Pointer(r.(*rtype))) ptrMap.Unlock() - return r.(*commonType) + return r.(*rtype) } // initialize p using *byte's ptrType as a prototype. p = new(ptrType) - var ibyte interface{} = (*byte)(nil) - bp := (*ptrType)(unsafe.Pointer(*(**runtimeType)(unsafe.Pointer(&ibyte)))) - *p = *bp + var iptr interface{} = (*unsafe.Pointer)(nil) + prototype := *(**ptrType)(unsafe.Pointer(&iptr)) + *p = *prototype p.string = &s @@ -1117,50 +1060,58 @@ func (ct *commonType) ptrTo() *commonType { // Create a good hash for the new string by using // the FNV-1 hash's mixing function to combine the // old hash and the new "*". - // p.hash = ct.hash*16777619 ^ '*' + // p.hash = fnv1(t.hash, '*') // This is the gccgo version. - p.hash = (ct.hash << 4) + 9 + p.hash = (t.hash << 4) + 9 p.uncommonType = nil p.ptrToThis = nil - p.elem = (*runtimeType)(unsafe.Pointer(ct)) + p.elem = t - q := canonicalize(&p.commonType) - p = (*ptrType)(unsafe.Pointer(q.(*commonType))) + q := canonicalize(&p.rtype) + p = (*ptrType)(unsafe.Pointer(q.(*rtype))) - ptrMap.m[ct] = p + ptrMap.m[t] = p ptrMap.Unlock() - return &p.commonType + return &p.rtype } -func (t *commonType) Implements(u Type) bool { +// fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function. +func fnv1(x uint32, list ...byte) uint32 { + for _, b := range list { + x = x*16777619 ^ uint32(b) + } + return x +} + +func (t *rtype) Implements(u Type) bool { if u == nil { panic("reflect: nil type passed to Type.Implements") } if u.Kind() != Interface { panic("reflect: non-interface type passed to Type.Implements") } - return implements(u.(*commonType), t) + return implements(u.(*rtype), t) } -func (t *commonType) AssignableTo(u Type) bool { +func (t *rtype) AssignableTo(u Type) bool { if u == nil { panic("reflect: nil type passed to Type.AssignableTo") } - uu := u.(*commonType) + uu := u.(*rtype) return directlyAssignable(uu, t) || implements(uu, t) } -func (t *commonType) ConvertibleTo(u Type) bool { +func (t *rtype) ConvertibleTo(u Type) bool { if u == nil { panic("reflect: nil type passed to Type.ConvertibleTo") } - uu := u.(*commonType) + uu := u.(*rtype) return convertOp(uu, t) != nil } // implements returns true if the type V implements the interface type T. -func implements(T, V *commonType) bool { +func implements(T, V *rtype) bool { if T.Kind() != Interface { return false } @@ -1218,7 +1169,7 @@ func implements(T, V *commonType) bool { // http://golang.org/doc/go_spec.html#Assignability // Ignoring the interface rules (implemented elsewhere) // and the ideal constant rules (no ideal constants at run time). -func directlyAssignable(T, V *commonType) bool { +func directlyAssignable(T, V *rtype) bool { // x's type V is identical to T? if T == V { return true @@ -1234,7 +1185,7 @@ func directlyAssignable(T, V *commonType) bool { return haveIdenticalUnderlyingType(T, V) } -func haveIdenticalUnderlyingType(T, V *commonType) bool { +func haveIdenticalUnderlyingType(T, V *rtype) bool { if T == V { return true } @@ -1330,3 +1281,286 @@ func haveIdenticalUnderlyingType(T, V *commonType) bool { return false } + +// The lookupCache caches ChanOf, MapOf, and SliceOf lookups. +var lookupCache struct { + sync.RWMutex + m map[cacheKey]*rtype +} + +// A cacheKey is the key for use in the lookupCache. +// Four values describe any of the types we are looking for: +// type kind, one or two subtypes, and an extra integer. +type cacheKey struct { + kind Kind + t1 *rtype + t2 *rtype + extra uintptr +} + +// cacheGet looks for a type under the key k in the lookupCache. +// If it finds one, it returns that type. +// If not, it returns nil with the cache locked. +// The caller is expected to use cachePut to unlock the cache. +func cacheGet(k cacheKey) Type { + lookupCache.RLock() + t := lookupCache.m[k] + lookupCache.RUnlock() + if t != nil { + return t + } + + lookupCache.Lock() + t = lookupCache.m[k] + if t != nil { + lookupCache.Unlock() + return t + } + + if lookupCache.m == nil { + lookupCache.m = make(map[cacheKey]*rtype) + } + + return nil +} + +// cachePut stores the given type in the cache, unlocks the cache, +// and returns the type. It is expected that the cache is locked +// because cacheGet returned nil. +func cachePut(k cacheKey, t *rtype) Type { + t = toType(t).common() + lookupCache.m[k] = t + lookupCache.Unlock() + return t +} + +// ChanOf returns the channel type with the given direction and and element type. +// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int. +// +// The gc runtime imposes a limit of 64 kB on channel element types. +// If t's size is equal to or exceeds this limit, ChanOf panics. +func ChanOf(dir ChanDir, t Type) Type { + typ := t.(*rtype) + + // Look in cache. + ckey := cacheKey{Chan, typ, nil, uintptr(dir)} + if ch := cacheGet(ckey); ch != nil { + return ch + } + + // This restriction is imposed by the gc compiler and the runtime. + if typ.size >= 1<<16 { + lookupCache.Unlock() + panic("reflect.ChanOf: element size too large") + } + + // Look in known types. + // TODO: Precedence when constructing string. + var s string + switch dir { + default: + lookupCache.Unlock() + panic("reflect.ChanOf: invalid dir") + case SendDir: + s = "chan<- " + *typ.string + case RecvDir: + s = "<-chan " + *typ.string + case BothDir: + s = "chan " + *typ.string + } + + // Make a channel type. + var ichan interface{} = (chan unsafe.Pointer)(nil) + prototype := *(**chanType)(unsafe.Pointer(&ichan)) + ch := new(chanType) + *ch = *prototype + ch.string = &s + + // gccgo uses a different hash. + // ch.hash = fnv1(typ.hash, 'c', byte(dir)) + ch.hash = 0 + if dir&SendDir != 0 { + ch.hash += 1 + } + if dir&RecvDir != 0 { + ch.hash += 2 + } + ch.hash += typ.hash << 2 + ch.hash <<= 3 + ch.hash += 15 + + ch.elem = typ + ch.uncommonType = nil + ch.ptrToThis = nil + + return cachePut(ckey, &ch.rtype) +} + +// MapOf returns the map type with the given key and element types. +// For example, if k represents int and e represents string, +// MapOf(k, e) represents map[int]string. +// +// If the key type is not a valid map key type (that is, if it does +// not implement Go's == operator), MapOf panics. TODO(rsc). +func MapOf(key, elem Type) Type { + ktyp := key.(*rtype) + etyp := elem.(*rtype) + + // TODO: Check for invalid key types. + + // Look in cache. + ckey := cacheKey{Map, ktyp, etyp, 0} + if mt := cacheGet(ckey); mt != nil { + return mt + } + + // Look in known types. + s := "map[" + *ktyp.string + "]" + *etyp.string + + // Make a map type. + var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) + prototype := *(**mapType)(unsafe.Pointer(&imap)) + mt := new(mapType) + *mt = *prototype + mt.string = &s + + // gccgo uses a different hash + // mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash)) + mt.hash = ktyp.hash + etyp.hash + 2 + 14 + + mt.key = ktyp + mt.elem = etyp + mt.uncommonType = nil + mt.ptrToThis = nil + + return cachePut(ckey, &mt.rtype) +} + +// SliceOf returns the slice type with element type t. +// For example, if t represents int, SliceOf(t) represents []int. +func SliceOf(t Type) Type { + typ := t.(*rtype) + + // Look in cache. + ckey := cacheKey{Slice, typ, nil, 0} + if slice := cacheGet(ckey); slice != nil { + return slice + } + + // Look in known types. + s := "[]" + *typ.string + + // Make a slice type. + var islice interface{} = ([]unsafe.Pointer)(nil) + prototype := *(**sliceType)(unsafe.Pointer(&islice)) + slice := new(sliceType) + *slice = *prototype + slice.string = &s + + // gccgo uses a different hash. + // slice.hash = fnv1(typ.hash, '[') + slice.hash = typ.hash + 1 + 13 + + slice.elem = typ + slice.uncommonType = nil + slice.ptrToThis = nil + + return cachePut(ckey, &slice.rtype) +} + +// ArrayOf returns the array type with the given count and element type. +// For example, if t represents int, ArrayOf(5, t) represents [5]int. +// +// If the resulting type would be larger than the available address space, +// ArrayOf panics. +// +// TODO(rsc): Unexported for now. Export once the alg field is set correctly +// for the type. This may require significant work. +func arrayOf(count int, elem Type) Type { + typ := elem.(*rtype) + slice := SliceOf(elem) + + // Look in cache. + ckey := cacheKey{Array, typ, nil, uintptr(count)} + if slice := cacheGet(ckey); slice != nil { + return slice + } + + // Look in known types. + s := "[" + strconv.Itoa(count) + "]" + *typ.string + + // Make an array type. + var iarray interface{} = [1]unsafe.Pointer{} + prototype := *(**arrayType)(unsafe.Pointer(&iarray)) + array := new(arrayType) + *array = *prototype + array.string = &s + + // gccgo uses a different hash. + // array.hash = fnv1(typ.hash, '[') + // for n := uint32(count); n > 0; n >>= 8 { + // array.hash = fnv1(array.hash, byte(n)) + // } + // array.hash = fnv1(array.hash, ']') + array.hash = typ.hash + 1 + 13 + + array.elem = typ + max := ^uintptr(0) / typ.size + if uintptr(count) > max { + panic("reflect.ArrayOf: array size would exceed virtual address space") + } + array.size = typ.size * uintptr(count) + array.align = typ.align + array.fieldAlign = typ.fieldAlign + // TODO: array.alg + // TODO: array.gc + array.uncommonType = nil + array.ptrToThis = nil + array.len = uintptr(count) + array.slice = slice.(*rtype) + + return cachePut(ckey, &array.rtype) +} + +// toType converts from a *rtype to a Type that can be returned +// to the client of package reflect. In gc, the only concern is that +// a nil *rtype must be replaced by a nil Type, but in gccgo this +// function takes care of ensuring that multiple *rtype for the same +// type are coalesced into a single Type. +var canonicalType = make(map[string]Type) + +var canonicalTypeLock sync.RWMutex + +func canonicalize(t Type) Type { + if t == nil { + return nil + } + u := t.uncommon() + var s string + if u == nil || u.PkgPath() == "" { + s = t.rawString() + } else { + s = u.PkgPath() + "." + u.Name() + } + canonicalTypeLock.RLock() + if r, ok := canonicalType[s]; ok { + canonicalTypeLock.RUnlock() + return r + } + canonicalTypeLock.RUnlock() + canonicalTypeLock.Lock() + if r, ok := canonicalType[s]; ok { + canonicalTypeLock.Unlock() + return r + } + canonicalType[s] = t + canonicalTypeLock.Unlock() + return t +} + +func toType(p *rtype) Type { + if p == nil { + return nil + } + return canonicalize(p) +} diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 4e55741..442f1c4 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -60,7 +60,7 @@ func memmove(adst, asrc unsafe.Pointer, n uintptr) { // direct operations. type Value struct { // typ holds the type of the value represented by a Value. - typ *commonType + typ *rtype // val holds the 1-word representation of the value. // If flag's flagIndir bit is set, then val is a pointer to the data. @@ -211,7 +211,7 @@ func storeIword(p unsafe.Pointer, w iword, n uintptr) { // emptyInterface is the header for an interface{} value. type emptyInterface struct { - typ *runtimeType + typ *rtype word iword } @@ -219,7 +219,7 @@ type emptyInterface struct { type nonEmptyInterface struct { // see ../runtime/iface.c:/Itab itab *struct { - typ *runtimeType // dynamic concrete type + typ *rtype // dynamic concrete type fun [100000]unsafe.Pointer // method table } word iword @@ -372,7 +372,7 @@ func (v Value) call(method string, in []Value) []Value { if m.pkgPath != nil { panic(method + " of unexported method") } - t = toCommonType(m.typ) + t = m.typ iface := (*nonEmptyInterface)(v.val) if iface.itab == nil { panic(method + " of method on nil interface value") @@ -389,7 +389,7 @@ func (v Value) call(method string, in []Value) []Value { panic(method + " of unexported method") } fn = m.tfn - t = toCommonType(m.mtyp) + t = m.mtyp rcvr = v.iword() } } else if v.flag&flagIndir != 0 { @@ -474,7 +474,7 @@ func (v Value) call(method string, in []Value) []Value { first_pointer := false for i, pv := range in { pv.mustBeExported() - targ := t.In(i).(*commonType) + targ := t.In(i).(*rtype) pv = pv.assignTo("reflect.Value.Call", targ, nil) if pv.flag&flagIndir == 0 { p := new(unsafe.Pointer) @@ -517,7 +517,7 @@ func (v Value) call(method string, in []Value) []Value { // gccgo specific test to see if typ is a method. We can tell by // looking at the string to see if there is a receiver. We need this // because for gccgo all methods take pointer receivers. -func isMethod(t *commonType) bool { +func isMethod(t *rtype) bool { if Kind(t.kind) != Func { return false } @@ -553,7 +553,7 @@ func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer) off := uintptr(0) in := make([]Value, 0, len(ftyp.in)) for _, arg := range ftyp.in { - typ := toCommonType(arg) + typ := arg off += -off & uintptr(typ.align-1) v := Value{typ, nil, flag(typ.Kind()) << flagKindShift} if typ.size <= ptrSize { @@ -582,7 +582,7 @@ func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer) if len(ftyp.out) > 0 { off += -off & (ptrSize - 1) for i, arg := range ftyp.out { - typ := toCommonType(arg) + typ := arg v := out[i] if v.typ != typ { panic("reflect: function created by MakeFunc using " + funcName(f) + @@ -665,7 +665,7 @@ func (v Value) Elem() Value { switch k { case Interface: var ( - typ *commonType + typ *rtype val unsafe.Pointer ) if v.typ.NumMethod() == 0 { @@ -674,7 +674,7 @@ func (v Value) Elem() Value { // nil interface value return Value{} } - typ = toCommonType(eface.typ) + typ = eface.typ val = unsafe.Pointer(eface.word) } else { iface := (*nonEmptyInterface)(v.val) @@ -682,7 +682,7 @@ func (v Value) Elem() Value { // nil interface value return Value{} } - typ = toCommonType(iface.itab.typ) + typ = iface.itab.typ val = unsafe.Pointer(iface.word) } fl := v.flag & flagRO @@ -702,7 +702,7 @@ func (v Value) Elem() Value { return Value{} } tt := (*ptrType)(unsafe.Pointer(v.typ)) - typ := toCommonType(tt.elem) + typ := tt.elem fl := v.flag&flagRO | flagIndir | flagAddr fl |= flag(typ.Kind() << flagKindShift) return Value{typ, val, fl} @@ -719,7 +719,7 @@ func (v Value) Field(i int) Value { panic("reflect: Field index out of range") } field := &tt.fields[i] - typ := toCommonType(field.typ) + typ := field.typ // Inherit permission bits from v. fl := v.flag & (flagRO | flagIndir | flagAddr) @@ -802,8 +802,10 @@ func (v Value) Float() float64 { panic(&ValueError{"reflect.Value.Float", k}) } +var uint8Type = TypeOf(uint8(0)).(*rtype) + // Index returns v's i'th element. -// It panics if v's Kind is not Array or Slice or i is out of range. +// It panics if v's Kind is not Array, Slice, or String or i is out of range. func (v Value) Index(i int) Value { k := v.kind() switch k { @@ -812,7 +814,7 @@ func (v Value) Index(i int) Value { if i < 0 || i > int(tt.len) { panic("reflect: array index out of range") } - typ := toCommonType(tt.elem) + typ := tt.elem fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array fl |= flag(typ.Kind()) << flagKindShift offset := uintptr(i) * typ.size @@ -840,10 +842,19 @@ func (v Value) Index(i int) Value { panic("reflect: slice index out of range") } tt := (*sliceType)(unsafe.Pointer(v.typ)) - typ := toCommonType(tt.elem) + typ := tt.elem fl |= flag(typ.Kind()) << flagKindShift val := unsafe.Pointer(s.Data + uintptr(i)*typ.size) return Value{typ, val, fl} + + case String: + fl := v.flag&flagRO | flag(Uint8<<flagKindShift) | flagIndir + s := (*StringHeader)(v.val) + if i < 0 || i >= s.Len { + panic("reflect: string index out of range") + } + val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i))) + return Value{uint8Type, unsafe.Pointer(&val), fl} } panic(&ValueError{"reflect.Value.Index", k}) } @@ -925,7 +936,7 @@ func valueInterface(v Value, safe bool) interface{} { // Non-interface value. var eface emptyInterface - eface.typ = v.typ.runtimeType() + eface.typ = toType(v.typ).common() eface.word = v.iword() if v.flag&flagIndir != 0 && v.kind() != Ptr && v.kind() != UnsafePointer { @@ -937,6 +948,10 @@ func valueInterface(v Value, safe bool) interface{} { eface.word = iword(ptr) } + if v.flag&flagIndir == 0 && v.kind() != Ptr && v.kind() != UnsafePointer { + panic("missing flagIndir") + } + return *(*interface{})(unsafe.Pointer(&eface)) } @@ -1026,13 +1041,13 @@ func (v Value) MapIndex(key Value) Value { // considered unexported. This is consistent with the // behavior for structs, which allow read but not write // of unexported fields. - key = key.assignTo("reflect.Value.MapIndex", toCommonType(tt.key), nil) + key = key.assignTo("reflect.Value.MapIndex", tt.key, nil) - word, ok := mapaccess(v.typ.runtimeType(), *(*iword)(v.iword()), key.iword()) + word, ok := mapaccess(v.typ, *(*iword)(v.iword()), key.iword()) if !ok { return Value{} } - typ := toCommonType(tt.elem) + typ := tt.elem fl := (v.flag | key.flag) & flagRO if typ.Kind() != Ptr && typ.Kind() != UnsafePointer { fl |= flagIndir @@ -1048,7 +1063,7 @@ func (v Value) MapIndex(key Value) Value { func (v Value) MapKeys() []Value { v.mustBe(Map) tt := (*mapType)(unsafe.Pointer(v.typ)) - keyType := toCommonType(tt.key) + keyType := tt.key fl := v.flag & flagRO fl |= flag(keyType.Kind()) << flagKindShift @@ -1061,7 +1076,7 @@ func (v Value) MapKeys() []Value { if m != nil { mlen = maplen(m) } - it := mapiterinit(v.typ.runtimeType(), m) + it := mapiterinit(v.typ, m) a := make([]Value, mlen) var i int for i = 0; i < len(a); i++ { @@ -1160,7 +1175,7 @@ func overflowFloat32(x float64) bool { if x < 0 { x = -x } - return math.MaxFloat32 <= x && x <= math.MaxFloat64 + return math.MaxFloat32 < x && x <= math.MaxFloat64 } // OverflowInt returns true if the int64 x cannot be represented by v's type. @@ -1230,9 +1245,9 @@ func (v Value) recv(nb bool) (val Value, ok bool) { if ChanDir(tt.dir)&RecvDir == 0 { panic("recv on send-only channel") } - word, selected, ok := chanrecv(v.typ.runtimeType(), *(*iword)(v.iword()), nb) + word, selected, ok := chanrecv(v.typ, *(*iword)(v.iword()), nb) if selected { - typ := toCommonType(tt.elem) + typ := tt.elem fl := flag(typ.Kind()) << flagKindShift if typ.Kind() != Ptr && typ.Kind() != UnsafePointer { fl |= flagIndir @@ -1259,8 +1274,8 @@ func (v Value) send(x Value, nb bool) (selected bool) { panic("send on recv-only channel") } x.mustBeExported() - x = x.assignTo("reflect.Value.Send", toCommonType(tt.elem), nil) - return chansend(v.typ.runtimeType(), *(*iword)(v.iword()), x.iword(), nb) + x = x.assignTo("reflect.Value.Send", tt.elem, nil) + return chansend(v.typ, *(*iword)(v.iword()), x.iword(), nb) } // Set assigns x to the value v. @@ -1382,12 +1397,12 @@ func (v Value) SetMapIndex(key, val Value) { v.mustBeExported() key.mustBeExported() tt := (*mapType)(unsafe.Pointer(v.typ)) - key = key.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.key), nil) + key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil) if val.typ != nil { val.mustBeExported() - val = val.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.elem), nil) + val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil) } - mapassign(v.typ.runtimeType(), *(*iword)(v.iword()), key.iword(), val.iword(), val.typ != nil) + mapassign(v.typ, *(*iword)(v.iword()), key.iword(), val.iword(), val.typ != nil) } // SetUint sets v's underlying value to x. @@ -1429,7 +1444,7 @@ func (v Value) SetString(x string) { } // Slice returns a slice of v. -// It panics if v's Kind is not Array or Slice. +// It panics if v's Kind is not Array, Slice, or String. func (v Value) Slice(beg, end int) Value { var ( cap int @@ -1439,21 +1454,34 @@ func (v Value) Slice(beg, end int) Value { switch k := v.kind(); k { default: panic(&ValueError{"reflect.Value.Slice", k}) + case Array: if v.flag&flagAddr == 0 { panic("reflect.Value.Slice: slice of unaddressable array") } tt := (*arrayType)(unsafe.Pointer(v.typ)) cap = int(tt.len) - typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice))) + typ = (*sliceType)(unsafe.Pointer(tt.slice)) base = v.val + case Slice: typ = (*sliceType)(unsafe.Pointer(v.typ)) s := (*SliceHeader)(v.val) base = unsafe.Pointer(s.Data) cap = s.Cap + case String: + s := (*StringHeader)(v.val) + if beg < 0 || end < beg || end > s.Len { + panic("reflect.Value.Slice: string slice index out of bounds") + } + var x string + val := (*StringHeader)(unsafe.Pointer(&x)) + val.Data = s.Data + uintptr(beg) + val.Len = end - beg + return Value{v.typ, unsafe.Pointer(&x), v.flag} } + if beg < 0 || end < beg || end > cap { panic("reflect.Value.Slice: slice index out of bounds") } @@ -1463,7 +1491,7 @@ func (v Value) Slice(beg, end int) Value { // Reinterpret as *SliceHeader to edit. s := (*SliceHeader)(unsafe.Pointer(&x)) - s.Data = uintptr(base) + uintptr(beg)*toCommonType(typ.elem).Size() + s.Data = uintptr(base) + uintptr(beg)*typ.elem.Size() s.Len = end - beg s.Cap = cap - beg @@ -1516,7 +1544,7 @@ func (v Value) Type() Type { } if f&flagMethod == 0 { // Easy case - return v.typ.toType() + return toType(v.typ) } // Method value. @@ -1529,7 +1557,7 @@ func (v Value) Type() Type { panic("reflect: broken Value") } m := &tt.methods[i] - return toCommonType(m.typ).toType() + return toType(m.typ) } // Method on concrete type. ut := v.typ.uncommon() @@ -1537,7 +1565,7 @@ func (v Value) Type() Type { panic("reflect: broken Value") } m := &ut.methods[i] - return toCommonType(m.mtyp).toType() + return toType(m.mtyp) } // Uint returns v's underlying value, as a uint64. @@ -1711,10 +1739,10 @@ func Copy(dst, src Value) int { // A runtimeSelect is a single case passed to rselect. // This must match ../runtime/chan.c:/runtimeSelect type runtimeSelect struct { - dir uintptr // 0, SendDir, or RecvDir - typ *runtimeType // channel type - ch iword // interface word for channel - val iword // interface word for value (for SendDir) + dir uintptr // 0, SendDir, or RecvDir + typ *rtype // channel type + ch iword // interface word for channel + val iword // interface word for value (for SendDir) } // rselect runs a select. It returns the index of the chosen case, @@ -1801,13 +1829,13 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { panic("reflect.Select: SendDir case using recv-only channel") } rc.ch = *(*iword)(ch.iword()) - rc.typ = tt.runtimeType() + rc.typ = &tt.rtype v := c.Send if !v.IsValid() { panic("reflect.Select: SendDir case missing Send value") } v.mustBeExported() - v = v.assignTo("reflect.Select", toCommonType(tt.elem), nil) + v = v.assignTo("reflect.Select", tt.elem, nil) rc.val = v.iword() case SelectRecv: @@ -1821,7 +1849,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { ch.mustBe(Chan) ch.mustBeExported() tt := (*chanType)(unsafe.Pointer(ch.typ)) - rc.typ = tt.runtimeType() + rc.typ = &tt.rtype if ChanDir(tt.dir)&RecvDir == 0 { panic("reflect.Select: RecvDir case using send-only channel") } @@ -1831,8 +1859,8 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { chosen, word, recvOK := rselect(runcases) if runcases[chosen].dir == uintptr(SelectRecv) { - tt := (*chanType)(unsafe.Pointer(toCommonType(runcases[chosen].typ))) - typ := toCommonType(tt.elem) + tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ)) + typ := tt.elem fl := flag(typ.Kind()) << flagKindShift if typ.Kind() != Ptr && typ.Kind() != UnsafePointer { fl |= flagIndir @@ -1847,8 +1875,8 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { */ // implemented in package runtime -func unsafe_New(Type) unsafe.Pointer -func unsafe_NewArray(Type, int) unsafe.Pointer +func unsafe_New(*rtype) unsafe.Pointer +func unsafe_NewArray(*rtype, int) unsafe.Pointer // MakeSlice creates a new zero-initialized slice value // for the specified slice type, length, and capacity. @@ -1871,7 +1899,7 @@ func MakeSlice(typ Type, len, cap int) Value { // Reinterpret as *SliceHeader to edit. s := (*SliceHeader)(unsafe.Pointer(&x)) - s.Data = uintptr(unsafe_NewArray(typ.Elem(), cap)) + s.Data = uintptr(unsafe_NewArray(typ.Elem().(*rtype), cap)) s.Len = len s.Cap = cap @@ -1889,7 +1917,7 @@ func MakeChan(typ Type, buffer int) Value { if typ.ChanDir() != BothDir { panic("reflect.MakeChan: unidirectional channel type") } - ch := makechan(typ.runtimeType(), uint64(buffer)) + ch := makechan(typ.(*rtype), uint64(buffer)) return Value{typ.common(), unsafe.Pointer(ch), flagIndir | (flag(Chan) << flagKindShift)} } @@ -1898,7 +1926,7 @@ func MakeMap(typ Type) Value { if typ.Kind() != Map { panic("reflect.MakeMap of non-map type") } - m := makemap(typ.runtimeType()) + m := makemap(typ.(*rtype)) return Value{typ.common(), unsafe.Pointer(m), flagIndir | (flag(Map) << flagKindShift)} } @@ -1929,7 +1957,7 @@ func ValueOf(i interface{}) Value { // For an interface value with the noAddr bit set, // the representation is identical to an empty interface. eface := *(*emptyInterface)(unsafe.Pointer(&i)) - typ := toCommonType(eface.typ) + typ := eface.typ fl := flag(typ.Kind()) << flagKindShift if typ.Kind() != Ptr && typ.Kind() != UnsafePointer { fl |= flagIndir @@ -1951,7 +1979,7 @@ func Zero(typ Type) Value { if t.Kind() == Ptr || t.Kind() == UnsafePointer { return Value{t, nil, fl} } - return Value{t, unsafe_New(typ), fl | flagIndir} + return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir} } // New returns a Value representing a pointer to a new zero value @@ -1960,7 +1988,7 @@ func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") } - ptr := unsafe_New(typ) + ptr := unsafe_New(typ.(*rtype)) fl := flag(Ptr) << flagKindShift return Value{typ.common().ptrTo(), ptr, fl} } @@ -1975,7 +2003,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value { // assignTo returns a value v that can be assigned directly to typ. // It panics if v is not assignable to typ. // For a conversion to an interface type, target is a suggested scratch space to use. -func (v Value) assignTo(context string, dst *commonType, target *interface{}) Value { +func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value { if v.flag&flagMethod != 0 { panic(context + ": cannot assign method value to type " + dst.String()) } @@ -1997,7 +2025,7 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va if dst.NumMethod() == 0 { *target = x } else { - ifaceE2I(dst.runtimeType(), x, unsafe.Pointer(target)) + ifaceE2I(dst, x, unsafe.Pointer(target)) } return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift} } @@ -2022,7 +2050,7 @@ func (v Value) Convert(t Type) Value { // convertOp returns the function to convert a value of type src // to a value of type dst. If the conversion is illegal, convertOp returns nil. -func convertOp(dst, src *commonType) func(Value, Type) Value { +func convertOp(dst, src *rtype) func(Value, Type) Value { switch src.Kind() { case Int, Int8, Int16, Int32, Int64: switch dst.Kind() { @@ -2109,9 +2137,9 @@ func makeInt(f flag, bits uint64, t Type) Value { typ := t.common() if typ.size > ptrSize { // Assume ptrSize >= 4, so this must be uint64. - ptr := unsafe_New(t) + ptr := unsafe_New(typ) *(*uint64)(unsafe.Pointer(ptr)) = bits - return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift} + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift} } var w iword switch typ.size { @@ -2133,9 +2161,9 @@ func makeFloat(f flag, v float64, t Type) Value { typ := t.common() if typ.size > ptrSize { // Assume ptrSize >= 4, so this must be float64. - ptr := unsafe_New(t) + ptr := unsafe_New(typ) *(*float64)(unsafe.Pointer(ptr)) = v - return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift} + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift} } var w iword @@ -2153,14 +2181,14 @@ func makeFloat(f flag, v float64, t Type) Value { func makeComplex(f flag, v complex128, t Type) Value { typ := t.common() if typ.size > ptrSize { - ptr := unsafe_New(t) + ptr := unsafe_New(typ) switch typ.size { case 8: *(*complex64)(unsafe.Pointer(ptr)) = complex64(v) case 16: *(*complex128)(unsafe.Pointer(ptr)) = v } - return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift} + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift} } // Assume ptrSize <= 8 so this must be complex64. @@ -2172,21 +2200,21 @@ func makeComplex(f flag, v complex128, t Type) Value { func makeString(f flag, v string, t Type) Value { ret := New(t).Elem() ret.SetString(v) - ret.flag = ret.flag&^flagAddr | f + ret.flag = ret.flag&^flagAddr | f | flagIndir return ret } func makeBytes(f flag, v []byte, t Type) Value { ret := New(t).Elem() ret.SetBytes(v) - ret.flag = ret.flag&^flagAddr | f + ret.flag = ret.flag&^flagAddr | f | flagIndir return ret } func makeRunes(f flag, v []rune, t Type) Value { ret := New(t).Elem() ret.setRunes(v) - ret.flag = ret.flag&^flagAddr | f + ret.flag = ret.flag&^flagAddr | f | flagIndir return ret } @@ -2287,7 +2315,7 @@ func cvtT2I(v Value, typ Type) Value { if typ.NumMethod() == 0 { *target = x } else { - ifaceE2I(typ.runtimeType(), x, unsafe.Pointer(target)) + ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target)) } return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift} } @@ -2306,20 +2334,20 @@ func cvtI2I(v Value, typ Type) Value { func chancap(ch iword) int func chanclose(ch iword) func chanlen(ch iword) int -func chanrecv(t *runtimeType, ch iword, nb bool) (val iword, selected, received bool) -func chansend(t *runtimeType, ch iword, val iword, nb bool) bool - -func makechan(typ *runtimeType, size uint64) (ch iword) -func makemap(t *runtimeType) (m iword) -func mapaccess(t *runtimeType, m iword, key iword) (val iword, ok bool) -func mapassign(t *runtimeType, m iword, key, val iword, ok bool) -func mapiterinit(t *runtimeType, m iword) *byte +func chanrecv(t *rtype, ch iword, nb bool) (val iword, selected, received bool) +func chansend(t *rtype, ch iword, val iword, nb bool) bool + +func makechan(typ *rtype, size uint64) (ch iword) +func makemap(t *rtype) (m iword) +func mapaccess(t *rtype, m iword, key iword) (val iword, ok bool) +func mapassign(t *rtype, m iword, key, val iword, ok bool) +func mapiterinit(t *rtype, m iword) *byte func mapiterkey(it *byte) (key iword, ok bool) func mapiternext(it *byte) func maplen(m iword) int -func call(typ *commonType, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer) -func ifaceE2I(t *runtimeType, src interface{}, dst unsafe.Pointer) +func call(typ *rtype, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer) +func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) // Dummy annotation marking that the value x escapes, // for use in cases where the reflect code is so clever that |