Commit 05a7d566 by Ian Lance Taylor

compiler, runtime: Use runtime functions to pass closure value.

This changes the compiler and runtime to not pass a closure
value as the last argument, but to instead pass it via
__go_set_closure and retrieve it via __go_get_closure.  This
eliminates the need for function descriptor wrapper functions.
It will make it possible to retrieve the closure value in a
reflect.MakeFunc function.

From-SVN: r202233
parent 3b18bc42
...@@ -1570,14 +1570,6 @@ class Func_descriptor_expression : public Expression ...@@ -1570,14 +1570,6 @@ class Func_descriptor_expression : public Expression
public: public:
Func_descriptor_expression(Named_object* fn); Func_descriptor_expression(Named_object* fn);
// Set the descriptor wrapper.
void
set_descriptor_wrapper(Named_object* dfn)
{
go_assert(this->dfn_ == NULL);
this->dfn_ = dfn;
}
// Make the function descriptor type, so that it can be converted. // Make the function descriptor type, so that it can be converted.
static void static void
make_func_descriptor_type(); make_func_descriptor_type();
...@@ -1594,7 +1586,8 @@ class Func_descriptor_expression : public Expression ...@@ -1594,7 +1586,8 @@ class Func_descriptor_expression : public Expression
{ } { }
Expression* Expression*
do_copy(); do_copy()
{ return Expression::make_func_descriptor(this->fn_); }
bool bool
do_is_addressable() const do_is_addressable() const
...@@ -1612,8 +1605,6 @@ class Func_descriptor_expression : public Expression ...@@ -1612,8 +1605,6 @@ class Func_descriptor_expression : public Expression
// The function for which this is the descriptor. // The function for which this is the descriptor.
Named_object* fn_; Named_object* fn_;
// The descriptor function.
Named_object* dfn_;
// The descriptor variable. // The descriptor variable.
Bvariable* dvar_; Bvariable* dvar_;
}; };
......
...@@ -1289,30 +1289,6 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) ...@@ -1289,30 +1289,6 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype))); functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype)));
go_assert(FUNCTION_POINTER_TYPE_P(functype)); go_assert(FUNCTION_POINTER_TYPE_P(functype));
functype = TREE_TYPE(functype); functype = TREE_TYPE(functype);
// In the struct, the function type always has a trailing
// closure argument. For the function body, we only use
// that trailing arg if this is a function literal or if it
// is a wrapper created to store in a descriptor. Remove it
// in that case.
if (this->enclosing_ == NULL && !this->is_descriptor_wrapper_)
{
tree old_params = TYPE_ARG_TYPES(functype);
go_assert(old_params != NULL_TREE
&& old_params != void_list_node);
tree new_params = NULL_TREE;
tree *pp = &new_params;
while (TREE_CHAIN (old_params) != void_list_node)
{
tree p = TREE_VALUE(old_params);
go_assert(TYPE_P(p));
*pp = tree_cons(NULL_TREE, p, NULL_TREE);
pp = &TREE_CHAIN(*pp);
old_params = TREE_CHAIN (old_params);
}
*pp = void_list_node;
functype = build_function_type(TREE_TYPE(functype), new_params);
}
} }
if (functype == error_mark_node) if (functype == error_mark_node)
...@@ -1423,26 +1399,6 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) ...@@ -1423,26 +1399,6 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype))); functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype)));
go_assert(FUNCTION_POINTER_TYPE_P(functype)); go_assert(FUNCTION_POINTER_TYPE_P(functype));
functype = TREE_TYPE(functype); functype = TREE_TYPE(functype);
// In the struct, the function type always has a trailing
// closure argument. Here we are referring to the function
// code directly, and we know it is not a function literal,
// and we know it is not a wrapper created to store in a
// descriptor. Remove that trailing argument.
tree old_params = TYPE_ARG_TYPES(functype);
go_assert(old_params != NULL_TREE && old_params != void_list_node);
tree new_params = NULL_TREE;
tree *pp = &new_params;
while (TREE_CHAIN (old_params) != void_list_node)
{
tree p = TREE_VALUE(old_params);
go_assert(TYPE_P(p));
*pp = tree_cons(NULL_TREE, p, NULL_TREE);
pp = &TREE_CHAIN(*pp);
old_params = TREE_CHAIN (old_params);
}
*pp = void_list_node;
functype = build_function_type(TREE_TYPE(functype), new_params);
} }
tree decl; tree decl;
...@@ -1659,8 +1615,13 @@ Function::build_tree(Gogo* gogo, Named_object* named_function) ...@@ -1659,8 +1615,13 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
} }
} }
// The closure variable is passed last, if this is a function *pp = NULL_TREE;
// literal or a descriptor wrapper.
DECL_ARGUMENTS(fndecl) = params;
// If we need a closure variable, fetch it by calling a runtime
// function. The caller will have called __go_set_closure before
// the function call.
if (this->closure_var_ != NULL) if (this->closure_var_ != NULL)
{ {
Bvariable* bvar = Bvariable* bvar =
...@@ -1668,25 +1629,25 @@ Function::build_tree(Gogo* gogo, Named_object* named_function) ...@@ -1668,25 +1629,25 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
tree var_decl = var_to_tree(bvar); tree var_decl = var_to_tree(bvar);
if (var_decl != error_mark_node) if (var_decl != error_mark_node)
{ {
go_assert(TREE_CODE(var_decl) == PARM_DECL); go_assert(TREE_CODE(var_decl) == VAR_DECL);
*pp = var_decl; static tree get_closure_fndecl;
pp = &DECL_CHAIN(*pp); tree get_closure = Gogo::call_builtin(&get_closure_fndecl,
this->location_,
"__go_get_closure",
0,
ptr_type_node);
// Mark the __go_get_closure function as pure, since it
// depends only on the global variable g.
DECL_PURE_P(get_closure_fndecl) = 1;
get_closure = fold_convert_loc(this->location_.gcc_location(),
TREE_TYPE(var_decl), get_closure);
DECL_INITIAL(var_decl) = get_closure;
DECL_CHAIN(var_decl) = declare_vars;
declare_vars = var_decl;
} }
} }
else if (this->enclosing_ != NULL || this->is_descriptor_wrapper_)
{
tree parm_decl = build_decl(this->location_.gcc_location(), PARM_DECL,
get_identifier("$closure"),
const_ptr_type_node);
DECL_CONTEXT(parm_decl) = current_function_decl;
DECL_ARG_TYPE(parm_decl) = const_ptr_type_node;
*pp = parm_decl;
pp = &DECL_CHAIN(*pp);
}
*pp = NULL_TREE;
DECL_ARGUMENTS(fndecl) = params;
if (this->block_ != NULL) if (this->block_ != NULL)
{ {
......
...@@ -1770,8 +1770,8 @@ Create_function_descriptors::function(Named_object* no) ...@@ -1770,8 +1770,8 @@ Create_function_descriptors::function(Named_object* no)
if (no->is_function() if (no->is_function()
&& no->func_value()->enclosing() == NULL && no->func_value()->enclosing() == NULL
&& !no->func_value()->is_method() && !no->func_value()->is_method()
&& !no->func_value()->is_descriptor_wrapper() && !Gogo::is_hidden_name(no->name())
&& !Gogo::is_hidden_name(no->name())) && !Gogo::is_thunk(no))
no->func_value()->descriptor(this->gogo_, no); no->func_value()->descriptor(this->gogo_, no);
return TRAVERSE_CONTINUE; return TRAVERSE_CONTINUE;
...@@ -2541,13 +2541,38 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s) ...@@ -2541,13 +2541,38 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
return TRAVERSE_CONTINUE; return TRAVERSE_CONTINUE;
// If there is only one expression with a side-effect, we can // If there is only one expression with a side-effect, we can
// usually leave it in place. However, for an assignment statement, // usually leave it in place.
// we need to evaluate an expression on the right hand side before if (c == 1)
// we evaluate any index expression on the left hand side, so for {
// that case we always move the expression. Otherwise we mishandle switch (s->classification())
// m[0] = len(m) where m is a map. {
if (c == 1 && s->classification() != Statement::STATEMENT_ASSIGNMENT) case Statement::STATEMENT_ASSIGNMENT:
return TRAVERSE_CONTINUE; // For an assignment statement, we need to evaluate an
// expression on the right hand side before we evaluate any
// index expression on the left hand side, so for that case
// we always move the expression. Otherwise we mishandle
// m[0] = len(m) where m is a map.
break;
case Statement::STATEMENT_EXPRESSION:
{
// If this is a call statement that doesn't return any
// values, it will not have been counted as a value to
// move. We need to move any subexpressions in case they
// are themselves call statements that require passing a
// closure.
Expression* expr = s->expression_statement()->expr();
if (expr->call_expression() != NULL
&& expr->call_expression()->result_count() == 0)
break;
return TRAVERSE_CONTINUE;
}
default:
// We can leave the expression in place.
return TRAVERSE_CONTINUE;
}
}
bool is_thunk = s->thunk_statement() != NULL; bool is_thunk = s->thunk_statement() != NULL;
for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin(); for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin();
...@@ -2803,7 +2828,7 @@ Build_recover_thunks::function(Named_object* orig_no) ...@@ -2803,7 +2828,7 @@ Build_recover_thunks::function(Named_object* orig_no)
Named_object* orig_closure_no = orig_func->closure_var(); Named_object* orig_closure_no = orig_func->closure_var();
Variable* orig_closure_var = orig_closure_no->var_value(); Variable* orig_closure_var = orig_closure_no->var_value();
Variable* new_var = new Variable(orig_closure_var->type(), NULL, false, Variable* new_var = new Variable(orig_closure_var->type(), NULL, false,
true, false, location); false, false, location);
snprintf(buf, sizeof buf, "closure.%u", count); snprintf(buf, sizeof buf, "closure.%u", count);
++count; ++count;
Named_object* new_closure_no = Named_object::make_variable(buf, NULL, Named_object* new_closure_no = Named_object::make_variable(buf, NULL,
...@@ -3275,7 +3300,7 @@ Function::Function(Function_type* type, Function* enclosing, Block* block, ...@@ -3275,7 +3300,7 @@ Function::Function(Function_type* type, Function* enclosing, Block* block,
local_type_count_(0), descriptor_(NULL), fndecl_(NULL), defer_stack_(NULL), local_type_count_(0), descriptor_(NULL), fndecl_(NULL), defer_stack_(NULL),
is_sink_(false), results_are_named_(false), nointerface_(false), is_sink_(false), results_are_named_(false), nointerface_(false),
calls_recover_(false), is_recover_thunk_(false), has_recover_thunk_(false), calls_recover_(false), is_recover_thunk_(false), has_recover_thunk_(false),
in_unique_section_(false), is_descriptor_wrapper_(false) in_unique_section_(false)
{ {
} }
...@@ -3357,9 +3382,9 @@ Function::closure_var() ...@@ -3357,9 +3382,9 @@ Function::closure_var()
Struct_field_list* sfl = new Struct_field_list; Struct_field_list* sfl = new Struct_field_list;
Type* struct_type = Type::make_struct_type(sfl, loc); Type* struct_type = Type::make_struct_type(sfl, loc);
Variable* var = new Variable(Type::make_pointer_type(struct_type), Variable* var = new Variable(Type::make_pointer_type(struct_type),
NULL, false, true, false, loc); NULL, false, false, false, loc);
var->set_is_used(); var->set_is_used();
this->closure_var_ = Named_object::make_variable("closure", NULL, var); this->closure_var_ = Named_object::make_variable("$closure", NULL, var);
// Note that the new variable is not in any binding contour. // Note that the new variable is not in any binding contour.
} }
return this->closure_var_; return this->closure_var_;
...@@ -3562,99 +3587,16 @@ Function::determine_types() ...@@ -3562,99 +3587,16 @@ Function::determine_types()
this->block_->determine_types(); this->block_->determine_types();
} }
// Build a wrapper function for a function descriptor. A function
// descriptor refers to a function that takes a closure as its last
// argument. In this case there will be no closure, but an indirect
// call will pass nil as the last argument. We need to build a
// wrapper function that accepts and discards that last argument, so
// that cases like -mrtd will work correctly. In most cases the
// wrapper function will simply be a jump.
Named_object*
Function::make_descriptor_wrapper(Gogo* gogo, Named_object* no,
Function_type* orig_fntype)
{
Location loc = no->location();
Type* vt = Type::make_pointer_type(Type::make_void_type());
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);
dno->func_value()->is_descriptor_wrapper_ = true;
// Put the wrapper in a unique section so that it can be discarded
// by the linker if it is not needed. Every top-level function will
// get a wrapper, in case there is a reference other than a call
// from some other package, but most will not need one.
dno->func_value()->set_in_unique_section();
gogo->start_block(loc);
Expression* fn = Expression::make_func_reference(no, NULL, loc);
// 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();
++p)
{
Named_object* p_no = gogo->lookup(p->name(), NULL);
go_assert(p_no != NULL
&& p_no->is_variable()
&& p_no->var_value()->is_parameter());
args->push_back(Expression::make_var_reference(p_no, loc));
}
}
Call_expression* call = Expression::make_call(fn, args,
orig_fntype->is_varargs(),
loc);
call->set_varargs_are_lowered();
Statement* s = Statement::make_return_from_call(call, loc);
gogo->add_statement(s);
Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc);
gogo->lower_block(dno, b);
gogo->finish_function(loc);
return dno;
}
// Return the function descriptor, the value you get when you refer to // Return the function descriptor, the value you get when you refer to
// the function in Go code without calling it. // the function in Go code without calling it.
Expression* Expression*
Function::descriptor(Gogo* gogo, Named_object* no) Function::descriptor(Gogo*, Named_object* no)
{ {
go_assert(!this->is_method()); go_assert(!this->is_method());
go_assert(this->closure_var_ == NULL); go_assert(this->closure_var_ == NULL);
go_assert(!this->is_descriptor_wrapper_);
if (this->descriptor_ == NULL) if (this->descriptor_ == NULL)
{ this->descriptor_ = Expression::make_func_descriptor(no);
// Make and record the descriptor first, so that when we lower
// the descriptor wrapper we don't try to make it again.
Func_descriptor_expression* descriptor =
Expression::make_func_descriptor(no);
this->descriptor_ = descriptor;
if (no->package() == NULL
&& !Linemap::is_predeclared_location(no->location()))
{
Named_object* dno = Function::make_descriptor_wrapper(gogo, no,
this->type_);
descriptor->set_descriptor_wrapper(dno);
}
}
return this->descriptor_; return this->descriptor_;
} }
...@@ -4193,24 +4135,11 @@ Bindings_snapshot::check_goto_defs(Location loc, const Block* block, ...@@ -4193,24 +4135,11 @@ Bindings_snapshot::check_goto_defs(Location loc, const Block* block,
// Return the function descriptor. // Return the function descriptor.
Expression* Expression*
Function_declaration::descriptor(Gogo* gogo, Named_object* no) Function_declaration::descriptor(Gogo*, Named_object* no)
{ {
go_assert(!this->fntype_->is_method()); go_assert(!this->fntype_->is_method());
if (this->descriptor_ == NULL) if (this->descriptor_ == NULL)
{ this->descriptor_ = Expression::make_func_descriptor(no);
// Make and record the descriptor first, so that when we lower
// the descriptor wrapper we don't try to make it again.
Func_descriptor_expression* descriptor =
Expression::make_func_descriptor(no);
this->descriptor_ = descriptor;
if (no->package() == NULL
&& !Linemap::is_predeclared_location(no->location()))
{
Named_object* dno = Function::make_descriptor_wrapper(gogo, no,
this->fntype_);
descriptor->set_descriptor_wrapper(dno);
}
}
return this->descriptor_; return this->descriptor_;
} }
......
...@@ -1050,12 +1050,6 @@ class Function ...@@ -1050,12 +1050,6 @@ class Function
set_in_unique_section() set_in_unique_section()
{ this->in_unique_section_ = true; } { this->in_unique_section_ = true; }
// Whether this function was created as a descriptor wrapper for
// another function.
bool
is_descriptor_wrapper() const
{ return this->is_descriptor_wrapper_; }
// Swap with another function. Used only for the thunk which calls // Swap with another function. Used only for the thunk which calls
// recover. // recover.
void void
...@@ -1085,10 +1079,6 @@ class Function ...@@ -1085,10 +1079,6 @@ class Function
this->descriptor_ = descriptor; this->descriptor_ = descriptor;
} }
// Build a descriptor wrapper function.
static Named_object*
make_descriptor_wrapper(Gogo*, Named_object*, Function_type*);
// Return the function's decl given an identifier. // Return the function's decl given an identifier.
tree tree
get_or_make_decl(Gogo*, Named_object*, tree id); get_or_make_decl(Gogo*, Named_object*, tree id);
...@@ -1190,9 +1180,6 @@ class Function ...@@ -1190,9 +1180,6 @@ class Function
// True if this function should be put in a unique section. This is // True if this function should be put in a unique section. This is
// turned on for field tracking. // turned on for field tracking.
bool in_unique_section_ : 1; bool in_unique_section_ : 1;
// True if this is a function wrapper created to put in a function
// descriptor.
bool is_descriptor_wrapper_ : 1;
}; };
// A snapshot of the current binding state. // A snapshot of the current binding state.
......
...@@ -1658,46 +1658,23 @@ Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok, ...@@ -1658,46 +1658,23 @@ Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
location); location);
} }
// An expression statement. // Class Expression_statement.
class Expression_statement : public Statement // Constructor.
{
public:
Expression_statement(Expression* expr, bool is_ignored)
: Statement(STATEMENT_EXPRESSION, expr->location()),
expr_(expr), is_ignored_(is_ignored)
{ }
Expression*
expr()
{ return this->expr_; }
protected:
int
do_traverse(Traverse* traverse)
{ return this->traverse_expression(traverse, &this->expr_); }
void
do_determine_types()
{ this->expr_->determine_type_no_context(); }
void
do_check_types(Gogo*);
bool
do_may_fall_through() const;
Bstatement* Expression_statement::Expression_statement(Expression* expr, bool is_ignored)
do_get_backend(Translate_context* context); : Statement(STATEMENT_EXPRESSION, expr->location()),
expr_(expr), is_ignored_(is_ignored)
{
}
void // Determine types.
do_dump_statement(Ast_dump_context*) const;
private: void
Expression* expr_; Expression_statement::do_determine_types()
// Whether the value of this expression is being explicitly ignored. {
bool is_ignored_; this->expr_->determine_type_no_context();
}; }
// Check the types of an expression statement. The only check we do // Check the types of an expression statement. The only check we do
// is to possibly give an error about discarding the value of the // is to possibly give an error about discarding the value of the
......
...@@ -17,6 +17,7 @@ class Function; ...@@ -17,6 +17,7 @@ class Function;
class Unnamed_label; class Unnamed_label;
class Temporary_statement; class Temporary_statement;
class Variable_declaration_statement; class Variable_declaration_statement;
class Expression_statement;
class Return_statement; class Return_statement;
class Thunk_statement; class Thunk_statement;
class Label_statement; class Label_statement;
...@@ -329,6 +330,14 @@ class Statement ...@@ -329,6 +330,14 @@ class Statement
STATEMENT_VARIABLE_DECLARATION>(); STATEMENT_VARIABLE_DECLARATION>();
} }
// If this is an expression statement, return it. Otherwise return
// NULL.
Expression_statement*
expression_statement()
{
return this->convert<Expression_statement, STATEMENT_EXPRESSION>();
}
// If this is a return statement, return it. Otherwise return NULL. // If this is a return statement, return it. Otherwise return NULL.
Return_statement* Return_statement*
return_statement() return_statement()
...@@ -636,6 +645,43 @@ class Return_statement : public Statement ...@@ -636,6 +645,43 @@ class Return_statement : public Statement
bool is_lowered_; bool is_lowered_;
}; };
// An expression statement.
class Expression_statement : public Statement
{
public:
Expression_statement(Expression* expr, bool is_ignored);
Expression*
expr()
{ return this->expr_; }
protected:
int
do_traverse(Traverse* traverse)
{ return this->traverse_expression(traverse, &this->expr_); }
void
do_determine_types();
void
do_check_types(Gogo*);
bool
do_may_fall_through() const;
Bstatement*
do_get_backend(Translate_context* context);
void
do_dump_statement(Ast_dump_context*) const;
private:
Expression* expr_;
// Whether the value of this expression is being explicitly ignored.
bool is_ignored_;
};
// A send statement. // A send statement.
class Send_statement : public Statement class Send_statement : public Statement
......
...@@ -3390,10 +3390,7 @@ Function_type::do_get_backend(Gogo* gogo) ...@@ -3390,10 +3390,7 @@ Function_type::do_get_backend(Gogo* gogo)
// When we do anything with a function value other than call it, it // When we do anything with a function value other than call it, it
// is represented as a pointer to a struct whose first field is the // is represented as a pointer to a struct whose first field is the
// actual function. So that is what we return as the type of a Go // actual function. So that is what we return as the type of a Go
// function. The function stored in the first field always that // function.
// takes one additional trailing argument: the closure pointer. For
// a top-level function, this additional argument will only be
// passed when invoking the function indirectly, via the struct.
Location loc = this->location(); Location loc = this->location();
Btype* struct_type = Btype* struct_type =
...@@ -3415,15 +3412,9 @@ Function_type::do_get_backend(Gogo* gogo) ...@@ -3415,15 +3412,9 @@ Function_type::do_get_backend(Gogo* gogo)
} }
std::vector<Backend::Btyped_identifier> bparameters; std::vector<Backend::Btyped_identifier> bparameters;
size_t last; if (this->parameters_ != NULL)
if (this->parameters_ == NULL)
{
bparameters.resize(1);
last = 0;
}
else
{ {
bparameters.resize(this->parameters_->size() + 1); bparameters.resize(this->parameters_->size());
size_t i = 0; size_t i = 0;
for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
p != this->parameters_->end(); p != this->parameters_->end();
...@@ -3433,12 +3424,8 @@ Function_type::do_get_backend(Gogo* gogo) ...@@ -3433,12 +3424,8 @@ Function_type::do_get_backend(Gogo* gogo)
bparameters[i].btype = p->type()->get_backend(gogo); bparameters[i].btype = p->type()->get_backend(gogo);
bparameters[i].location = p->location(); bparameters[i].location = p->location();
} }
last = i; go_assert(i == bparameters.size());
} }
go_assert(last + 1 == bparameters.size());
bparameters[last].name = "$closure";
bparameters[last].btype = ptr_struct_type;
bparameters[last].location = loc;
std::vector<Backend::Btyped_identifier> bresults; std::vector<Backend::Btyped_identifier> bresults;
if (this->results_ != NULL) if (this->results_ != NULL)
...@@ -3840,7 +3827,7 @@ Function_type::copy_with_receiver(Type* receiver_type) const ...@@ -3840,7 +3827,7 @@ Function_type::copy_with_receiver(Type* receiver_type) const
// closure parameter. // closure parameter.
Function_type* Function_type*
Function_type::copy_with_closure(Type* closure_type) const Function_type::copy_with_names() const
{ {
Typed_identifier_list* new_params = new Typed_identifier_list(); Typed_identifier_list* new_params = new Typed_identifier_list();
const Typed_identifier_list* orig_params = this->parameters_; const Typed_identifier_list* orig_params = this->parameters_;
...@@ -3858,8 +3845,6 @@ Function_type::copy_with_closure(Type* closure_type) const ...@@ -3858,8 +3845,6 @@ Function_type::copy_with_closure(Type* closure_type) const
p->location())); p->location()));
} }
} }
new_params->push_back(Typed_identifier("closure.0", closure_type,
this->location_));
const Typed_identifier_list* orig_results = this->results_; const Typed_identifier_list* orig_results = this->results_;
Typed_identifier_list* new_results; Typed_identifier_list* new_results;
......
...@@ -1789,11 +1789,11 @@ class Function_type : public Type ...@@ -1789,11 +1789,11 @@ class Function_type : public Type
Function_type* Function_type*
copy_with_receiver(Type*) const; copy_with_receiver(Type*) const;
// Return a copy of this type ignoring any receiver and adding a // Return a copy of this type ignoring any receiver and using dummy
// final closure parameter of type CLOSURE_TYPE. This is used when // names for all parameters. This is used for thunks for method
// creating descriptors. // values.
Function_type* Function_type*
copy_with_closure(Type* closure_type) const; copy_with_names() const;
static Type* static Type*
make_function_type_descriptor_type(); make_function_type_descriptor_type();
......
...@@ -434,9 +434,6 @@ func (v Value) call(op string, in []Value) []Value { ...@@ -434,9 +434,6 @@ func (v Value) call(op string, in []Value) []Value {
nin++ nin++
} }
firstPointer := len(in) > 0 && Kind(t.In(0).(*rtype).kind) != Ptr && v.flag&flagMethod == 0 && isMethod(v.typ) firstPointer := len(in) > 0 && Kind(t.In(0).(*rtype).kind) != Ptr && v.flag&flagMethod == 0 && isMethod(v.typ)
if v.flag&flagMethod == 0 && !firstPointer {
nin++
}
params := make([]unsafe.Pointer, nin) params := make([]unsafe.Pointer, nin)
off := 0 off := 0
if v.flag&flagMethod != 0 { if v.flag&flagMethod != 0 {
...@@ -464,10 +461,6 @@ func (v Value) call(op string, in []Value) []Value { ...@@ -464,10 +461,6 @@ func (v Value) call(op string, in []Value) []Value {
} }
off++ off++
} }
if v.flag&flagMethod == 0 && !firstPointer {
// Closure argument.
params[off] = unsafe.Pointer(&fn)
}
ret := make([]Value, nout) ret := make([]Value, nout)
results := make([]unsafe.Pointer, nout) results := make([]unsafe.Pointer, nout)
......
...@@ -302,9 +302,7 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface, ...@@ -302,9 +302,7 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
in_types = ((const struct __go_type_descriptor **) in_types = ((const struct __go_type_descriptor **)
func->__in.__values); func->__in.__values);
num_args = (num_params num_args = num_params + (is_interface ? 1 : 0);
+ (is_interface ? 1 : 0)
+ (!is_interface && !is_method ? 1 : 0));
args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *)); args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
i = 0; i = 0;
off = 0; off = 0;
...@@ -321,12 +319,6 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface, ...@@ -321,12 +319,6 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
for (; i < num_params; ++i) for (; i < num_params; ++i)
args[i + off] = go_type_to_ffi (in_types[i]); args[i + off] = go_type_to_ffi (in_types[i]);
if (!is_interface && !is_method)
{
// There is a closure argument, a pointer.
args[i + off] = &ffi_type_pointer;
}
rettype = go_func_return_ffi (func); rettype = go_func_return_ffi (func);
status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args); status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
...@@ -511,9 +503,8 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result, ...@@ -511,9 +503,8 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result,
regardless of FUNC_TYPE, it is passed as a pointer. regardless of FUNC_TYPE, it is passed as a pointer.
If neither IS_INTERFACE nor IS_METHOD is true then we are calling a If neither IS_INTERFACE nor IS_METHOD is true then we are calling a
function indirectly, and the caller is responsible for passing a function indirectly, and we must pass a closure pointer via
trailing closure argument, a pointer, which is not described in __go_set_closure. The pointer to pass is simply FUNC_VAL. */
FUNC_TYPE. */
void void
reflect_call (const struct __go_func_type *func_type, FuncVal *func_val, reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
...@@ -528,6 +519,8 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val, ...@@ -528,6 +519,8 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
call_result = (unsigned char *) malloc (go_results_size (func_type)); call_result = (unsigned char *) malloc (go_results_size (func_type));
if (!is_interface && !is_method)
__go_set_closure (func_val);
ffi_call (&cif, func_val->fn, call_result, params); ffi_call (&cif, func_val->fn, call_result, params);
/* Some day we may need to free result values if RESULTS is /* Some day we may need to free result values if RESULTS is
......
...@@ -2263,12 +2263,11 @@ runfinq(void* dummy __attribute__ ((unused))) ...@@ -2263,12 +2263,11 @@ runfinq(void* dummy __attribute__ ((unused)))
for(; fb; fb=next) { for(; fb; fb=next) {
next = fb->next; next = fb->next;
for(i=0; i<(uint32)fb->cnt; i++) { for(i=0; i<(uint32)fb->cnt; i++) {
void *params[2]; void *param;
f = &fb->fin[i]; f = &fb->fin[i];
params[0] = &f->arg; param = &f->arg;
params[1] = f; reflect_call(f->ft, f->fn, 0, 0, &param, nil);
reflect_call(f->ft, f->fn, 0, 0, params, nil);
f->fn = nil; f->fn = nil;
f->arg = nil; f->arg = nil;
} }
......
...@@ -2832,3 +2832,23 @@ runtime_proc_scan(void (*addroot)(Obj)) ...@@ -2832,3 +2832,23 @@ runtime_proc_scan(void (*addroot)(Obj))
{ {
addroot((Obj){(byte*)&runtime_sched, sizeof runtime_sched, 0}); addroot((Obj){(byte*)&runtime_sched, sizeof runtime_sched, 0});
} }
// When a function calls a closure, it passes the closure value to
// __go_set_closure immediately before the function call. When a
// function uses a closure, it calls __go_get_closure immediately on
// function entry. This is a hack, but it will work on any system.
// It would be better to use the static chain register when there is
// one. It is also worth considering expanding these functions
// directly in the compiler.
void
__go_set_closure(void* v)
{
g->closure = v;
}
void *
__go_get_closure(void)
{
return g->closure;
}
...@@ -190,6 +190,7 @@ struct Location ...@@ -190,6 +190,7 @@ struct Location
struct G struct G
{ {
void* closure; // Closure value.
Defer* defer; Defer* defer;
Panic* panic; Panic* panic;
void* exception; // current exception being thrown void* exception; // current exception being thrown
...@@ -759,3 +760,6 @@ extern void runtime_main(void*); ...@@ -759,3 +760,6 @@ extern void runtime_main(void*);
int32 getproccount(void); int32 getproccount(void);
#define PREFETCH(p) __builtin_prefetch(p) #define PREFETCH(p) __builtin_prefetch(p)
void __go_set_closure(void*);
void* __go_get_closure(void);
...@@ -46,10 +46,9 @@ static void siftdown(int32); ...@@ -46,10 +46,9 @@ static void siftdown(int32);
// Ready the goroutine e.data. // Ready the goroutine e.data.
static void static void
ready(int64 now, Eface e, void *closure) ready(int64 now, Eface e)
{ {
USED(now); USED(now);
USED(closure);
runtime_ready(e.__object); runtime_ready(e.__object);
} }
...@@ -166,7 +165,7 @@ timerproc(void* dummy __attribute__ ((unused))) ...@@ -166,7 +165,7 @@ timerproc(void* dummy __attribute__ ((unused)))
{ {
int64 delta, now; int64 delta, now;
Timer *t; Timer *t;
void (*f)(int64, Eface, void *); void (*f)(int64, Eface);
Eface arg; Eface arg;
for(;;) { for(;;) {
...@@ -197,7 +196,8 @@ timerproc(void* dummy __attribute__ ((unused))) ...@@ -197,7 +196,8 @@ timerproc(void* dummy __attribute__ ((unused)))
runtime_unlock(&timers); runtime_unlock(&timers);
if(raceenabled) if(raceenabled)
runtime_raceacquire(t); runtime_raceacquire(t);
f(now, arg, &t->fv); __go_set_closure(t->fv);
f(now, arg);
runtime_lock(&timers); runtime_lock(&timers);
} }
if(delta < 0) { if(delta < 0) {
......
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