diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-09-03 21:52:37 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-09-03 21:52:37 +0000 |
commit | f8bdf81a026b110398982d31e55f3313ca2e4eb9 (patch) | |
tree | 5f956e4c89959ef335ef73b7ec6e00e4bc2c12d5 | |
parent | 631d940c80b318d435d498744950dc1eeacafeaa (diff) | |
download | gcc-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.cc | 121 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 13 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 87 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 155 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 13 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 49 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 46 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 25 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 8 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 7 | ||||
-rw-r--r-- | libgo/runtime/go-reflect-call.c | 17 | ||||
-rw-r--r-- | libgo/runtime/mgc0.c | 7 | ||||
-rw-r--r-- | libgo/runtime/proc.c | 20 | ||||
-rw-r--r-- | libgo/runtime/runtime.h | 4 | ||||
-rw-r--r-- | libgo/runtime/time.goc | 8 |
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, ¶m, 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) { |