From 8925290cf701fc8f7ec95e4df3d6a8d423b26780 Mon Sep 17 00:00:00 2001
From: Keith Randall "use of closed network connection".
+ For interface types and values, Method, + MethodByName, and + NumMethod now + operate on the interface's exported method set, rather than its full method set. +
4294967295.
-- For interface types and values, Method, - MethodByName, and - NumMethod now - operate on the interface's exported method set, rather than its full method set. -
-
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 229fcfeaee..21429af782 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -1275,9 +1275,8 @@ func dtypesym(t *types.Type) *obj.LSym {
}
ot = dgopkgpath(lsym, ot, tpkg)
- xcount := sort.Search(n, func(i int) bool { return !types.IsExported(m[i].name.Name) })
ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
- ot = duintptr(lsym, ot, uint64(xcount))
+ ot = duintptr(lsym, ot, uint64(n))
ot = duintptr(lsym, ot, uint64(n))
dataAdd := imethodSize() * n
ot = dextratype(lsym, ot, t, dataAdd)
diff --git a/src/internal/reflectlite/type.go b/src/internal/reflectlite/type.go
index 37cf03594f..15ba30da36 100644
--- a/src/internal/reflectlite/type.go
+++ b/src/internal/reflectlite/type.go
@@ -234,13 +234,10 @@ type imethod struct {
// interfaceType represents an interface type.
type interfaceType struct {
rtype
- pkgPath name // import path
- expMethods []imethod // sorted by name, see runtime/type.go:interfacetype to see how it is encoded.
+ pkgPath name // import path
+ methods []imethod // sorted by hash
}
-func (t *interfaceType) methods() []imethod { return t.expMethods[:cap(t.expMethods)] }
-func (t *interfaceType) isEmpty() bool { return cap(t.expMethods) == 0 }
-
// mapType represents a map type.
type mapType struct {
rtype
@@ -698,7 +695,7 @@ func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
}
// NumMethod returns the number of interface methods in the type's method set.
-func (t *interfaceType) NumMethod() int { return len(t.expMethods) }
+func (t *interfaceType) NumMethod() int { return len(t.methods) }
// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
@@ -735,10 +732,9 @@ func implements(T, V *rtype) bool {
return false
}
t := (*interfaceType)(unsafe.Pointer(T))
- if t.isEmpty() {
+ if len(t.methods) == 0 {
return true
}
- tmethods := t.methods()
// The same algorithm applies in both cases, but the
// method tables for an interface type and a concrete type
@@ -755,11 +751,10 @@ func implements(T, V *rtype) bool {
if V.Kind() == Interface {
v := (*interfaceType)(unsafe.Pointer(V))
i := 0
- vmethods := v.methods()
- for j := 0; j < len(vmethods); j++ {
- tm := &tmethods[i]
+ for j := 0; j < len(v.methods); j++ {
+ tm := &t.methods[i]
tmName := t.nameOff(tm.name)
- vm := &vmethods[j]
+ vm := &v.methods[j]
vmName := V.nameOff(vm.name)
if vmName.name() == tmName.name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
if !tmName.isExported() {
@@ -775,7 +770,7 @@ func implements(T, V *rtype) bool {
continue
}
}
- if i++; i >= len(tmethods) {
+ if i++; i >= len(t.methods) {
return true
}
}
@@ -790,7 +785,7 @@ func implements(T, V *rtype) bool {
i := 0
vmethods := v.methods()
for j := 0; j < int(v.mcount); j++ {
- tm := &tmethods[i]
+ tm := &t.methods[i]
tmName := t.nameOff(tm.name)
vm := vmethods[j]
vmName := V.nameOff(vm.name)
@@ -808,7 +803,7 @@ func implements(T, V *rtype) bool {
continue
}
}
- if i++; i >= len(tmethods) {
+ if i++; i >= len(t.methods) {
return true
}
}
@@ -902,7 +897,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
case Interface:
t := (*interfaceType)(unsafe.Pointer(T))
v := (*interfaceType)(unsafe.Pointer(V))
- if t.isEmpty() && v.isEmpty() {
+ if len(t.methods) == 0 && len(v.methods) == 0 {
return true
}
// Might have the same methods but still
@@ -967,11 +962,3 @@ func toType(t *rtype) Type {
func ifaceIndir(t *rtype) bool {
return t.kind&kindDirectIface == 0
}
-
-func isEmptyIface(t *rtype) bool {
- if t.Kind() != Interface {
- return false
- }
- tt := (*interfaceType)(unsafe.Pointer(t))
- return tt.isEmpty()
-}
diff --git a/src/internal/reflectlite/value.go b/src/internal/reflectlite/value.go
index fb0ec77b58..0365eeeabf 100644
--- a/src/internal/reflectlite/value.go
+++ b/src/internal/reflectlite/value.go
@@ -228,7 +228,7 @@ func (v Value) Elem() Value {
switch k {
case Interface:
var eface interface{}
- if isEmptyIface(v.typ) {
+ if v.typ.NumMethod() == 0 {
eface = *(*interface{})(v.ptr)
} else {
eface = (interface{})(*(*interface {
@@ -433,7 +433,7 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
return Value{dst, nil, flag(Interface)}
}
x := valueInterface(v)
- if isEmptyIface(dst) {
+ if dst.NumMethod() == 0 {
*(*interface{})(target) = x
} else {
ifaceE2I(dst, x, target)
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index be15362aae..a12712d254 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -2995,14 +2995,6 @@ func TestUnexportedMethods(t *testing.T) {
if got := typ.NumMethod(); got != 0 {
t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
}
-
- var i unexpI
- if got := TypeOf(&i).Elem().NumMethod(); got != 0 {
- t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
- }
- if got := ValueOf(&i).Elem().NumMethod(); got != 0 {
- t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
- }
}
type InnerInt struct {
@@ -3656,21 +3648,21 @@ func TestCallPanic(t *testing.T) {
v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
badCall(func() { call(v.Field(0).Method(0)) }) // .t0.W
badCall(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
- badMethod(func() { call(v.Field(0).Method(1)) }) // .t0.w
+ badCall(func() { call(v.Field(0).Method(1)) }) // .t0.w
badMethod(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y
ok(func() { call(v.Field(1).Elem().Method(0)) }) // .T1.Y
- badMethod(func() { call(v.Field(1).Method(1)) }) // .T1.y
+ badCall(func() { call(v.Field(1).Method(1)) }) // .T1.y
badMethod(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y
ok(func() { call(v.Field(2).Method(0)) }) // .NamedT0.W
ok(func() { call(v.Field(2).Elem().Method(0)) }) // .NamedT0.W
- badMethod(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w
+ badCall(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w
badMethod(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w
ok(func() { call(v.Field(3).Method(0)) }) // .NamedT1.Y
ok(func() { call(v.Field(3).Elem().Method(0)) }) // .NamedT1.Y
- badMethod(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
+ badCall(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
badMethod(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
@@ -3680,7 +3672,7 @@ func TestCallPanic(t *testing.T) {
badCall(func() { call(v.Field(5).Method(0)) }) // .namedT0.W
badCall(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
- badMethod(func() { call(v.Field(5).Method(1)) }) // .namedT0.w
+ badCall(func() { call(v.Field(5).Method(1)) }) // .namedT0.w
badMethod(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w
badCall(func() { call(v.Field(6).Method(0)) }) // .namedT1.Y
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 0b34ca0c94..a3a616701b 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -386,14 +386,10 @@ type imethod struct {
// interfaceType represents an interface type.
type interfaceType struct {
rtype
- pkgPath name // import path
- expMethods []imethod // sorted by name, see runtime/type.go:interfacetype to see how it is encoded.
+ pkgPath name // import path
+ methods []imethod // sorted by hash
}
-// methods returns t's full method set, both exported and non-exported.
-func (t *interfaceType) methods() []imethod { return t.expMethods[:cap(t.expMethods)] }
-func (t *interfaceType) isEmpty() bool { return cap(t.expMethods) == 0 }
-
// mapType represents a map type.
type mapType struct {
rtype
@@ -1053,22 +1049,25 @@ func (d ChanDir) String() string {
// Method returns the i'th method in the type's method set.
func (t *interfaceType) Method(i int) (m Method) {
- if i < 0 || i >= len(t.expMethods) {
- panic("reflect: Method index out of range")
+ if i < 0 || i >= len(t.methods) {
+ return
}
- p := &t.expMethods[i]
+ p := &t.methods[i]
pname := t.nameOff(p.name)
m.Name = pname.name()
if !pname.isExported() {
- panic("reflect: unexported method: " + pname.name())
+ m.PkgPath = pname.pkgPath()
+ if m.PkgPath == "" {
+ m.PkgPath = t.pkgPath.name()
+ }
}
m.Type = toType(t.typeOff(p.typ))
m.Index = i
return
}
-// NumMethod returns the number of exported interface methods in the type's method set.
-func (t *interfaceType) NumMethod() int { return len(t.expMethods) }
+// NumMethod returns the number of interface methods in the type's method set.
+func (t *interfaceType) NumMethod() int { return len(t.methods) }
// MethodByName method with the given name in the type's method set.
func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
@@ -1076,8 +1075,8 @@ func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
return
}
var p *imethod
- for i := range t.expMethods {
- p = &t.expMethods[i]
+ for i := range t.methods {
+ p = &t.methods[i]
if t.nameOff(p.name).name() == name {
return t.Method(i), true
}
@@ -1486,10 +1485,9 @@ func implements(T, V *rtype) bool {
return false
}
t := (*interfaceType)(unsafe.Pointer(T))
- if t.isEmpty() {
+ if len(t.methods) == 0 {
return true
}
- tmethods := t.methods()
// The same algorithm applies in both cases, but the
// method tables for an interface type and a concrete type
@@ -1506,11 +1504,10 @@ func implements(T, V *rtype) bool {
if V.Kind() == Interface {
v := (*interfaceType)(unsafe.Pointer(V))
i := 0
- vmethods := v.methods()
- for j := 0; j < len(vmethods); j++ {
- tm := &tmethods[i]
+ for j := 0; j < len(v.methods); j++ {
+ tm := &t.methods[i]
tmName := t.nameOff(tm.name)
- vm := &vmethods[j]
+ vm := &v.methods[j]
vmName := V.nameOff(vm.name)
if vmName.name() == tmName.name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
if !tmName.isExported() {
@@ -1526,7 +1523,7 @@ func implements(T, V *rtype) bool {
continue
}
}
- if i++; i >= len(tmethods) {
+ if i++; i >= len(t.methods) {
return true
}
}
@@ -1541,7 +1538,7 @@ func implements(T, V *rtype) bool {
i := 0
vmethods := v.methods()
for j := 0; j < int(v.mcount); j++ {
- tm := &tmethods[i]
+ tm := &t.methods[i]
tmName := t.nameOff(tm.name)
vm := vmethods[j]
vmName := V.nameOff(vm.name)
@@ -1559,7 +1556,7 @@ func implements(T, V *rtype) bool {
continue
}
}
- if i++; i >= len(tmethods) {
+ if i++; i >= len(t.methods) {
return true
}
}
@@ -1661,7 +1658,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
case Interface:
t := (*interfaceType)(unsafe.Pointer(T))
v := (*interfaceType)(unsafe.Pointer(V))
- if t.isEmpty() && v.isEmpty() {
+ if len(t.methods) == 0 && len(v.methods) == 0 {
return true
}
// Might have the same methods but still
@@ -2445,7 +2442,7 @@ func StructOf(fields []StructField) Type {
switch f.typ.Kind() {
case Interface:
ift := (*interfaceType)(unsafe.Pointer(ft))
- for im, m := range ift.methods() {
+ for im, m := range ift.methods {
if ift.nameOff(m.name).pkgPath() != "" {
// TODO(sbinet). Issue 15924.
panic("reflect: embedded interface with unexported method(s) not implemented")
@@ -3152,11 +3149,3 @@ func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
}
}
}
-
-func isEmptyIface(rt *rtype) bool {
- if rt.Kind() != Interface {
- return false
- }
- tt := (*interfaceType)(unsafe.Pointer(rt))
- return len(tt.methods()) == 0
-}
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 24eab6a2c6..bf926a7453 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -636,11 +636,10 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *rtype, t *fu
i := methodIndex
if v.typ.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(v.typ))
- ttmethods := tt.methods()
- if uint(i) >= uint(len(ttmethods)) {
+ if uint(i) >= uint(len(tt.methods)) {
panic("reflect: internal error: invalid method index")
}
- m := &ttmethods[i]
+ m := &tt.methods[i]
if !tt.nameOff(m.name).isExported() {
panic("reflect: " + op + " of unexported method")
}
@@ -814,7 +813,7 @@ func (v Value) Elem() Value {
switch k {
case Interface:
var eface interface{}
- if isEmptyIface(v.typ) {
+ if v.typ.NumMethod() == 0 {
eface = *(*interface{})(v.ptr)
} else {
eface = (interface{})(*(*interface {
@@ -1035,7 +1034,7 @@ func valueInterface(v Value, safe bool) interface{} {
// Special case: return the element inside the interface.
// Empty interface has one layout, all interfaces with
// methods have a second layout.
- if isEmptyIface(v.typ) {
+ if v.NumMethod() == 0 {
return *(*interface{})(v.ptr)
}
return *(*interface {
@@ -1919,11 +1918,10 @@ func (v Value) Type() Type {
if v.typ.Kind() == Interface {
// Method on interface.
tt := (*interfaceType)(unsafe.Pointer(v.typ))
- ttmethods := tt.methods()
- if uint(i) >= uint(len(ttmethods)) {
+ if uint(i) >= uint(len(tt.methods)) {
panic("reflect: internal error: invalid method index")
}
- m := &ttmethods[i]
+ m := &tt.methods[i]
return v.typ.typeOff(m.typ)
}
// Method on concrete type.
@@ -2441,7 +2439,7 @@ func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value
return Value{dst, nil, flag(Interface)}
}
x := valueInterface(v, false)
- if isEmptyIface(dst) {
+ if dst.NumMethod() == 0 {
*(*interface{})(target) = x
} else {
ifaceE2I(dst, x, target)
@@ -2730,11 +2728,10 @@ func cvtDirect(v Value, typ Type) Value {
func cvtT2I(v Value, typ Type) Value {
target := unsafe_New(typ.common())
x := valueInterface(v, false)
- rt := typ.(*rtype)
- if isEmptyIface(rt) {
+ if typ.NumMethod() == 0 {
*(*interface{})(target) = x
} else {
- ifaceE2I(rt, x, target)
+ ifaceE2I(typ.(*rtype), x, target)
}
return Value{typ.common(), target, v.flag.ro() | flagIndir | flag(Interface)}
}
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index 2ec3fc3658..1b3bf1180d 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -166,7 +166,7 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr {
return strhash(p, h)
case kindInterface:
i := (*interfacetype)(unsafe.Pointer(t))
- if i.isEmpty() {
+ if len(i.mhdr) == 0 {
return nilinterhash(p, h)
}
return interhash(p, h)
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index f8b7d429a3..0504b89363 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -31,17 +31,16 @@ func itabHashFunc(inter *interfacetype, typ *_type) uintptr {
}
func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
- if inter.isEmpty() {
+ if len(inter.mhdr) == 0 {
throw("internal error - misuse of itab")
}
- imethods := inter.methods()
// easy case
if typ.tflag&tflagUncommon == 0 {
if canfail {
return nil
}
- name := inter.typ.nameOff(imethods[0].name)
+ name := inter.typ.nameOff(inter.mhdr[0].name)
panic(&TypeAssertionError{nil, typ, &inter.typ, name.name()})
}
@@ -64,7 +63,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
}
// Entry doesn't exist yet. Make a new entry & add it.
- m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(imethods)-1)*sys.PtrSize, 0, &memstats.other_sys))
+ m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))
m.inter = inter
m._type = typ
// The hash is used in type switches. However, compiler statically generates itab's
@@ -198,8 +197,7 @@ func (m *itab) init() string {
// and interface names are unique,
// so can iterate over both in lock step;
// the loop is O(ni+nt) not O(ni*nt).
- imethods := inter.methods()
- ni := len(imethods)
+ ni := len(inter.mhdr)
nt := int(x.mcount)
xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt]
j := 0
@@ -207,7 +205,7 @@ func (m *itab) init() string {
var fun0 unsafe.Pointer
imethods:
for k := 0; k < ni; k++ {
- i := &imethods[k]
+ i := &inter.mhdr[k]
itype := inter.typ.typeOff(i.ityp)
name := inter.typ.nameOff(i.name)
iname := name.name()
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index 6ec5133be0..f4dbd77252 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -210,7 +210,7 @@ func runfinq() {
// set up with empty interface
(*eface)(frame)._type = &f.ot.typ
(*eface)(frame).data = f.arg
- if !ityp.isEmpty() {
+ if len(ityp.mhdr) != 0 {
// convert to interface with methods
// this conversion is guaranteed to succeed - we checked in SetFinalizer
*(*iface)(frame) = assertE2I(ityp, *(*eface)(frame))
@@ -394,7 +394,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
}
case fint.kind&kindMask == kindInterface:
ityp := (*interfacetype)(unsafe.Pointer(fint))
- if ityp.isEmpty() {
+ if len(ityp.mhdr) == 0 {
// ok - satisfies empty interface
goto okarg
}
diff --git a/src/runtime/type.go b/src/runtime/type.go
index 36492619e1..81455f3532 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -366,19 +366,7 @@ type imethod struct {
type interfacetype struct {
typ _type
pkgpath name
- // expMethods contains all interface methods.
- //
- // - len(expMethods) returns number of exported methods.
- // - cap(expMethods) returns all interface methods, including both exported/non-exported methods.
- expMethods []imethod
-}
-
-func (it *interfacetype) methods() []imethod {
- return it.expMethods[:cap(it.expMethods)]
-}
-
-func (it *interfacetype) isEmpty() bool {
- return cap(it.expMethods) == 0
+ mhdr []imethod
}
type maptype struct {
@@ -676,15 +664,13 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
if it.pkgpath.name() != iv.pkgpath.name() {
return false
}
- itmethods := it.methods()
- ivmethods := iv.methods()
- if len(itmethods) != len(ivmethods) {
+ if len(it.mhdr) != len(iv.mhdr) {
return false
}
- for i := range itmethods {
- tm := &itmethods[i]
- vm := &ivmethods[i]
- // Note the expMethods array can be relocated from
+ for i := range it.mhdr {
+ tm := &it.mhdr[i]
+ vm := &iv.mhdr[i]
+ // Note the mhdr array can be relocated from
// another module. See #17724.
tname := resolveNameOff(unsafe.Pointer(tm), tm.name)
vname := resolveNameOff(unsafe.Pointer(vm), vm.name)
--
cgit v1.3
From f0ff6d4a67ec9a956aa655d487543da034cf576b Mon Sep 17 00:00:00 2001
From: Robert Griesemer