From fb83aeb49971769172ddc9dbb9051f68f5dbd5ea Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 17 May 2019 05:49:22 +0000 Subject: [PATCH] re PR go/90482 (Many 32-bit Solaris/SPARC tests FAIL with SIGBUS) PR go/90482 compiler: make value method of direct interface type takes pointer Currently, a value method of a direct interface type takes the value of the receiver, which is pointer shaped, as the first parameter. When this method is called through interface, we actually pass the interface data as a pointer. On most platforms this is ok, as the underlying calling convention is the same, except that on SPARC32, the calling convention is actually different. This CL changes the method function actually takes a pointer. The function will convert the pointer to the pointer-shaped receiver type (a no-op conversion from machine code's aspect). For a direct call, in the caller we convert the receiver to a pointer (also no-op conversion) before invoking the method. For an interface call, we pass the pointer as before. This way, it is consistent that we always pass a pointer. Hopefully this fixes SPARC32 build and https://gcc.gnu.org/PR90482. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/177758 From-SVN: r271310 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 14 ++++++++++++-- gcc/go/gofrontend/expressions.h | 8 +++++--- gcc/go/gofrontend/gogo.cc | 26 ++++++++++++++++---------- gcc/go/gofrontend/types.cc | 11 ++++++++--- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 578bef74be3..304c910b2d0 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -f8a3668cbcfa3f8cd6c26c62bce416714cd401fc +b5ab7b419d6328f5126ba8d6795280129eaf6e79 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index dd559b4c0dd..ad898b7f38c 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -11263,6 +11263,16 @@ Call_expression::do_get_backend(Translate_context* context) else has_closure_arg = true; + Expression* first_arg = NULL; + if (!is_interface_method && fntype->is_method()) + { + first_arg = this->args_->front(); + if (first_arg->type()->points_to() == NULL + && first_arg->type()->is_direct_iface_type()) + first_arg = Expression::unpack_direct_iface(first_arg, + first_arg->location()); + } + int nargs; std::vector fn_args; if (this->args_ == NULL || this->args_->empty()) @@ -11279,7 +11289,7 @@ Call_expression::do_get_backend(Translate_context* context) && this->args_->size() == 1); nargs = 1; fn_args.resize(1); - fn_args[0] = this->args_->front()->get_backend(context); + fn_args[0] = first_arg->get_backend(context); } else { @@ -11294,7 +11304,7 @@ Call_expression::do_get_backend(Translate_context* context) Expression_list::const_iterator pe = this->args_->begin(); if (!is_interface_method && fntype->is_method()) { - fn_args[i] = (*pe)->get_backend(context); + fn_args[i] = first_arg->get_backend(context); ++pe; ++i; } diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 21a214db632..3527d7a897b 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1063,6 +1063,11 @@ class Expression static Expression* pack_direct_iface(Type*, Expression*, Location); + // Return an expression of the underlying pointer for a direct interface + // type (the opposite of pack_direct_iface). + static Expression* + unpack_direct_iface(Expression*, Location); + // Dump an expression to a dump constext. void dump_expression(Ast_dump_context*) const; @@ -1230,9 +1235,6 @@ class Expression : NULL); } - static Expression* - unpack_direct_iface(Expression*, Location); - static Expression* get_interface_type_descriptor(Expression*); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 02120f2e1fd..e94c5679d6d 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -6052,9 +6052,10 @@ Function::build(Gogo* gogo, Named_object* named_function) // We always pass the receiver to a method as a pointer. If // the receiver is declared as a non-pointer type, then we - // copy the value into a local variable. + // copy the value into a local variable. For direct interface + // type we pack the pointer into the type. if ((*p)->var_value()->is_receiver() - && !(*p)->var_value()->type()->is_direct_iface_type()) + && (*p)->var_value()->type()->points_to() == NULL) { std::string name = (*p)->name() + ".pointer"; Type* var_type = (*p)->var_value()->type(); @@ -6066,14 +6067,19 @@ Function::build(Gogo* gogo, Named_object* named_function) parm_bvar = parm_no->get_backend_variable(gogo, named_function); vars.push_back(bvar); - Expression* parm_ref = + + Expression* parm_ref = Expression::make_var_reference(parm_no, loc); - parm_ref = - Expression::make_dereference(parm_ref, - Expression::NIL_CHECK_NEEDED, - loc); - if ((*p)->var_value()->is_in_heap()) - parm_ref = Expression::make_heap_expression(parm_ref, loc); + Type* recv_type = (*p)->var_value()->type(); + if (recv_type->is_direct_iface_type()) + parm_ref = Expression::pack_direct_iface(recv_type, parm_ref, loc); + else + parm_ref = + Expression::make_dereference(parm_ref, + Expression::NIL_CHECK_NEEDED, + loc); + if ((*p)->var_value()->is_in_heap()) + parm_ref = Expression::make_heap_expression(parm_ref, loc); var_inits.push_back(parm_ref->get_backend(&context)); } else if ((*p)->var_value()->is_in_heap()) @@ -7531,7 +7537,7 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, else { bool is_parameter = this->is_parameter_; - if (this->is_receiver_ && !type->is_direct_iface_type()) + if (this->is_receiver_ && type->points_to() == NULL) is_parameter = false; if (this->is_in_heap()) { diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 371b65fc20e..52606261833 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -4760,10 +4760,15 @@ Function_type::get_backend_fntype(Gogo* gogo) // We always pass the address of the receiver parameter, in // order to make interface calls work with unknown types, // except for direct interface types where the interface call - // actually passes value. + // actually passes the underlying pointer of the value. Type* rtype = this->receiver_->type(); - if (!rtype->is_direct_iface_type()) - rtype = Type::make_pointer_type(rtype); + if (rtype->points_to() == NULL) + { + if (rtype->is_direct_iface_type()) + rtype = Type::make_pointer_type(Type::make_void_type()); + else + rtype = Type::make_pointer_type(rtype); + } breceiver.btype = rtype->get_backend(gogo); breceiver.location = this->receiver_->location(); } -- 2.30.2