summaryrefslogtreecommitdiff
path: root/libgo/go/reflect
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-01-02 15:05:27 -0800
committerIan Lance Taylor <iant@golang.org>2020-01-21 23:53:22 -0800
commit5a8ea165926cb0737ab03bc48c18dc5198ab5305 (patch)
tree962dc3357c57f019f85658f99e2e753e30201c27 /libgo/go/reflect
parent6ac6529e155c9baa0aaaed7aca06bd38ebda5b43 (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.go92
-rw-r--r--libgo/go/reflect/deepequal.go16
-rw-r--r--libgo/go/reflect/type.go212
-rw-r--r--libgo/go/reflect/value.go17
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.