compiler, runtime: Use runtime functions to pass closure value.
authorIan Lance Taylor <ian@gcc.gnu.org>
Tue, 3 Sep 2013 21:52:37 +0000 (21:52 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 3 Sep 2013 21:52:37 +0000 (21:52 +0000)
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

15 files changed:
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h
libgo/go/reflect/value.go
libgo/runtime/go-reflect-call.c
libgo/runtime/mgc0.c
libgo/runtime/proc.c
libgo/runtime/runtime.h
libgo/runtime/time.goc

index 2b60d90a5dc6071633e3321a27aa42a7c5bbb5fe..78a427398c2b79394db5364bcdcafab36217f75e 100644 (file)
@@ -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);
index 67a4bb985e66f52efd7646c10c4ffe6e762f5fff..95584f2748ba3863cde6b5679cc23588bdff1bbd 100644 (file)
@@ -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_;
 };
index a1fe5fec7ca6e77d8a1af6da2e8e960ad70c1eec..69797f93342f609701ff7fc792f1a93dbf6e8dbf 100644 (file)
@@ -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)
     {
index 4e5bd44783157606f0a03ee085133bfca758fd4e..be8ec5939f32e8c06c8b9b3e616a61c44aa8478f 100644 (file)
@@ -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_;
 }
 
index b6e9e45a1cb4ae8a25274a111c6761824018cad2..6a87f2d562ccc8650e7c2b914e4269e0de168c13 100644 (file)
@@ -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.
index 7314918a9a16e2516e7f41f18f89ba6ae47e79eb..0261f9d4882b79b1e34cf83abd2f857f4345d569 100644 (file)
@@ -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
index fb2ae334293c8753706ea9f97fe66a7cdd039871..b128fa0a8eb1cb1e96168be75dc6281809eaf66f 100644 (file)
@@ -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
index b32c0587e6cdac181126775b56cfd8bcf97a13e1..9ce329d55035ca1773a78fd2543a05f433716a1a 100644 (file)
@@ -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;
index 8bc022eb8243398fa7db71dfef12ac9d0b6ddc1c..d207fe5a375e2860a121f9bb88c1cefd1a17355d 100644 (file)
@@ -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();
index 6bf66c8caf62f505d153ba10c62ce4664daafa6f..45a08587973b5be33eedee57dc8ade0c2a922dcc 100644 (file)
@@ -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)
index 83b9eba04363cbde9faf0c8394c8bfebc4c832d9..5cf370798bfe4b0e7049ce1df22c9fc17bc5d322 100644 (file)
@@ -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
index 36afd2b964d281b09b57a681590a1048f92f8236..c3b32111ca04d00786b752805c6621c4a4f74fbb 100644 (file)
@@ -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;
                        }
index d42ff3362ee8acf0e9b11f25af924c2387ba8b00..0e77a3e0603d0001919d717e32c004b86a1f517d 100644 (file)
@@ -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;
+}
index 78fd388186a147b121a5c376e1aaa1d6fa31a40e..d2e7d4c11bc02c062d57ef4d783b19713ea8f6bc 100644 (file)
@@ -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);
index e06b75ccb3dd65d51898c3d7d1eeb25536f952d4..8d12fe010800964ce2f6677f0a6bc7bba8ce97ef 100644 (file)
@@ -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) {