diff options
author | Ian Lance Taylor <iant@golang.org> | 2017-01-14 00:05:42 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2017-01-14 00:05:42 +0000 |
commit | c2047754c300b68c05d65faa8dc2925fe67b71b4 (patch) | |
tree | e183ae81a1f48a02945cb6de463a70c5be1b06f6 /libgo/go/reflect | |
parent | 829afb8f05602bb31c9c597b24df7377fed4f059 (diff) | |
download | gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.zip gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.gz gcc-c2047754c300b68c05d65faa8dc2925fe67b71b4.tar.bz2 |
libgo: update to Go 1.8 release candidate 1
Compiler changes:
* Change map assignment to use mapassign and assign value directly.
* Change string iteration to use decoderune, faster for ASCII strings.
* Change makeslice to take int, and use makeslice64 for larger values.
* Add new noverflow field to hmap struct used for maps.
Unresolved problems, to be fixed later:
* Commented out test in go/types/sizes_test.go that doesn't compile.
* Commented out reflect.TestStructOf test for padding after zero-sized field.
Reviewed-on: https://go-review.googlesource.com/35231
gotools/:
Updates for Go 1.8rc1.
* Makefile.am (go_cmd_go_files): Add bug.go.
(s-zdefaultcc): Write defaultPkgConfig.
* Makefile.in: Rebuild.
From-SVN: r244456
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 247 | ||||
-rw-r--r-- | libgo/go/reflect/deepequal.go | 11 | ||||
-rw-r--r-- | libgo/go/reflect/example_test.go | 41 | ||||
-rw-r--r-- | libgo/go/reflect/export_test.go | 4 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc.go | 2 | ||||
-rw-r--r-- | libgo/go/reflect/swapper.go | 74 | ||||
-rw-r--r-- | libgo/go/reflect/type.go | 122 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 4 |
8 files changed, 444 insertions, 61 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index e601c2c..f51e95f 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -648,6 +648,20 @@ var ( type self struct{} +type Loop *Loop +type Loopy interface{} + +var loop1, loop2 Loop +var loopy1, loopy2 Loopy + +func init() { + loop1 = &loop2 + loop2 = &loop1 + + loopy1 = &loopy2 + loopy2 = &loopy1 +} + var deepEqualTests = []DeepEqualTest{ // Equalities {nil, nil, true}, @@ -706,6 +720,12 @@ var deepEqualTests = []DeepEqualTest{ {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false}, {Basic{1, 0.5}, NotBasic{1, 0.5}, false}, {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false}, + + // Possible loops. + {&loop1, &loop1, true}, + {&loop1, &loop2, true}, + {&loopy1, &loopy1, true}, + {&loopy1, &loopy2, true}, } func TestDeepEqual(t *testing.T) { @@ -1535,6 +1555,34 @@ func BenchmarkCall(b *testing.B) { }) } +func BenchmarkCallArgCopy(b *testing.B) { + byteArray := func(n int) Value { + return Zero(ArrayOf(n, TypeOf(byte(0)))) + } + sizes := [...]struct { + fv Value + arg Value + }{ + {ValueOf(func(a [128]byte) {}), byteArray(128)}, + {ValueOf(func(a [256]byte) {}), byteArray(256)}, + {ValueOf(func(a [1024]byte) {}), byteArray(1024)}, + {ValueOf(func(a [4096]byte) {}), byteArray(4096)}, + {ValueOf(func(a [65536]byte) {}), byteArray(65536)}, + } + for _, size := range sizes { + bench := func(b *testing.B) { + args := []Value{size.arg} + b.SetBytes(int64(size.arg.Len())) + b.ResetTimer() + for i := 0; i < b.N; i++ { + size.fv.Call(args) + } + } + name := fmt.Sprintf("size=%v", size.arg.Len()) + b.Run(name, bench) + } +} + func TestMakeFunc(t *testing.T) { f := dummy fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in }) @@ -2277,25 +2325,39 @@ func TestFieldPkgPath(t *testing.T) { unexported string OtherPkgFields }{}) - for _, test := range []struct { + + type pkgpathTest struct { index []int pkgPath string anonymous bool - }{ + } + + checkPkgPath := func(name string, s []pkgpathTest) { + for _, test := range s { + f := typ.FieldByIndex(test.index) + if got, want := f.PkgPath, test.pkgPath; got != want { + t.Errorf("%s: Field(%d).PkgPath = %q, want %q", name, test.index, got, want) + } + if got, want := f.Anonymous, test.anonymous; got != want { + t.Errorf("%s: Field(%d).Anonymous = %v, want %v", name, test.index, got, want) + } + } + } + + checkPkgPath("testStruct", []pkgpathTest{ {[]int{0}, "", false}, // Exported {[]int{1}, "reflect_test", false}, // unexported {[]int{2}, "", true}, // OtherPkgFields {[]int{2, 0}, "", false}, // OtherExported {[]int{2, 1}, "reflect", false}, // otherUnexported - } { - f := typ.FieldByIndex(test.index) - if got, want := f.PkgPath, test.pkgPath; got != want { - t.Errorf("Field(%d).PkgPath = %q, want %q", test.index, got, want) - } - if got, want := f.Anonymous, test.anonymous; got != want { - t.Errorf("Field(%d).Anonymous = %v, want %v", test.index, got, want) - } - } + }) + + type localOtherPkgFields OtherPkgFields + typ = TypeOf(localOtherPkgFields{}) + checkPkgPath("localOtherPkgFields", []pkgpathTest{ + {[]int{0}, "", false}, // OtherExported + {[]int{1}, "reflect", false}, // otherUnexported + }) } func TestVariadicType(t *testing.T) { @@ -3077,6 +3139,9 @@ func ReadWriterV(x io.ReadWriter) Value { } type Empty struct{} +type MyStruct struct { + x int `some:"tag"` +} type MyString string type MyBytes []byte type MyRunes []int32 @@ -3388,6 +3453,35 @@ var convertTests = []struct { {V((func())(nil)), V(MyFunc(nil))}, {V((MyFunc)(nil)), V((func())(nil))}, + // structs with different tags + {V(struct { + x int `some:"foo"` + }{}), V(struct { + x int `some:"bar"` + }{})}, + + {V(struct { + x int `some:"bar"` + }{}), V(struct { + x int `some:"foo"` + }{})}, + + {V(MyStruct{}), V(struct { + x int `some:"foo"` + }{})}, + + {V(struct { + x int `some:"foo"` + }{}), V(MyStruct{})}, + + {V(MyStruct{}), V(struct { + x int `some:"bar"` + }{})}, + + {V(struct { + x int `some:"bar"` + }{}), V(MyStruct{})}, + // can convert *byte and *MyByte {V((*byte)(nil)), V((*MyByte)(nil))}, {V((*MyByte)(nil)), V((*byte)(nil))}, @@ -3973,6 +4067,39 @@ func TestStructOf(t *testing.T) { } } + // Check size and alignment with a trailing zero-sized field. + st = StructOf([]StructField{ + { + Name: "F1", + Type: TypeOf(byte(0)), + }, + { + Name: "F2", + Type: TypeOf([0]*byte{}), + }, + }) + stt = TypeOf(struct { + G1 byte + G2 [0]*byte + }{}) + // Broken with gccgo for now--gccgo does not pad structs yet. + // if st.Size() != stt.Size() { + // t.Errorf("constructed zero-padded struct size = %v, want %v", st.Size(), stt.Size()) + // } + if st.Align() != stt.Align() { + t.Errorf("constructed zero-padded struct align = %v, want %v", st.Align(), stt.Align()) + } + if st.FieldAlign() != stt.FieldAlign() { + t.Errorf("constructed zero-padded struct field align = %v, want %v", st.FieldAlign(), stt.FieldAlign()) + } + for i := 0; i < st.NumField(); i++ { + o1 := st.Field(i).Offset + o2 := stt.Field(i).Offset + if o1 != o2 { + t.Errorf("constructed zero-padded struct field %v offset = %v, want %v", i, o1, o2) + } + } + // check duplicate names shouldPanic(func() { StructOf([]StructField{ @@ -5788,3 +5915,101 @@ func BenchmarkNew(b *testing.B) { New(v) } } + +func TestSwapper(t *testing.T) { + type I int + var a, b, c I + type pair struct { + x, y int + } + type pairPtr struct { + x, y int + p *I + } + type S string + + tests := []struct { + in interface{} + i, j int + want interface{} + }{ + { + in: []int{1, 20, 300}, + i: 0, + j: 2, + want: []int{300, 20, 1}, + }, + { + in: []uintptr{1, 20, 300}, + i: 0, + j: 2, + want: []uintptr{300, 20, 1}, + }, + { + in: []int16{1, 20, 300}, + i: 0, + j: 2, + want: []int16{300, 20, 1}, + }, + { + in: []int8{1, 20, 100}, + i: 0, + j: 2, + want: []int8{100, 20, 1}, + }, + { + in: []*I{&a, &b, &c}, + i: 0, + j: 2, + want: []*I{&c, &b, &a}, + }, + { + in: []string{"eric", "sergey", "larry"}, + i: 0, + j: 2, + want: []string{"larry", "sergey", "eric"}, + }, + { + in: []S{"eric", "sergey", "larry"}, + i: 0, + j: 2, + want: []S{"larry", "sergey", "eric"}, + }, + { + in: []pair{{1, 2}, {3, 4}, {5, 6}}, + i: 0, + j: 2, + want: []pair{{5, 6}, {3, 4}, {1, 2}}, + }, + { + in: []pairPtr{{1, 2, &a}, {3, 4, &b}, {5, 6, &c}}, + i: 0, + j: 2, + want: []pairPtr{{5, 6, &c}, {3, 4, &b}, {1, 2, &a}}, + }, + } + for i, tt := range tests { + inStr := fmt.Sprint(tt.in) + Swapper(tt.in)(tt.i, tt.j) + if !DeepEqual(tt.in, tt.want) { + t.Errorf("%d. swapping %v and %v of %v = %v; want %v", i, tt.i, tt.j, inStr, tt.in, tt.want) + } + } +} + +// TestUnaddressableField tests that the reflect package will not allow +// a type from another package to be used as a named type with an +// unexported field. +// +// This ensures that unexported fields cannot be modified by other packages. +func TestUnaddressableField(t *testing.T) { + var b Buffer // type defined in reflect, a different package + var localBuffer struct { + buf []byte + } + lv := ValueOf(&localBuffer).Elem() + rv := ValueOf(b) + shouldPanic(func() { + lv.Set(rv) + }) +} diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go index 9770358..f3fd704 100644 --- a/libgo/go/reflect/deepequal.go +++ b/libgo/go/reflect/deepequal.go @@ -30,9 +30,13 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { } // if depth > 10 { panic("deepValueEqual") } // for debugging + + // 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 { - case Array, Map, Slice, Struct: + case Map, Slice, Ptr, Interface: return true } return false @@ -142,8 +146,9 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { // // Interface values are deeply equal if they hold deeply equal concrete values. // -// Map values are deeply equal if they are the same map object -// or if they have the same length and their corresponding keys +// Map values are deeply equal when all of the following are true: +// they are both nil or both non-nil, they have the same length, +// and either they are the same map object or their corresponding keys // (matched using Go equality) map to deeply equal values. // // Pointer values are deeply equal if they are equal using Go's == operator diff --git a/libgo/go/reflect/example_test.go b/libgo/go/reflect/example_test.go index 9e2b9b3..f959b95 100644 --- a/libgo/go/reflect/example_test.go +++ b/libgo/go/reflect/example_test.go @@ -5,6 +5,8 @@ package reflect_test import ( + "bytes" + "encoding/json" "fmt" "io" "os" @@ -107,3 +109,42 @@ func ExampleTypeOf() { // Output: // true } + +func ExampleStructOf() { + typ := reflect.StructOf([]reflect.StructField{ + { + Name: "Height", + Type: reflect.TypeOf(float64(0)), + Tag: `json:"height"`, + }, + { + Name: "Age", + Type: reflect.TypeOf(int(0)), + Tag: `json:"age"`, + }, + }) + + v := reflect.New(typ).Elem() + v.Field(0).SetFloat(0.4) + v.Field(1).SetInt(2) + s := v.Addr().Interface() + + w := new(bytes.Buffer) + if err := json.NewEncoder(w).Encode(s); err != nil { + panic(err) + } + + fmt.Printf("value: %+v\n", s) + fmt.Printf("json: %s", w.Bytes()) + + r := bytes.NewReader([]byte(`{"height":1.5,"age":10}`)) + if err := json.NewDecoder(r).Decode(s); err != nil { + panic(err) + } + fmt.Printf("value: %+v\n", s) + + // Output: + // value: &{Height:0.4 Age:2} + // json: {"height":0.4,"age":2} + // value: &{Height:1.5 Age:10} +} diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go index a06e8d0..92b1302 100644 --- a/libgo/go/reflect/export_test.go +++ b/libgo/go/reflect/export_test.go @@ -83,3 +83,7 @@ func ResolveReflectName(s string) { resolveReflectName(newName(s, "", "", false)) } */ + +type Buffer struct { + buf []byte +} diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go index 3a9fd28..91df328 100644 --- a/libgo/go/reflect/makefunc.go +++ b/libgo/go/reflect/makefunc.go @@ -12,8 +12,8 @@ import ( // makeFuncImpl is the closure value implementing the function // returned by MakeFunc. +// The first three words are layed out like ffi_go_closure. type makeFuncImpl struct { - // These first three words are layed out like ffi_go_closure. code uintptr ffi_cif unsafe.Pointer ffi_fun func(unsafe.Pointer, unsafe.Pointer) diff --git a/libgo/go/reflect/swapper.go b/libgo/go/reflect/swapper.go new file mode 100644 index 0000000..5441cb0 --- /dev/null +++ b/libgo/go/reflect/swapper.go @@ -0,0 +1,74 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import "unsafe" + +// Swapper returns a function that swaps the elements in the provided +// slice. +// +// Swapper panics if the provided interface is not a slice. +func Swapper(slice interface{}) func(i, j int) { + v := ValueOf(slice) + if v.Kind() != Slice { + panic(&ValueError{Method: "Swapper", Kind: v.Kind()}) + } + // Fast path for slices of size 0 and 1. Nothing to swap. + switch v.Len() { + case 0: + return func(i, j int) { panic("reflect: slice index out of range") } + case 1: + return func(i, j int) { + if i != 0 || j != 0 { + panic("reflect: slice index out of range") + } + } + } + + typ := v.Type().Elem().(*rtype) + size := typ.Size() + hasPtr := typ.kind&kindNoPointers == 0 + + // Some common & small cases, without using memmove: + if hasPtr { + if size == ptrSize { + ps := *(*[]unsafe.Pointer)(v.ptr) + return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } + } + if typ.Kind() == String { + ss := *(*[]string)(v.ptr) + return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] } + } + } else { + switch size { + case 8: + is := *(*[]int64)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 4: + is := *(*[]int32)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 2: + is := *(*[]int16)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 1: + is := *(*[]int8)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + } + } + + s := (*sliceHeader)(v.ptr) + tmp := unsafe_New(typ) // swap scratch space + + return func(i, j int) { + if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { + panic("reflect: slice index out of range") + } + val1 := arrayAt(s.Data, i, size) + val2 := arrayAt(s.Data, j, size) + typedmemmove(typ, tmp, val1) + typedmemmove(typ, val1, val2) + typedmemmove(typ, val2, tmp) + } +} diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 4f13f14..07a355d 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -28,6 +28,9 @@ import ( // Use the Kind method to find out the kind of type before // calling kind-specific methods. Calling a method // inappropriate to the kind of type causes a run-time panic. +// +// Type values are comparable, such as with the == operator. +// Two Type values are equal if they represent identical types. type Type interface { // Methods applicable to all types. @@ -59,7 +62,7 @@ type Type interface { // method signature, without a receiver, and the Func field is nil. MethodByName(string) (Method, bool) - // NumMethod returns the number of methods in the type's method set. + // NumMethod returns the number of exported methods in the type's method set. NumMethod() int // Name returns the type's name within its package. @@ -79,7 +82,7 @@ type Type interface { // String returns a string representation of the type. // The string representation may use shortened package names // (e.g., base64 instead of "encoding/base64") and is not - // guaranteed to be unique among types. To test for equality, + // guaranteed to be unique among types. To test for type identity, // compare the Types directly. String() string @@ -155,9 +158,18 @@ type Type interface { // and a boolean indicating if the field was found. FieldByName(name string) (StructField, bool) - // FieldByNameFunc returns the first struct field with a name + // FieldByNameFunc returns the struct field with a name // that satisfies the match function and a boolean indicating if // the field was found. + // + // FieldByNameFunc considers the fields in the struct itself + // and then the fields in any anonymous structs, in breadth first order, + // stopping at the shallowest nesting depth containing one or more + // fields satisfying the match function. If multiple fields at that depth + // satisfy the match function, they cancel each other + // and FieldByNameFunc returns no match. + // This behavior mirrors Go's handling of name lookup in + // structs containing anonymous fields. FieldByNameFunc(match func(string) bool) (StructField, bool) // In returns the type of a function type's i'th input parameter. @@ -826,7 +838,7 @@ func (tag StructTag) Get(key string) string { // the value returned by Lookup is unspecified. func (tag StructTag) Lookup(key string) (value string, ok bool) { // When modifying this code, also update the validateStructTag code - // in golang.org/x/tools/cmd/vet/structtag.go. + // in cmd/vet/structtag.go. for tag != "" { // Skip leading space. @@ -1157,12 +1169,11 @@ func (t *rtype) ptrTo() *rtype { // Create a new ptrType starting with the description // of an *unsafe.Pointer. - p = new(ptrType) var iptr interface{} = (*unsafe.Pointer)(nil) prototype := *(**ptrType)(unsafe.Pointer(&iptr)) - *p = *prototype + pp := *prototype - p.string = &s + pp.string = &s // For the type structures linked into the binary, the // compiler provides a good hash of the string. @@ -1171,17 +1182,17 @@ func (t *rtype) ptrTo() *rtype { // old hash and the new "*". // p.hash = fnv1(t.hash, '*') // This is the gccgo version. - p.hash = (t.hash << 4) + 9 + pp.hash = (t.hash << 4) + 9 - p.uncommonType = nil - p.ptrToThis = nil - p.elem = t + pp.uncommonType = nil + pp.ptrToThis = nil + pp.elem = t if t.kind&kindNoPointers != 0 { - p.gc = unsafe.Pointer(&ptrDataGCProg) + pp.gc = unsafe.Pointer(&ptrDataGCProg) } else { - p.gc = unsafe.Pointer(&ptrGC{ - width: p.size, + pp.gc = unsafe.Pointer(&ptrGC{ + width: pp.size, op: _GC_PTR, off: 0, elemgc: t.gc, @@ -1189,7 +1200,7 @@ func (t *rtype) ptrTo() *rtype { }) } - q := canonicalize(&p.rtype) + q := canonicalize(&pp.rtype) p = (*ptrType)(unsafe.Pointer(q.(*rtype))) ptrMap.m[t] = p @@ -1331,10 +1342,22 @@ func directlyAssignable(T, V *rtype) bool { } // x's type T and V must have identical underlying types. - return haveIdenticalUnderlyingType(T, V) + return haveIdenticalUnderlyingType(T, V, true) +} + +func haveIdenticalType(T, V Type, cmpTags bool) bool { + if cmpTags { + return T == V + } + + if T.Name() != V.Name() || T.Kind() != V.Kind() { + return false + } + + return haveIdenticalUnderlyingType(T.common(), V.common(), false) } -func haveIdenticalUnderlyingType(T, V *rtype) bool { +func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool { if T == V { return true } @@ -1353,18 +1376,18 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool { // Composite types. switch kind { case Array: - return T.Elem() == V.Elem() && T.Len() == V.Len() + 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 && T.Elem() == V.Elem() { + if V.ChanDir() == BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) { return true } // Otherwise continue test for identical underlying type. - return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem() + return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) case Func: t := (*funcType)(unsafe.Pointer(T)) @@ -1373,12 +1396,12 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool { return false } for i, typ := range t.in { - if typ != v.in[i] { + if !haveIdenticalType(typ, v.in[i], cmpTags) { return false } } for i, typ := range t.out { - if typ != v.out[i] { + if !haveIdenticalType(typ, v.out[i], cmpTags) { return false } } @@ -1395,10 +1418,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool { return false case Map: - return T.Key() == V.Key() && T.Elem() == V.Elem() + return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) case Ptr, Slice: - return T.Elem() == V.Elem() + return haveIdenticalType(T.Elem(), V.Elem(), cmpTags) case Struct: t := (*structType)(unsafe.Pointer(T)) @@ -1415,10 +1438,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool { if tf.pkgPath != vf.pkgPath && (tf.pkgPath == nil || vf.pkgPath == nil || *tf.pkgPath != *vf.pkgPath) { return false } - if tf.typ != vf.typ { + if !haveIdenticalType(tf.typ, vf.typ, cmpTags) { return false } - if tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) { + if cmpTags && tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) { return false } if tf.offset != vf.offset { @@ -1539,8 +1562,7 @@ func ChanOf(dir ChanDir, t Type) Type { // Make a channel type. var ichan interface{} = (chan unsafe.Pointer)(nil) prototype := *(**chanType)(unsafe.Pointer(&ichan)) - ch := new(chanType) - *ch = *prototype + ch := *prototype ch.dir = uintptr(dir) ch.string = &s @@ -1602,8 +1624,7 @@ func MapOf(key, elem Type) Type { // Make a map type. var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) - mt := new(mapType) - *mt = **(**mapType)(unsafe.Pointer(&imap)) + mt := **(**mapType)(unsafe.Pointer(&imap)) mt.string = &s // gccgo uses a different hash @@ -1684,7 +1705,7 @@ func FuncOf(in, out []Type, variadic bool) Type { // Look in cache. funcLookupCache.RLock() for _, t := range funcLookupCache.m[hash] { - if haveIdenticalUnderlyingType(&ft.rtype, t) { + if haveIdenticalUnderlyingType(&ft.rtype, t, true) { funcLookupCache.RUnlock() return t } @@ -1698,7 +1719,7 @@ func FuncOf(in, out []Type, variadic bool) Type { funcLookupCache.m = make(map[uint32][]*rtype) } for _, t := range funcLookupCache.m[hash] { - if haveIdenticalUnderlyingType(&ft.rtype, t) { + if haveIdenticalUnderlyingType(&ft.rtype, t, true) { return t } } @@ -1885,12 +1906,13 @@ func bucketOf(ktyp, etyp *rtype) *rtype { gcPtr = unsafe.Pointer(&gc[0]) } - b := new(rtype) - b.align = int8(maxAlign) - b.fieldAlign = uint8(maxAlign) - b.size = size - b.kind = kind - b.gc = gcPtr + b := &rtype{ + align: int8(maxAlign), + fieldAlign: uint8(maxAlign), + size: size, + kind: kind, + gc: gcPtr, + } s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" b.string = &s return b @@ -2002,8 +2024,7 @@ func SliceOf(t Type) Type { // Make a slice type. var islice interface{} = ([]unsafe.Pointer)(nil) prototype := *(**sliceType)(unsafe.Pointer(&islice)) - slice := new(sliceType) - *slice = *prototype + slice := *prototype slice.string = &s // gccgo uses a different hash. @@ -2061,6 +2082,7 @@ func StructOf(fields []StructField) Type { hasPtr = false // records whether at least one struct-field is a pointer ) + lastzero := uintptr(0) repr = append(repr, "struct {"...) for i, field := range fields { if field.Type == nil { @@ -2138,9 +2160,22 @@ func StructOf(fields []StructField) Type { } size = f.offset + ft.size + if ft.size == 0 { + lastzero = size + } + fs[i] = f } + if size > 0 && lastzero == size { + // This is a non-zero sized struct that ends in a + // zero-sized field. We add an extra byte of padding, + // to ensure that taking the address of the final + // zero-sized field can't manufacture a pointer to the + // next object in the heap. See issue 9401. + size++ + } + if len(fs) > 0 { repr = append(repr, ' ') } @@ -2162,7 +2197,7 @@ func StructOf(fields []StructField) Type { structLookupCache.RLock() for _, st := range structLookupCache.m[hash] { t := st.common() - if haveIdenticalUnderlyingType(&typ.rtype, t) { + if haveIdenticalUnderlyingType(&typ.rtype, t, true) { structLookupCache.RUnlock() return t } @@ -2179,7 +2214,7 @@ func StructOf(fields []StructField) Type { } for _, st := range structLookupCache.m[hash] { t := st.common() - if haveIdenticalUnderlyingType(&typ.rtype, t) { + if haveIdenticalUnderlyingType(&typ.rtype, t, true) { return t } } @@ -2295,8 +2330,7 @@ func ArrayOf(count int, elem Type) Type { // Make an array type. var iarray interface{} = [1]unsafe.Pointer{} prototype := *(**arrayType)(unsafe.Pointer(&iarray)) - array := new(arrayType) - *array = *prototype + array := *prototype array.string = &s // gccgo uses a different hash. diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 1d18876..1b4c540 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -2113,14 +2113,14 @@ func convertOp(dst, src *rtype) func(Value, Type) Value { } // dst and src have same underlying type. - if haveIdenticalUnderlyingType(dst, src) { + if haveIdenticalUnderlyingType(dst, src, false) { return cvtDirect } // dst and src are unnamed pointer types with same underlying base type. if dst.Kind() == Ptr && dst.Name() == "" && src.Kind() == Ptr && src.Name() == "" && - haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common()) { + haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common(), false) { return cvtDirect } |