const char* debug_escape_hash;
int64_t nil_check_size_threshold;
bool debug_optimization;
+ bool need_eqtype;
};
extern void go_create_gogo (const struct go_create_gogo_args*);
args.debug_escape_hash = go_debug_escape_hash;
args.nil_check_size_threshold = TARGET_AIX ? -1 : 4096;
args.debug_optimization = go_debug_optimization;
+ args.need_eqtype = TARGET_AIX ? true : false;
args.linemap = go_get_linemap();
args.backend = go_get_backend();
go_create_gogo (&args);
-307665073fce992ea8112f74b91954e770afcc70
+c512af85eb8c75a759b5e4fc6b72041fe09b75f1
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
// assignment.
Expression*
-Expression::convert_for_assignment(Gogo*, Type* lhs_type,
+Expression::convert_for_assignment(Gogo* gogo, Type* lhs_type,
Expression* rhs, Location location)
{
Type* rhs_type = rhs->type();
location);
}
else if (!are_identical && rhs_type->interface_type() != NULL)
- return Expression::convert_interface_to_type(lhs_type, rhs, location);
+ return Expression::convert_interface_to_type(gogo, lhs_type, rhs, location);
else if (lhs_type->is_slice_type() && rhs_type->is_nil_type())
{
// Assigning nil to a slice.
// non-interface type.
Expression*
-Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs,
+Expression::convert_interface_to_type(Gogo* gogo, Type *lhs_type, Expression* rhs,
Location location)
{
// We are going to evaluate RHS multiple times.
// Build an expression to check that the type is valid. It will
// panic with an appropriate runtime type error if the type is not
// valid.
- // (lhs_type != rhs_type ? panicdottype(lhs_type, rhs_type, inter_type) :
- // nil /*dummy*/)
+ // (lhs_type == rhs_type ? nil /*dummy*/ :
+ // panicdottype(lhs_type, rhs_type, inter_type))
+ // For some Oses, we need to call runtime.eqtype instead of
+ // lhs_type == rhs_type, as we may have unmerged type descriptors
+ // from shared libraries.
Expression* lhs_type_expr = Expression::make_type_descriptor(lhs_type,
location);
Expression* rhs_descriptor =
Expression* rhs_inter_expr = Expression::make_type_descriptor(rhs_type,
location);
- Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, lhs_type_expr,
- rhs_descriptor, location);
+ Expression* cond;
+ if (gogo->need_eqtype()) {
+ cond = Runtime::make_call(Runtime::EQTYPE, location,
+ 2, lhs_type_expr,
+ rhs_descriptor);
+ } else {
+ cond = Expression::make_binary(OPERATOR_EQEQ, lhs_type_expr,
+ rhs_descriptor, location);
+ }
+
rhs_descriptor = Expression::get_interface_type_descriptor(rhs);
Expression* panic = Runtime::make_call(Runtime::PANICDOTTYPE, location,
3, lhs_type_expr->copy(),
rhs_descriptor,
rhs_inter_expr);
Expression* nil = Expression::make_nil(location);
- Expression* check = Expression::make_conditional(cond, panic, nil,
+ Expression* check = Expression::make_conditional(cond, nil, panic,
location);
// If the conversion succeeds, pull out the value.
}
static Expression*
- convert_interface_to_type(Type*, Expression*, Location);
+ convert_interface_to_type(Gogo*, Type*, Expression*, Location);
static Expression*
import_identifier(Import_function_body*, Location);
::gogo->set_nil_check_size_threshold(args->nil_check_size_threshold);
if (args->debug_optimization)
::gogo->set_debug_optimization(args->debug_optimization);
+ if (args->need_eqtype)
+ ::gogo->set_need_eqtype(args->need_eqtype);
}
// Parse the input files.
debug_escape_level_(0),
debug_optimization_(false),
nil_check_size_threshold_(4096),
+ need_eqtype_(false),
verify_types_(),
interface_types_(),
specific_type_functions_(),
set_nil_check_size_threshold(int64_t bytes)
{ this->nil_check_size_threshold_ = bytes; }
+ // Return whether runtime.eqtype calls are needed when comparing
+ // type descriptors.
+ bool
+ need_eqtype() const
+ { return this->need_eqtype_; }
+
+ // Set if calls to runtime.eqtype are needed.
+ void
+ set_need_eqtype(bool b)
+ { this->need_eqtype_ = b; }
+
// Import a package. FILENAME is the file name argument, LOCAL_NAME
// is the local name to give to the package. If LOCAL_NAME is empty
// the declarations are added to the global scope.
bool debug_optimization_;
// Nil-check size threshhold.
int64_t nil_check_size_threshold_;
+ // Whether runtime.eqtype calls are needed when comparing type
+ // descriptors.
+ bool need_eqtype_;
// A list of types to verify.
std::vector<Type*> verify_types_;
// A list of interface types defined while parsing.
// Return whether we can convert a type to an interface type.
DEF_GO_RUNTIME(IFACET2IP, "runtime.ifaceT2Ip", P2(TYPE, TYPE), R1(BOOL))
+// Compare two type descriptors for equality.
+DEF_GO_RUNTIME(EQTYPE, "runtime.eqtype", P2(TYPE, TYPE), R1(BOOL))
+
// Compare two empty interface values.
DEF_GO_RUNTIME(EFACEEQ, "runtime.efaceeq", P2(EFACE, EFACE), R1(BOOL))
}
func efaceeq(x, y eface) bool {
t := x._type
- if t != y._type {
+ if !eqtype(t, y._type) {
return false
}
if t == nil {
return false
}
t := *(**_type)(xtab)
- if t != *(**_type)(y.tab) {
+ if !eqtype(t, *(**_type)(y.tab)) {
return false
}
eq := t.equal
return false
}
xt := *(**_type)(x.tab)
- if xt != t {
+ if !eqtype(xt, t) {
return false
}
eq := t.equal
return false
}
xt := *(**_type)(x.tab)
- if xt != y._type {
+ if !eqtype(xt, y._type) {
return false
}
eq := xt.equal
if x._type == nil {
return false
}
- if x._type != t {
+ if !eqtype(x._type, t) {
return false
}
eq := t.equal
--- /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 runtime
+
+import (
+ _ "unsafe"
+)
+
+// go:linkname is required as eqtype is a compiler-called
+// function on some OSes.
+//
+//go:linkname eqtype
+
+// Return whether two type descriptors are equal.
+func eqtype(t1, t2 *_type) 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
+
+package runtime
+
+import (
+ _ "unsafe"
+)
+
+// eqtype is a compiler-called function.
+//
+//go:linkname eqtype
+
+// Return whether two type descriptors are equal.
+// This is gccgo-specific, as some linkers are not able
+// to merge identical type descriptors coming from
+// different object or shared object files.
+func eqtype(t1, t2 *_type) 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()
+ }
+}
ri++
}
- if lhsMethod.typ != rhsMethod.mtyp {
+ if !eqtype(lhsMethod.typ, rhsMethod.mtyp) {
m.methods[1] = nil
return *lhsMethod.name
}
// Convert an empty interface to a pointer non-interface type.
func ifaceE2T2P(t *_type, e eface) (unsafe.Pointer, bool) {
- if t != e._type {
+ if !eqtype(t, e._type) {
return nil, false
} else {
return e.data, true
// Convert a non-empty interface to a pointer non-interface type.
func ifaceI2T2P(t *_type, i iface) (unsafe.Pointer, bool) {
- if i.tab == nil || t != *(**_type)(i.tab) {
+ if i.tab == nil || !eqtype(t, *(**_type)(i.tab)) {
return nil, false
} else {
return i.data, true
// Convert an empty interface to a non-pointer non-interface type.
func ifaceE2T2(t *_type, e eface, ret unsafe.Pointer) bool {
- if t != e._type {
+ if !eqtype(t, e._type) {
typedmemclr(t, ret)
return false
} else {
// Convert a non-empty interface to a non-pointer non-interface type.
func ifaceI2T2(t *_type, i iface, ret unsafe.Pointer) bool {
- if i.tab == nil || t != *(**_type)(i.tab) {
+ if i.tab == nil || !eqtype(t, *(**_type)(i.tab)) {
typedmemclr(t, ret)
return false
} else {
ri++
}
- if fromMethod.mtyp != toMethod.typ {
+ if !eqtype(fromMethod.mtyp, toMethod.typ) {
return false
}