This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Go patch committed: Rework closure value passing


This patch changes the way that closure values are passed in the Go
frontend.  In June I changed the code to pass a closure value as the
last argument to a function, which required adding descriptor wrapper
functions for all top-level functions to accept and ignore that
argument.  This patch changes the code to instead call __go_set_closure
before calling a function and have the function call __go_get_closure
after it is called.  This eliminates the need for the descriptor wrapper
functions.

This is also a step toward implementing reflect.MakeFunc, a standard
library function.  An implementation of MakeFunc requires retrieving the
closure value without knowing what arguments are passed to the function.
That will be possible via __go_get_closure, when it was not possible
with the older scheme.

It would be nice to be able to use the static chain register here.  We
can't, because GCC only permits using the static chain with a known
function, not for an indirect call as is required by Go.  In the future
it would be possible to write a target-specific implementation of
__go_set_closure and __go_get_closure to use the static chain register,
or, really, any register not used to pass parameters.  This would work
because we would know that both the caller and callee are Go functions,
or are functions that do not use the static chain.

Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline and 4.8 branch.

Ian

diff -r f571bacb20cc go/expressions.cc
--- a/go/expressions.cc	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/expressions.cc	Tue Sep 03 14:40:41 2013 -0700
@@ -1382,7 +1382,7 @@
 
 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 @@
   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 @@
   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 @@
       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 @@
     }
 
   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,18 +6786,18 @@
   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);
 
+  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);
+
   gogo->start_block(loc);
 
-  Named_object* cp = gogo->lookup("closure.0", NULL);
-  go_assert(cp != NULL
-	    && cp->is_variable()
-	    && cp->var_value()->is_parameter());
-
   // Field 0 of the closure is the function code pointer, field 1 is
   // the value on which to invoke the method.
   Expression* arg = Expression::make_var_reference(cp, loc);
@@ -6831,7 +6815,7 @@
       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 @@
   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;
-  else
-    closure_arg = 1;
+    has_closure_arg = false;
+  else
+    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 @@
       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 @@
       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 @@
 	    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 @@
     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)
-	{
-	  go_assert(closure_arg == 1 && nargs > 0);
-	  args[nargs - 1] = func->closure()->get_tree(context);
+      if (!has_closure)
+	closure_tree = NULL_TREE;
+      else
+	{
+	  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 @@
 			   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 @@
 					   &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 @@
   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,26 +11618,26 @@
     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);
 
+  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);
+
   gogo->start_block(loc);
 
-  Named_object* cp = gogo->lookup("closure.0", NULL);
-  go_assert(cp != NULL
-	    && cp->is_variable()
-	    && cp->var_value()->is_parameter());
-
   // Field 0 of the closure is the function code pointer, field 1 is
   // the value on which to invoke the method.
   Expression* arg = Expression::make_var_reference(cp, loc);
@@ -11647,7 +11656,7 @@
       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 -r f571bacb20cc go/expressions.h
--- a/go/expressions.h	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/expressions.h	Tue Sep 03 14:40:41 2013 -0700
@@ -1570,14 +1570,6 @@
  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 @@
   { }
 
   Expression*
-  do_copy();
+  do_copy()
+  { return Expression::make_func_descriptor(this->fn_); }
 
   bool
   do_is_addressable() const
@@ -1612,8 +1605,6 @@
 
   // The function for which this is the descriptor.
   Named_object* fn_;
-  // The descriptor function.
-  Named_object* dfn_;
   // The descriptor variable.
   Bvariable* dvar_;
 };
diff -r f571bacb20cc go/gogo-tree.cc
--- a/go/gogo-tree.cc	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/gogo-tree.cc	Tue Sep 03 14:40:41 2013 -0700
@@ -1289,30 +1289,6 @@
 	  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 @@
 	  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 @@
 	}
     }
 
-  // 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 @@
       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 -r f571bacb20cc go/gogo.cc
--- a/go/gogo.cc	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/gogo.cc	Tue Sep 03 14:40:41 2013 -0700
@@ -1770,8 +1770,8 @@
   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 @@
     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 @@
       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 @@
     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 @@
       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 @@
     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 @@
 // 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 -r f571bacb20cc go/gogo.h
--- a/go/gogo.h	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/gogo.h	Tue Sep 03 14:40:41 2013 -0700
@@ -1050,12 +1050,6 @@
   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 @@
     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 @@
   // 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 -r f571bacb20cc go/statements.cc
--- a/go/statements.cc	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/statements.cc	Tue Sep 03 14:40:41 2013 -0700
@@ -1658,46 +1658,23 @@
 						   location);
 }
 
-// An 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;
-
-  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_;
-};
+// Class Expression_statement.
+
+// Constructor.
+
+Expression_statement::Expression_statement(Expression* expr, bool is_ignored)
+  : Statement(STATEMENT_EXPRESSION, expr->location()),
+    expr_(expr), is_ignored_(is_ignored)
+{
+}
+
+// Determine types.
+
+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 -r f571bacb20cc go/statements.h
--- a/go/statements.h	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/statements.h	Tue Sep 03 14:40:41 2013 -0700
@@ -17,6 +17,7 @@
 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 @@
 			 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 @@
   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 -r f571bacb20cc go/types.cc
--- a/go/types.cc	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/types.cc	Tue Sep 03 14:40:41 2013 -0700
@@ -3390,10 +3390,7 @@
   // 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 @@
     }
 
   std::vector<Backend::Btyped_identifier> bparameters;
-  size_t last;
-  if (this->parameters_ == NULL)
-    {
-      bparameters.resize(1);
-      last = 0;
-    }
-  else
-    {
-      bparameters.resize(this->parameters_->size() + 1);
+  if (this->parameters_ != NULL)
+    {
+      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 @@
 	  bparameters[i].btype = p->type()->get_backend(gogo);
 	  bparameters[i].location = p->location();
 	}
-      last = i;
-    }
-  go_assert(last + 1 == bparameters.size());
-  bparameters[last].name = "$closure";
-  bparameters[last].btype = ptr_struct_type;
-  bparameters[last].location = loc;
+      go_assert(i == bparameters.size());
+    }
 
   std::vector<Backend::Btyped_identifier> bresults;
   if (this->results_ != NULL)
@@ -3840,7 +3827,7 @@
 // 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 @@
 						 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 -r f571bacb20cc go/types.h
--- a/go/types.h	Fri Aug 23 14:03:20 2013 -0700
+++ b/go/types.h	Tue Sep 03 14:40:41 2013 -0700
@@ -1789,11 +1789,11 @@
   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 -r f571bacb20cc libgo/go/reflect/value.go
--- a/libgo/go/reflect/value.go	Fri Aug 23 14:03:20 2013 -0700
+++ b/libgo/go/reflect/value.go	Tue Sep 03 14:40:41 2013 -0700
@@ -434,9 +434,6 @@
 		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 @@
 		}
 		off++
 	}
-	if v.flag&flagMethod == 0 && !firstPointer {
-		// Closure argument.
-		params[off] = unsafe.Pointer(&fn)
-	}
 
 	ret := make([]Value, nout)
 	results := make([]unsafe.Pointer, nout)
diff -r f571bacb20cc libgo/runtime/go-reflect-call.c
--- a/libgo/runtime/go-reflect-call.c	Fri Aug 23 14:03:20 2013 -0700
+++ b/libgo/runtime/go-reflect-call.c	Tue Sep 03 14:40:41 2013 -0700
@@ -302,9 +302,7 @@
   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 @@
   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 @@
    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 @@
 
   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 -r f571bacb20cc libgo/runtime/mgc0.c
--- a/libgo/runtime/mgc0.c	Fri Aug 23 14:03:20 2013 -0700
+++ b/libgo/runtime/mgc0.c	Tue Sep 03 14:40:41 2013 -0700
@@ -2263,12 +2263,11 @@
 		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 -r f571bacb20cc libgo/runtime/proc.c
--- a/libgo/runtime/proc.c	Fri Aug 23 14:03:20 2013 -0700
+++ b/libgo/runtime/proc.c	Tue Sep 03 14:40:41 2013 -0700
@@ -2832,3 +2832,23 @@
 {
 	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 -r f571bacb20cc libgo/runtime/runtime.h
--- a/libgo/runtime/runtime.h	Fri Aug 23 14:03:20 2013 -0700
+++ b/libgo/runtime/runtime.h	Tue Sep 03 14:40:41 2013 -0700
@@ -190,6 +190,7 @@
 
 struct	G
 {
+	void*	closure;	// Closure value.
 	Defer*	defer;
 	Panic*	panic;
 	void*	exception;	// current exception being thrown
@@ -759,3 +760,6 @@
 int32 getproccount(void);
 
 #define PREFETCH(p) __builtin_prefetch(p)
+
+void	__go_set_closure(void*);
+void*	__go_get_closure(void);
diff -r f571bacb20cc libgo/runtime/time.goc
--- a/libgo/runtime/time.goc	Fri Aug 23 14:03:20 2013 -0700
+++ b/libgo/runtime/time.goc	Tue Sep 03 14:40:41 2013 -0700
@@ -46,10 +46,9 @@
 
 // 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 @@
 {
 	int64 delta, now;
 	Timer *t;
-	void (*f)(int64, Eface, void *);
+	void (*f)(int64, Eface);
 	Eface arg;
 
 	for(;;) {
@@ -197,7 +196,8 @@
 			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) {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]