diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-01-02 15:05:27 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-01-21 23:53:22 -0800 |
commit | 5a8ea165926cb0737ab03bc48c18dc5198ab5305 (patch) | |
tree | 962dc3357c57f019f85658f99e2e753e30201c27 /libgo/go/reflect | |
parent | 6ac6529e155c9baa0aaaed7aca06bd38ebda5b43 (diff) |
libgo: update to Go1.14beta1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/214297
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 92 | ||||
-rw-r--r-- | libgo/go/reflect/deepequal.go | 16 | ||||
-rw-r--r-- | libgo/go/reflect/type.go | 212 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 17 |
4 files changed, 193 insertions, 144 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 6e06485f018..c9ed0a9e52d 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -787,6 +787,7 @@ type Loopy interface{} var loop1, loop2 Loop var loopy1, loopy2 Loopy +var cycleMap1, cycleMap2, cycleMap3 map[string]interface{} func init() { loop1 = &loop2 @@ -794,6 +795,13 @@ func init() { loopy1 = &loopy2 loopy2 = &loopy1 + + cycleMap1 = map[string]interface{}{} + cycleMap1["cycle"] = cycleMap1 + cycleMap2 = map[string]interface{}{} + cycleMap2["cycle"] = cycleMap2 + cycleMap3 = map[string]interface{}{} + cycleMap3["different"] = cycleMap3 } var deepEqualTests = []DeepEqualTest{ @@ -860,6 +868,8 @@ var deepEqualTests = []DeepEqualTest{ {&loop1, &loop2, true}, {&loopy1, &loopy1, true}, {&loopy1, &loopy2, true}, + {&cycleMap1, &cycleMap2, true}, + {&cycleMap1, &cycleMap3, false}, } func TestDeepEqual(t *testing.T) { @@ -868,7 +878,7 @@ func TestDeepEqual(t *testing.T) { test.b = test.a } if r := DeepEqual(test.a, test.b); r != test.eq { - t.Errorf("DeepEqual(%v, %v) = %v, want %v", test.a, test.b, r, test.eq) + t.Errorf("DeepEqual(%#v, %#v) = %v, want %v", test.a, test.b, r, test.eq) } } } @@ -3634,6 +3644,13 @@ type MyRunes []int32 type MyFunc func() type MyByte byte +type IntChan chan int +type IntChanRecv <-chan int +type IntChanSend chan<- int +type BytesChan chan []byte +type BytesChanRecv <-chan []byte +type BytesChanSend chan<- []byte + var convertTests = []struct { in Value out Value @@ -3995,10 +4012,6 @@ var convertTests = []struct { {V((***byte)(nil)), V((***byte)(nil))}, {V((***int32)(nil)), V((***int32)(nil))}, {V((***int64)(nil)), V((***int64)(nil))}, - {V((chan int)(nil)), V((<-chan int)(nil))}, - {V((chan int)(nil)), V((chan<- int)(nil))}, - {V((chan string)(nil)), V((<-chan string)(nil))}, - {V((chan string)(nil)), V((chan<- string)(nil))}, {V((chan byte)(nil)), V((chan byte)(nil))}, {V((chan MyByte)(nil)), V((chan MyByte)(nil))}, {V((map[int]bool)(nil)), V((map[int]bool)(nil))}, @@ -4010,6 +4023,40 @@ var convertTests = []struct { {V(new(io.Reader)), V(new(io.Reader))}, {V(new(io.Writer)), V(new(io.Writer))}, + // channels + {V(IntChan(nil)), V((chan<- int)(nil))}, + {V(IntChan(nil)), V((<-chan int)(nil))}, + {V((chan int)(nil)), V(IntChanRecv(nil))}, + {V((chan int)(nil)), V(IntChanSend(nil))}, + {V(IntChanRecv(nil)), V((<-chan int)(nil))}, + {V((<-chan int)(nil)), V(IntChanRecv(nil))}, + {V(IntChanSend(nil)), V((chan<- int)(nil))}, + {V((chan<- int)(nil)), V(IntChanSend(nil))}, + {V(IntChan(nil)), V((chan int)(nil))}, + {V((chan int)(nil)), V(IntChan(nil))}, + {V((chan int)(nil)), V((<-chan int)(nil))}, + {V((chan int)(nil)), V((chan<- int)(nil))}, + {V(BytesChan(nil)), V((chan<- []byte)(nil))}, + {V(BytesChan(nil)), V((<-chan []byte)(nil))}, + {V((chan []byte)(nil)), V(BytesChanRecv(nil))}, + {V((chan []byte)(nil)), V(BytesChanSend(nil))}, + {V(BytesChanRecv(nil)), V((<-chan []byte)(nil))}, + {V((<-chan []byte)(nil)), V(BytesChanRecv(nil))}, + {V(BytesChanSend(nil)), V((chan<- []byte)(nil))}, + {V((chan<- []byte)(nil)), V(BytesChanSend(nil))}, + {V(BytesChan(nil)), V((chan []byte)(nil))}, + {V((chan []byte)(nil)), V(BytesChan(nil))}, + {V((chan []byte)(nil)), V((<-chan []byte)(nil))}, + {V((chan []byte)(nil)), V((chan<- []byte)(nil))}, + + // cannot convert other instances (channels) + {V(IntChan(nil)), V(IntChan(nil))}, + {V(IntChanRecv(nil)), V(IntChanRecv(nil))}, + {V(IntChanSend(nil)), V(IntChanSend(nil))}, + {V(BytesChan(nil)), V(BytesChan(nil))}, + {V(BytesChanRecv(nil)), V(BytesChanRecv(nil))}, + {V(BytesChanSend(nil)), V(BytesChanSend(nil))}, + // interfaces {V(int(1)), EmptyInterfaceV(int(1))}, {V(string("hello")), EmptyInterfaceV(string("hello"))}, @@ -4734,17 +4781,14 @@ func TestStructOfExportRules(t *testing.T) { mustPanic: true, }, { - field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"}, - mustPanic: true, + field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"}, - mustPanic: true, + field: StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "S", Type: TypeOf(S1{})}, - mustPanic: false, - exported: true, + field: StructField{Name: "S", Type: TypeOf(S1{})}, + exported: true, }, { field: StructField{Name: "S", Type: TypeOf((*S1)(nil))}, @@ -4775,20 +4819,16 @@ func TestStructOfExportRules(t *testing.T) { mustPanic: true, }, { - field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"}, - mustPanic: true, // TODO(sbinet): creating a name with a package path + field: StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"}, - mustPanic: true, // TODO(sbinet): creating a name with a package path + field: StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"}, - mustPanic: true, // TODO(sbinet): creating a name with a package path + field: StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"}, }, { - field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"}, - mustPanic: true, // TODO(sbinet): creating a name with a package path + field: StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"}, }, { field: StructField{Name: "", Type: TypeOf(ΦType{})}, @@ -6120,9 +6160,6 @@ var funcLayoutTests []funcLayoutTest func init() { var argAlign uintptr = PtrSize - if runtime.GOARCH == "amd64p32" { - argAlign = 2 * PtrSize - } roundup := func(x uintptr, a uintptr) uintptr { return (x + a - 1) / a * a } @@ -6435,7 +6472,7 @@ func TestGCBits(t *testing.T) { join(hdr, rep(8, lit(0, 1)), rep(8, lit(1)), lit(1))) verifyMapBucket(t, Tint64, Tptr, map[int64]Xptr(nil), - join(hdr, rep(8, rep(8/PtrSize, lit(0))), rep(8, lit(1)), naclpad(), lit(1))) + join(hdr, rep(8, rep(8/PtrSize, lit(0))), rep(8, lit(1)), lit(1))) verifyMapBucket(t, Tscalar, Tscalar, map[Xscalar]Xscalar(nil), @@ -6462,13 +6499,6 @@ func TestGCBits(t *testing.T) { join(hdr, rep(8, lit(1)), rep(8, lit(1)), lit(1))) } -func naclpad() []byte { - if runtime.GOARCH == "amd64p32" { - return lit(0) - } - return nil -} - func rep(n int, b []byte) []byte { return bytes.Repeat(b, n) } func join(b ...[]byte) []byte { return bytes.Join(b, nil) } func lit(x ...byte) []byte { return x } diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go index 5b6694d3f0b..f2d46165b50 100644 --- a/libgo/go/reflect/deepequal.go +++ b/libgo/go/reflect/deepequal.go @@ -33,18 +33,20 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { // We want to avoid putting more in the visited map than we need to. // For any possible reference cycle that might be encountered, - // hard(t) needs to return true for at least one of the types in the cycle. - hard := func(k Kind) bool { - switch k { + // hard(v1, v2) needs to return true for at least one of the types in the cycle, + // and it's safe and valid to get Value's internal pointer. + hard := func(v1, v2 Value) bool { + switch v1.Kind() { case Map, Slice, Ptr, Interface: - return true + // Nil pointers cannot be cyclic. Avoid putting them in the visited map. + return !v1.IsNil() && !v2.IsNil() } return false } - if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) { - addr1 := unsafe.Pointer(v1.UnsafeAddr()) - addr2 := unsafe.Pointer(v2.UnsafeAddr()) + if hard(v1, v2) { + addr1 := v1.ptr + addr2 := v2.ptr if uintptr(addr1) > uintptr(addr2) { // Canonicalize order to reduce number of entries in visited. // Assumes non-moving garbage collector. diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 41ed383fc8e..a3506748a25 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 diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 15a502465f7..147a9c47298 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -884,7 +884,7 @@ func (v Value) IsNil() bool { // IsValid reports whether v represents a value. // It returns false if v is the zero Value. // If IsValid returns false, all other methods except String panic. -// Most functions and methods never return an invalid value. +// Most functions and methods never return an invalid Value. // If one does, its documentation states the conditions explicitly. func (v Value) IsValid() bool { return v.flag != 0 @@ -1225,6 +1225,11 @@ func (v Value) OverflowUint(x uint64) bool { panic(&ValueError{"reflect.Value.OverflowUint", v.kind()}) } +//go:nocheckptr +// This prevents inlining Value.Pointer when -d=checkptr is enabled, +// which ensures cmd/compile can recognize unsafe.Pointer(v.Pointer()) +// and make an exception. + // Pointer returns v's value as a uintptr. // It returns uintptr instead of unsafe.Pointer so that // code using reflect cannot obtain unsafe.Pointers @@ -1722,6 +1727,11 @@ func (v Value) Uint() uint64 { panic(&ValueError{"reflect.Value.Uint", v.kind()}) } +//go:nocheckptr +// This prevents inlining Value.UnsafeAddr when -d=checkptr is enabled, +// which ensures cmd/compile can recognize unsafe.Pointer(v.UnsafeAddr()) +// and make an exception. + // UnsafeAddr returns a pointer to v's data. // It is for advanced clients that also import the "unsafe" package. // It panics if v is not addressable. @@ -2274,6 +2284,11 @@ func convertOp(dst, src *rtype) func(Value, Type) Value { return cvtRunesString } } + + case Chan: + if dst.Kind() == Chan && specialChannelAssignability(dst, src) { + return cvtDirect + } } // dst and src have same underlying type. |