diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index b3042d0b532..f5aa6a9d384 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -e0b906b13cbc947406c634aaf8b06270292bd7e0 +b42744825e3f2d1d2981eedbb67d6ac6419b8122 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 6f9775dd5a2..0dd869bb9c2 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -292,11 +292,11 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs, } Expression* obj; - if (rhs_type->points_to() != NULL) + if (rhs_type->is_direct_iface_type()) { // We are assigning a pointer to the interface; the interface // holds the pointer itself. - obj = rhs; + obj = unpack_direct_iface(rhs, location); } else { @@ -310,6 +310,60 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs, return Expression::make_interface_value(lhs_type, first_field, obj, location); } +// Return an expression for the pointer-typed value of a direct interface +// type. Specifically, for single field struct or array, get the single +// field, and do this recursively. The reason for this is that we don't +// want to assign a struct or an array to a pointer-typed field. The +// backend may not like that. + +Expression* +Expression::unpack_direct_iface(Expression* rhs, Location loc) +{ + Struct_type* st = rhs->type()->struct_type(); + if (st != NULL) + { + go_assert(st->field_count() == 1); + Expression* field = Expression::make_field_reference(rhs, 0, loc); + return unpack_direct_iface(field, loc); + } + Array_type* at = rhs->type()->array_type(); + if (at != NULL) + { + int64_t len; + bool ok = at->int_length(&len); + go_assert(ok && len == 1); + Type* int_type = Type::lookup_integer_type("int"); + Expression* index = Expression::make_integer_ul(0, int_type, loc); + Expression* elem = Expression::make_array_index(rhs, index, NULL, NULL, loc); + return unpack_direct_iface(elem, loc); + } + return rhs; +} + +// The opposite of unpack_direct_iface. + +Expression* +Expression::pack_direct_iface(Type* t, Expression* rhs, Location loc) +{ + if (rhs->type() == t) + return rhs; + Struct_type* st = t->struct_type(); + if (st != NULL) + { + Expression_list* vals = new Expression_list(); + vals->push_back(pack_direct_iface(st->field(0)->type(), rhs, loc)); + return Expression::make_struct_composite_literal(t, vals, loc); + } + Array_type* at = t->array_type(); + if (at != NULL) + { + Expression_list* vals = new Expression_list(); + vals->push_back(pack_direct_iface(at->element_type(), rhs, loc)); + return Expression::make_array_composite_literal(t, vals, loc); + } + return Expression::make_unsafe_cast(t, rhs, loc); +} + // Return an expression for the type descriptor of RHS. Expression* @@ -426,9 +480,11 @@ Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs, Expression* obj = Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT, location); - // If the value is a pointer, then it is the value we want. + // If the value is a direct interface, then it is the value we want. // Otherwise it points to the value. - if (lhs_type->points_to() == NULL) + if (lhs_type->is_direct_iface_type()) + obj = Expression::pack_direct_iface(lhs_type, obj, location); + else { obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), obj, location); @@ -3871,9 +3927,9 @@ Unsafe_type_conversion_expression::do_get_backend(Translate_context* context) && Type::are_convertible(t, et, NULL)); } else if (t->map_type() != NULL) - go_assert(et->map_type() != NULL); + go_assert(et->map_type() != NULL || et->points_to() != NULL); else if (t->channel_type() != NULL) - go_assert(et->channel_type() != NULL); + go_assert(et->channel_type() != NULL || et->points_to() != NULL); else if (t->points_to() != NULL) go_assert(et->points_to() != NULL || et->channel_type() != NULL @@ -3881,6 +3937,8 @@ Unsafe_type_conversion_expression::do_get_backend(Translate_context* context) || et->function_type() != NULL || et->integer_type() != NULL || et->is_nil_type()); + else if (t->function_type() != NULL) + go_assert(et->points_to() != NULL); else if (et->is_unsafe_pointer_type()) go_assert(t->points_to() != NULL || (t->integer_type() != NULL @@ -3899,8 +3957,6 @@ Unsafe_type_conversion_expression::do_get_backend(Translate_context* context) || et->map_type() != NULL || et->channel_type() != NULL || et->is_nil_type()); - else if (t->function_type() != NULL) - go_assert(et->points_to() != NULL); else go_unreachable(); @@ -6723,10 +6779,10 @@ Expression::comparison(Translate_context* context, Type* result_type, } // The right operand is not an interface. We need to take its - // address if it is not a pointer. + // address if it is not a direct interface type. Expression* pointer_arg = NULL; - if (right_type->points_to() != NULL) - pointer_arg = right; + if (right_type->is_direct_iface_type()) + pointer_arg = Expression::unpack_direct_iface(right, location); else { go_assert(right->is_addressable()); @@ -9871,11 +9927,15 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, if (bme != NULL) { Named_object* methodfn = bme->function(); + Function_type* mft = (methodfn->is_function() + ? methodfn->func_value()->type() + : methodfn->func_declaration_value()->type()); Expression* first_arg = bme->first_argument(); - // We always pass a pointer when calling a method. - if (first_arg->type()->points_to() == NULL - && !first_arg->type()->is_error()) + // We always pass a pointer when calling a method, except for + // direct interface types when calling a value method. + if (!first_arg->type()->is_error() + && !first_arg->type()->is_direct_iface_type()) { first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc); // We may need to create a temporary variable so that we can @@ -9884,6 +9944,12 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, Unary_expression* ue = static_cast(first_arg); ue->set_create_temp(); } + else if (mft->receiver()->type()->points_to() == NULL + && first_arg->type()->points_to() != NULL + && first_arg->type()->points_to()->is_direct_iface_type()) + first_arg = Expression::make_dereference(first_arg, + Expression::NIL_CHECK_DEFAULT, + loc); // If we are calling a method which was inherited from an // embedded struct, and the method did not get a stub, then the @@ -16018,11 +16084,19 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) else m = st->method_function(p->name(), &is_ambiguous); go_assert(m != NULL); - Named_object* no = m->named_object(); + Named_object* no = + (this->is_pointer_ + && this->type_->is_direct_iface_type() + && m->is_value_method() + ? m->iface_stub_object() + : m->named_object()); go_assert(no->is_function() || no->is_function_declaration()); - Btype* fcn_btype = m->type()->get_backend_fntype(gogo); + Function_type* fcn_type = (no->is_function() + ? no->func_value()->type() + : no->func_declaration_value()->type()); + Btype* fcn_btype = fcn_type->get_backend_fntype(gogo); Backend::Btyped_identifier bmtype(p->name(), fcn_btype, loc); bstructfields.push_back(bmtype); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 43aaccf9769..af7b00c081d 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1036,6 +1036,11 @@ class Expression static Expression* check_bounds(Expression* val, Location); + // Return an expression for constructing a direct interface type from a + // pointer. + static Expression* + pack_direct_iface(Type*, Expression*, Location); + // Dump an expression to a dump constext. void dump_expression(Ast_dump_context*) const; @@ -1197,6 +1202,9 @@ class Expression static Expression* convert_type_to_interface(Type*, Expression*, Location); + 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 11bc7ddf616..f45576ee77d 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -6039,7 +6039,7 @@ Function::build(Gogo* gogo, Named_object* named_function) // the receiver is declared as a non-pointer type, then we // copy the value into a local variable. if ((*p)->var_value()->is_receiver() - && (*p)->var_value()->type()->points_to() == NULL) + && !(*p)->var_value()->type()->is_direct_iface_type()) { std::string name = (*p)->name() + ".pointer"; Type* var_type = (*p)->var_value()->type(); @@ -7516,7 +7516,7 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, else { bool is_parameter = this->is_parameter_; - if (this->is_receiver_ && type->points_to() == NULL) + if (this->is_receiver_ && !type->is_direct_iface_type()) is_parameter = false; if (this->is_in_heap()) { diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index e9cbfd8ed1a..5796d2d245f 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -2313,6 +2313,49 @@ Type::write_named_equal(Gogo* gogo, Named_type* name) gogo->add_statement(s); } +// Return whether this type is stored directly in an interface's +// data word. +// +// Since finalize_methods runs before type checking, we may see a +// malformed type like 'type T struct { x T }'. Use a visited map +// to avoid infinite recursion. + +bool +Type::is_direct_iface_type() const +{ + Unordered_set(const Type*) visited; + return this->is_direct_iface_type_helper(&visited); +} + +bool +Type::is_direct_iface_type_helper(Unordered_set(const Type*)* visited) const +{ + if (this->points_to() != NULL + || this->channel_type() != NULL + || this->function_type() != NULL + || this->map_type() != NULL) + return true; + + std::pair ins + = visited->insert(this); + if (!ins.second) + // malformed circular type + return false; + + const Struct_type* st = this->struct_type(); + if (st != NULL) + return (st->field_count() == 1 + && st->field(0)->type()->is_direct_iface_type_helper(visited)); + const Array_type* at = this->array_type(); + if (at != NULL && !at->is_slice_type()) + { + int64_t len; + return (at->int_length(&len) && len == 1 + && at->element_type()->is_direct_iface_type_helper(visited)); + } + return false; +} + // Return a composite literal for the type descriptor for a plain type // of kind RUNTIME_TYPE_KIND named NAME. @@ -2331,7 +2374,7 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, if (!this->has_pointer()) runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS; - if (this->points_to() != NULL) + if (this->is_direct_iface_type()) runtime_type_kind |= RUNTIME_TYPE_KIND_DIRECT_IFACE; int64_t ptrsize; int64_t ptrdata; @@ -3397,9 +3440,14 @@ Type::method_constructor(Gogo*, Type* method_type, vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); } - Named_object* no = (m->needs_stub_method() - ? m->stub_object() - : m->named_object()); + Named_object* no = + ((this->points_to() != NULL + && this->points_to()->is_direct_iface_type() + && m->is_value_method()) + ? m->iface_stub_object() + : (m->needs_stub_method() + ? m->stub_object() + : m->named_object())); Function_type* mtype; if (no->is_function()) @@ -4708,9 +4756,11 @@ Function_type::get_backend_fntype(Gogo* gogo) breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name()); // We always pass the address of the receiver parameter, in - // order to make interface calls work with unknown types. + // order to make interface calls work with unknown types, + // except for direct interface types where the interface call + // actually passes value. Type* rtype = this->receiver_->type(); - if (rtype->points_to() == NULL) + if (!rtype->is_direct_iface_type()) rtype = Type::make_pointer_type(rtype); breceiver.btype = rtype->get_backend(gogo); breceiver.location = this->receiver_->location(); @@ -11020,6 +11070,8 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location, *all_methods = NULL; } Type::build_stub_methods(gogo, type, *all_methods, location); + if (type->is_direct_iface_type()) + Type::build_direct_iface_stub_methods(gogo, type, *all_methods, location); } // Add the methods for TYPE to *METHODS. FIELD_INDEXES is used to @@ -11383,6 +11435,165 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, gogo->add_statement(Statement::make_return_from_call(call, location)); } +// Build direct interface stub methods for TYPE as needed. METHODS +// is the set of methods for the type. LOCATION is the location of +// the type definition. +// +// This is for an interface holding a pointer to the type and invoking +// a value method. The interface data is the pointer, and is passed +// to the stub, which dereferences it and passes to the actual method. + +void +Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type, + Methods* methods, Location loc) +{ + if (methods == NULL) + return; + + for (Methods::const_iterator p = methods->begin(); + p != methods->end(); + ++p) + { + Method* m = p->second; + if (!m->is_value_method()) + continue; + + Type* receiver_type = const_cast(type); + receiver_type = Type::make_pointer_type(receiver_type); + const std::string& name(p->first); + Function_type* fntype = m->type(); + + static unsigned int counter; + char buf[100]; + snprintf(buf, sizeof buf, "$ptr%u", counter); + ++counter; + Typed_identifier* receiver = + new Typed_identifier(buf, receiver_type, m->receiver_location()); + + const Typed_identifier_list* params = fntype->parameters(); + Typed_identifier_list* stub_params; + if (params == NULL || params->empty()) + stub_params = NULL; + else + { + // We give each stub parameter a unique name. + stub_params = new Typed_identifier_list(); + for (Typed_identifier_list::const_iterator pp = params->begin(); + pp != params->end(); + ++pp) + { + char pbuf[100]; + snprintf(pbuf, sizeof pbuf, "$p%u", counter); + stub_params->push_back(Typed_identifier(pbuf, pp->type(), + pp->location())); + ++counter; + } + } + + const Typed_identifier_list* fnresults = fntype->results(); + Typed_identifier_list* stub_results; + if (fnresults == NULL || fnresults->empty()) + stub_results = NULL; + else + { + // We create the result parameters without any names, since + // we won't refer to them. + stub_results = new Typed_identifier_list(); + for (Typed_identifier_list::const_iterator pr = fnresults->begin(); + pr != fnresults->end(); + ++pr) + stub_results->push_back(Typed_identifier("", pr->type(), + pr->location())); + } + + Function_type* stub_type = Type::make_function_type(receiver, + stub_params, + stub_results, + fntype->location()); + if (fntype->is_varargs()) + stub_type->set_is_varargs(); + + // We only create the function in the package which creates the + // type. + const Package* package; + if (type->named_type() == NULL) + package = NULL; + else + package = type->named_type()->named_object()->package(); + + std::string stub_name = gogo->stub_method_name(package, name) + "2"; + Named_object* stub; + if (package != NULL) + stub = Named_object::make_function_declaration(stub_name, package, + stub_type, loc); + else + { + stub = gogo->start_function(stub_name, stub_type, false, + fntype->location()); + Type::build_one_iface_stub_method(gogo, m, buf, stub_params, + fntype->is_varargs(), loc); + gogo->finish_function(fntype->location()); + + if (type->named_type() == NULL && stub->is_function()) + stub->func_value()->set_is_unnamed_type_stub_method(); + if (m->nointerface() && stub->is_function()) + stub->func_value()->set_nointerface(); + } + + m->set_iface_stub_object(stub); + } +} + +// Build a stub method for METHOD of direct interface type T. +// RECEIVER_NAME is the name we used for the receiver. +// PARAMS is the list of function parameters. +// +// The stub looks like +// +// func ($ptr *T, PARAMS) { +// (*$ptr).METHOD(PARAMS) +// } + +void +Type::build_one_iface_stub_method(Gogo* gogo, Method* method, + const char* receiver_name, + const Typed_identifier_list* params, + bool is_varargs, Location loc) +{ + Named_object* receiver_object = gogo->lookup(receiver_name, NULL); + go_assert(receiver_object != NULL); + + Expression* expr = Expression::make_var_reference(receiver_object, loc); + expr = Expression::make_dereference(expr, + Expression::NIL_CHECK_DEFAULT, + loc); + + Expression_list* arguments; + if (params == NULL || params->empty()) + arguments = NULL; + else + { + arguments = new Expression_list(); + for (Typed_identifier_list::const_iterator p = params->begin(); + p != params->end(); + ++p) + { + Named_object* param = gogo->lookup(p->name(), NULL); + go_assert(param != NULL); + Expression* param_ref = Expression::make_var_reference(param, + loc); + arguments->push_back(param_ref); + } + } + + Expression* func = method->bind_method(expr, loc); + go_assert(func != NULL); + Call_expression* call = Expression::make_call(func, arguments, is_varargs, + loc); + + gogo->add_statement(Statement::make_return_from_call(call, loc)); +} + // Apply FIELD_INDEXES to EXPR. The field indexes have to be applied // in reverse order. diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 07121dd4756..721d1fc64ac 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -186,6 +186,22 @@ class Method this->stub_ = no; } + // Get the direct interface method stub object. + Named_object* + iface_stub_object() const + { + go_assert(this->iface_stub_ != NULL); + return this->iface_stub_; + } + + // Set the direct interface method stub object. + void + set_iface_stub_object(Named_object* no) + { + go_assert(this->iface_stub_ == NULL); + this->iface_stub_ = no; + } + // Return true if this method should not participate in any // interfaces. bool @@ -196,7 +212,7 @@ class Method // These objects are only built by the child classes. Method(const Field_indexes* field_indexes, unsigned int depth, bool is_value_method, bool needs_stub_method) - : field_indexes_(field_indexes), depth_(depth), stub_(NULL), + : field_indexes_(field_indexes), depth_(depth), stub_(NULL), iface_stub_(NULL), is_value_method_(is_value_method), needs_stub_method_(needs_stub_method), is_ambiguous_(false) { } @@ -230,6 +246,9 @@ class Method // If a stub method is required, this is its object. This is only // set after stub methods are built in finalize_methods. Named_object* stub_; + // Stub object for direct interface type. This is only set after + // stub methods are built in finalize_methods. + Named_object* iface_stub_; // Whether this is a value method--a method that does not require a // pointer. bool is_value_method_; @@ -923,6 +942,11 @@ class Type is_unsafe_pointer_type() const { return this->points_to() != NULL && this->points_to()->is_void_type(); } + // Return whether this type is stored directly in an interface's + // data word. + bool + is_direct_iface_type() const; + // Return a version of this type with any expressions copied, but // only if copying the expressions will affect the size of the type. // If there are no such expressions in the type (expressions can @@ -1321,6 +1345,15 @@ class Type const Typed_identifier_list*, bool is_varargs, Location); + // Build direct interface stub methods for a type. + static void + build_direct_iface_stub_methods(Gogo*, const Type*, Methods*, Location); + + static void + build_one_iface_stub_method(Gogo*, Method*, const char*, + const Typed_identifier_list*, + bool, Location); + static Expression* apply_field_indexes(Expression*, const Method::Field_indexes*, Location); @@ -1333,6 +1366,11 @@ class Type bool* is_method, bool* found_pointer_method, std::string* ambig1, std::string* ambig2); + // Helper function for is_direct_iface_type, to prevent infinite + // recursion. + bool + is_direct_iface_type_helper(Unordered_set(const Type*)*) const; + // Get the backend representation for a type without looking in the // hash table for identical types. Btype* diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 599ab272e79..9452255f9a6 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -4136,7 +4136,6 @@ func TestArrayOfGenericAlg(t *testing.T) { } func TestArrayOfDirectIface(t *testing.T) { - t.Skip("skipping test because gccgo uses a different directiface value") { type T [1]*byte i1 := Zero(TypeOf(T{})).Interface() @@ -4775,9 +4774,6 @@ func TestStructOfGenericAlg(t *testing.T) { } } -/* -gccgo does not use the same directiface settings as gc. - func TestStructOfDirectIface(t *testing.T) { { type T struct{ X [1]*byte } @@ -4826,7 +4822,6 @@ func TestStructOfDirectIface(t *testing.T) { } } } -*/ type StructI int diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index ea97b7d93fb..fb2e5d4b6df 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -2204,7 +2204,14 @@ func StructOf(fields []StructField) Type { typ.equalfn = nil } - typ.kind &^= kindDirectIface + switch { + case len(fs) == 1 && !ifaceIndir(fs[0].typ): + // structs of 1 direct iface type can be direct + typ.kind |= kindDirectIface + default: + typ.kind &^= kindDirectIface + } + typ.uncommonType = nil typ.ptrToThis = nil @@ -2405,7 +2412,13 @@ func ArrayOf(count int, elem Type) Type { array.ptrdata = array.size // overestimate but ok; must match program } - array.kind &^= kindDirectIface + switch { + case count == 1 && !ifaceIndir(typ): + // array of 1 direct iface type can be direct + array.kind |= kindDirectIface + default: + array.kind &^= kindDirectIface + } esize := typ.size diff --git a/libgo/go/runtime/iface.go b/libgo/go/runtime/iface.go index dc9247625b1..1c3a5f3d87f 100644 --- a/libgo/go/runtime/iface.go +++ b/libgo/go/runtime/iface.go @@ -68,10 +68,9 @@ import ( // pointer to memory that holds the value. It follows from this that // kindDirectIface can only be set for a type whose representation is // simply a pointer. In the current gccgo implementation, this is set -// only for pointer types (including unsafe.Pointer). In the future it -// could also be set for other types: channels, maps, functions, -// single-field structs and single-element arrays whose single field -// is simply a pointer. +// for types that are pointer-shaped, including unsafe.Pointer, channels, +// maps, functions, single-field structs and single-element arrays whose +// single field is simply a pointer-shaped type. // For a nil interface value both fields in the interface struct are nil. @@ -458,7 +457,11 @@ func ifaceE2T2(t *_type, e eface, ret unsafe.Pointer) bool { typedmemclr(t, ret) return false } else { - typedmemmove(t, ret, e.data) + if isDirectIface(t) { + *(*unsafe.Pointer)(ret) = e.data + } else { + typedmemmove(t, ret, e.data) + } return true } } @@ -469,7 +472,11 @@ func ifaceI2T2(t *_type, i iface, ret unsafe.Pointer) bool { typedmemclr(t, ret) return false } else { - typedmemmove(t, ret, i.data) + if isDirectIface(t) { + *(*unsafe.Pointer)(ret) = i.data + } else { + typedmemmove(t, ret, i.data) + } return true } } diff --git a/libgo/go/runtime/pprof/proto.go b/libgo/go/runtime/pprof/proto.go index 27cd09e7870..ef3eeb156bf 100644 --- a/libgo/go/runtime/pprof/proto.go +++ b/libgo/go/runtime/pprof/proto.go @@ -29,7 +29,7 @@ func funcPC(f interface{}) uintptr { data unsafe.Pointer } i := (*iface)(unsafe.Pointer(&f)) - r := **(**uintptr)(i.data) + r := *(*uintptr)(i.data) if internalcpu.FunctionDescriptors { // With PPC64 ELF ABI v1 function descriptors the // function address is a pointer to a struct whose diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index 0e6c9e19b09..8146c1d0206 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -446,7 +446,7 @@ func releaseSudog(s *sudog) { //go:nosplit func funcPC(f interface{}) uintptr { i := (*iface)(unsafe.Pointer(&f)) - r := **(**uintptr)(i.data) + r := *(*uintptr)(i.data) if cpu.FunctionDescriptors { // With PPC64 ELF ABI v1 function descriptors the // function address is a pointer to a struct whose diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c index a72b4e85454..31ff4747b98 100644 --- a/libgo/runtime/go-callers.c +++ b/libgo/runtime/go-callers.c @@ -75,7 +75,7 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno, return 0; if (p - function > 3 && __builtin_strcmp (p - 3, "..r") == 0) return 0; - if (p - function > 6 && __builtin_strcmp (p - 6, "..stub") == 0) + if (p - function > 6 && __builtin_strncmp (p - 6, "..stub", 6) == 0) return 0; }