-2563706e4ead80d6906d66ae23c8915c360583ad
+fef8afc1876f4a1d5e9a8fd54c21bf5917966e10
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
# Also use -fno-inline to get better results from the memory profiler.
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
+if LIBGO_IS_AIX
+# reflect tests must be done with -static-libgo. Otherwize,
+# there will be a duplication of the canonicalization map.
+reflect_check_GOCFLAGS = -static-libgo -Wl,-bbigtoc
+endif
+
if HAVE_STATIC_LINK
# Use -static for the syscall tests if possible, because otherwise when
# running as root the re-execs ignore LD_LIBRARY_PATH.
# Also use -fno-inline to get better results from the memory profiler.
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
+# reflect tests must be done with -static-libgo. Otherwize,
+# there will be a duplication of the canonicalization map.
+@LIBGO_IS_AIX_TRUE@reflect_check_GOCFLAGS = -static-libgo -Wl,-bbigtoc
+
# Use -static for the syscall tests if possible, because otherwise when
# running as root the re-execs ignore LD_LIBRARY_PATH.
@HAVE_STATIC_LINK_TRUE@syscall_check_GOCFLAGS = -static
--- /dev/null
+// Copyright 2020 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.
+
+//+build !aix !gccgo
+
+package reflectlite
+
+// rtypeEqual returns true if both types are identical.
+func rtypeEqual(t1, t2 *rtype) bool {
+ return t1 == t2
+}
--- /dev/null
+// Copyright 2020 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.
+
+//+build aix,gccgo
+
+// AIX linker isn't able to merge identical type descriptors coming from
+// different objects. Thus, two rtypes might have two different pointers
+// even if they are the same. Thus, instead of pointer equality, string
+// field is checked.
+
+package reflectlite
+
+// rtypeEqual returns true if both types are identical.
+func rtypeEqual(t1, t2 *rtype) bool {
+ switch {
+ case t1 == t2:
+ return true
+ case t1 == nil || t2 == nil:
+ return false
+ case t1.kind != t2.kind || t1.hash != t2.hash:
+ return false
+ default:
+ return t1.String() == t2.String()
+ }
+}
for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i]
vm := &v.methods[j]
- if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && toType(vm.typ).common() == toType(tm.typ).common() {
+ if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && rtypeEqual(toType(vm.typ).common(), toType(tm.typ).common()) {
if i++; i >= len(t.methods) {
return true
}
for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i]
vm := &v.methods[j]
- if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && toType(vm.mtyp).common() == toType(tm.typ).common() {
+ if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && rtypeEqual(toType(vm.mtyp).common(), toType(tm.typ).common()) {
if i++; i >= len(t.methods) {
return true
}
// and the ideal constant rules (no ideal constants at run time).
func directlyAssignable(T, V *rtype) bool {
// x's type V is identical to T?
- if T == V {
+ if rtypeEqual(T, V) {
return true
}
}
func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
- if T == V {
+ if rtypeEqual(T, V) {
return true
}
--- /dev/null
+// Copyright 2020 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.
+
+// +build !aix !gccgo
+
+package reflect
+
+// rtypeEqual returns true if both rtypes are identical.
+func rtypeEqual(t1, t2 *rtype) bool {
+ return t1 == t2
+}
+
+// typeEqual returns true if both Types are identical.
+func typeEqual(t1, t2 Type) bool {
+ return t1 == t2
+}
+
+func toType(p *rtype) Type {
+ if p == nil {
+ return nil
+ }
+ return p
+}
--- /dev/null
+// Copyright 2020 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.
+
+//+build aix,gccgo
+
+// AIX linker isn't able to merge identical type descriptors coming from
+// different objects. Thus, two rtypes might have two different pointers
+// even if they are the same. Thus, instead of pointer equality, string
+// field is checked.
+
+package reflect
+
+import (
+ "sync"
+)
+
+// rtypeEqual returns true if both rtypes are identical.
+func rtypeEqual(t1, t2 *rtype) bool {
+ switch {
+ case t1 == t2:
+ return true
+ case t1 == nil || t2 == nil:
+ return false
+ case t1.kind != t2.kind || t1.hash != t2.hash:
+ return false
+ default:
+ return t1.String() == t2.String()
+ }
+}
+
+// typeEqual returns true if both Types are identical.
+func typeEqual(t1, t2 Type) bool {
+ return rtypeEqual(t1.common(), t2.common())
+}
+
+// toType converts from a *rtype to a Type that can be returned
+// to the client of package reflect. The only concern is that
+// a nil *rtype must be replaced by a nil Type.
+// On AIX, as type duplications can occur, it also ensure that
+// multiple *rtype for the same type are coalesced into a single
+// Type.
+
+var canonicalType = make(map[string]Type)
+
+var canonicalTypeLock sync.RWMutex
+
+func canonicalize(t Type) Type {
+ if t == nil {
+ return nil
+ }
+ s := t.rawString()
+ canonicalTypeLock.RLock()
+ if r, ok := canonicalType[s]; ok {
+ canonicalTypeLock.RUnlock()
+ return r
+ }
+ canonicalTypeLock.RUnlock()
+ canonicalTypeLock.Lock()
+ if r, ok := canonicalType[s]; ok {
+ canonicalTypeLock.Unlock()
+ return r
+ }
+ canonicalType[s] = t
+ canonicalTypeLock.Unlock()
+ return t
+}
+
+func toType(p *rtype) Type {
+ if p == nil {
+ return nil
+ }
+ return canonicalize(p)
+}
// Look in known types.
s := "*" + *t.string
if tt := lookupType(s); tt != nil {
- p := (*ptrType)(unsafe.Pointer(tt))
+ p := (*ptrType)(unsafe.Pointer(toType(tt).(*rtype)))
if p.elem == t {
pi, _ := ptrMap.LoadOrStore(t, p)
return &pi.(*ptrType).rtype
pp.ptrToThis = nil
pp.elem = t
- pi, _ := ptrMap.LoadOrStore(t, &pp)
+ q := toType(&pp.rtype).(*rtype)
+ p := (*ptrType)(unsafe.Pointer(q))
+ pi, _ := ptrMap.LoadOrStore(t, p)
return &pi.(*ptrType).rtype
}
// and the ideal constant rules (no ideal constants at run time).
func directlyAssignable(T, V *rtype) bool {
// x's type V is identical to T?
- if T == V {
+ if rtypeEqual(T, V) {
return true
}
}
func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
- if T == V {
+ if rtypeEqual(T, V) {
return true
}
s = "chan " + *typ.string
}
if tt := lookupType(s); tt != nil {
- ch := (*chanType)(unsafe.Pointer(tt))
+ ch := (*chanType)(unsafe.Pointer(toType(tt).(*rtype)))
if ch.elem == typ && ch.dir == uintptr(dir) {
ti, _ := lookupCache.LoadOrStore(ckey, tt)
return ti.(Type)
ch.uncommonType = nil
ch.ptrToThis = nil
- ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype)
+ ti, _ := lookupCache.LoadOrStore(ckey, toType(&ch.rtype).(*rtype))
return ti.(Type)
}
// Look in known types.
s := "map[" + *ktyp.string + "]" + *etyp.string
if tt := lookupType(s); tt != nil {
- mt := (*mapType)(unsafe.Pointer(tt))
+ mt := (*mapType)(unsafe.Pointer(toType(tt).(*rtype)))
if mt.key == ktyp && mt.elem == etyp {
ti, _ := lookupCache.LoadOrStore(ckey, tt)
return ti.(Type)
mt.flags |= 16
}
- ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype)
+ ti, _ := lookupCache.LoadOrStore(ckey, toType(&mt.rtype).(*rtype))
return ti.(Type)
}
ft.string = &str
ft.uncommonType = nil
ft.ptrToThis = nil
- return addToCache(&ft.rtype)
+ return addToCache(toType(&ft.rtype).(*rtype))
}
// funcStr builds a string representation of a funcType.
// Look in known types.
s := "[]" + *typ.string
if tt := lookupType(s); tt != nil {
- slice := (*sliceType)(unsafe.Pointer(tt))
+ slice := (*sliceType)(unsafe.Pointer(toType(tt).(*rtype)))
if slice.elem == typ {
ti, _ := lookupCache.LoadOrStore(ckey, tt)
return ti.(Type)
slice.uncommonType = nil
slice.ptrToThis = nil
- ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype)
+ ti, _ := lookupCache.LoadOrStore(ckey, toType(&slice.rtype).(*rtype))
return ti.(Type)
}
typ.uncommonType = nil
typ.ptrToThis = nil
- return addToCache(&typ.rtype)
+ return addToCache(toType(&typ.rtype).(*rtype))
}
// runtimeStructField takes a StructField value passed to StructOf and
// Look in known types.
s := "[" + strconv.Itoa(count) + "]" + *typ.string
if tt := lookupType(s); tt != nil {
- array := (*arrayType)(unsafe.Pointer(tt))
+ array := (*arrayType)(unsafe.Pointer(toType(tt).(*rtype)))
if array.elem == typ {
ti, _ := lookupCache.LoadOrStore(ckey, tt)
return ti.(Type)
array.kind &^= kindDirectIface
}
- ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype)
+ ti, _ := lookupCache.LoadOrStore(ckey, toType(&array.rtype).(*rtype))
return ti.(Type)
}
return x
}
-// toType converts from a *rtype to a Type that can be returned
-// to the client of package reflect. The only concern is that
-// a nil *rtype must be replaced by a nil Type.
-func toType(p *rtype) Type {
- if p == nil {
- return nil
- }
- return p
-}
-
// Look up a compiler-generated type descriptor.
// Implemented in runtime.
func lookupType(s string) *rtype
}
func typesMustMatch(what string, t1, t2 Type) {
- if t1 != t2 {
+ if !typeEqual(t1, t2) {
panic(what + ": " + t1.String() + " != " + t2.String())
}
}