This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gccgo] Don't build an unnecessary thunk for a method expression
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org, gofrontend-dev at googlegroups dot com
- Date: Wed, 10 Nov 2010 16:52:03 -0800
- Subject: [gccgo] Don't build an unnecessary thunk for a method expression
In some cases the Go frontend has to build a thunk for a method
expression. However, when the method expression expects a pointer type
for the receiver parameter, this is not necessary. In that case we can
simply reuse the existing function, but we have to give it a different
type. This patch implements this minor optimization. Committed to
gccgo branch.
Ian
diff -r 66c086401876 go/expressions.cc
--- a/go/expressions.cc Wed Nov 10 16:44:36 2010 -0800
+++ b/go/expressions.cc Wed Nov 10 16:47:29 2010 -0800
@@ -2715,7 +2715,7 @@
Type_conversion_expression(Type* type, Expression* expr,
source_location location)
: Expression(EXPRESSION_CONVERSION, location),
- type_(type), expr_(expr)
+ type_(type), expr_(expr), may_convert_function_types_(false)
{ }
// Return the type to which we are converting.
@@ -2728,6 +2728,15 @@
expr() const
{ return this->expr_; }
+ // Permit converting from one function type to another. This is
+ // used internally for method expressions.
+ void
+ set_may_convert_function_types()
+ {
+ this->may_convert_function_types_ = true;
+ }
+
+ // Import a type conversion expression.
static Expression*
do_import(Import*);
@@ -2786,6 +2795,9 @@
Type* type_;
// The expression to convert.
Expression* expr_;
+ // True if this is permitted to convert function types. This is
+ // used internally for method expressions.
+ bool may_convert_function_types_;
};
// Traversal.
@@ -3098,6 +3110,11 @@
Type* expr_type = this->expr_->type();
std::string reason;
+ if (this->may_convert_function_types_
+ && type->function_type() != NULL
+ && expr_type->function_type() != NULL)
+ return;
+
if (Type::are_convertible(type, expr_type, &reason))
return;
@@ -3260,6 +3277,10 @@
else if (type->is_unsafe_pointer_type()
&& expr_type->integer_type() != NULL)
ret = convert_to_pointer(type_tree, expr_tree);
+ else if (this->may_convert_function_types_
+ && type->function_type() != NULL
+ && expr_type->function_type() != NULL)
+ ret = fold_convert_loc(this->location(), type_tree, expr_tree);
else
ret = Expression::convert_for_assignment(context, type, expr_type,
expr_tree, this->location());
@@ -9747,8 +9768,6 @@
return Expression::make_error(location);
}
- std::string method_name = Gogo::thunk_name();
-
// Build a new function type in which the receiver becomes the first
// argument.
Function_type* method_type = method->type();
@@ -9786,7 +9805,26 @@
if (method_type->is_varargs())
fntype->set_is_varargs();
- Named_object* no = gogo->start_function(method_name, fntype, false, location);
+ // We generate methods which always takes a pointer to the receiver
+ // as their first argument. If this is for a pointer type, we can
+ // simply reuse the existing function. We use an internal hack to
+ // get the right type.
+
+ if (is_pointer)
+ {
+ Named_object* mno = (method->needs_stub_method()
+ ? method->stub_object()
+ : method->named_object());
+ Expression* f = Expression::make_func_reference(mno, NULL, location);
+ f = Expression::make_cast(fntype, f, location);
+ Type_conversion_expression* tce =
+ static_cast<Type_conversion_expression*>(f);
+ tce->set_may_convert_function_types();
+ return f;
+ }
+
+ Named_object* no = gogo->start_function(Gogo::thunk_name(), fntype, false,
+ location);
Named_object* vno = gogo->lookup(receiver_name, NULL);
gcc_assert(vno != NULL);