summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-09-03 21:52:37 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-09-03 21:52:37 +0000
commitf8bdf81a026b110398982d31e55f3313ca2e4eb9 (patch)
tree5f956e4c89959ef335ef73b7ec6e00e4bc2c12d5
parent631d940c80b318d435d498744950dc1eeacafeaa (diff)
downloadgcc-f8bdf81a026b110398982d31e55f3313ca2e4eb9.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202233 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/go/gofrontend/expressions.cc121
-rw-r--r--gcc/go/gofrontend/expressions.h13
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc87
-rw-r--r--gcc/go/gofrontend/gogo.cc155
-rw-r--r--gcc/go/gofrontend/gogo.h13
-rw-r--r--gcc/go/gofrontend/statements.cc49
-rw-r--r--gcc/go/gofrontend/statements.h46
-rw-r--r--gcc/go/gofrontend/types.cc25
-rw-r--r--gcc/go/gofrontend/types.h8
-rw-r--r--libgo/go/reflect/value.go7
-rw-r--r--libgo/runtime/go-reflect-call.c17
-rw-r--r--libgo/runtime/mgc0.c7
-rw-r--r--libgo/runtime/proc.c20
-rw-r--r--libgo/runtime/runtime.h4
-rw-r--r--libgo/runtime/time.goc8
15 files changed, 237 insertions, 343 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 2b60d90a5dc..78a427398c2 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -1382,7 +1382,7 @@ Expression::make_func_reference(Named_object* function, Expression* closure,
Func_descriptor_expression::Func_descriptor_expression(Named_object* fn)
: Expression(EXPRESSION_FUNC_DESCRIPTOR, fn->location()),
- fn_(fn), dfn_(NULL), dvar_(NULL)
+ fn_(fn), dvar_(NULL)
{
go_assert(!fn->is_function() || !fn->func_value()->needs_closure());
}
@@ -1417,18 +1417,6 @@ Func_descriptor_expression::do_type()
return Func_descriptor_expression::descriptor_type;
}
-// Copy a Func_descriptor_expression;
-
-Expression*
-Func_descriptor_expression::do_copy()
-{
- Func_descriptor_expression* fde =
- Expression::make_func_descriptor(this->fn_);
- if (this->dfn_ != NULL)
- fde->set_descriptor_wrapper(this->dfn_);
- return fde;
-}
-
// The tree for a function descriptor.
tree
@@ -1455,11 +1443,8 @@ Func_descriptor_expression::do_get_tree(Translate_context* context)
Bvariable* bvar;
if (no->package() != NULL
|| Linemap::is_predeclared_location(no->location()))
- {
- bvar = context->backend()->immutable_struct_reference(var_name, btype,
- loc);
- go_assert(this->dfn_ == NULL);
- }
+ bvar = context->backend()->immutable_struct_reference(var_name, btype,
+ loc);
else
{
Location bloc = Linemap::predeclared_location();
@@ -1469,8 +1454,7 @@ Func_descriptor_expression::do_get_tree(Translate_context* context)
bvar = context->backend()->immutable_struct(var_name, is_hidden, false,
btype, bloc);
Expression_list* vals = new Expression_list();
- go_assert(this->dfn_ != NULL);
- vals->push_back(Expression::make_func_code_reference(this->dfn_, bloc));
+ vals->push_back(Expression::make_func_code_reference(this->fn_, bloc));
Expression* init =
Expression::make_struct_composite_literal(this->type(), vals, bloc);
Translate_context bcontext(gogo, NULL, NULL, NULL);
@@ -6792,8 +6776,8 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
}
Struct_field_list* sfl = new Struct_field_list();
- // The type here is wrong--it should be new_fntype. But we don't
- // have new_fntype yet, and it doesn't really matter.
+ // The type here is wrong--it should be the C function type. But it
+ // doesn't really matter.
Type* vt = Type::make_pointer_type(Type::make_void_type());
sfl->push_back(Struct_field(Typed_identifier("fn.0", vt, loc)));
sfl->push_back(Struct_field(Typed_identifier("val.1",
@@ -6802,17 +6786,17 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
Type* closure_type = Type::make_struct_type(sfl, loc);
closure_type = Type::make_pointer_type(closure_type);
- Function_type* new_fntype = orig_fntype->copy_with_closure(closure_type);
+ Function_type* new_fntype = orig_fntype->copy_with_names();
Named_object* new_no = gogo->start_function(Gogo::thunk_name(), new_fntype,
false, loc);
- gogo->start_block(loc);
+ Variable* cvar = new Variable(closure_type, NULL, false, false, false, loc);
+ cvar->set_is_used();
+ Named_object* cp = Named_object::make_variable("$closure", NULL, cvar);
+ new_no->func_value()->set_closure_var(cp);
- Named_object* cp = gogo->lookup("closure.0", NULL);
- go_assert(cp != NULL
- && cp->is_variable()
- && cp->var_value()->is_parameter());
+ gogo->start_block(loc);
// Field 0 of the closure is the function code pointer, field 1 is
// the value on which to invoke the method.
@@ -6831,7 +6815,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
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 != new_params->end();
++p)
{
Named_object* p_no = gogo->lookup(p->name(), NULL);
@@ -9729,21 +9713,21 @@ Call_expression::do_get_tree(Translate_context* context)
const bool has_closure = func != NULL && func->closure() != NULL;
const bool is_interface_method = interface_method != NULL;
- int closure_arg;
+ bool has_closure_arg;
if (has_closure)
- closure_arg = 1;
+ has_closure_arg = true;
else if (func != NULL)
- closure_arg = 0;
+ has_closure_arg = false;
else if (is_interface_method)
- closure_arg = 0;
+ has_closure_arg = false;
else
- closure_arg = 1;
+ has_closure_arg = true;
int nargs;
tree* args;
if (this->args_ == NULL || this->args_->empty())
{
- nargs = (is_interface_method ? 1 : 0) + closure_arg;
+ nargs = is_interface_method ? 1 : 0;
args = nargs == 0 ? NULL : new tree[nargs];
}
else if (fntype->parameters() == NULL || fntype->parameters()->empty())
@@ -9752,7 +9736,7 @@ Call_expression::do_get_tree(Translate_context* context)
go_assert(!is_interface_method
&& fntype->is_method()
&& this->args_->size() == 1);
- nargs = 1 + closure_arg;
+ nargs = 1;
args = new tree[nargs];
args[0] = this->args_->front()->get_tree(context);
}
@@ -9763,7 +9747,6 @@ Call_expression::do_get_tree(Translate_context* context)
nargs = this->args_->size();
int i = is_interface_method ? 1 : 0;
nargs += i;
- nargs += closure_arg;
args = new tree[nargs];
Typed_identifier_list::const_iterator pp = params->begin();
@@ -9787,7 +9770,7 @@ Call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
go_assert(pp == params->end());
- go_assert(i + closure_arg == nargs);
+ go_assert(i == nargs);
}
tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
@@ -9806,21 +9789,23 @@ Call_expression::do_get_tree(Translate_context* context)
return error_mark_node;
tree fn;
+ tree closure_tree;
if (func != NULL)
{
Named_object* no = func->named_object();
- go_assert(!no->is_function()
- || !no->func_value()->is_descriptor_wrapper());
fn = Func_expression::get_code_pointer(gogo, no, location);
- if (has_closure)
+ if (!has_closure)
+ closure_tree = NULL_TREE;
+ else
{
- go_assert(closure_arg == 1 && nargs > 0);
- args[nargs - 1] = func->closure()->get_tree(context);
+ closure_tree = func->closure()->get_tree(context);
+ if (closure_tree == error_mark_node)
+ return error_mark_node;
}
}
else if (!is_interface_method)
{
- tree closure_tree = this->fn_->get_tree(context);
+ closure_tree = this->fn_->get_tree(context);
if (closure_tree == error_mark_node)
return error_mark_node;
tree fnc = fold_convert_loc(location.gcc_location(), fntype_tree,
@@ -9834,8 +9819,6 @@ Call_expression::do_get_tree(Translate_context* context)
build_fold_indirect_ref_loc(location.gcc_location(),
fnc),
field, NULL_TREE);
- go_assert(closure_arg == 1 && nargs > 0);
- args[nargs - 1] = closure_tree;
}
else
{
@@ -9843,7 +9826,7 @@ Call_expression::do_get_tree(Translate_context* context)
&args[0]);
if (fn == error_mark_node)
return error_mark_node;
- go_assert(closure_arg == 0);
+ closure_tree = NULL_TREE;
}
if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
@@ -9894,6 +9877,32 @@ Call_expression::do_get_tree(Translate_context* context)
if (func == NULL)
fn = save_expr(fn);
+ if (!has_closure_arg)
+ go_assert(closure_tree == NULL_TREE);
+ else
+ {
+ // Pass the closure argument by calling the function function
+ // __go_set_closure. In the order_evaluations pass we have
+ // ensured that if any parameters contain call expressions, they
+ // will have been moved out to temporary variables.
+
+ go_assert(closure_tree != NULL_TREE);
+ closure_tree = fold_convert_loc(location.gcc_location(), ptr_type_node,
+ closure_tree);
+ static tree set_closure_fndecl;
+ tree set_closure = Gogo::call_builtin(&set_closure_fndecl,
+ location,
+ "__go_set_closure",
+ 1,
+ void_type_node,
+ ptr_type_node,
+ closure_tree);
+ if (set_closure == error_mark_node)
+ return error_mark_node;
+ fn = build2_loc(location.gcc_location(), COMPOUND_EXPR,
+ TREE_TYPE(fn), set_closure, fn);
+ }
+
tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
fn, nargs, args);
delete[] args;
@@ -11609,25 +11618,25 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
return Named_object::make_erroneous_name(Gogo::thunk_name());
Struct_field_list* sfl = new Struct_field_list();
- // The type here is wrong--it should be new_fntype. But we don't
- // have new_fntype yet, and it doesn't really matter.
+ // The type here is wrong--it should be the C function type. But it
+ // doesn't really matter.
Type* vt = Type::make_pointer_type(Type::make_void_type());
sfl->push_back(Struct_field(Typed_identifier("fn.0", vt, loc)));
sfl->push_back(Struct_field(Typed_identifier("val.1", type, loc)));
Type* closure_type = Type::make_struct_type(sfl, loc);
closure_type = Type::make_pointer_type(closure_type);
- Function_type* new_fntype = orig_fntype->copy_with_closure(closure_type);
+ Function_type* new_fntype = orig_fntype->copy_with_names();
Named_object* new_no = gogo->start_function(Gogo::thunk_name(), new_fntype,
false, loc);
- gogo->start_block(loc);
+ Variable* cvar = new Variable(closure_type, NULL, false, false, false, loc);
+ cvar->set_is_used();
+ Named_object* cp = Named_object::make_variable("$closure", NULL, cvar);
+ new_no->func_value()->set_closure_var(cp);
- Named_object* cp = gogo->lookup("closure.0", NULL);
- go_assert(cp != NULL
- && cp->is_variable()
- && cp->var_value()->is_parameter());
+ gogo->start_block(loc);
// Field 0 of the closure is the function code pointer, field 1 is
// the value on which to invoke the method.
@@ -11647,7 +11656,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
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 != new_params->end();
++p)
{
Named_object* p_no = gogo->lookup(p->name(), NULL);
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 67a4bb985e6..95584f2748b 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -1570,14 +1570,6 @@ class Func_descriptor_expression : public Expression
public:
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.
static void
make_func_descriptor_type();
@@ -1594,7 +1586,8 @@ class Func_descriptor_expression : public Expression
{ }
Expression*
- do_copy();
+ do_copy()
+ { return Expression::make_func_descriptor(this->fn_); }
bool
do_is_addressable() const
@@ -1612,8 +1605,6 @@ class Func_descriptor_expression : public Expression
// The function for which this is the descriptor.
Named_object* fn_;
- // The descriptor function.
- Named_object* dfn_;
// The descriptor variable.
Bvariable* dvar_;
};
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index a1fe5fec7ca..69797f93342 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -1289,30 +1289,6 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype)));
go_assert(FUNCTION_POINTER_TYPE_P(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)
@@ -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)));
go_assert(FUNCTION_POINTER_TYPE_P(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;
@@ -1659,8 +1615,13 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
}
}
- // The closure variable is passed last, if this is a function
- // literal or a descriptor wrapper.
+ *pp = NULL_TREE;
+
+ 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)
{
Bvariable* bvar =
@@ -1668,25 +1629,25 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
tree var_decl = var_to_tree(bvar);
if (var_decl != error_mark_node)
{
- go_assert(TREE_CODE(var_decl) == PARM_DECL);
- *pp = var_decl;
- pp = &DECL_CHAIN(*pp);
+ go_assert(TREE_CODE(var_decl) == VAR_DECL);
+ static tree get_closure_fndecl;
+ 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)
{
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 4e5bd447831..be8ec5939f3 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -1770,8 +1770,8 @@ Create_function_descriptors::function(Named_object* no)
if (no->is_function()
&& no->func_value()->enclosing() == NULL
&& !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);
return TRAVERSE_CONTINUE;
@@ -2541,13 +2541,38 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
return TRAVERSE_CONTINUE;
// If there is only one expression with a side-effect, we can
- // usually leave it in place. However, 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.
- if (c == 1 && s->classification() != Statement::STATEMENT_ASSIGNMENT)
- return TRAVERSE_CONTINUE;
+ // usually leave it in place.
+ if (c == 1)
+ {
+ switch (s->classification())
+ {
+ case Statement::STATEMENT_ASSIGNMENT:
+ // 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;
for (Find_eval_ordering::const_iterator p = find_eval_ordering.begin();
@@ -2803,7 +2828,7 @@ Build_recover_thunks::function(Named_object* orig_no)
Named_object* orig_closure_no = orig_func->closure_var();
Variable* orig_closure_var = orig_closure_no->var_value();
Variable* new_var = new Variable(orig_closure_var->type(), NULL, false,
- true, false, location);
+ false, false, location);
snprintf(buf, sizeof buf, "closure.%u", count);
++count;
Named_object* new_closure_no = Named_object::make_variable(buf, NULL,
@@ -3275,7 +3300,7 @@ Function::Function(Function_type* type, Function* enclosing, Block* block,
local_type_count_(0), descriptor_(NULL), fndecl_(NULL), defer_stack_(NULL),
is_sink_(false), results_are_named_(false), nointerface_(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()
Struct_field_list* sfl = new Struct_field_list;
Type* struct_type = Type::make_struct_type(sfl, loc);
Variable* var = new Variable(Type::make_pointer_type(struct_type),
- NULL, false, true, false, loc);
+ NULL, false, false, false, loc);
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.
}
return this->closure_var_;
@@ -3562,99 +3587,16 @@ Function::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
// the function in Go code without calling it.
Expression*
-Function::descriptor(Gogo* gogo, Named_object* no)
+Function::descriptor(Gogo*, Named_object* no)
{
go_assert(!this->is_method());
go_assert(this->closure_var_ == NULL);
- go_assert(!this->is_descriptor_wrapper_);
if (this->descriptor_ == NULL)
- {
- // 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);
- }
- }
+ this->descriptor_ = Expression::make_func_descriptor(no);
return this->descriptor_;
}
@@ -4193,24 +4135,11 @@ Bindings_snapshot::check_goto_defs(Location loc, const Block* block,
// Return the function descriptor.
Expression*
-Function_declaration::descriptor(Gogo* gogo, Named_object* no)
+Function_declaration::descriptor(Gogo*, Named_object* no)
{
go_assert(!this->fntype_->is_method());
if (this->descriptor_ == NULL)
- {
- // 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);
- }
- }
+ this->descriptor_ = Expression::make_func_descriptor(no);
return this->descriptor_;
}
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index b6e9e45a1cb..6a87f2d562c 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -1050,12 +1050,6 @@ class Function
set_in_unique_section()
{ 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
// recover.
void
@@ -1085,10 +1079,6 @@ class Function
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.
tree
get_or_make_decl(Gogo*, Named_object*, tree id);
@@ -1190,9 +1180,6 @@ class Function
// True if this function should be put in a unique section. This is
// turned on for field tracking.
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.
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 7314918a9a1..0261f9d4882 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -1658,46 +1658,23 @@ Statement::make_tuple_type_guard_assignment(Expression* val, Expression* ok,
location);
}
-// An expression statement.
+// Class Expression_statement.
-class Expression_statement : public Statement
-{
- 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;
+// Constructor.
- Bstatement*
- do_get_backend(Translate_context* context);
+Expression_statement::Expression_statement(Expression* expr, bool is_ignored)
+ : Statement(STATEMENT_EXPRESSION, expr->location()),
+ expr_(expr), is_ignored_(is_ignored)
+{
+}
- void
- do_dump_statement(Ast_dump_context*) const;
+// Determine types.
- private:
- Expression* expr_;
- // Whether the value of this expression is being explicitly ignored.
- bool is_ignored_;
-};
+void
+Expression_statement::do_determine_types()
+{
+ this->expr_->determine_type_no_context();
+}
// Check the types of an expression statement. The only check we do
// is to possibly give an error about discarding the value of the
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index fb2ae334293..b128fa0a8eb 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -17,6 +17,7 @@ class Function;
class Unnamed_label;
class Temporary_statement;
class Variable_declaration_statement;
+class Expression_statement;
class Return_statement;
class Thunk_statement;
class Label_statement;
@@ -329,6 +330,14 @@ class Statement
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.
Return_statement*
return_statement()
@@ -636,6 +645,43 @@ class Return_statement : public Statement
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.
class Send_statement : public Statement
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index b32c0587e6c..9ce329d5503 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -3390,10 +3390,7 @@ Function_type::do_get_backend(Gogo* gogo)
// 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
// actual function. So that is what we return as the type of a Go
- // function. The function stored in the first field always that
- // 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.
+ // function.
Location loc = this->location();
Btype* struct_type =
@@ -3415,15 +3412,9 @@ Function_type::do_get_backend(Gogo* gogo)
}
std::vector<Backend::Btyped_identifier> bparameters;
- size_t last;
- if (this->parameters_ == NULL)
- {
- bparameters.resize(1);
- last = 0;
- }
- else
+ if (this->parameters_ != NULL)
{
- bparameters.resize(this->parameters_->size() + 1);
+ bparameters.resize(this->parameters_->size());
size_t i = 0;
for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
p != this->parameters_->end();
@@ -3433,12 +3424,8 @@ Function_type::do_get_backend(Gogo* gogo)
bparameters[i].btype = p->type()->get_backend(gogo);
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;
if (this->results_ != NULL)
@@ -3840,7 +3827,7 @@ Function_type::copy_with_receiver(Type* receiver_type) const
// closure parameter.
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();
const Typed_identifier_list* orig_params = this->parameters_;
@@ -3858,8 +3845,6 @@ Function_type::copy_with_closure(Type* closure_type) const
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;
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 8bc022eb824..d207fe5a375 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1789,11 +1789,11 @@ 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.
+ // Return a copy of this type ignoring any receiver and using dummy
+ // names for all parameters. This is used for thunks for method
+ // values.
Function_type*
- copy_with_closure(Type* closure_type) const;
+ copy_with_names() const;
static Type*
make_function_type_descriptor_type();
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 6bf66c8caf6..45a08587973 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -434,9 +434,6 @@ func (v Value) call(op string, in []Value) []Value {
nin++
}
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)
off := 0
if v.flag&flagMethod != 0 {
@@ -464,10 +461,6 @@ func (v Value) call(op string, in []Value) []Value {
}
off++
}
- if v.flag&flagMethod == 0 && !firstPointer {
- // Closure argument.
- params[off] = unsafe.Pointer(&fn)
- }
ret := make([]Value, nout)
results := make([]unsafe.Pointer, nout)
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
index 83b9eba0436..5cf370798bf 100644
--- a/libgo/runtime/go-reflect-call.c
+++ b/libgo/runtime/go-reflect-call.c
@@ -302,9 +302,7 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
in_types = ((const struct __go_type_descriptor **)
func->__in.__values);
- num_args = (num_params
- + (is_interface ? 1 : 0)
- + (!is_interface && !is_method ? 1 : 0));
+ num_args = num_params + (is_interface ? 1 : 0);
args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
i = 0;
off = 0;
@@ -321,12 +319,6 @@ go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
for (; i < num_params; ++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);
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,
regardless of FUNC_TYPE, it is passed as a pointer.
If neither IS_INTERFACE nor IS_METHOD is true then we are calling a
- function indirectly, and the caller is responsible for passing a
- trailing closure argument, a pointer, which is not described in
- FUNC_TYPE. */
+ function indirectly, and we must pass a closure pointer via
+ __go_set_closure. The pointer to pass is simply FUNC_VAL. */
void
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));
+ if (!is_interface && !is_method)
+ __go_set_closure (func_val);
ffi_call (&cif, func_val->fn, call_result, params);
/* Some day we may need to free result values if RESULTS is
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 36afd2b964d..c3b32111ca0 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -2263,12 +2263,11 @@ runfinq(void* dummy __attribute__ ((unused)))
for(; fb; fb=next) {
next = fb->next;
for(i=0; i<(uint32)fb->cnt; i++) {
- void *params[2];
+ void *param;
f = &fb->fin[i];
- params[0] = &f->arg;
- params[1] = f;
- reflect_call(f->ft, f->fn, 0, 0, params, nil);
+ param = &f->arg;
+ reflect_call(f->ft, f->fn, 0, 0, &param, nil);
f->fn = nil;
f->arg = nil;
}
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index d42ff3362ee..0e77a3e0603 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -2832,3 +2832,23 @@ runtime_proc_scan(void (*addroot)(Obj))
{
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;
+}
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 78fd388186a..d2e7d4c11bc 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -190,6 +190,7 @@ struct Location
struct G
{
+ void* closure; // Closure value.
Defer* defer;
Panic* panic;
void* exception; // current exception being thrown
@@ -759,3 +760,6 @@ extern void runtime_main(void*);
int32 getproccount(void);
#define PREFETCH(p) __builtin_prefetch(p)
+
+void __go_set_closure(void*);
+void* __go_get_closure(void);
diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc
index e06b75ccb3d..8d12fe01080 100644
--- a/libgo/runtime/time.goc
+++ b/libgo/runtime/time.goc
@@ -46,10 +46,9 @@ static void siftdown(int32);
// Ready the goroutine e.data.
static void
-ready(int64 now, Eface e, void *closure)
+ready(int64 now, Eface e)
{
USED(now);
- USED(closure);
runtime_ready(e.__object);
}
@@ -166,7 +165,7 @@ timerproc(void* dummy __attribute__ ((unused)))
{
int64 delta, now;
Timer *t;
- void (*f)(int64, Eface, void *);
+ void (*f)(int64, Eface);
Eface arg;
for(;;) {
@@ -197,7 +196,8 @@ timerproc(void* dummy __attribute__ ((unused)))
runtime_unlock(&timers);
if(raceenabled)
runtime_raceacquire(t);
- f(now, arg, &t->fv);
+ __go_set_closure(t->fv);
+ f(now, arg);
runtime_lock(&timers);
}
if(delta < 0) {