runtime: revert eqtype for AIX
AIX linker is not able to merge identical type descriptors in a single symbol if there are coming from different object or shared object files. This results into several pointers referencing the same type descriptors. Thus, eqtype is needed to ensure that these different symbols will be considered as the same type descriptor. Fixes golang/go#39276 gcc/go/ChangeLog: * go-c.h (struct go_create_gogo_args): Add need_eqtype field. * go-lang.c (go_langhook_init): Set need_eqtype. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/235697
This commit is contained in:
parent
6366866623
commit
f4b9b13680
13 changed files with 107 additions and 21 deletions
|
@ -50,6 +50,7 @@ struct go_create_gogo_args
|
|||
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*);
|
||||
|
|
|
@ -119,6 +119,7 @@ go_langhook_init (void)
|
|||
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);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
307665073fce992ea8112f74b91954e770afcc70
|
||||
c512af85eb8c75a759b5e4fc6b72041fe09b75f1
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -208,7 +208,7 @@ Expression::is_same_variable(Expression* a, Expression* b)
|
|||
// 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();
|
||||
|
@ -229,7 +229,7 @@ Expression::convert_for_assignment(Gogo*, Type* lhs_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.
|
||||
|
@ -498,7 +498,7 @@ Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs,
|
|||
// 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.
|
||||
|
@ -507,8 +507,11 @@ Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs,
|
|||
// 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 =
|
||||
|
@ -518,15 +521,23 @@ Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs,
|
|||
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.
|
||||
|
|
|
@ -1273,7 +1273,7 @@ class Expression
|
|||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -46,6 +46,8 @@ go_create_gogo(const struct go_create_gogo_args* args)
|
|||
::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.
|
||||
|
|
|
@ -57,6 +57,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
|
|||
debug_escape_level_(0),
|
||||
debug_optimization_(false),
|
||||
nil_check_size_threshold_(4096),
|
||||
need_eqtype_(false),
|
||||
verify_types_(),
|
||||
interface_types_(),
|
||||
specific_type_functions_(),
|
||||
|
|
|
@ -360,6 +360,17 @@ class Gogo
|
|||
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.
|
||||
|
@ -1161,6 +1172,9 @@ class Gogo
|
|||
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.
|
||||
|
|
|
@ -340,6 +340,9 @@ DEF_GO_RUNTIME(PANICDOTTYPE, "runtime.panicdottype", P3(TYPE, TYPE, TYPE),
|
|||
// 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))
|
||||
|
||||
|
|
|
@ -276,7 +276,7 @@ func nilinterequal(p, q unsafe.Pointer) bool {
|
|||
}
|
||||
func efaceeq(x, y eface) bool {
|
||||
t := x._type
|
||||
if t != y._type {
|
||||
if !eqtype(t, y._type) {
|
||||
return false
|
||||
}
|
||||
if t == nil {
|
||||
|
@ -301,7 +301,7 @@ func ifaceeq(x, y iface) bool {
|
|||
return false
|
||||
}
|
||||
t := *(**_type)(xtab)
|
||||
if t != *(**_type)(y.tab) {
|
||||
if !eqtype(t, *(**_type)(y.tab)) {
|
||||
return false
|
||||
}
|
||||
eq := t.equal
|
||||
|
@ -322,7 +322,7 @@ func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool {
|
|||
return false
|
||||
}
|
||||
xt := *(**_type)(x.tab)
|
||||
if xt != t {
|
||||
if !eqtype(xt, t) {
|
||||
return false
|
||||
}
|
||||
eq := t.equal
|
||||
|
@ -343,7 +343,7 @@ func ifaceefaceeq(x iface, y eface) bool {
|
|||
return false
|
||||
}
|
||||
xt := *(**_type)(x.tab)
|
||||
if xt != y._type {
|
||||
if !eqtype(xt, y._type) {
|
||||
return false
|
||||
}
|
||||
eq := xt.equal
|
||||
|
@ -360,7 +360,7 @@ func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool {
|
|||
if x._type == nil {
|
||||
return false
|
||||
}
|
||||
if x._type != t {
|
||||
if !eqtype(x._type, t) {
|
||||
return false
|
||||
}
|
||||
eq := t.equal
|
||||
|
|
21
libgo/go/runtime/eqtype.go
Normal file
21
libgo/go/runtime/eqtype.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
// 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
|
||||
}
|
32
libgo/go/runtime/eqtype_aix_gccgo.go
Normal file
32
libgo/go/runtime/eqtype_aix_gccgo.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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()
|
||||
}
|
||||
}
|
|
@ -232,7 +232,7 @@ func (m *itab) init() string {
|
|||
ri++
|
||||
}
|
||||
|
||||
if lhsMethod.typ != rhsMethod.mtyp {
|
||||
if !eqtype(lhsMethod.typ, rhsMethod.mtyp) {
|
||||
m.methods[1] = nil
|
||||
return *lhsMethod.name
|
||||
}
|
||||
|
@ -406,7 +406,7 @@ func ifaceI2I2(inter *_type, i iface) (iface, bool) {
|
|||
|
||||
// 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
|
||||
|
@ -415,7 +415,7 @@ func ifaceE2T2P(t *_type, e eface) (unsafe.Pointer, bool) {
|
|||
|
||||
// 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
|
||||
|
@ -424,7 +424,7 @@ func ifaceI2T2P(t *_type, i iface) (unsafe.Pointer, bool) {
|
|||
|
||||
// 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 {
|
||||
|
@ -439,7 +439,7 @@ func ifaceE2T2(t *_type, e eface, ret unsafe.Pointer) bool {
|
|||
|
||||
// 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 {
|
||||
|
@ -485,7 +485,7 @@ func ifaceT2Ip(to, from *_type) bool {
|
|||
ri++
|
||||
}
|
||||
|
||||
if fromMethod.mtyp != toMethod.typ {
|
||||
if !eqtype(fromMethod.mtyp, toMethod.typ) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue