@@ -304,7 +304,7 @@ class Gcc_backend : public Backend
Bexpression*
call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
- Location);
+ Bexpression* static_chain, Location);
// Statements.
@@ -385,6 +385,9 @@ class Gcc_backend : public Backend
Location);
Bvariable*
+ static_chain_variable(Bfunction*, const std::string&, Btype*, Location);
+
+ Bvariable*
temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool,
Location, Bstatement**);
@@ -1759,7 +1762,7 @@ Gcc_backend::array_index_expression(Bexpression* array, Bexpression* index,
Bexpression*
Gcc_backend::call_expression(Bexpression* fn_expr,
const std::vector<Bexpression*>& fn_args,
- Location location)
+ Bexpression* chain_expr, Location location)
{
tree fn = fn_expr->get_tree();
if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
@@ -1819,6 +1822,9 @@ Gcc_backend::call_expression(Bexpression* fn_expr,
excess_type != NULL_TREE ? excess_type : rettype,
fn, nargs, args);
+ if (chain_expr)
+ CALL_EXPR_STATIC_CHAIN (ret) = chain_expr->get_tree();
+
if (excess_type != NULL_TREE)
{
// Calling convert here can undo our excess precision change.
@@ -2440,6 +2446,40 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
return new Bvariable(decl);
}
+// Make a static chain variable.
+
+Bvariable*
+Gcc_backend::static_chain_variable(Bfunction* function, const std::string& name,
+ Btype* btype, Location location)
+{
+ tree type_tree = btype->get_tree();
+ if (type_tree == error_mark_node)
+ return this->error_variable();
+ tree decl = build_decl(location.gcc_location(), PARM_DECL,
+ get_identifier_from_string(name), type_tree);
+ tree fndecl = function->get_tree();
+ DECL_CONTEXT(decl) = fndecl;
+ DECL_ARG_TYPE(decl) = type_tree;
+ TREE_USED(decl) = 1;
+ DECL_ARTIFICIAL(decl) = 1;
+ DECL_IGNORED_P(decl) = 1;
+ TREE_READONLY(decl) = 1;
+
+ struct function *f = DECL_STRUCT_FUNCTION(fndecl);
+ if (f == NULL)
+ {
+ push_struct_function(fndecl);
+ pop_cfun();
+ f = DECL_STRUCT_FUNCTION(fndecl);
+ }
+ gcc_assert(f->static_chain_decl == NULL);
+ f->static_chain_decl = decl;
+ DECL_STATIC_CHAIN(fndecl) = 1;
+
+ go_preserve_from_gc(decl);
+ return new Bvariable(decl);
+}
+
// Make a temporary variable.
Bvariable*
@@ -374,7 +374,7 @@ class Backend
// Create an expression for a call to FN with ARGS.
virtual Bexpression*
call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
- Location) = 0;
+ Bexpression* static_chain, Location) = 0;
// Statements.
@@ -528,6 +528,11 @@ class Backend
Btype* type, bool is_address_taken,
Location location) = 0;
+ // Create a static chain parameter. This is the closure parameter.
+ virtual Bvariable*
+ static_chain_variable(Bfunction* function, const std::string& name,
+ Btype* type, Location location) = 0;
+
// Create a temporary variable. A temporary variable has no name,
// just a type. We pass in FUNCTION and BLOCK in case they are
// needed. If INIT is not NULL, the variable should be initialized
@@ -6621,6 +6621,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
Variable* cvar = new Variable(closure_type, NULL, false, false, false, loc);
cvar->set_is_used();
+ cvar->set_is_closure();
Named_object* cp = Named_object::make_variable("$closure", NULL, cvar);
new_no->func_value()->set_closure_var(cp);
@@ -9571,19 +9572,11 @@ Call_expression::do_get_backend(Translate_context* context)
fn_args[0] = first_arg->get_backend(context);
}
- if (!has_closure_arg)
- go_assert(closure == NULL);
+ Bexpression* bclosure = NULL;
+ if (has_closure_arg)
+ bclosure = closure->get_backend(context);
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 != NULL);
- Expression* set_closure =
- Runtime::make_call(Runtime::SET_CLOSURE, location, 1, closure);
- fn = Expression::make_compound(set_closure, fn, location);
- }
+ go_assert(closure == NULL);
Bexpression* bfn = fn->get_backend(context);
@@ -9599,7 +9592,8 @@ Call_expression::do_get_backend(Translate_context* context)
bfn = gogo->backend()->convert_expression(bft, bfn, location);
}
- Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, location);
+ Bexpression* call = gogo->backend()->call_expression(bfn, fn_args,
+ bclosure, location);
if (this->results_ != NULL)
{
@@ -11373,6 +11367,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
Variable* cvar = new Variable(closure_type, NULL, false, false, false, loc);
cvar->set_is_used();
+ cvar->set_is_closure();
Named_object* cp = Named_object::make_variable("$closure", NULL, cvar);
new_no->func_value()->set_closure_var(cp);
@@ -702,7 +702,8 @@ Gogo::init_imports(std::vector<Bstatement*>& init_stmts)
Bexpression* pfunc_code =
this->backend()->function_code_expression(pfunc, unknown_loc);
Bexpression* pfunc_call =
- this->backend()->call_expression(pfunc_code, empty_args, unknown_loc);
+ this->backend()->call_expression(pfunc_code, empty_args,
+ NULL, unknown_loc);
init_stmts.push_back(this->backend()->expression_statement(pfunc_call));
}
}
@@ -1354,7 +1355,7 @@ Gogo::write_globals()
this->backend()->function_code_expression(initfn, func_loc);
Bexpression* call = this->backend()->call_expression(func_code,
empty_args,
- func_loc);
+ NULL, func_loc);
init_stmts.push_back(this->backend()->expression_statement(call));
}
@@ -3856,6 +3857,7 @@ Build_recover_thunks::function(Named_object* orig_no)
Variable* orig_closure_var = orig_closure_no->var_value();
Variable* new_var = new Variable(orig_closure_var->type(), NULL, false,
false, false, location);
+ new_var->set_is_closure();
snprintf(buf, sizeof buf, "closure.%u", count);
++count;
Named_object* new_closure_no = Named_object::make_variable(buf, NULL,
@@ -4466,6 +4468,7 @@ Function::closure_var()
Variable* var = new Variable(Type::make_pointer_type(struct_type),
NULL, false, false, false, loc);
var->set_is_used();
+ var->set_is_closure();
this->closure_var_ = Named_object::make_variable("$closure", NULL, var);
// Note that the new variable is not in any binding contour.
}
@@ -5128,18 +5131,12 @@ Function::build(Gogo* gogo, Named_object* named_function)
return;
}
- // 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 we need a closure variable, make sure to create it.
+ // It gets installed in the function as a side effect of creation.
if (this->closure_var_ != NULL)
{
- Bvariable* closure_bvar =
- this->closure_var_->get_backend_variable(gogo, named_function);
- vars.push_back(closure_bvar);
-
- Expression* closure =
- Runtime::make_call(Runtime::GET_CLOSURE, this->location_, 0);
- var_inits.push_back(closure->get_backend(&context));
+ go_assert(this->closure_var_->var_value()->is_closure());
+ this->closure_var_->get_backend_variable(gogo, named_function);
}
if (this->block_ != NULL)
@@ -5673,7 +5670,8 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
Location location)
: type_(type), init_(init), preinit_(NULL), location_(location),
backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
- is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false),
+ is_closure_(false), is_receiver_(is_receiver),
+ is_varargs_parameter_(false), is_used_(false),
is_address_taken_(false), is_non_escaping_address_taken_(false),
seen_(false), init_is_lowered_(false), init_is_flattened_(false),
type_from_init_tuple_(false), type_from_range_index_(false),
@@ -6212,7 +6210,10 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function,
Bfunction* bfunction = function->func_value()->get_decl();
bool is_address_taken = (this->is_non_escaping_address_taken_
&& !this->is_in_heap());
- if (is_parameter)
+ if (this->is_closure())
+ bvar = backend->static_chain_variable(bfunction, n, btype,
+ this->location_);
+ else if (is_parameter)
bvar = backend->parameter_variable(bfunction, n, btype,
is_address_taken,
this->location_);
@@ -1340,6 +1340,18 @@ class Variable
is_parameter() const
{ return this->is_parameter_; }
+ // Return whether this is a closure (static chain) parameter.
+ bool
+ is_closure() const
+ { return this->is_closure_; }
+
+ // Change this parameter to be a closure.
+ void
+ set_is_closure()
+ {
+ this->is_closure_ = true;
+ }
+
// Return whether this is the receiver parameter of a method.
bool
is_receiver() const
@@ -1561,6 +1573,8 @@ class Variable
bool is_global_ : 1;
// Whether this is a function parameter.
bool is_parameter_ : 1;
+ // Whether this is a closure parameter.
+ bool is_closure_ : 1;
// Whether this is the receiver parameter of a method.
bool is_receiver_ : 1;
// Whether this is the varargs parameter of a function.
@@ -230,12 +230,6 @@ DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER))
// Start a new goroutine.
DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0())
-// Get the function closure.
-DEF_GO_RUNTIME(GET_CLOSURE, "__go_get_closure", P0(), R1(POINTER))
-
-// Set the function closure.
-DEF_GO_RUNTIME(SET_CLOSURE, "__go_set_closure", P1(POINTER), R0())
-
// Defer a function.
DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0())