diff options
Diffstat (limited to 'libgo/go/reflect/type.go')
-rw-r--r-- | libgo/go/reflect/type.go | 212 |
1 files changed, 107 insertions, 105 deletions
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 41ed383..a350674 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -633,13 +633,17 @@ func (t *rtype) PkgPath() string { return t.uncommonType.PkgPath() } +func (t *rtype) hasName() bool { + return t.uncommonType != nil && t.uncommonType.name != nil +} + func (t *rtype) Name() string { return t.uncommonType.Name() } func (t *rtype) ChanDir() ChanDir { if t.Kind() != Chan { - panic("reflect: ChanDir of non-chan type") + panic("reflect: ChanDir of non-chan type " + t.String()) } tt := (*chanType)(unsafe.Pointer(t)) return ChanDir(tt.dir) @@ -647,7 +651,7 @@ func (t *rtype) ChanDir() ChanDir { func (t *rtype) IsVariadic() bool { if t.Kind() != Func { - panic("reflect: IsVariadic of non-func type") + panic("reflect: IsVariadic of non-func type " + t.String()) } tt := (*funcType)(unsafe.Pointer(t)) return tt.dotdotdot @@ -671,12 +675,12 @@ func (t *rtype) Elem() Type { tt := (*sliceType)(unsafe.Pointer(t)) return toType(tt.elem) } - panic("reflect: Elem of invalid type") + panic("reflect: Elem of invalid type " + t.String()) } func (t *rtype) Field(i int) StructField { if t.Kind() != Struct { - panic("reflect: Field of non-struct type") + panic("reflect: Field of non-struct type " + t.String()) } tt := (*structType)(unsafe.Pointer(t)) return tt.Field(i) @@ -684,7 +688,7 @@ func (t *rtype) Field(i int) StructField { func (t *rtype) FieldByIndex(index []int) StructField { if t.Kind() != Struct { - panic("reflect: FieldByIndex of non-struct type") + panic("reflect: FieldByIndex of non-struct type " + t.String()) } tt := (*structType)(unsafe.Pointer(t)) return tt.FieldByIndex(index) @@ -692,7 +696,7 @@ func (t *rtype) FieldByIndex(index []int) StructField { func (t *rtype) FieldByName(name string) (StructField, bool) { if t.Kind() != Struct { - panic("reflect: FieldByName of non-struct type") + panic("reflect: FieldByName of non-struct type " + t.String()) } tt := (*structType)(unsafe.Pointer(t)) return tt.FieldByName(name) @@ -700,7 +704,7 @@ func (t *rtype) FieldByName(name string) (StructField, bool) { func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) { if t.Kind() != Struct { - panic("reflect: FieldByNameFunc of non-struct type") + panic("reflect: FieldByNameFunc of non-struct type " + t.String()) } tt := (*structType)(unsafe.Pointer(t)) return tt.FieldByNameFunc(match) @@ -708,7 +712,7 @@ func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) { func (t *rtype) In(i int) Type { if t.Kind() != Func { - panic("reflect: In of non-func type") + panic("reflect: In of non-func type " + t.String()) } tt := (*funcType)(unsafe.Pointer(t)) return toType(tt.in[i]) @@ -716,7 +720,7 @@ func (t *rtype) In(i int) Type { func (t *rtype) Key() Type { if t.Kind() != Map { - panic("reflect: Key of non-map type") + panic("reflect: Key of non-map type " + t.String()) } tt := (*mapType)(unsafe.Pointer(t)) return toType(tt.key) @@ -724,7 +728,7 @@ func (t *rtype) Key() Type { func (t *rtype) Len() int { if t.Kind() != Array { - panic("reflect: Len of non-array type") + panic("reflect: Len of non-array type " + t.String()) } tt := (*arrayType)(unsafe.Pointer(t)) return int(tt.len) @@ -732,7 +736,7 @@ func (t *rtype) Len() int { func (t *rtype) NumField() int { if t.Kind() != Struct { - panic("reflect: NumField of non-struct type") + panic("reflect: NumField of non-struct type " + t.String()) } tt := (*structType)(unsafe.Pointer(t)) return len(tt.fields) @@ -740,7 +744,7 @@ func (t *rtype) NumField() int { func (t *rtype) NumIn() int { if t.Kind() != Func { - panic("reflect: NumIn of non-func type") + panic("reflect: NumIn of non-func type " + t.String()) } tt := (*funcType)(unsafe.Pointer(t)) return len(tt.in) @@ -748,7 +752,7 @@ func (t *rtype) NumIn() int { func (t *rtype) NumOut() int { if t.Kind() != Func { - panic("reflect: NumOut of non-func type") + panic("reflect: NumOut of non-func type " + t.String()) } tt := (*funcType)(unsafe.Pointer(t)) return len(tt.out) @@ -756,7 +760,7 @@ func (t *rtype) NumOut() int { func (t *rtype) Out(i int) Type { if t.Kind() != Func { - panic("reflect: Out of non-func type") + panic("reflect: Out of non-func type " + t.String()) } tt := (*funcType)(unsafe.Pointer(t)) return toType(tt.out[i]) @@ -1250,6 +1254,18 @@ func implements(T, V *rtype) bool { return false } +// specialChannelAssignability reports whether a value x of channel type V +// can be directly assigned (using memmove) to another channel type T. +// https://golang.org/doc/go_spec.html#Assignability +// T and V must be both of Chan kind. +func specialChannelAssignability(T, V *rtype) bool { + // Special case: + // x is a bidirectional channel value, T is a channel type, + // x's type V and T have identical element types, + // and at least one of V or T is not a defined type. + return V.ChanDir() == BothDir && (T.Name() == "" || V.Name() == "") && haveIdenticalType(T.Elem(), V.Elem(), true) +} + // directlyAssignable reports whether a value x of type V can be directly // assigned (using memmove) to a value of type T. // https://golang.org/doc/go_spec.html#Assignability @@ -1263,11 +1279,15 @@ func directlyAssignable(T, V *rtype) bool { // Otherwise at least one of T and V must not be defined // and they must have the same kind. - if T.Name() != "" && V.Name() != "" || T.Kind() != V.Kind() { + if T.hasName() && V.hasName() || T.Kind() != V.Kind() { return false } - // x's type T and V must have identical underlying types. + if T.Kind() == Chan && specialChannelAssignability(T, V) { + return true + } + + // x's type T and V must have identical underlying types. return haveIdenticalUnderlyingType(T, V, true) } @@ -1305,14 +1325,6 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool { return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) case Chan: - // Special case: - // x is a bidirectional channel value, T is a channel type, - // and x's type V and T have identical element types. - if V.ChanDir() == BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) { - return true - } - - // Otherwise continue test for identical underlying type. return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) case Func: @@ -1800,36 +1812,14 @@ func bucketOf(ktyp, etyp *rtype) *rtype { base := psize / ptrSize if ktyp.ptrdata != 0 { - if ktyp.kind&kindGCProg != 0 { - panic("reflect: unexpected GC program in MapOf") - } - kmask := (*[16]byte)(unsafe.Pointer(ktyp.gcdata)) - for i := uintptr(0); i < ktyp.ptrdata/ptrSize; i++ { - if (kmask[i/8]>>(i%8))&1 != 0 { - for j := uintptr(0); j < bucketSize; j++ { - word := base + j*ktyp.size/ptrSize + i - mask[word/8] |= 1 << (word % 8) - } - } - } + emitGCMask(mask, base, ktyp, bucketSize) } psize += bucketSize * ktyp.size psize = align(psize, uintptr(etyp.fieldAlign)) base = psize / ptrSize if etyp.ptrdata != 0 { - if etyp.kind&kindGCProg != 0 { - panic("reflect: unexpected GC program in MapOf") - } - emask := (*[16]byte)(unsafe.Pointer(etyp.gcdata)) - for i := uintptr(0); i < etyp.ptrdata/ptrSize; i++ { - if (emask[i/8]>>(i%8))&1 != 0 { - for j := uintptr(0); j < bucketSize; j++ { - word := base + j*etyp.size/ptrSize + i - mask[word/8] |= 1 << (word % 8) - } - } - } + emitGCMask(mask, base, etyp, bucketSize) } word := ovoff / ptrSize @@ -1856,6 +1846,55 @@ func bucketOf(ktyp, etyp *rtype) *rtype { return b } +func (t *rtype) gcSlice(begin, end uintptr) []byte { + return (*[1 << 30]byte)(unsafe.Pointer(t.gcdata))[begin:end:end] +} + +// emitGCMask writes the GC mask for [n]typ into out, starting at bit +// offset base. +func emitGCMask(out []byte, base uintptr, typ *rtype, n uintptr) { + if typ.kind&kindGCProg != 0 { + panic("reflect: unexpected GC program") + } + ptrs := typ.ptrdata / ptrSize + words := typ.size / ptrSize + mask := typ.gcSlice(0, (ptrs+7)/8) + for j := uintptr(0); j < ptrs; j++ { + if (mask[j/8]>>(j%8))&1 != 0 { + for i := uintptr(0); i < n; i++ { + k := base + i*words + j + out[k/8] |= 1 << (k % 8) + } + } + } +} + +// appendGCProg appends the GC program for the first ptrdata bytes of +// typ to dst and returns the extended slice. +func appendGCProg(dst []byte, typ *rtype) []byte { + if typ.kind&kindGCProg != 0 { + // Element has GC program; emit one element. + n := uintptr(*(*uint32)(unsafe.Pointer(typ.gcdata))) + prog := typ.gcSlice(4, 4+n-1) + return append(dst, prog...) + } + + // Element is small with pointer mask; use as literal bits. + ptrs := typ.ptrdata / ptrSize + mask := typ.gcSlice(0, (ptrs+7)/8) + + // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). + for ; ptrs > 120; ptrs -= 120 { + dst = append(dst, 120) + dst = append(dst, mask[:15]...) + mask = mask[15:] + } + + dst = append(dst, byte(ptrs)) + dst = append(dst, mask...) + return dst +} + // SliceOf returns the slice type with element type t. // For example, if t represents int, SliceOf(t) represents []int. func SliceOf(t Type) Type { @@ -2146,25 +2185,7 @@ func StructOf(fields []StructField) Type { off = ft.offset() } - elemGC := (*[1 << 30]byte)(unsafe.Pointer(ft.typ.gcdata))[:] - elemPtrs := ft.typ.ptrdata / ptrSize - if ft.typ.kind&kindGCProg == 0 { - // Element is small with pointer mask; use as literal bits. - mask := elemGC - // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). - var n uintptr - for n = elemPtrs; n > 120; n -= 120 { - prog = append(prog, 120) - prog = append(prog, mask[:15]...) - mask = mask[15:] - } - prog = append(prog, byte(n)) - prog = append(prog, mask[:(n+7)/8]...) - } else { - // Element has GC program; emit one element. - elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1] - prog = append(prog, elemProg...) - } + prog = appendGCProg(prog, ft.typ) off += ft.typ.ptrdata } prog = append(prog, 0) @@ -2209,15 +2230,18 @@ func StructOf(fields []StructField) Type { } func runtimeStructField(field StructField) structField { - if field.PkgPath != "" { - panic("reflect.StructOf: StructOf does not allow unexported fields") + if field.Anonymous && field.PkgPath != "" { + panic("reflect.StructOf: field \"" + field.Name + "\" is anonymous but has PkgPath set") } - // Best-effort check for misuse. - // Since PkgPath is empty, not much harm done if Unicode lowercase slips through. - c := field.Name[0] - if 'a' <= c && c <= 'z' || c == '_' { - panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath") + exported := field.PkgPath == "" + if exported { + // Best-effort check for misuse. + // Since this field will be treated as exported, not much harm done if Unicode lowercase slips through. + c := field.Name[0] + if 'a' <= c && c <= 'z' || c == '_' { + panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath") + } } offsetEmbed := uintptr(0) @@ -2234,9 +2258,14 @@ func runtimeStructField(field StructField) structField { tag = &st } + var pkgPath *string + if field.PkgPath != "" { + s := field.PkgPath + pkgPath = &s + } return structField{ name: name, - pkgPath: nil, + pkgPath: pkgPath, typ: field.Type.common(), tag: tag, offsetEmbed: offsetEmbed, @@ -2346,42 +2375,16 @@ func ArrayOf(count int, elem Type) Type { // Create direct pointer mask by turning each 1 bit in elem // into count 1 bits in larger mask. mask := make([]byte, (array.ptrdata/ptrSize+7)/8) - elemMask := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:] - elemWords := typ.size / ptrSize - for j := uintptr(0); j < typ.ptrdata/ptrSize; j++ { - if (elemMask[j/8]>>(j%8))&1 != 0 { - for i := uintptr(0); i < array.len; i++ { - k := i*elemWords + j - mask[k/8] |= 1 << (k % 8) - } - } - } + emitGCMask(mask, 0, typ, array.len) array.gcdata = &mask[0] default: // Create program that emits one element // and then repeats to make the array. prog := []byte{0, 0, 0, 0} // will be length of prog - elemGC := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:] - elemPtrs := typ.ptrdata / ptrSize - if typ.kind&kindGCProg == 0 { - // Element is small with pointer mask; use as literal bits. - mask := elemGC - // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). - var n uintptr - for n = elemPtrs; n > 120; n -= 120 { - prog = append(prog, 120) - prog = append(prog, mask[:15]...) - mask = mask[15:] - } - prog = append(prog, byte(n)) - prog = append(prog, mask[:(n+7)/8]...) - } else { - // Element has GC program; emit one element. - elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1] - prog = append(prog, elemProg...) - } + prog = appendGCProg(prog, typ) // Pad from ptrdata to size. + elemPtrs := typ.ptrdata / ptrSize elemWords := typ.size / ptrSize if elemPtrs < elemWords { // Emit literal 0 bit, then repeat as needed. @@ -2462,7 +2465,6 @@ func ifaceIndir(t *rtype) bool { return t.kind&kindDirectIface == 0 } -// Layout matches runtime.gobitvector (well enough). type bitVector struct { n uint32 // number of bits data []byte |