Commit 571d3f91 by Ian Lance Taylor

compiler: Add support for method values.

From-SVN: r200379
parent 39953c79
......@@ -16,6 +16,7 @@ class Translate_context;
class Traverse;
class Statement_inserter;
class Type;
class Method;
struct Type_context;
class Integer_type;
class Float_type;
......@@ -224,9 +225,11 @@ class Expression
make_call_result(Call_expression*, unsigned int index);
// Make an expression which is a method bound to its first
// parameter.
// parameter. METHOD is the method being called, FUNCTION is the
// function to call.
static Bound_method_expression*
make_bound_method(Expression* object, Named_object* method, Location);
make_bound_method(Expression* object, const Method* method,
Named_object* function, Location);
// Make an index or slice expression. This is a parser expression
// which represents LEFT[START:END]. END may be NULL, meaning an
......@@ -1079,8 +1082,7 @@ class Set_and_use_temporary_expression : public Expression
do_type();
void
do_determine_type(const Type_context*)
{ }
do_determine_type(const Type_context*);
Expression*
do_copy()
......@@ -1852,10 +1854,10 @@ class Map_index_expression : public Expression
class Bound_method_expression : public Expression
{
public:
Bound_method_expression(Expression* expr, Named_object* method,
Location location)
Bound_method_expression(Expression* expr, const Method *method,
Named_object* function, Location location)
: Expression(EXPRESSION_BOUND_METHOD, location),
expr_(expr), expr_type_(NULL), method_(method)
expr_(expr), expr_type_(NULL), method_(method), function_(function)
{ }
// Return the object which is the first argument.
......@@ -1870,20 +1872,33 @@ class Bound_method_expression : public Expression
first_argument_type() const
{ return this->expr_type_; }
// Return the method function.
Named_object*
method()
// Return the method.
const Method*
method() const
{ return this->method_; }
// Return the function to call.
Named_object*
function() const
{ return this->function_; }
// Set the implicit type of the expression.
void
set_first_argument_type(Type* type)
{ this->expr_type_ = type; }
// Create a thunk to call FUNCTION, for METHOD, when it is used as
// part of a method value.
static Named_object*
create_thunk(Gogo*, const Method* method, Named_object* function);
protected:
int
do_traverse(Traverse*);
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Type*
do_type();
......@@ -1897,7 +1912,7 @@ class Bound_method_expression : public Expression
do_copy()
{
return new Bound_method_expression(this->expr_->copy(), this->method_,
this->location());
this->function_, this->location());
}
tree
......@@ -1907,6 +1922,11 @@ class Bound_method_expression : public Expression
do_dump_expression(Ast_dump_context*) const;
private:
// A mapping from method functions to the thunks we have created for
// them.
typedef Unordered_map(Named_object*, Named_object*) Method_value_thunks;
static Method_value_thunks method_value_thunks;
// The object used to find the method. This is passed to the method
// as the first argument.
Expression* expr_;
......@@ -1914,8 +1934,12 @@ class Bound_method_expression : public Expression
// NULL in the normal case, non-NULL when using a method from an
// anonymous field which does not require a stub.
Type* expr_type_;
// The method itself.
Named_object* method_;
// The method.
const Method* method_;
// The function to call. This is not the same as
// method_->named_object() when the method has a stub. This will be
// the real function rather than the stub.
Named_object* function_;
};
// A reference to a field in a struct.
......@@ -2031,6 +2055,11 @@ class Interface_field_reference_expression : public Expression
name() const
{ return this->name_; }
// Create a thunk to call the method NAME in TYPE when it is used as
// part of a method value.
static Named_object*
create_thunk(Gogo*, Interface_type* type, const std::string& name);
// Return a tree for the pointer to the function to call, given a
// tree for the expression.
tree
......@@ -2046,6 +2075,9 @@ class Interface_field_reference_expression : public Expression
int
do_traverse(Traverse* traverse);
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Type*
do_type();
......@@ -2070,6 +2102,13 @@ class Interface_field_reference_expression : public Expression
do_dump_expression(Ast_dump_context*) const;
private:
// A mapping from interface types to a list of thunks we have
// created for methods.
typedef std::vector<std::pair<std::string, Named_object*> > Method_thunks;
typedef Unordered_map(Interface_type*, Method_thunks*)
Interface_method_thunks;
static Interface_method_thunks interface_method_thunks;
// The expression for the interface object. This should have a type
// of interface or pointer to interface.
Expression* expr_;
......
......@@ -1795,11 +1795,36 @@ Create_function_descriptors::expression(Expression** pexpr)
return TRAVERSE_CONTINUE;
}
Bound_method_expression* bme = expr->bound_method_expression();
if (bme != NULL)
{
// We would not get here for a call to this method, so this is a
// method value. We need to create a thunk.
Bound_method_expression::create_thunk(this->gogo_, bme->method(),
bme->function());
return TRAVERSE_CONTINUE;
}
Interface_field_reference_expression* ifre =
expr->interface_field_reference_expression();
if (ifre != NULL)
{
// We would not get here for a call to this interface method, so
// this is a method value. We need to create a thunk.
Interface_type* type = ifre->expr()->type()->interface_type();
if (type != NULL)
Interface_field_reference_expression::create_thunk(this->gogo_, type,
ifre->name());
return TRAVERSE_CONTINUE;
}
Call_expression* ce = expr->call_expression();
if (ce != NULL)
{
Expression* fn = ce->fn();
if (fn->func_expression() != NULL)
if (fn->func_expression() != NULL
|| fn->bound_method_expression() != NULL
|| fn->interface_field_reference_expression() != NULL)
{
// Traverse the arguments but not the function.
Expression_list* args = ce->args();
......@@ -2806,22 +2831,7 @@ Build_recover_thunks::function(Named_object* orig_no)
// Any varargs call has already been lowered.
call->set_varargs_are_lowered();
Statement* s;
if (orig_fntype->results() == NULL || orig_fntype->results()->empty())
s = Statement::make_statement(call, true);
else
{
Expression_list* vals = new Expression_list();
size_t rc = orig_fntype->results()->size();
if (rc == 1)
vals->push_back(call);
else
{
for (size_t i = 0; i < rc; ++i)
vals->push_back(Expression::make_call_result(call, i));
}
s = Statement::make_return_statement(vals, location);
}
Statement* s = Statement::make_return_from_call(call, location);
s->determine_types();
gogo->add_statement(s);
......@@ -3557,42 +3567,8 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
{
Location loc = no->location();
Typed_identifier_list* new_params = new Typed_identifier_list();
const Typed_identifier_list* orig_params = orig_fntype->parameters();
if (orig_params != NULL && !orig_params->empty())
{
static int count;
char buf[50];
for (Typed_identifier_list::const_iterator p = orig_params->begin();
p != orig_params->end();
++p)
{
snprintf(buf, sizeof buf, "pt.%u", count);
++count;
new_params->push_back(Typed_identifier(buf, p->type(),
p->location()));
}
}
Type* vt = Type::make_pointer_type(Type::make_void_type());
new_params->push_back(Typed_identifier("closure.0", vt, loc));
const Typed_identifier_list* orig_results = orig_fntype->results();
Typed_identifier_list* new_results;
if (orig_results == NULL || orig_results->empty())
new_results = NULL;
else
{
new_results = new Typed_identifier_list();
for (Typed_identifier_list::const_iterator p = orig_results->begin();
p != orig_results->end();
++p)
new_results->push_back(Typed_identifier("", p->type(),
p->location()));
}
Function_type* new_fntype = Type::make_function_type(NULL, new_params,
new_results,
loc);
Function_type* new_fntype = orig_fntype->copy_with_closure(vt);
std::string name = no->name() + "$descriptorfn";
Named_object* dno = gogo->start_function(name, new_fntype, false, loc);
......@@ -3602,13 +3578,16 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
Expression* fn = Expression::make_func_reference(no, NULL, loc);
// Call the wrapper function, passing all of the arguments except
// for the last one (the last argument is the ignored closure).
// Call the function begin wrapped, passing all of the arguments
// except for the last one (the last argument is the ignored
// closure).
const Typed_identifier_list* orig_params = orig_fntype->parameters();
Expression_list* args;
if (orig_params == NULL || orig_params->empty())
args = NULL;
else
{
const Typed_identifier_list* new_params = new_fntype->parameters();
args = new Expression_list();
for (Typed_identifier_list::const_iterator p = new_params->begin();
p + 1 != new_params->end();
......@@ -3627,23 +3606,7 @@ Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
loc);
call->set_varargs_are_lowered();
Statement* s;
if (orig_results == NULL || orig_results->empty())
s = Statement::make_statement(call, true);
else
{
Expression_list* vals = new Expression_list();
size_t rc = orig_results->size();
if (rc == 1)
vals->push_back(call);
else
{
for (size_t i = 0; i < rc; ++i)
vals->push_back(Expression::make_call_result(call, i));
}
s = Statement::make_return_statement(vals, loc);
}
Statement* s = Statement::make_return_from_call(call, loc);
gogo->add_statement(s);
Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc);
......
......@@ -2815,6 +2815,28 @@ Statement::make_return_statement(Expression_list* vals,
return new Return_statement(vals, location);
}
// Make a statement that returns the result of a call expression.
Statement*
Statement::make_return_from_call(Call_expression* call, Location location)
{
size_t rc = call->result_count();
if (rc == 0)
return Statement::make_statement(call, true);
else
{
Expression_list* vals = new Expression_list();
if (rc == 1)
vals->push_back(call);
else
{
for (size_t i = 0; i < rc; ++i)
vals->push_back(Expression::make_call_result(call, i));
}
return Statement::make_return_statement(vals, location);
}
}
// A break or continue statement.
class Bc_statement : public Statement
......
......@@ -207,6 +207,13 @@ class Statement
static Return_statement*
make_return_statement(Expression_list*, Location);
// Make a statement that returns the result of a call expression.
// If the call does not return any results, this just returns the
// call expression as a statement, assuming that the function will
// end immediately afterward.
static Statement*
make_return_from_call(Call_expression*, Location);
// Make a break statement.
static Statement*
make_break_statement(Unnamed_label* label, Location);
......
......@@ -3396,7 +3396,8 @@ Function_type::do_get_backend(Gogo* gogo)
// passed when invoking the function indirectly, via the struct.
Location loc = this->location();
Btype* struct_type = gogo->backend()->placeholder_struct_type("", loc);
Btype* struct_type =
gogo->backend()->placeholder_struct_type("__go_descriptor", loc);
Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type);
Backend::Btyped_identifier breceiver;
......@@ -3835,6 +3836,49 @@ Function_type::copy_with_receiver(Type* receiver_type) const
return ret;
}
// Make a copy of a function type ignoring any receiver and adding a
// closure parameter.
Function_type*
Function_type::copy_with_closure(Type* closure_type) const
{
Typed_identifier_list* new_params = new Typed_identifier_list();
const Typed_identifier_list* orig_params = this->parameters_;
if (orig_params != NULL && !orig_params->empty())
{
static int count;
char buf[50];
for (Typed_identifier_list::const_iterator p = orig_params->begin();
p != orig_params->end();
++p)
{
snprintf(buf, sizeof buf, "pt.%u", count);
++count;
new_params->push_back(Typed_identifier(buf, p->type(),
p->location()));
}
}
new_params->push_back(Typed_identifier("closure.0", closure_type,
this->location_));
const Typed_identifier_list* orig_results = this->results_;
Typed_identifier_list* new_results;
if (orig_results == NULL || orig_results->empty())
new_results = NULL;
else
{
new_results = new Typed_identifier_list();
for (Typed_identifier_list::const_iterator p = orig_results->begin();
p != orig_results->end();
++p)
new_results->push_back(Typed_identifier("", p->type(),
p->location()));
}
return Type::make_function_type(NULL, new_params, new_results,
this->location());
}
// Make a function type.
Function_type*
......@@ -7580,7 +7624,7 @@ Method::bind_method(Expression* expr, Location location) const
// the child class.
return this->do_bind_method(expr, location);
}
return Expression::make_bound_method(expr, this->stub_, location);
return Expression::make_bound_method(expr, this, this->stub_, location);
}
// Return the named object associated with a method. This may only be
......@@ -7623,8 +7667,8 @@ Expression*
Named_method::do_bind_method(Expression* expr, Location location) const
{
Named_object* no = this->named_object_;
Bound_method_expression* bme = Expression::make_bound_method(expr, no,
location);
Bound_method_expression* bme = Expression::make_bound_method(expr, this,
no, location);
// If this is not a local method, and it does not use a stub, then
// the real method expects a different type. We need to cast the
// first argument.
......@@ -9002,28 +9046,16 @@ Type::build_one_stub_method(Gogo* gogo, Method* method,
Call_expression* call = Expression::make_call(func, arguments, is_varargs,
location);
call->set_hidden_fields_are_ok();
size_t count = call->result_count();
if (count == 0)
gogo->add_statement(Statement::make_statement(call, true));
else
{
Expression_list* retvals = new Expression_list();
if (count <= 1)
retvals->push_back(call);
else
{
for (size_t i = 0; i < count; ++i)
retvals->push_back(Expression::make_call_result(call, i));
}
Return_statement* retstat = Statement::make_return_statement(retvals,
location);
Statement* s = Statement::make_return_from_call(call, location);
Return_statement* retstat = s->return_statement();
if (retstat != NULL)
{
// We can return values with hidden fields from a stub. This is
// necessary if the method is itself hidden.
retstat->set_hidden_fields_are_ok();
gogo->add_statement(retstat);
}
gogo->add_statement(s);
}
// Apply FIELD_INDEXES to EXPR. The field indexes have to be applied
......
......@@ -1789,6 +1789,12 @@ class Function_type : public Type
Function_type*
copy_with_receiver(Type*) const;
// Return a copy of this type ignoring any receiver and adding a
// final closure parameter of type CLOSURE_TYPE. This is used when
// creating descriptors.
Function_type*
copy_with_closure(Type* closure_type) const;
static Type*
make_function_type_descriptor_type();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment