diff mbox

Use static chain and libffi for Go closures

Message ID 54B83B61.1010108@redhat.com
State New
Headers show

Commit Message

Richard Henderson Jan. 15, 2015, 10:12 p.m. UTC
All of this has been posted before.

I believe the ABI change is something we should have for gcc 5.

Yes, the libffi merge has been causing problems (on targets that
don't even support libgo, annoyingly), but missing support for
the new libffi interfaces is easier to remedy in a dot release
than the change from __thread variable to static chain register
for implementing closures.


r~
gcc/go/
	* go-gcc.cc (Gcc_backend::call_expression): Add chain_expr argument.
	(Gcc_backend::static_chain_variable): New method.

Comments

Ian Lance Taylor Jan. 16, 2015, 10:59 p.m. UTC | #1
On Thu, Jan 15, 2015 at 2:12 PM, Richard Henderson <rth@redhat.com> wrote:
>
> All of this has been posted before.
>
> I believe the ABI change is something we should have for gcc 5.
>
> Yes, the libffi merge has been causing problems (on targets that
> don't even support libgo, annoyingly), but missing support for
> the new libffi interfaces is easier to remedy in a dot release
> than the change from __thread variable to static chain register
> for implementing closures.

Thanks very much.  Looks great.  Committed to mainline.

Ian
Andreas Schwab Jan. 17, 2015, 9:52 a.m. UTC | #2
../../../libgo/go/reflect/makefunc_ffi_c.c:21:53: error: unknown type name 'ffi_go_closure'
 void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
                                                     ^
../../../libgo/go/reflect/makefunc_ffi_c.c:86:48: error: unknown type name 'ffi_go_closure'
 makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
                                                ^
make[4]: *** [reflect/makefunc_ffi_c.lo] Error 1

Andreas.
Richard Henderson Jan. 17, 2015, 7:02 p.m. UTC | #3
On 01/17/2015 01:52 AM, Andreas Schwab wrote:
> ../../../libgo/go/reflect/makefunc_ffi_c.c:21:53: error: unknown type name 'ffi_go_closure'
>  void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>                                                      ^
> ../../../libgo/go/reflect/makefunc_ffi_c.c:86:48: error: unknown type name 'ffi_go_closure'
>  makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>                                                 ^
> make[4]: *** [reflect/makefunc_ffi_c.lo] Error 1

What target?


r~
Andreas Schwab Jan. 17, 2015, 7:07 p.m. UTC | #4
Richard Henderson <rth@redhat.com> writes:

> On 01/17/2015 01:52 AM, Andreas Schwab wrote:
>> ../../../libgo/go/reflect/makefunc_ffi_c.c:21:53: error: unknown type name 'ffi_go_closure'
>>  void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>                                                      ^
>> ../../../libgo/go/reflect/makefunc_ffi_c.c:86:48: error: unknown type name 'ffi_go_closure'
>>  makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>                                                 ^
>> make[4]: *** [reflect/makefunc_ffi_c.lo] Error 1
>
> What target?

Why does it matter?

Andreas.
Richard Henderson Jan. 17, 2015, 9:26 p.m. UTC | #5
On 01/17/2015 11:07 AM, Andreas Schwab wrote:
> Richard Henderson <rth@redhat.com> writes:
> 
>> On 01/17/2015 01:52 AM, Andreas Schwab wrote:
>>> ../../../libgo/go/reflect/makefunc_ffi_c.c:21:53: error: unknown type name 'ffi_go_closure'
>>>  void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>>                                                      ^
>>> ../../../libgo/go/reflect/makefunc_ffi_c.c:86:48: error: unknown type name 'ffi_go_closure'
>>>  makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>>                                                 ^
>>> make[4]: *** [reflect/makefunc_ffi_c.lo] Error 1
>>
>> What target?
> 
> Why does it matter?

Because I don't see that error here, obviously.


r~
Andrew Pinski Jan. 17, 2015, 10:02 p.m. UTC | #6
On Sat, Jan 17, 2015 at 1:26 PM, Richard Henderson <rth@redhat.com> wrote:
> On 01/17/2015 11:07 AM, Andreas Schwab wrote:
>> Richard Henderson <rth@redhat.com> writes:
>>
>>> On 01/17/2015 01:52 AM, Andreas Schwab wrote:
>>>> ../../../libgo/go/reflect/makefunc_ffi_c.c:21:53: error: unknown type name 'ffi_go_closure'
>>>>  void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>>>                                                      ^
>>>> ../../../libgo/go/reflect/makefunc_ffi_c.c:86:48: error: unknown type name 'ffi_go_closure'
>>>>  makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>>>                                                 ^
>>>> make[4]: *** [reflect/makefunc_ffi_c.lo] Error 1
>>>
>>> What target?
>>
>> Why does it matter?
>
> Because I don't see that error here, obviously.


It fails for me with mips64-linux-gnu.

Thanks,
Andrew Pinski

>
>
> r~
>
Andreas Schwab Jan. 17, 2015, 10:02 p.m. UTC | #7
Andrew Pinski <pinskia@gmail.com> writes:

> On Sat, Jan 17, 2015 at 1:26 PM, Richard Henderson <rth@redhat.com> wrote:
>> On 01/17/2015 11:07 AM, Andreas Schwab wrote:
>>> Richard Henderson <rth@redhat.com> writes:
>>>
>>>> On 01/17/2015 01:52 AM, Andreas Schwab wrote:
>>>>> ../../../libgo/go/reflect/makefunc_ffi_c.c:21:53: error: unknown type name 'ffi_go_closure'
>>>>>  void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>>>>                                                      ^
>>>>> ../../../libgo/go/reflect/makefunc_ffi_c.c:86:48: error: unknown type name 'ffi_go_closure'
>>>>>  makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>>>>                                                 ^
>>>>> make[4]: *** [reflect/makefunc_ffi_c.lo] Error 1
>>>>
>>>> What target?
>>>
>>> Why does it matter?
>>
>> Because I don't see that error here, obviously.
>
>
> It fails for me with mips64-linux-gnu.

It fails almost everywhere.

Andreas.
Andrew Pinski Jan. 17, 2015, 10:07 p.m. UTC | #8
On Sat, Jan 17, 2015 at 2:02 PM, Andreas Schwab <schwab@linux-m68k.org> wrote:
> Andrew Pinski <pinskia@gmail.com> writes:
>
>> On Sat, Jan 17, 2015 at 1:26 PM, Richard Henderson <rth@redhat.com> wrote:
>>> On 01/17/2015 11:07 AM, Andreas Schwab wrote:
>>>> Richard Henderson <rth@redhat.com> writes:
>>>>
>>>>> On 01/17/2015 01:52 AM, Andreas Schwab wrote:
>>>>>> ../../../libgo/go/reflect/makefunc_ffi_c.c:21:53: error: unknown type name 'ffi_go_closure'
>>>>>>  void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>>>>>                                                      ^
>>>>>> ../../../libgo/go/reflect/makefunc_ffi_c.c:86:48: error: unknown type name 'ffi_go_closure'
>>>>>>  makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
>>>>>>                                                 ^
>>>>>> make[4]: *** [reflect/makefunc_ffi_c.lo] Error 1
>>>>>
>>>>> What target?
>>>>
>>>> Why does it matter?
>>>
>>> Because I don't see that error here, obviously.
>>
>>
>> It fails for me with mips64-linux-gnu.
>
> It fails almost everywhere.


Well it is working for aarch64-linux-gnu and x86_64-linux-gnu (the two
other targets I care about).

Thanks,
Andrew

>
> Andreas.
>
> --
> Andreas Schwab, schwab@linux-m68k.org
> GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
> "And now for something completely different."
diff mbox

Patch

diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index d8b80b6..1ce1ff2 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -322,7 +322,7 @@  class Gcc_backend : public Backend
 
   Bexpression*
   call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
-                  Location);
+                  Bexpression* static_chain, Location);
 
   // Statements.
 
@@ -403,6 +403,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**);
 
@@ -1808,7 +1811,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)
@@ -1868,6 +1871,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.
@@ -2489,6 +2495,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*
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index 46b2a6d..31ed8df 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -375,7 +375,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.
 
@@ -529,6 +529,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
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 564c5b7..ee8af84 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -6321,6 +6321,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);
 
@@ -9328,19 +9329,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);
 
@@ -9356,7 +9349,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)
     {
@@ -11132,6 +11126,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);
 
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 49be6af..7bc54fc 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -698,7 +698,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));
     }
 }
@@ -1413,7 +1414,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));
     }
 
@@ -3915,6 +3916,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,
@@ -4518,6 +4520,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.
     }
@@ -5188,18 +5191,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)
@@ -5733,7 +5730,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),
@@ -6287,7 +6285,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_);
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index a75ae4b..8a16637 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -1364,6 +1364,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
@@ -1585,6 +1597,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.
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index bec1cfc..43025dd 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -230,12 +230,6 @@  DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P2(TYPE, UINTPTR), R1(POIN
 // 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())
 
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 0ce3576..6d0f2d3 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -934,44 +934,10 @@  go_path_files = \
 	go/path/match.go \
 	go/path/path.go
 
-if LIBGO_IS_X86_64
-go_reflect_makefunc_file = \
-	go/reflect/makefuncgo_amd64.go
-go_reflect_makefunc_s_file = \
-	go/reflect/makefunc_amd64.S
-else
-if LIBGO_IS_386
-go_reflect_makefunc_file = \
-	go/reflect/makefuncgo_386.go
-go_reflect_makefunc_s_file = \
-	go/reflect/makefunc_386.S
-else
-if LIBGO_IS_S390
-go_reflect_makefunc_file = \
-	go/reflect/makefuncgo_s390.go
-go_reflect_makefunc_s_file = \
-	go/reflect/makefunc_s390.c
-else
-if LIBGO_IS_S390X
-go_reflect_makefunc_file = \
-	go/reflect/makefuncgo_s390x.go \
-	go/reflect/makefuncgo_s390.go
-go_reflect_makefunc_s_file = \
-	go/reflect/makefunc_s390.c
-else
-go_reflect_makefunc_file =
-go_reflect_makefunc_s_file = \
-	go/reflect/makefunc_dummy.c
-endif
-endif
-endif
-endif
-
 go_reflect_files = \
 	go/reflect/deepequal.go \
 	go/reflect/makefunc.go \
 	go/reflect/makefunc_ffi.go \
-	$(go_reflect_makefunc_file) \
 	go/reflect/type.go \
 	go/reflect/value.go
 go_reflect_makefunc_c_file = \
@@ -1893,7 +1859,6 @@  libgo_go_objs = \
 	os.lo \
 	path.lo \
 	reflect-go.lo \
-	reflect/makefunc.lo \
 	reflect/makefunc_ffi_c.lo \
 	regexp.lo \
 	runtime-go.lo \
@@ -2312,9 +2277,6 @@  reflect-go.lo: $(go_reflect_files)
 	$(BUILDPACKAGE)
 reflect/check: $(CHECK_DEPS)
 	@$(CHECK)
-reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
-	@$(MKDIR_P) reflect
-	$(LTCOMPILE) -c -o $@ $<
 reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file)
 	@$(MKDIR_P) reflect
 	$(LTCOMPILE) -c -o $@ $<
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 495dc35..710f4ee 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -141,11 +141,11 @@  am__DEPENDENCIES_1 =
 am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
 	encoding.lo errors.lo expvar.lo flag.lo fmt.lo hash.lo html.lo \
 	image.lo io.lo log.lo math.lo mime.lo net.lo os.lo path.lo \
-	reflect-go.lo reflect/makefunc.lo reflect/makefunc_ffi_c.lo \
-	regexp.lo runtime-go.lo sort.lo strconv.lo strings.lo \
-	strings/index.lo sync.lo syscall.lo syscall/errno.lo \
-	syscall/signame.lo syscall/wait.lo testing.lo time-go.lo \
-	unicode.lo archive/tar.lo archive/zip.lo compress/bzip2.lo \
+	reflect-go.lo reflect/makefunc_ffi_c.lo regexp.lo \
+	runtime-go.lo sort.lo strconv.lo strings.lo strings/index.lo \
+	sync.lo syscall.lo syscall/errno.lo syscall/signame.lo \
+	syscall/wait.lo testing.lo time-go.lo unicode.lo \
+	archive/tar.lo archive/zip.lo compress/bzip2.lo \
 	compress/flate.lo compress/gzip.lo compress/lzw.lo \
 	compress/zlib.lo container/heap.lo container/list.lo \
 	container/ring.lo crypto/aes.lo crypto/cipher.lo crypto/des.lo \
@@ -1124,40 +1124,10 @@  go_path_files = \
 	go/path/match.go \
 	go/path/path.go
 
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = 
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefuncgo_s390x.go \
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefuncgo_s390.go
-
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefuncgo_s390.go
-
-@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
-@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefuncgo_386.go
-
-@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_file = \
-@LIBGO_IS_X86_64_TRUE@	go/reflect/makefuncgo_amd64.go
-
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_FALSE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_dummy.c
-
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390X_TRUE@@LIBGO_IS_S390_FALSE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_s390.c
-
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_386_FALSE@@LIBGO_IS_S390_TRUE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_s390.c
-
-@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_386.S
-
-@LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_X86_64_TRUE@	go/reflect/makefunc_amd64.S
-
 go_reflect_files = \
 	go/reflect/deepequal.go \
 	go/reflect/makefunc.go \
 	go/reflect/makefunc_ffi.go \
-	$(go_reflect_makefunc_file) \
 	go/reflect/type.go \
 	go/reflect/value.go
 
@@ -1962,7 +1932,6 @@  libgo_go_objs = \
 	os.lo \
 	path.lo \
 	reflect-go.lo \
-	reflect/makefunc.lo \
 	reflect/makefunc_ffi_c.lo \
 	regexp.lo \
 	runtime-go.lo \
@@ -4656,9 +4625,6 @@  reflect-go.lo: $(go_reflect_files)
 	$(BUILDPACKAGE)
 reflect/check: $(CHECK_DEPS)
 	@$(CHECK)
-reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
-	@$(MKDIR_P) reflect
-	$(LTCOMPILE) -c -o $@ $<
 reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file)
 	@$(MKDIR_P) reflect
 	$(LTCOMPILE) -c -o $@ $<
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 276be26..3299c37 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -7,14 +7,17 @@ 
 package reflect
 
 import (
-	"runtime"
 	"unsafe"
 )
 
 // makeFuncImpl is the closure value implementing the function
 // returned by MakeFunc.
 type makeFuncImpl struct {
-	code uintptr
+	// These first three words are layed out like ffi_go_closure.
+	code	uintptr
+	ffi_cif	unsafe.Pointer
+	ffi_fun	func(unsafe.Pointer, unsafe.Pointer)
+
 	typ  *funcType
 	fn   func([]Value) []Value
 
@@ -22,10 +25,6 @@  type makeFuncImpl struct {
 	// method values.
 	method int
 	rcvr   Value
-
-	// When using FFI, hold onto the FFI closure for the garbage
-	// collector.
-	ffi *ffiData
 }
 
 // MakeFunc returns a new function of the given Type
@@ -58,37 +57,18 @@  func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 	t := typ.common()
 	ftyp := (*funcType)(unsafe.Pointer(t))
 
-	var code uintptr
-	var ffi *ffiData
-	switch runtime.GOARCH {
-	case "amd64", "386", "s390", "s390x":
-		// Indirect Go func value (dummy) to obtain actual
-		// code address. (A Go func value is a pointer to a C
-		// function pointer. http://golang.org/s/go11func.)
-		dummy := makeFuncStub
-		code = **(**uintptr)(unsafe.Pointer(&dummy))
-	default:
-		code, ffi = makeFuncFFI(ftyp, fn)
-	}
-
 	impl := &makeFuncImpl{
-		code:   code,
 		typ:    ftyp,
 		fn:     fn,
 		method: -1,
-		ffi:    ffi,
 	}
 
+	impl.fn = fn
+	makeFuncFFI(ftyp, impl)
+
 	return Value{t, unsafe.Pointer(&impl), flag(Func) | flagIndir}
 }
 
-// makeFuncStub is an assembly function that is the code half of
-// the function returned from MakeFunc. It expects a *callReflectFunc
-// as its context register, and its job is to invoke callReflect(ctxt, frame)
-// where ctxt is the context register and frame is a pointer to the first
-// word in the passed-in argument frame.
-func makeFuncStub()
-
 // makeMethodValue converts v from the rcvr+method index representation
 // of a method value to an actual method func value, which is
 // basically the receiver value with a special bit set, into a true
@@ -123,16 +103,7 @@  func makeMethodValue(op string, v Value) Value {
 		rcvr:   rcvr,
 	}
 
-	switch runtime.GOARCH {
-	case "amd64", "386":
-		// Indirect Go func value (dummy) to obtain actual
-		// code address. (A Go func value is a pointer to a C
-		// function pointer. http://golang.org/s/go11func.)
-		dummy := makeFuncStub
-		fv.code = **(**uintptr)(unsafe.Pointer(&dummy))
-	default:
-		fv.code, fv.ffi = makeFuncFFI(ftyp, fv.call)
-	}
+	makeFuncFFI(ftyp, fv)
 
 	return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func) | flagIndir}
 }
@@ -158,16 +129,7 @@  func makeValueMethod(v Value) Value {
 		rcvr:   v,
 	}
 
-	switch runtime.GOARCH {
-	case "amd64", "386", "s390", "s390x":
-		// Indirect Go func value (dummy) to obtain actual
-		// code address. (A Go func value is a pointer to a C
-		// function pointer. http://golang.org/s/go11func.)
-		dummy := makeFuncStub
-		impl.code = **(**uintptr)(unsafe.Pointer(&dummy))
-	default:
-		impl.code, impl.ffi = makeFuncFFI(ftyp, impl.call)
-	}
+	makeFuncFFI(ftyp, impl)
 
 	return Value{t, unsafe.Pointer(&impl), v.flag&flagRO | flag(Func) | flagIndir}
 }
diff --git a/libgo/go/reflect/makefunc_386.S b/libgo/go/reflect/makefunc_386.S
deleted file mode 100644
index 0e2e764..0000000
--- a/libgo/go/reflect/makefunc_386.S
+++ /dev/null
@@ -1,230 +0,0 @@ 
-/* Copyright 2013 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.
-
-   MakeFunc 386 assembly code.  */
-
-#include "config.h"
-
-	.globl reflect.makeFuncStub
-
-#ifdef __ELF__
-	.type reflect.makeFuncStub,@function
-#endif
-
-reflect.makeFuncStub:
-.LFB1:
-
-	/* Go does not provide any equivalent to the regparm function
-	   attribute, so on Go we do not need to worry about passing
-	   parameters in registers.  We just pass a pointer to the
-	   arguments on the stack.
-	
-	   We do need to pick up the return values, though, so we pass
-	   a pointer to a struct that looks like this.
-	   struct {
-	     esp uint32		// 0x0
-	     eax uint32		// 0x4
-	     st0 float64	// 0x8
-	     sr  bool		// 0x10
-	     sf  bool		// 0x11
-	   }
-	   The sr field is set by the function to a non-zero value if
-	   the function takes a struct hidden pointer that must be
-	   popped off the stack.  */
-
-	pushl	%ebp
-.LCFI0:
-	movl	%esp, %ebp
-.LCFI1:
-	pushl	%ebx		/* In case this is PIC.  */
-	subl	$36, %esp	/* Enough for args and to align stack.  */
-.LCFI2:
-
-#ifdef __PIC__
-	call	__x86.get_pc_thunk.bx
-	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
-#endif
-
-	leal	8(%ebp), %eax	/* Set esp field in struct.  */
-	movl	%eax, -24(%ebp)
-
-	/* For MakeFunc functions that call recover.  */
-	movl	4(%ebp), %eax
-	movl	%eax, (%esp)
-#ifdef __PIC__
-	call	__go_makefunc_can_recover@PLT
-#else
-	call	__go_makefunc_can_recover
-#endif
-
-#ifdef __PIC__
-	call	__go_get_closure@PLT
-#else
-	call	__go_get_closure
-#endif
-
-	movl	%eax, 4(%esp)
-
-	leal	-24(%ebp), %eax
-	movl	%eax, (%esp)
-
-#ifdef __PIC__
-	call	reflect.MakeFuncStubGo@PLT
-#else
-	call	reflect.MakeFuncStubGo
-#endif
-
-	/* MakeFunc functions can no longer call recover.  */
-#ifdef __PIC__
-	call __go_makefunc_returning@PLT
-#else
-	call __go_makefunc_returning
-#endif
-
-	/* Set return registers.  */
-
-	movl	-20(%ebp), %eax
-
-	cmpb	$0, -7(%ebp)
-	je	2f
-
-	fldl	-16(%ebp)
-
-#ifdef __SSE2__
-	/* In case we are compiling with -msseregparm.  This won't work
-	   correctly if only SSE1 is supported, but that seems unlikely.  */
-	movsd	-16(%ebp), %xmm0
-#endif
-
-2:
-	movb	-8(%ebp), %dl
-
-	addl	$36, %esp
-	popl	%ebx
-.LCFI3:
-	popl	%ebp
-.LCFI4:
-
-	testb	%dl,%dl
-	jne	1f
-	ret
-1:
-	ret	$4
-.LFE1:
-#ifdef __ELF__
-	.size	reflect.makeFuncStub, . - reflect.makeFuncStub
-#endif
-
-#ifdef __PIC__
-#ifdef HAVE_AS_COMDAT_GAS
-	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
-#else
-	/* Sun as needs a different syntax.  */
-	.section	.text.__x86.get_pc_thunk.bx%__x86.get_pc_thunk.bx,"ax",@progbits
-	.group		__x86.get_pc_thunk.bx,.text.__x86.get_pc_thunk.bx%__x86.get_pc_thunk.bx,#comdat
-#endif
-	.globl	__x86.get_pc_thunk.bx
-	.hidden	__x86.get_pc_thunk.bx
-#ifdef __ELF__
-	.type	__x86.get_pc_thunk.bx, @function
-#endif
-__x86.get_pc_thunk.bx:
-.LFB2:
-	movl	(%esp), %ebx
-	ret
-.LFE2:
-#ifdef __ELF__
-	.size	__x86.get_pc_thunk.bx, . - __x86.get_pc_thunk.bx
-#endif
-#endif
-
-#ifdef __ELF__
-#if defined __PIC__
-# if defined __sun__ && defined __svr4__
-/* 32-bit Solaris 2/x86 uses datarel encoding for PIC.  GNU ld before 2.22
-   doesn't correctly sort .eh_frame_hdr with mixed encodings, so match this.  */
-#  define FDE_ENCODING		0x30	/* datarel */
-#  define FDE_ENCODE(X)		X@GOTOFF
-# else
-#  define FDE_ENCODING		0x1b	/* pcrel sdata4 */
-#  if defined HAVE_AS_X86_PCREL
-#   define FDE_ENCODE(X)	X-.
-#  else
-#   define FDE_ENCODE(X)	X@rel
-#  endif
-# endif
-#else
-# define FDE_ENCODING		0	/* absolute */
-# define FDE_ENCODE(X)		X
-#endif
-
-	.section	.eh_frame,EH_FRAME_FLAGS,@progbits
-.Lframe1:
-	.long	.LECIE1-.LSCIE1	/* Length of Common Information Entry */
-.LSCIE1:
-	.long	0x0	/* CIE Identifier Tag */
-	.byte	0x1	/* CIE Version */
-	.ascii "zR\0"	/* CIE Augmentation */
-	.byte	0x1	/* .uleb128 0x1; CIE Code Alignment Factor */
-	.byte	0x7c	/* .sleb128 -4; CIE Data Alignment Factor */
-	.byte	0x8	/* CIE RA Column */
-	.byte	0x1	/* .uleb128 0x1; Augmentation size */
-	.byte	FDE_ENCODING
-	.byte	0xc	/* DW_CFA_def_cfa */
-	.byte	0x4	/* .uleb128 0x4 */
-	.byte	0x4	/* .uleb128 0x4 */
-	.byte	0x88	/* DW_CFA_offset, column 0x8 */
-	.byte	0x1	/* .uleb128 0x1 */
-	.align 4
-.LECIE1:
-.LSFDE1:
-	.long	.LEFDE1-.LASFDE1	/* FDE Length */
-.LASFDE1:
-	.long	.LASFDE1-.Lframe1	/* FDE CIE offset */
-	.long	FDE_ENCODE(.LFB1)	/* FDE initial location */
-	.long	.LFE1-.LFB1		/* FDE address range */
-	.byte	0x0	/* .uleb128 0x0; Augmentation size */
-	.byte	0x4	/* DW_CFA_advance_loc4 */
-	.long	.LCFI0-.LFB1
-	.byte	0xe	/* DW_CFA_def_cfa_offset */
-	.byte	0x8	/* .uleb128 0x8 */
-	.byte	0x85	/* DW_CFA_offset, column 0x5 */
-	.byte	0x2	/* .uleb128 0x2 */
-	.byte	0x4	/* DW_CFA_advance_loc4 */
-	.long	.LCFI1-.LCFI0
-	.byte	0xd	/* DW_CFA_def_cfa_register */
-	.byte	0x5	/* .uleb128 0x5 */
-	.byte	0x4	/* DW_CFA_advance_loc4 */
-	.long	.LCFI2-.LCFI1
-	.byte	0x83	/* .DW_CFA_offset, column 0x3 */
-	.byte	0x3	/* .uleb128 0x3 */
-	.byte	0x4	/* DW_CFA_advance_loc4 */
-	.long	.LCFI3-.LCFI2
-	.byte	0xc3	/* DW_CFA_restore, column 0x3 */
-	.byte	0x4	/* DW_CFA_advance_loc4 */
-	.long	.LCFI4-.LCFI3
-	.byte	0xc5	/* DW_CFA_restore, column 0x5 */
-	.byte	0xc	/* DW_CFA_def_cfa */
-	.byte	0x4	/* .uleb128 0x4 */
-	.byte	0x4	/* .uleb128 0x4 */
-	.align 4
-.LEFDE1:
-#ifdef __PIC__
-.LSFDE2:
-	.long	.LEFDE2-.LASFDE2	/* FDE Length */
-.LASFDE2:
-	.long	.LASFDE2-.Lframe1	/* FDE CIE offset */
-	.long	FDE_ENCODE(.LFB2)	/* FDE initial location */
-	.long	.LFE2-.LFB2		/* FDE address range */
-	.byte	0x0	/* .uleb128 0x0; Augmentation size */
-	.align 4
-.LEFDE2:
-#endif /* __PIC__ */
-#endif /* __ELF__ */
-
-#if defined(__ELF__) && defined(__linux__)
-	.section	.note.GNU-stack,"",@progbits
-	.section	.note.GNU-split-stack,"",@progbits
-	.section	.note.GNU-no-split-stack,"",@progbits
-#endif
diff --git a/libgo/go/reflect/makefunc_amd64.S b/libgo/go/reflect/makefunc_amd64.S
deleted file mode 100644
index 88302ee..0000000
--- a/libgo/go/reflect/makefunc_amd64.S
+++ /dev/null
@@ -1,177 +0,0 @@ 
-# Copyright 2013 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# MakeFunc amd64 assembly code.
-
-#include "config.h"
-
-	.global	reflect.makeFuncStub
-
-#ifdef __ELF__
-	.type	reflect.makeFuncStub,@function
-#endif
-
-reflect.makeFuncStub:
-.LFB1:
-
-	# Store all the parameter registers in a struct that looks
-	# like:
-	# struct {
-	#   rax uint64		// 0x0
-	#   rdi uint64		// 0x8
-	#   rsi uint64		// 0x10
-	#   rdx uint64		// 0x18
-	#   rcx uint64		// 0x20
-	#   r8 uint64		// 0x28
-	#   r9 uint64		// 0x30
-	#   rsp uint64		// 0x38 Pointer to arguments on stack.
-	#   xmm0 [2]uint64	// 0x40
-	#   xmm1 [2]uint64	// 0x50
-	#   xmm2 [2]uint64	// 0x60
-	#   xmm3 [2]uint64	// 0x70
-	#   xmm4 [2]uint64	// 0x80
-	#   xmm5 [2]uint64	// 0x90
-	#   xmm6 [2]uint64	// 0xa0
-	#   xmm7 [2]uint64	// 0xb0
-	# };
-
-	pushq	%rbp
-.LCFI0:
-	movq	%rsp, %rbp
-.LCFI1:
-
-	subq	$0xc0, %rsp		# Space for struct on stack.
-
-	movq	%rax, 0x0(%rsp)
-	movq	%rdi, 0x8(%rsp)
-	movq	%rsi, 0x10(%rsp)
-	movq	%rdx, 0x18(%rsp)
-	movq	%rcx, 0x20(%rsp)
-	movq	%r8, 0x28(%rsp)
-	movq	%r9, 0x30(%rsp)
-	leaq	16(%rbp), %rax
-	movq	%rax, 0x38(%rsp)
-	movdqa	%xmm0, 0x40(%rsp)
-	movdqa	%xmm1, 0x50(%rsp)
-	movdqa	%xmm2, 0x60(%rsp)
-	movdqa	%xmm3, 0x70(%rsp)
-	movdqa	%xmm4, 0x80(%rsp)
-	movdqa	%xmm5, 0x90(%rsp)
-	movdqa	%xmm6, 0xa0(%rsp)
-	movdqa	%xmm7, 0xb0(%rsp)
-
-	/* For MakeFunc functions that call recover.  */
-	movq	8(%rbp), %rdi
-#ifdef __PIC__
-	call	__go_makefunc_can_recover@PLT
-#else
-	call	__go_makefunc_can_recover
-#endif
-
-	# Get function type.
-#ifdef __PIC__
-	call	__go_get_closure@PLT
-#else
-	call	__go_get_closure
-#endif
-	movq	%rax, %rsi
-
-	movq	%rsp, %rdi
-
-#ifdef __PIC__
-	call	reflect.MakeFuncStubGo@PLT
-#else
-	call	reflect.MakeFuncStubGo
-#endif
-
-	/* MakeFunc functions can no longer call recover.  */
-#ifdef __PIC__
-	call __go_makefunc_returning@PLT
-#else
-	call __go_makefunc_returning
-#endif
-
-	# The structure will be updated with any return values.  Load
-	# all possible return registers before returning to the caller.
-
-	movq	0x0(%rsp), %rax
-	movq	0x18(%rsp), %rdx
-	movq	0x8(%rsp), %rdi
-	movq	0x10(%rsp), %rsi
-	movdqa	0x40(%rsp), %xmm0
-	movdqa	0x50(%rsp), %xmm1
-
-	# long double values are returned on the floating point stack,
-	# but we don't worry about that since Go doesn't have a long
-	# double type.
-
-	leave
-.LCFI2:
-
-	ret
-.LFE1:
-
-#ifdef __ELF__
-	.size	reflect.makeFuncStub, . - reflect.makeFuncStub
-#endif
-
-#ifdef __ELF__
-#ifdef HAVE_AS_X86_64_UNWIND_SECTION_TYPE
-	.section	.eh_frame,"a",@unwind
-#else
-	.section	.eh_frame,"a",@progbits
-#endif
-.Lframe1:
-	.long	.LECIE1-.LSCIE1	/* Length of Common Information Entry */
-.LSCIE1:
-	.long	0x0		/* CIE Identifier Tag */
-	.byte	0x1		/* CIE Version */
-	.ascii "zR\0"		/* CIE Augmentation */
-	.uleb128 1		/* CIE Code Alignment Factor */
-	.sleb128 -8		/* CIE Data Alignment Factor */
-	.byte	0x10		/* CIE RA Column */
-	.uleb128 1		/* Augmentation size */
-	.byte	0x1b		/* FDE Encoding (pcrel sdata4) */
-	.byte	0xc		/* DW_CFA_def_cfa, %rsp offset 8 */
-	.uleb128 7
-	.uleb128 8
-	.byte	0x80+16		/* DW_CFA_offset, %rip offset 1*-8 */
-	.uleb128 1
-	.align 8
-.LECIE1:
-.LSFDE1:
-	.long	.LEFDE1-.LASFDE1	/* FDE Length */
-.LASFDE1:
-	.long	.LASFDE1-.Lframe1	/* FDE CIE offset */
-#if HAVE_AS_X86_PCREL
-	.long	.LFB1-.			/* FDE initial location */
-#else
-	.long	.LFB1@rel
-#endif
-	.long	.LFE1-.LFB1		/* FDE address range */
-	.uleb128 0x0			/* Augmentation size */
-	.byte	0x4			/* DW_CFA_advance_loc4 */
-	.long	.LCFI0-.LFB1
-	.byte	0xe			/* DW_CFA_def_cfa_offset */
-	.uleb128 16
-	.byte	0x86			/* DW_CFA_offset, column 0x6 */
-	.uleb128 2
-	.byte	0x4			/* DW_CFA_advance_loc4 */
-	.long	.LCFI1-.LCFI0
-	.byte	0xd			/* DW_CFA_def_cfa_register */
-	.uleb128 6
-	.byte	0x2			/* DW_CFA_advance_loc1 */
-	.byte	.LCFI2-.LCFI1
-	.byte	0xc			/* DW_CFA_def_cfa */
-	.uleb128 7
-	.uleb128 8
-	.align 8
-.LEFDE1:
-#endif /* __ELF__ */
-
-#if defined(__ELF__) && defined(__linux__)
-	.section	.note.GNU-stack,"",@progbits
-	.section	.note.GNU-split-stack,"",@progbits
-	.section	.note.GNU-no-split-stack,"",@progbits
-#endif
diff --git a/libgo/go/reflect/makefunc_dummy.c b/libgo/go/reflect/makefunc_dummy.c
deleted file mode 100644
index 8eff0c1..0000000
--- a/libgo/go/reflect/makefunc_dummy.c
+++ /dev/null
@@ -1,15 +0,0 @@ 
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "runtime.h"
-
-/* Dummy function for processors that implement MakeFunc using FFI
-   rather than having builtin support.  */
-
-void makeFuncStub (void) __asm__ ("reflect.makeFuncStub");
-
-void makeFuncStub (void)
-{
-  runtime_throw ("impossible call to makeFuncStub");
-}
diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go
index 40c1ea8..6b61f23 100644
--- a/libgo/go/reflect/makefunc_ffi.go
+++ b/libgo/go/reflect/makefunc_ffi.go
@@ -5,52 +5,27 @@ 
 package reflect
 
 import (
-	"runtime"
 	"unsafe"
 )
 
-// The ffi function, written in C, allocates an FFI closure.  It
-// returns the code and data pointers.  When the code pointer is
-// called, it will call callback.  CIF is an FFI data structure
-// allocated as part of the closure, and is returned to ensure that
-// the GC retains it.
-func ffi(ftyp *funcType, callback func(unsafe.Pointer, unsafe.Pointer)) (code uintptr, data uintptr, cif unsafe.Pointer)
-
-// The ffiFree function, written in C, releases the FFI closure.
-func ffiFree(uintptr)
-
-// An ffiData holds the information needed to preserve an FFI closure
-// for the garbage collector.
-type ffiData struct {
-	code     uintptr
-	data     uintptr
-	cif      unsafe.Pointer
-	callback func(unsafe.Pointer, unsafe.Pointer)
-}
-
-// The makeFuncFFI function uses libffi closures to implement
-// reflect.MakeFunc.  This is used for processors for which we don't
-// have more efficient support.
-func makeFuncFFI(ftyp *funcType, fn func(args []Value) (results []Value)) (uintptr, *ffiData) {
-	callback := func(params, results unsafe.Pointer) {
-		ffiCall(ftyp, fn, params, results)
-	}
-
-	code, data, cif := ffi(ftyp, callback)
-
-	c := &ffiData{code: code, data: data, cif: cif, callback: callback}
-
-	runtime.SetFinalizer(c,
-		func(p *ffiData) {
-			ffiFree(p.data)
-		})
-
-	return code, c
-}
-
-// ffiCall takes pointers to the parameters, calls the function, and
-// stores the results back into memory.
-func ffiCall(ftyp *funcType, fn func([]Value) []Value, params unsafe.Pointer, results unsafe.Pointer) {
+// The makeFuncFFI function, written in C, fills in an FFI closure.
+// It arranges for ffiCall to be invoked directly from FFI.
+func makeFuncFFI(ftyp *funcType, impl *makeFuncImpl)
+
+// FFICallbackGo implements the Go side of the libffi callback.
+// It is exported so that C code can call it.
+//
+// The call chain arriving here looks like
+//   some_go_caller
+//   ->some_ffi_internals
+//     ->ffi_callback (in C)
+//       ->FFICallbackGo
+//
+// The ffi_callback handles __go_makefunc_can_recover, and
+// then passes off the data as received from ffi here.
+
+func FFICallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFuncImpl) {
+	ftyp := impl.typ
 	in := make([]Value, 0, len(ftyp.in))
 	ap := params
 	for _, rt := range ftyp.in {
@@ -61,18 +36,18 @@  func ffiCall(ftyp *funcType, fn func([]Value) []Value, params unsafe.Pointer, re
 		ap = (unsafe.Pointer)(uintptr(ap) + ptrSize)
 	}
 
-	out := fn(in)
+	out := impl.call(in)
 
 	off := uintptr(0)
 	for i, typ := range ftyp.out {
 		v := out[i]
 		if v.typ != typ {
-			panic("reflect: function created by MakeFunc using " + funcName(fn) +
+			panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
 				" returned wrong type: have " +
 				out[i].typ.String() + " for " + typ.String())
 		}
 		if v.flag&flagRO != 0 {
-			panic("reflect: function created by MakeFunc using " + funcName(fn) +
+			panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
 				" returned value obtained from unexported field")
 		}
 
diff --git a/libgo/go/reflect/makefunc_ffi_c.c b/libgo/go/reflect/makefunc_ffi_c.c
index a3dfd4a..727ae81 100644
--- a/libgo/go/reflect/makefunc_ffi_c.c
+++ b/libgo/go/reflect/makefunc_ffi_c.c
@@ -10,7 +10,7 @@ 
 
 #include "go-ffi.h"
 
-#if FFI_CLOSURES
+#if FFI_GO_CLOSURES
 #define USE_LIBFFI_CLOSURES
 #endif
 
@@ -18,36 +18,28 @@ 
 
 /* Declare C functions with the names used to call from Go.  */
 
-struct ffi_ret {
-  void *code;
-  void *data;
-  void *cif;
-};
-
-struct ffi_ret ffi(const struct __go_func_type *ftyp, FuncVal *callback)
-  __asm__ (GOSYM_PREFIX "reflect.ffi");
-
-void ffiFree(void *data)
-  __asm__ (GOSYM_PREFIX "reflect.ffiFree");
+void makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
+  __asm__ (GOSYM_PREFIX "reflect.makeFuncFFI");
 
 #ifdef USE_LIBFFI_CLOSURES
 
-/* The function that we pass to ffi_prep_closure_loc.  This calls the
-   Go callback function (passed in user_data) with the pointer to the
-   arguments and the results area.  */
+/* The function that we pass to ffi_prep_closure_loc.  This calls the Go
+   function ffiCall with the pointer to the arguments, the results area,
+   and the closure structure.  */
+
+void FFICallbackGo(void *result, void **args, ffi_go_closure *closure)
+  __asm__ (GOSYM_PREFIX "reflect.FFICallbackGo");
 
 static void ffi_callback (ffi_cif *, void *, void **, void *)
   __asm__ ("reflect.ffi_callback");
 
 static void
 ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
-	      void **args, void *user_data)
+	      void **args, void *closure)
 {
   Location locs[8];
   int n;
   int i;
-  FuncVal *fv;
-  void (*f) (void *, void *);
 
   /* This function is called from some series of FFI closure functions
      called by a Go function.  We want to see whether the caller of
@@ -69,10 +61,7 @@  ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
   if (i < n)
     __go_makefunc_ffi_can_recover (locs + i, n - i);
 
-  fv = (FuncVal *) user_data;
-  __go_set_closure (fv);
-  f = (void *) fv->fn;
-  f (args, results);
+  FFICallbackGo(results, args, closure);
 
   if (i < n)
     __go_makefunc_returning ();
@@ -80,46 +69,21 @@  ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
 
 /* Allocate an FFI closure and arrange to call ffi_callback.  */
 
-struct ffi_ret
-ffi (const struct __go_func_type *ftyp, FuncVal *callback)
+void
+makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
 {
   ffi_cif *cif;
-  void *code;
-  void *data;
-  struct ffi_ret ret;
 
   cif = (ffi_cif *) __go_alloc (sizeof (ffi_cif));
   __go_func_to_cif (ftyp, 0, 0, cif);
-  data = ffi_closure_alloc (sizeof (ffi_closure), &code);
-  if (data == NULL)
-    runtime_panicstring ("ffi_closure_alloc failed");
-  if (ffi_prep_closure_loc (data, cif, ffi_callback, callback, code)
-      != FFI_OK)
-    runtime_panicstring ("ffi_prep_closure_loc failed");
-  ret.code = code;
-  ret.data = data;
-  ret.cif = cif;
-  return ret;
-}
-
-/* Free the FFI closure.  */
 
-void
-ffiFree (void *data)
-{
-  ffi_closure_free (data);
+  ffi_prep_go_closure(impl, cif, ffi_callback);
 }
 
 #else /* !defined(USE_LIBFFI_CLOSURES) */
 
-struct ffi_ret
-ffi(const struct __go_func_type *ftyp, FuncVal *callback)
-{
-  runtime_panicstring ("libgo built without FFI does not support "
-		       "reflect.MakeFunc");
-}
-
-void ffiFree(void *data)
+void
+makeFuncFFI(const struct __go_func_type *ftyp, ffi_go_closure *impl)
 {
   runtime_panicstring ("libgo built without FFI does not support "
 		       "reflect.MakeFunc");
diff --git a/libgo/go/reflect/makefunc_s390.c b/libgo/go/reflect/makefunc_s390.c
deleted file mode 100644
index 78a960c..0000000
--- a/libgo/go/reflect/makefunc_s390.c
+++ /dev/null
@@ -1,86 +0,0 @@ 
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "runtime.h"
-#include "go-panic.h"
-
-#ifdef __s390x__
-#  define S390_GO_USE_64_BIT_ABI 1
-#  define S390_GO_S390X_ARGS , double f4, double f6
-#  define S390_GO_S390X_FIELDS double f4; double f6;
-   extern void S390xMakeFuncStubGo(void *, void *)
-	asm ("reflect.S390xMakeFuncStubGo");
-#  define S390_GO_MakeFuncStubGo(r, c) S390xMakeFuncStubGo((r), (c))
-#else
-#  define S390_GO_USE_64_BIT_ABI 0
-#  define S390_GO_S390X_ARGS
-#  define S390_GO_S390X_FIELDS
-   extern void S390MakeFuncStubGo(void *, void *)
-	asm ("reflect.S390MakeFuncStubGo");
-#  define S390_GO_MakeFuncStubGo(r, c) S390MakeFuncStubGo((r), (c))
-   /* Needed to make the unused 64 bit abi conditional code compile.  */
-#  define f4 f0
-#  define f6 f2
-#endif
-
-/* Structure to store all registers used for parameter passing.  */
-typedef struct
-{
-	long r2;
-	long r3;
-	long r4;
-	long r5;
-	long r6;
-	/* Pointer to non-register arguments on the stack.  */
-	long stack_args;
-	double f0;
-	double f2;
-	S390_GO_S390X_FIELDS
-} s390Regs;
-
-void
-makeFuncStub(long r2, long r3, long r4, long r5, long r6,
-	unsigned long stack_args, double f0, double f2
-	S390_GO_S390X_ARGS)
-	asm ("reflect.makeFuncStub");
-
-void
-makeFuncStub(long r2, long r3, long r4, long r5, long r6,
-	unsigned long stack_args, double f0, double f2
-	S390_GO_S390X_ARGS)
-{
-	s390Regs regs;
-	void *closure;
-
-	/* Store the registers in a structure that is passed on to the Go stub
-	   function.  */
-	regs.r2 = r2;
-	regs.r3 = r3;
-	regs.r4 = r4;
-	regs.r5 = r5;
-	regs.r6 = r6;
-	regs.stack_args = (long)&stack_args;
-	regs.f0 = f0;
-	regs.f2 = f2;
-	if (S390_GO_USE_64_BIT_ABI) {
-		regs.f4 = f4;
-		regs.f6 = f6;
-	}
-	/* For MakeFunc functions that call recover.  */
-	__go_makefunc_can_recover(__builtin_return_address(0));
-	/* Call the Go stub function.  */
-	closure = __go_get_closure();
-	S390_GO_MakeFuncStubGo(&regs, closure);
-	/* MakeFunc functions can no longer call recover.  */
-	__go_makefunc_returning();
-	/* Restore all possible return registers.  */
-	if (S390_GO_USE_64_BIT_ABI) {
-		asm volatile ("lg\t%%r2,0(%0)" : : "a" (&regs.r2) : "r2" );
-		asm volatile ("ld\t%%f0,0(%0)" : : "a" (&regs.f0) : "f0" );
-	} else {
-		asm volatile ("l\t%%r2,0(%0)" : : "a" (&regs.r2) : "r2" );
-		asm volatile ("l\t%%r3,0(%0)" : : "a" (&regs.r3) : "r3" );
-		asm volatile ("ld\t%%f0,0(%0)" : : "a" (&regs.f0) : "f0" );
-	}
-}
diff --git a/libgo/go/reflect/makefuncgo_386.go b/libgo/go/reflect/makefuncgo_386.go
deleted file mode 100644
index c20f0ac..0000000
--- a/libgo/go/reflect/makefuncgo_386.go
+++ /dev/null
@@ -1,139 +0,0 @@ 
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// MakeFunc 386 implementation.
-
-package reflect
-
-import "unsafe"
-
-// The assembler stub will pass a pointer to this structure.  We
-// assume that no parameters are passed in registers--that is, we do
-// not support the -mregparm option.  On return we will set the
-// registers that might hold result values.
-type i386Regs struct {
-	esp uint32
-	eax uint32  // Value to return in %eax.
-	st0 float64 // Value to return in %st(0).
-	sr  bool    // Set to true if hidden struct pointer.
-	sf  bool    // Set to true if returning float
-}
-
-// MakeFuncStubGo implements the 386 calling convention for MakeFunc.
-// This should not be called.  It is exported so that assembly code
-// can call it.
-
-func MakeFuncStubGo(regs *i386Regs, c *makeFuncImpl) {
-	ftyp := c.typ
-
-	// See if the result requires a struct.  If it does, the first
-	// parameter is a pointer to the struct.
-	retStruct := false
-	retEmpty := false
-	switch len(ftyp.out) {
-	case 0:
-		retEmpty = true
-	case 1:
-		if ftyp.out[0].size == 0 {
-			retEmpty = true
-		} else {
-			switch ftyp.out[0].Kind() {
-			case Complex64, Complex128, Array, Interface, Slice, String, Struct:
-				retStruct = true
-			}
-		}
-	default:
-		size := uintptr(0)
-		for _, typ := range ftyp.out {
-			size += typ.size
-		}
-		if size == 0 {
-			retEmpty = true
-		} else {
-			retStruct = true
-		}
-	}
-
-	in := make([]Value, 0, len(ftyp.in))
-	ap := uintptr(regs.esp)
-
-	regs.sr = false
-	regs.sf = false
-	var retPtr unsafe.Pointer
-	if retStruct {
-		retPtr = *(*unsafe.Pointer)(unsafe.Pointer(ap))
-		ap += ptrSize
-		regs.sr = true
-	}
-
-	for _, rt := range ftyp.in {
-		ap = align(ap, ptrSize)
-
-		// We have to copy the argument onto the heap in case
-		// the function hangs on the reflect.Value we pass it.
-		p := unsafe_New(rt)
-		memmove(p, unsafe.Pointer(ap), rt.size)
-
-		v := Value{rt, p, flag(rt.Kind()) | flagIndir}
-		in = append(in, v)
-		ap += rt.size
-	}
-
-	// Call the real function.
-
-	out := c.call(in)
-
-	if len(out) != len(ftyp.out) {
-		panic("reflect: wrong return count from function created by MakeFunc")
-	}
-
-	for i, typ := range ftyp.out {
-		v := out[i]
-		if v.typ != typ {
-			panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
-				" returned wrong type: have " +
-				out[i].typ.String() + " for " + typ.String())
-		}
-		if v.flag&flagRO != 0 {
-			panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
-				" returned value obtained from unexported field")
-		}
-	}
-
-	if retEmpty {
-		return
-	}
-
-	if retStruct {
-		off := uintptr(0)
-		for i, typ := range ftyp.out {
-			v := out[i]
-			off = align(off, uintptr(typ.fieldAlign))
-			addr := unsafe.Pointer(uintptr(retPtr) + off)
-			if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
-				*(*unsafe.Pointer)(addr) = v.ptr
-			} else {
-				memmove(addr, v.ptr, typ.size)
-			}
-			off += typ.size
-		}
-		regs.eax = uint32(uintptr(retPtr))
-		return
-	}
-
-	if len(ftyp.out) != 1 {
-		panic("inconsistency")
-	}
-
-	v := out[0]
-	switch v.Kind() {
-	case Ptr, UnsafePointer, Chan, Func, Map:
-		regs.eax = uint32(uintptr(v.pointer()))
-	case Float32, Float64:
-		regs.st0 = v.Float()
-		regs.sf = true
-	default:
-		memmove(unsafe.Pointer(&regs.eax), v.ptr, v.typ.size)
-	}
-}
diff --git a/libgo/go/reflect/makefuncgo_amd64.go b/libgo/go/reflect/makefuncgo_amd64.go
deleted file mode 100644
index a236aa2..0000000
--- a/libgo/go/reflect/makefuncgo_amd64.go
+++ /dev/null
@@ -1,496 +0,0 @@ 
-// Copyright 2013 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// MakeFunc amd64 implementation.
-
-package reflect
-
-import "unsafe"
-
-// The assembler stub will pass a pointer to this structure.
-// This will come in holding all the registers that might hold
-// function parameters.  On return we will set the registers that
-// might hold result values.
-type amd64Regs struct {
-	rax  uint64
-	rdi  uint64
-	rsi  uint64
-	rdx  uint64
-	rcx  uint64
-	r8   uint64
-	r9   uint64
-	rsp  uint64
-	xmm0 [2]uint64
-	xmm1 [2]uint64
-	xmm2 [2]uint64
-	xmm3 [2]uint64
-	xmm4 [2]uint64
-	xmm5 [2]uint64
-	xmm6 [2]uint64
-	xmm7 [2]uint64
-}
-
-// Argument classifications.  The amd64 ELF ABI uses several more, but
-// these are the only ones that arise for Go types.
-type amd64Class int
-
-const (
-	amd64Integer amd64Class = iota
-	amd64SSE
-	amd64NoClass
-	amd64Memory
-)
-
-// amd64Classify returns the one or two register classes needed to
-// pass the value of type.  Go types never need more than two
-// registers.  amd64Memory means the value is stored in memory.
-// amd64NoClass means the register is not used.
-func amd64Classify(typ *rtype) (amd64Class, amd64Class) {
-	switch typ.Kind() {
-	default:
-		panic("internal error--unknown kind in amd64Classify")
-
-	case Bool, Int, Int8, Int16, Int32, Int64,
-		Uint, Uint8, Uint16, Uint32, Uint64,
-		Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
-
-		return amd64Integer, amd64NoClass
-
-	case Float32, Float64, Complex64:
-		return amd64SSE, amd64NoClass
-
-	case Complex128:
-		return amd64SSE, amd64SSE
-
-	case Array:
-		if typ.size == 0 {
-			return amd64NoClass, amd64NoClass
-		} else if typ.size > 16 {
-			return amd64Memory, amd64NoClass
-		}
-		atyp := (*arrayType)(unsafe.Pointer(typ))
-		eclass1, eclass2 := amd64Classify(atyp.elem)
-		if eclass1 == amd64Memory {
-			return amd64Memory, amd64NoClass
-		}
-		if eclass2 == amd64NoClass && typ.size > 8 {
-			eclass2 = eclass1
-		}
-		return eclass1, eclass2
-
-	case Interface:
-		return amd64Integer, amd64Integer
-
-	case Slice:
-		return amd64Memory, amd64NoClass
-
-	case String:
-		return amd64Integer, amd64Integer
-
-	case Struct:
-		if typ.size == 0 {
-			return amd64NoClass, amd64NoClass
-		} else if typ.size > 16 {
-			return amd64Memory, amd64NoClass
-		}
-		var first, second amd64Class
-		f := amd64NoClass
-		onFirst := true
-		styp := (*structType)(unsafe.Pointer(typ))
-		for _, field := range styp.fields {
-			if onFirst && field.offset >= 8 {
-				first = f
-				f = amd64NoClass
-				onFirst = false
-			}
-			fclass1, fclass2 := amd64Classify(field.typ)
-			f = amd64MergeClasses(f, fclass1)
-			if fclass2 != amd64NoClass {
-				if !onFirst {
-					panic("amd64Classify inconsistent")
-				}
-				first = f
-				f = fclass2
-				onFirst = false
-			}
-		}
-		if onFirst {
-			first = f
-			second = amd64NoClass
-		} else {
-			second = f
-		}
-		if first == amd64Memory || second == amd64Memory {
-			return amd64Memory, amd64NoClass
-		}
-		return first, second
-	}
-}
-
-// amd64MergeClasses merges two register classes as described in the
-// amd64 ELF ABI.
-func amd64MergeClasses(c1, c2 amd64Class) amd64Class {
-	switch {
-	case c1 == c2:
-		return c1
-	case c1 == amd64NoClass:
-		return c2
-	case c2 == amd64NoClass:
-		return c1
-	case c1 == amd64Memory || c2 == amd64Memory:
-		return amd64Memory
-	case c1 == amd64Integer || c2 == amd64Integer:
-		return amd64Integer
-	default:
-		return amd64SSE
-	}
-}
-
-// MakeFuncStubGo implements the amd64 calling convention for
-// MakeFunc.  This should not be called.  It is exported so that
-// assembly code can call it.
-
-func MakeFuncStubGo(regs *amd64Regs, c *makeFuncImpl) {
-	ftyp := c.typ
-
-	// See if the result requires a struct.  If it does, the first
-	// parameter is a pointer to the struct.
-	var ret1, ret2 amd64Class
-	switch len(ftyp.out) {
-	case 0:
-		ret1, ret2 = amd64NoClass, amd64NoClass
-	case 1:
-		ret1, ret2 = amd64Classify(ftyp.out[0])
-	default:
-		off := uintptr(0)
-		f := amd64NoClass
-		onFirst := true
-		for _, rt := range ftyp.out {
-			off = align(off, uintptr(rt.fieldAlign))
-
-			if onFirst && off >= 8 {
-				ret1 = f
-				f = amd64NoClass
-				onFirst = false
-			}
-
-			off += rt.size
-			if off > 16 {
-				break
-			}
-
-			fclass1, fclass2 := amd64Classify(rt)
-			f = amd64MergeClasses(f, fclass1)
-			if fclass2 != amd64NoClass {
-				if !onFirst {
-					panic("amd64Classify inconsistent")
-				}
-				ret1 = f
-				f = fclass2
-				onFirst = false
-			}
-		}
-		if off > 16 {
-			ret1, ret2 = amd64Memory, amd64NoClass
-		} else {
-			if onFirst {
-				ret1, ret2 = f, amd64NoClass
-			} else {
-				ret2 = f
-			}
-		}
-		if ret1 == amd64Memory || ret2 == amd64Memory {
-			ret1, ret2 = amd64Memory, amd64NoClass
-		}
-	}
-
-	in := make([]Value, 0, len(ftyp.in))
-	intreg := 0
-	ssereg := 0
-	ap := uintptr(regs.rsp)
-
-	maxIntregs := 6 // When we support Windows, this would be 4.
-	maxSSEregs := 8
-
-	if ret1 == amd64Memory {
-		// We are returning a value in memory, which means
-		// that the first argument is a hidden parameter
-		// pointing to that return area.
-		intreg++
-	}
-
-argloop:
-	for _, rt := range ftyp.in {
-		c1, c2 := amd64Classify(rt)
-
-		fl := flag(rt.Kind())
-		if c2 == amd64NoClass {
-
-			// Argument is passed in a single register or
-			// in memory.
-
-			switch c1 {
-			case amd64NoClass:
-				v := Value{rt, nil, fl | flagIndir}
-				in = append(in, v)
-				continue argloop
-			case amd64Integer:
-				if intreg < maxIntregs {
-					reg := amd64IntregVal(regs, intreg)
-					iw := unsafe.Pointer(reg)
-					if k := rt.Kind(); k != Ptr && k != UnsafePointer {
-						iw = unsafe.Pointer(&reg)
-						fl |= flagIndir
-					}
-					v := Value{rt, iw, fl}
-					in = append(in, v)
-					intreg++
-					continue argloop
-				}
-			case amd64SSE:
-				if ssereg < maxSSEregs {
-					reg := amd64SSEregVal(regs, ssereg)
-					v := Value{rt, unsafe.Pointer(&reg), fl | flagIndir}
-					in = append(in, v)
-					ssereg++
-					continue argloop
-				}
-			}
-
-			in, ap = amd64Memarg(in, ap, rt)
-			continue argloop
-		}
-
-		// Argument is passed in two registers.
-
-		nintregs := 0
-		nsseregs := 0
-		switch c1 {
-		case amd64Integer:
-			nintregs++
-		case amd64SSE:
-			nsseregs++
-		default:
-			panic("inconsistent")
-		}
-		switch c2 {
-		case amd64Integer:
-			nintregs++
-		case amd64SSE:
-			nsseregs++
-		default:
-			panic("inconsistent")
-		}
-
-		// If the whole argument does not fit in registers, it
-		// is passed in memory.
-
-		if intreg+nintregs > maxIntregs || ssereg+nsseregs > maxSSEregs {
-			in, ap = amd64Memarg(in, ap, rt)
-			continue argloop
-		}
-
-		var word1, word2 uintptr
-		switch c1 {
-		case amd64Integer:
-			word1 = amd64IntregVal(regs, intreg)
-			intreg++
-		case amd64SSE:
-			word1 = amd64SSEregVal(regs, ssereg)
-			ssereg++
-		}
-		switch c2 {
-		case amd64Integer:
-			word2 = amd64IntregVal(regs, intreg)
-			intreg++
-		case amd64SSE:
-			word2 = amd64SSEregVal(regs, ssereg)
-			ssereg++
-		}
-
-		p := unsafe_New(rt)
-		*(*uintptr)(p) = word1
-		*(*uintptr)(unsafe.Pointer(uintptr(p) + ptrSize)) = word2
-		v := Value{rt, p, fl | flagIndir}
-		in = append(in, v)
-	}
-
-	// All the real arguments have been found and turned into
-	// Value's.  Call the real function.
-
-	out := c.call(in)
-
-	if len(out) != len(ftyp.out) {
-		panic("reflect: wrong return count from function created by MakeFunc")
-	}
-
-	for i, typ := range ftyp.out {
-		v := out[i]
-		if v.typ != typ {
-			panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
-				" returned wrong type: have " +
-				out[i].typ.String() + " for " + typ.String())
-		}
-		if v.flag&flagRO != 0 {
-			panic("reflect: function created by MakeFunc using " + funcName(c.fn) +
-				" returned value obtained from unexported field")
-		}
-	}
-
-	if ret1 == amd64NoClass {
-		return
-	}
-
-	if ret1 == amd64Memory {
-		// The address of the memory area was passed as a
-		// hidden parameter in %rdi.
-		ptr := unsafe.Pointer(uintptr(regs.rdi))
-		off := uintptr(0)
-		for i, typ := range ftyp.out {
-			v := out[i]
-			off = align(off, uintptr(typ.fieldAlign))
-			addr := unsafe.Pointer(uintptr(ptr) + off)
-			if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
-				*(*unsafe.Pointer)(addr) = v.ptr
-			} else {
-				memmove(addr, v.ptr, typ.size)
-			}
-			off += typ.size
-		}
-		return
-	}
-
-	if len(out) == 1 && ret2 == amd64NoClass {
-		v := out[0]
-		var w unsafe.Pointer
-		switch v.Kind() {
-		case Ptr, UnsafePointer, Chan, Func, Map:
-			w = v.pointer()
-		default:
-			memmove(unsafe.Pointer(&w), v.ptr, v.typ.size)
-		}
-		switch ret1 {
-		case amd64Integer:
-			regs.rax = uint64(uintptr(w))
-		case amd64SSE:
-			regs.xmm0[0] = uint64(uintptr(w))
-			regs.xmm0[1] = 0
-		default:
-			panic("inconsistency")
-		}
-		return
-	}
-
-	var buf [2]unsafe.Pointer
-	ptr := unsafe.Pointer(&buf[0])
-	off := uintptr(0)
-	for i, typ := range ftyp.out {
-		v := out[i]
-		off = align(off, uintptr(typ.fieldAlign))
-		addr := unsafe.Pointer(uintptr(ptr) + off)
-		if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
-			*(*unsafe.Pointer)(addr) = v.ptr
-		} else {
-			memmove(addr, v.ptr, typ.size)
-		}
-		off += uintptr(typ.size)
-	}
-
-	switch ret1 {
-	case amd64Integer:
-		regs.rax = *(*uint64)(unsafe.Pointer(&buf[0]))
-	case amd64SSE:
-		regs.xmm0[0] = *(*uint64)(unsafe.Pointer(&buf[0]))
-		regs.xmm0[1] = 0
-	default:
-		panic("inconsistency")
-	}
-
-	switch ret2 {
-	case amd64Integer:
-		reg := *(*uint64)(unsafe.Pointer(&buf[1]))
-		if ret1 == amd64Integer {
-			regs.rdx = reg
-		} else {
-			regs.rax = reg
-		}
-	case amd64SSE:
-		reg := *(*uint64)(unsafe.Pointer(&buf[1]))
-		if ret1 == amd64Integer {
-			regs.xmm0[0] = reg
-			regs.xmm0[1] = 0
-		} else {
-			regs.xmm1[0] = reg
-			regs.xmm1[1] = 0
-		}
-	case amd64NoClass:
-	default:
-		panic("inconsistency")
-	}
-}
-
-// The amd64Memarg function adds an argument passed in memory.
-func amd64Memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) {
-	ap = align(ap, ptrSize)
-	ap = align(ap, uintptr(rt.align))
-
-	// We have to copy the argument onto the heap in case the
-	// function hangs onto the reflect.Value we pass it.
-	p := unsafe_New(rt)
-	memmove(p, unsafe.Pointer(ap), rt.size)
-
-	v := Value{rt, p, flag(rt.Kind()) | flagIndir}
-	in = append(in, v)
-	ap += rt.size
-	return in, ap
-}
-
-// The amd64IntregVal function returns the value of integer register i.
-func amd64IntregVal(regs *amd64Regs, i int) uintptr {
-	var r uint64
-	switch i {
-	case 0:
-		r = regs.rdi
-	case 1:
-		r = regs.rsi
-	case 2:
-		r = regs.rdx
-	case 3:
-		r = regs.rcx
-	case 4:
-		r = regs.r8
-	case 5:
-		r = regs.r9
-	default:
-		panic("amd64IntregVal: bad index")
-	}
-	return uintptr(r)
-}
-
-// The amd64SSEregVal function returns the value of SSE register i.
-// Note that although SSE registers can hold two uinptr's, for the
-// types we use in Go we only ever use the least significant one.  The
-// most significant one would only be used for 128 bit types.
-func amd64SSEregVal(regs *amd64Regs, i int) uintptr {
-	var r uint64
-	switch i {
-	case 0:
-		r = regs.xmm0[0]
-	case 1:
-		r = regs.xmm1[0]
-	case 2:
-		r = regs.xmm2[0]
-	case 3:
-		r = regs.xmm3[0]
-	case 4:
-		r = regs.xmm4[0]
-	case 5:
-		r = regs.xmm5[0]
-	case 6:
-		r = regs.xmm6[0]
-	case 7:
-		r = regs.xmm7[0]
-	}
-	return uintptr(r)
-}
diff --git a/libgo/go/reflect/makefuncgo_s390.go b/libgo/go/reflect/makefuncgo_s390.go
deleted file mode 100644
index 47daa77..0000000
--- a/libgo/go/reflect/makefuncgo_s390.go
+++ /dev/null
@@ -1,454 +0,0 @@ 
-// Copyright 2014 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// MakeFunc s390 implementation.
-
-package reflect
-
-import "unsafe"
-
-// Convenience types and constants.
-const s390_arch_stack_slot_align uintptr = 4
-const s390_num_gr = 5
-const s390_num_fr = 2
-
-type s390_arch_gr_t uint32
-type s390_arch_fr_t uint64
-
-// The assembler stub will pass a pointer to this structure.
-// This will come in holding all the registers that might hold
-// function parameters.  On return we will set the registers that
-// might hold result values.
-type s390_regs struct {
-	r2         s390_arch_gr_t
-	r3         s390_arch_gr_t
-	r4         s390_arch_gr_t
-	r5         s390_arch_gr_t
-	r6         s390_arch_gr_t
-	stack_args s390_arch_gr_t
-	f0         s390_arch_fr_t
-	f2         s390_arch_fr_t
-}
-
-// Argument classifications that arise for Go types.
-type s390_arg_t int
-
-const (
-	s390_general_reg s390_arg_t = iota
-	s390_general_reg_pair
-	s390_float_reg
-	// Argument passed as a pointer to an in-memory value.
-	s390_mem_ptr
-	s390_empty
-)
-
-// s390ClassifyParameter returns the register class needed to
-// pass the value of type TYP.  s390_empty means the register is
-// not used.  The second and third return values are the offset of
-// an rtype parameter passed in a register (second) or stack slot
-// (third).
-func s390ClassifyParameter(typ *rtype) (s390_arg_t, uintptr, uintptr) {
-	offset := s390_arch_stack_slot_align - typ.Size()
-	if typ.Size() > s390_arch_stack_slot_align {
-		offset = 0
-	}
-	switch typ.Kind() {
-	default:
-		panic("internal error--unknown kind in s390ClassifyParameter")
-	case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32:
-		return s390_general_reg, offset, offset
-	case Int64, Uint64:
-		return s390_general_reg_pair, 0, 0
-	case Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
-		return s390_general_reg, 0, 0
-	case Float32, Float64:
-		return s390_float_reg, 0, offset
-	case Complex64, Complex128:
-		// Complex numbers are passed by reference.
-		return s390_mem_ptr, 0, 0
-	case Array, Struct:
-		var ityp *rtype
-		var length int
-
-		if typ.Size() == 0 {
-			return s390_empty, 0, 0
-		}
-		switch typ.Size() {
-		default:
-			// Pointer to memory.
-			return s390_mem_ptr, 0, 0
-		case 1, 2:
-			// Pass in an integer register.
-			return s390_general_reg, offset, offset
-
-		case 4, 8:
-			// See below.
-		}
-		if typ.Kind() == Array {
-			atyp := (*arrayType)(unsafe.Pointer(typ))
-			length = atyp.Len()
-			ityp = atyp.elem
-		} else {
-			styp := (*structType)(unsafe.Pointer(typ))
-			length = len(styp.fields)
-			ityp = styp.fields[0].typ
-		}
-		if length == 1 {
-			class, off_reg, off_slot := s390ClassifyParameter(ityp)
-			if class == s390_float_reg {
-				// The array (stored in a structure) or struct
-				// is "equivalent to a floating point type" as
-				// defined in the S390 Abi.  Note that this
-				// can only be the case in the case 4 of the
-				// switch above.
-				return s390_float_reg, off_reg, off_slot
-			}
-		}
-		switch typ.Size() {
-		case 4:
-			return s390_general_reg, offset, offset
-		case 8:
-			return s390_general_reg_pair, 0, 0
-		default:
-			return s390_general_reg, 0, 0
-		}
-	case Interface, String:
-		// Structure of size 8.
-		return s390_general_reg_pair, 0, 0
-
-	case Slice:
-		return s390_mem_ptr, 0, 0
-	}
-}
-
-// s390ClassifyReturn returns the register classes needed to
-// return the value of type TYP.  s390_empty means the register is
-// not used.  The second value is the offset of an rtype return
-// parameter if stored in a register.
-func s390ClassifyReturn(typ *rtype) (s390_arg_t, uintptr) {
-	offset := s390_arch_stack_slot_align - typ.Size()
-	if typ.Size() > s390_arch_stack_slot_align {
-		offset = 0
-	}
-	switch typ.Kind() {
-	default:
-		panic("internal error--unknown kind in s390ClassifyReturn")
-	case Bool, Int, Int8, Int16, Int32,
-		Uint, Uint8, Uint16, Uint32, Uintptr:
-
-		return s390_general_reg, offset
-	case Int64, Uint64:
-		return s390_general_reg_pair, 0
-	case Chan, Func, Map, Ptr, UnsafePointer:
-		return s390_general_reg, 0
-	case Float32, Float64:
-		return s390_float_reg, 0
-	case Complex64, Complex128:
-		return s390_mem_ptr, 0
-	case Interface, Slice, String:
-		return s390_mem_ptr, 0
-	case Array, Struct:
-		if typ.size == 0 {
-			return s390_empty, 0
-		}
-		// No optimization is done for returned structures and arrays.
-		return s390_mem_ptr, 0
-	}
-}
-
-// Given a value of type *rtype left aligned in an unsafe.Pointer,
-// reload the value so that it can be stored in a general or
-// floating point register.  For general registers the value is
-// sign extend and right aligned.
-func s390ReloadForRegister(typ *rtype, w uintptr, offset uintptr) uintptr {
-	var do_sign_extend bool = false
-	var gr s390_arch_gr_t
-
-	switch typ.Kind() {
-	case Int, Int8, Int16, Int32:
-		do_sign_extend = true
-	default:
-		// Handle all other cases in the next switch.
-	}
-	switch typ.size {
-	case 1:
-		if do_sign_extend == true {
-			se := int32(*(*int8)(unsafe.Pointer(&w)))
-			gr = *(*s390_arch_gr_t)(unsafe.Pointer(&se))
-		} else {
-			e := int32(*(*uint8)(unsafe.Pointer(&w)))
-			gr = *(*s390_arch_gr_t)(unsafe.Pointer(&e))
-		}
-	case 2:
-		if do_sign_extend == true {
-			se := int32(*(*int16)(unsafe.Pointer(&w)))
-			gr = *(*s390_arch_gr_t)(unsafe.Pointer(&se))
-		} else {
-			e := int32(*(*uint16)(unsafe.Pointer(&w)))
-			gr = *(*s390_arch_gr_t)(unsafe.Pointer(&e))
-		}
-	default:
-		panic("reflect: bad size in s390ReloadForRegister")
-	}
-
-	return *(*uintptr)(unsafe.Pointer(&gr))
-}
-
-// MakeFuncStubGo implements the s390 calling convention for
-// MakeFunc.  This should not be called.  It is exported so that
-// assembly code can call it.
-func S390MakeFuncStubGo(regs *s390_regs, c *makeFuncImpl) {
-	ftyp := c.typ
-	gr := 0
-	fr := 0
-	ap := uintptr(regs.stack_args)
-
-	// See if the result requires a struct.  If it does, the first
-	// parameter is a pointer to the struct.
-	var ret_class s390_arg_t
-	var ret_off_reg uintptr
-	var ret_type *rtype
-
-	switch len(ftyp.out) {
-	case 0:
-		ret_type = nil
-		ret_class, ret_off_reg = s390_empty, 0
-	case 1:
-		ret_type = ftyp.out[0]
-		ret_class, ret_off_reg = s390ClassifyReturn(ret_type)
-	default:
-		ret_type = nil
-		ret_class, ret_off_reg = s390_mem_ptr, 0
-	}
-	in := make([]Value, 0, len(ftyp.in))
-	if ret_class == s390_mem_ptr {
-		// We are returning a value in memory, which means
-		// that the first argument is a hidden parameter
-		// pointing to that return area.
-		gr++
-	}
-
-argloop:
-	for _, rt := range ftyp.in {
-		class, off_reg, off_slot := s390ClassifyParameter(rt)
-		fl := flag(rt.Kind())
-		switch class {
-		case s390_empty:
-			v := Value{rt, nil, fl | flagIndir}
-			in = append(in, v)
-			continue argloop
-		case s390_general_reg:
-			// Values stored in a general register are right
-			// aligned.
-			if gr < s390_num_gr {
-				val := s390_general_reg_val(regs, gr)
-				iw := unsafe.Pointer(&val)
-				k := rt.Kind()
-				if k != Ptr && k != UnsafePointer {
-					ix := uintptr(unsafe.Pointer(&val))
-					ix += off_reg
-					iw = unsafe.Pointer(ix)
-					fl |= flagIndir
-				}
-				v := Value{rt, iw, fl}
-				in = append(in, v)
-				gr++
-			} else {
-				in, ap = s390_add_stackreg(
-					in, ap, rt, off_slot)
-			}
-			continue argloop
-		case s390_general_reg_pair:
-			// 64-bit integers and structs are passed in a register
-			// pair.
-			if gr+1 < s390_num_gr {
-				val := uint64(s390_general_reg_val(regs, gr))<<32 + uint64(s390_general_reg_val(regs, gr+1))
-				iw := unsafe.Pointer(&val)
-				v := Value{rt, iw, fl | flagIndir}
-				in = append(in, v)
-				gr += 2
-			} else {
-				in, ap = s390_add_stackreg(in, ap, rt, off_slot)
-				gr = s390_num_gr
-			}
-			continue argloop
-		case s390_float_reg:
-			// In a register, floats are left aligned, but in a
-			// stack slot they are right aligned.
-			if fr < s390_num_fr {
-				val := s390_float_reg_val(regs, fr)
-				ix := uintptr(unsafe.Pointer(&val))
-				v := Value{
-					rt, unsafe.Pointer(unsafe.Pointer(ix)),
-					fl | flagIndir,
-				}
-				in = append(in, v)
-				fr++
-			} else {
-				in, ap = s390_add_stackreg(
-					in, ap, rt, off_slot)
-			}
-			continue argloop
-		case s390_mem_ptr:
-			if gr < s390_num_gr {
-				// Register holding a pointer to memory.
-				val := s390_general_reg_val(regs, gr)
-				v := Value{
-					rt, unsafe.Pointer(uintptr(val)),
-					fl | flagIndir}
-				in = append(in, v)
-				gr++
-			} else {
-				// Stack slot holding a pointer to memory.
-				in, ap = s390_add_memarg(in, ap, rt)
-			}
-			continue argloop
-		}
-		panic("reflect: argtype not handled in MakeFunc:argloop")
-	}
-
-	// All the real arguments have been found and turned into
-	// Values.  Call the real function.
-
-	out := c.call(in)
-
-	if len(out) != len(ftyp.out) {
-		panic("reflect: wrong return count from function created by MakeFunc")
-	}
-
-	for i, typ := range ftyp.out {
-		v := out[i]
-		if v.typ != typ {
-			panic(
-				"reflect: function created by MakeFunc using " +
-					funcName(c.fn) + " returned wrong type: have " +
-					out[i].typ.String() + " for " + typ.String())
-		}
-		if v.flag&flagRO != 0 {
-			panic(
-				"reflect: function created by MakeFunc using " +
-					funcName(c.fn) + " returned value obtained " +
-					"from unexported field")
-		}
-	}
-
-	switch ret_class {
-	case s390_general_reg, s390_float_reg, s390_general_reg_pair:
-		// Single return value in a general or floating point register.
-		v := out[0]
-		var w uintptr
-		switch v.Kind() {
-		case Ptr, UnsafePointer, Chan, Func, Map:
-			w = uintptr(v.pointer())
-		default:
-			memmove(unsafe.Pointer(&w), v.ptr, v.typ.size)
-			if ret_off_reg != 0 {
-				w = s390ReloadForRegister(
-					ret_type, w, ret_off_reg)
-			}
-		}
-		if ret_class == s390_float_reg {
-			regs.f0 = s390_arch_fr_t(uintptr(w))
-		} else if ret_class == s390_general_reg {
-			regs.r2 = s390_arch_gr_t(uintptr(w))
-		} else {
-			regs.r2 = s390_arch_gr_t(uintptr(w) >> 32)
-			regs.r3 = s390_arch_gr_t(uintptr(w) & 0xffffffff)
-		}
-
-	case s390_mem_ptr:
-		// The address of the memory area was passed as a hidden
-		// parameter in %r2.  Multiple return values are always returned
-		// in an in-memory structure.
-		ptr := unsafe.Pointer(uintptr(regs.r2))
-		off := uintptr(0)
-		for i, typ := range ftyp.out {
-			v := out[i]
-			off = align(off, uintptr(typ.fieldAlign))
-			addr := unsafe.Pointer(uintptr(ptr) + off)
-			if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
-				*(*unsafe.Pointer)(addr) = v.ptr
-			} else {
-				memmove(addr, v.ptr, typ.size)
-			}
-			off += typ.size
-		}
-
-	case s390_empty:
-	}
-
-	return
-}
-
-// The s390_add_stackreg function adds an argument passed on the
-// stack that could be passed in a register.
-func s390_add_stackreg(in []Value, ap uintptr, rt *rtype, offset uintptr) ([]Value, uintptr) {
-	// If we're not already at the beginning of a stack slot, round up to
-	// the beginning of the next one.
-	ap = align(ap, s390_arch_stack_slot_align)
-	// If offset is > 0, the data is right aligned on the stack slot.
-	ap += offset
-
-	// We have to copy the argument onto the heap in case the
-	// function hangs onto the reflect.Value we pass it.
-	p := unsafe_New(rt)
-	memmove(p, unsafe.Pointer(ap), rt.size)
-
-	v := Value{rt, p, flag(rt.Kind()) | flagIndir}
-	in = append(in, v)
-	ap += rt.size
-	ap = align(ap, s390_arch_stack_slot_align)
-
-	return in, ap
-}
-
-// The s390_add_memarg function adds an argument passed in memory.
-func s390_add_memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) {
-	// If we're not already at the beginning of a stack slot,
-	// round up to the beginning of the next one.
-	ap = align(ap, s390_arch_stack_slot_align)
-
-	// We have to copy the argument onto the heap in case the
-	// function hangs onto the reflect.Value we pass it.
-	p := unsafe_New(rt)
-	memmove(p, *(*unsafe.Pointer)(unsafe.Pointer(ap)), rt.size)
-
-	v := Value{rt, p, flag(rt.Kind()) | flagIndir}
-	in = append(in, v)
-	ap += s390_arch_stack_slot_align
-
-	return in, ap
-}
-
-// The s390_general_reg_val function returns the value of integer register GR.
-func s390_general_reg_val(regs *s390_regs, gr int) s390_arch_gr_t {
-	switch gr {
-	case 0:
-		return regs.r2
-	case 1:
-		return regs.r3
-	case 2:
-		return regs.r4
-	case 3:
-		return regs.r5
-	case 4:
-		return regs.r6
-	default:
-		panic("s390_general_reg_val: bad integer register")
-	}
-}
-
-// The s390_float_reg_val function returns the value of float register FR.
-func s390_float_reg_val(regs *s390_regs, fr int) uintptr {
-	var r s390_arch_fr_t
-	switch fr {
-	case 0:
-		r = regs.f0
-	case 1:
-		r = regs.f2
-	default:
-		panic("s390_float_reg_val: bad floating point register")
-	}
-	return uintptr(r)
-}
diff --git a/libgo/go/reflect/makefuncgo_s390x.go b/libgo/go/reflect/makefuncgo_s390x.go
deleted file mode 100644
index ea4c93e..0000000
--- a/libgo/go/reflect/makefuncgo_s390x.go
+++ /dev/null
@@ -1,436 +0,0 @@ 
-// Copyright 2014 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// MakeFunc s390x implementation.
-
-package reflect
-
-import "unsafe"
-
-// Convenience types and constants.
-const s390x_arch_stack_slot_align uintptr = 8
-const s390x_num_gr = 5
-const s390x_num_fr = 4
-
-type s390x_arch_gr_t uint64
-type s390x_arch_fr_t uint64
-
-// The assembler stub will pass a pointer to this structure.
-// This will come in holding all the registers that might hold
-// function parameters.  On return we will set the registers that
-// might hold result values.
-type s390x_regs struct {
-	r2         s390x_arch_gr_t
-	r3         s390x_arch_gr_t
-	r4         s390x_arch_gr_t
-	r5         s390x_arch_gr_t
-	r6         s390x_arch_gr_t
-	stack_args s390x_arch_gr_t
-	f0         s390x_arch_fr_t
-	f2         s390x_arch_fr_t
-	f4         s390x_arch_fr_t
-	f6         s390x_arch_fr_t
-}
-
-// Argument classifications that arise for Go types.
-type s390x_arg_t int
-
-const (
-	s390x_general_reg s390x_arg_t = iota
-	s390x_float_reg
-	// Argument passed as a pointer to an in-memory value.
-	s390x_mem_ptr
-	s390x_empty
-)
-
-// s390xClassifyParameter returns the register class needed to
-// pass the value of type TYP.  s390x_empty means the register is
-// not used.  The second and third return values are the offset of
-// an rtype parameter passed in a register (second) or stack slot
-// (third).
-func s390xClassifyParameter(typ *rtype) (s390x_arg_t, uintptr, uintptr) {
-	offset := s390x_arch_stack_slot_align - typ.Size()
-	switch typ.Kind() {
-	default:
-		panic("internal error--unknown kind in s390xClassifyParameter")
-	case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32:
-		return s390x_general_reg, offset, offset
-	case Int64, Uint64, Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
-		return s390x_general_reg, 0, 0
-	case Float32, Float64:
-		return s390x_float_reg, 0, offset
-	case Complex64, Complex128:
-		// Complex numbers are passed by reference.
-		return s390x_mem_ptr, 0, 0
-	case Array, Struct:
-		var ityp *rtype
-		var length int
-
-		if typ.Size() == 0 {
-			return s390x_empty, 0, 0
-		}
-		switch typ.Size() {
-		default:
-			// Pointer to memory.
-			return s390x_mem_ptr, 0, 0
-		case 1, 2:
-			// Pass in an integer register.
-			return s390x_general_reg, offset, offset
-
-		case 4, 8:
-			// See below.
-		}
-		if typ.Kind() == Array {
-			atyp := (*arrayType)(unsafe.Pointer(typ))
-			length = atyp.Len()
-			ityp = atyp.elem
-		} else {
-			styp := (*structType)(unsafe.Pointer(typ))
-			length = len(styp.fields)
-			ityp = styp.fields[0].typ
-		}
-		if length == 1 {
-			class, off_reg, off_slot := s390xClassifyParameter(ityp)
-			if class == s390x_float_reg {
-				// The array (stored in a structure) or struct
-				// is "equivalent to a floating point type" as
-				// defined in the S390x Abi.  Note that this
-				// can only be the case in the cases 4 and 8 of
-				// the switch above.
-				return s390x_float_reg, off_reg, off_slot
-			}
-		}
-		// Otherwise pass in an integer register.
-		switch typ.Size() {
-		case 4, 8:
-			return s390x_general_reg, offset, offset
-		default:
-			return s390x_general_reg, 0, 0
-		}
-	case Interface, Slice, String:
-		return s390x_mem_ptr, 0, 0
-	}
-}
-
-// s390xClassifyReturn returns the register classes needed to
-// return the value of type TYP.  s390_empty means the register is
-// not used.  The second value is the offset of an rtype return
-// parameter if stored in a register.
-func s390xClassifyReturn(typ *rtype) (s390x_arg_t, uintptr) {
-	offset := s390x_arch_stack_slot_align - typ.Size()
-	switch typ.Kind() {
-	default:
-		panic("internal error--unknown kind in s390xClassifyReturn")
-	case Bool, Int, Int8, Int16, Int32, Int64,
-		Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
-
-		return s390x_general_reg, offset
-	case Chan, Func, Map, Ptr, UnsafePointer:
-		return s390x_general_reg, 0
-	case Float32, Float64:
-		return s390x_float_reg, 0
-	case Complex64, Complex128:
-		return s390x_mem_ptr, 0
-	case Interface, Slice, String:
-		return s390x_mem_ptr, 0
-	case Array, Struct:
-		if typ.size == 0 {
-			return s390x_empty, 0
-		}
-		// No optimization is done for returned structures and arrays.
-		return s390x_mem_ptr, 0
-	}
-}
-
-// Given a value of type *rtype left aligned in an unsafe.Pointer,
-// reload the value so that it can be stored in a general or
-// floating point register.  For general registers the value is
-// sign extend and right aligned.
-func s390xReloadForRegister(typ *rtype, w uintptr, offset uintptr) uintptr {
-	var do_sign_extend bool = false
-	var gr s390x_arch_gr_t
-
-	switch typ.Kind() {
-	case Int, Int8, Int16, Int32, Int64:
-		do_sign_extend = true
-	default:
-		// Handle all other cases in the next switch.
-	}
-	switch typ.size {
-	case 1:
-		if do_sign_extend == true {
-			se := int64(*(*int8)(unsafe.Pointer(&w)))
-			gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
-		} else {
-			e := int64(*(*uint8)(unsafe.Pointer(&w)))
-			gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
-		}
-	case 2:
-		if do_sign_extend == true {
-			se := int64(*(*int16)(unsafe.Pointer(&w)))
-			gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
-		} else {
-			e := int64(*(*uint16)(unsafe.Pointer(&w)))
-			gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
-		}
-	case 4:
-		if do_sign_extend == true {
-			se := int64(*(*int32)(unsafe.Pointer(&w)))
-			gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
-		} else {
-			e := int64(*(*uint32)(unsafe.Pointer(&w)))
-			gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
-		}
-	default:
-		panic("reflect: bad size in s390xReloadForRegister")
-	}
-
-	return *(*uintptr)(unsafe.Pointer(&gr))
-}
-
-// MakeFuncStubGo implements the s390x calling convention for
-// MakeFunc.  This should not be called.  It is exported so that
-// assembly code can call it.
-func S390xMakeFuncStubGo(regs *s390x_regs, c *makeFuncImpl) {
-	ftyp := c.typ
-	gr := 0
-	fr := 0
-	ap := uintptr(regs.stack_args)
-
-	// See if the result requires a struct.  If it does, the first
-	// parameter is a pointer to the struct.
-	var ret_class s390x_arg_t
-	var ret_off_reg uintptr
-	var ret_type *rtype
-
-	switch len(ftyp.out) {
-	case 0:
-		ret_type = nil
-		ret_class, ret_off_reg = s390x_empty, 0
-	case 1:
-		ret_type = ftyp.out[0]
-		ret_class, ret_off_reg = s390xClassifyReturn(ret_type)
-	default:
-		ret_type = nil
-		ret_class, ret_off_reg = s390x_mem_ptr, 0
-	}
-	in := make([]Value, 0, len(ftyp.in))
-	if ret_class == s390x_mem_ptr {
-		// We are returning a value in memory, which means
-		// that the first argument is a hidden parameter
-		// pointing to that return area.
-		gr++
-	}
-
-argloop:
-	for _, rt := range ftyp.in {
-		class, off_reg, off_slot := s390xClassifyParameter(rt)
-		fl := flag(rt.Kind())
-		switch class {
-		case s390x_empty:
-			v := Value{rt, nil, fl | flagIndir}
-			in = append(in, v)
-			continue argloop
-		case s390x_general_reg:
-			// Values stored in a general register are right
-			// aligned.
-			if gr < s390x_num_gr {
-				val := s390x_general_reg_val(regs, gr)
-				iw := unsafe.Pointer(val)
-				k := rt.Kind()
-				if k != Ptr && k != UnsafePointer {
-					ix := uintptr(unsafe.Pointer(&val))
-					ix += off_reg
-					iw = unsafe.Pointer(ix)
-					fl |= flagIndir
-				}
-				v := Value{rt, iw, fl}
-				in = append(in, v)
-				gr++
-			} else {
-				in, ap = s390x_add_stackreg(
-					in, ap, rt, off_slot)
-			}
-			continue argloop
-		case s390x_float_reg:
-			// In a register, floats are left aligned, but in a
-			// stack slot they are right aligned.
-			if fr < s390x_num_fr {
-				val := s390x_float_reg_val(regs, fr)
-				ix := uintptr(unsafe.Pointer(&val))
-				v := Value{
-					rt, unsafe.Pointer(unsafe.Pointer(ix)),
-					fl | flagIndir,
-				}
-				in = append(in, v)
-				fr++
-			} else {
-				in, ap = s390x_add_stackreg(
-					in, ap, rt, off_slot)
-			}
-			continue argloop
-		case s390x_mem_ptr:
-			if gr < s390x_num_gr {
-				// Register holding a pointer to memory.
-				val := s390x_general_reg_val(regs, gr)
-				v := Value{
-					rt, unsafe.Pointer(val), fl | flagIndir}
-				in = append(in, v)
-				gr++
-			} else {
-				// Stack slot holding a pointer to memory.
-				in, ap = s390x_add_memarg(in, ap, rt)
-			}
-			continue argloop
-		}
-		panic("reflect: argtype not handled in MakeFunc:argloop")
-	}
-
-	// All the real arguments have been found and turned into
-	// Values.  Call the real function.
-
-	out := c.call(in)
-
-	if len(out) != len(ftyp.out) {
-		panic("reflect: wrong return count from function created by MakeFunc")
-	}
-
-	for i, typ := range ftyp.out {
-		v := out[i]
-		if v.typ != typ {
-			panic(
-				"reflect: function created by MakeFunc using " +
-					funcName(c.fn) + " returned wrong type: have " +
-					out[i].typ.String() + " for " + typ.String())
-		}
-		if v.flag&flagRO != 0 {
-			panic(
-				"reflect: function created by MakeFunc using " +
-					funcName(c.fn) + " returned value obtained " +
-					"from unexported field")
-		}
-	}
-
-	switch ret_class {
-	case s390x_general_reg, s390x_float_reg:
-		// Single return value in a general or floating point register.
-		v := out[0]
-		var w uintptr
-		switch v.Kind() {
-		case Ptr, UnsafePointer, Chan, Func, Map:
-			w = uintptr(v.pointer())
-		} else {
-			memmove(unsafe.Pointer(&w), v.ptr, v.typ.size)
-			if ret_off_reg != 0 {
-				w = s390xReloadForRegister(
-					ret_type, w, ret_off_reg)
-			}
-		}
-		if ret_class == s390x_float_reg {
-			regs.f0 = s390x_arch_fr_t(w)
-		} else {
-			regs.r2 = s390x_arch_gr_t(w)
-		}
-
-	case s390x_mem_ptr:
-		// The address of the memory area was passed as a hidden
-		// parameter in %r2.  Multiple return values are always returned
-		// in an in-memory structure.
-		ptr := unsafe.Pointer(uintptr(regs.r2))
-		off := uintptr(0)
-		for i, typ := range ftyp.out {
-			v := out[i]
-			off = align(off, uintptr(typ.fieldAlign))
-			addr := unsafe.Pointer(uintptr(ptr) + off)
-			if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
-				*(*unsafe.Pointer)(addr) = v.ptr
-			} else {
-				memmove(addr, v.ptr, typ.size)
-			}
-			off += typ.size
-		}
-
-	case s390x_empty:
-	}
-
-	return
-}
-
-// The s390x_add_stackreg function adds an argument passed on the
-// stack that could be passed in a register.
-func s390x_add_stackreg(in []Value, ap uintptr, rt *rtype, offset uintptr) ([]Value, uintptr) {
-	// If we're not already at the beginning of a stack slot, round up to
-	// the beginning of the next one.
-	ap = align(ap, s390x_arch_stack_slot_align)
-	// If offset is > 0, the data is right aligned on the stack slot.
-	ap += offset
-
-	// We have to copy the argument onto the heap in case the
-	// function hangs onto the reflect.Value we pass it.
-	p := unsafe_New(rt)
-	memmove(p, unsafe.Pointer(ap), rt.size)
-
-	v := Value{rt, p, flag(rt.Kind()) | flagIndir}
-	in = append(in, v)
-	ap += rt.size
-	ap = align(ap, s390x_arch_stack_slot_align)
-
-	return in, ap
-}
-
-// The s390x_add_memarg function adds an argument passed in memory.
-func s390x_add_memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) {
-	// If we're not already at the beginning of a stack slot,
-	// round up to the beginning of the next one.
-	ap = align(ap, s390x_arch_stack_slot_align)
-
-	// We have to copy the argument onto the heap in case the
-	// function hangs onto the reflect.Value we pass it.
-	p := unsafe_New(rt)
-	memmove(p, *(*unsafe.Pointer)(unsafe.Pointer(ap)), rt.size)
-
-	v := Value{rt, p, flag(rt.Kind()) | flagIndir}
-	in = append(in, v)
-	ap += s390x_arch_stack_slot_align
-
-	return in, ap
-}
-
-// The s390x_general_reg_val function returns the value of integer register GR.
-func s390x_general_reg_val(regs *s390x_regs, gr int) uintptr {
-	var r s390x_arch_gr_t
-	switch gr {
-	case 0:
-		r = regs.r2
-	case 1:
-		r = regs.r3
-	case 2:
-		r = regs.r4
-	case 3:
-		r = regs.r5
-	case 4:
-		r = regs.r6
-	default:
-		panic("s390x_general_reg_val: bad integer register")
-	}
-	return uintptr(r)
-}
-
-// The s390x_float_reg_val function returns the value of float register FR.
-func s390x_float_reg_val(regs *s390x_regs, fr int) uintptr {
-	var r s390x_arch_fr_t
-	switch fr {
-	case 0:
-		r = regs.f0
-	case 1:
-		r = regs.f2
-	case 2:
-		r = regs.f4
-	case 3:
-		r = regs.f6
-	default:
-		panic("s390x_float_reg_val: bad floating point register")
-	}
-	return uintptr(r)
-}
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index 09210b3..7cc4f7f 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -308,9 +308,6 @@  func (v Value) CallSlice(in []Value) []Value {
 
 var callGC bool // for testing; see TestCallMethodJump
 
-var makeFuncStubFn = makeFuncStub
-var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn))
-
 func (v Value) call(op string, in []Value) []Value {
 	// Get function pointer, type.
 	t := v.typ
@@ -388,17 +385,6 @@  func (v Value) call(op string, in []Value) []Value {
 	}
 	nout := t.NumOut()
 
-	// If target is makeFuncStub, short circuit the unpack onto stack /
-	// pack back into []Value for the args and return values.  Just do the
-	// call directly.
-	// We need to do this here because otherwise we have a situation where
-	// reflect.callXX calls makeFuncStub, neither of which knows the
-	// layout of the args.  That's bad for precise gc & stack copying.
-	x := (*makeFuncImpl)(fn)
-	if x.code == makeFuncStubCode {
-		return x.call(in)
-	}
-
 	if v.flag&flagMethod != 0 {
 		nin++
 	}
@@ -1120,16 +1106,6 @@  func (v Value) Pointer() uintptr {
 	case Chan, Map, Ptr, UnsafePointer:
 		return uintptr(v.pointer())
 	case Func:
-		if v.flag&flagMethod != 0 {
-			// As the doc comment says, the returned pointer is an
-			// underlying code pointer but not necessarily enough to
-			// identify a single function uniquely. All method expressions
-			// created via reflect have the same underlying code pointer,
-			// so their Pointers are equal. The function used here must
-			// match the one used in makeMethodValue.
-			f := makeFuncStub
-			return **(**uintptr)(unsafe.Pointer(&f))
-		}
 		p := v.pointer()
 		// Non-nil func value points at data block.
 		// First word of data block is actual code.
diff --git a/libgo/runtime/go-ffi.c b/libgo/runtime/go-ffi.c
index 21879b9..3e97203 100644
--- a/libgo/runtime/go-ffi.c
+++ b/libgo/runtime/go-ffi.c
@@ -30,8 +30,6 @@  static ffi_type *go_struct_to_ffi (const struct __go_struct_type *)
   __attribute__ ((no_split_stack));
 static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack));
 static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack));
-static ffi_type *go_complex_to_ffi (ffi_type *)
-  __attribute__ ((no_split_stack, unused));
 static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *)
   __attribute__ ((no_split_stack));
 static ffi_type *go_func_return_ffi (const struct __go_func_type *)
@@ -142,7 +140,15 @@  go_interface_to_ffi (void)
   return ret;
 }
 
-/* Return an ffi_type for a Go complex type.  */
+
+#ifndef FFI_TARGET_HAS_COMPLEX_TYPE
+/* If libffi hasn't been updated for this target to support complex,
+   pretend complex is a structure.  Warning: This does not work for
+   all ABIs.  Eventually libffi should be updated for all targets
+   and this should go away.  */
+
+static ffi_type *go_complex_to_ffi (ffi_type *)
+  __attribute__ ((no_split_stack, unused));
 
 static ffi_type *
 go_complex_to_ffi (ffi_type *float_type)
@@ -157,6 +163,7 @@  go_complex_to_ffi (ffi_type *float_type)
   ret->elements[2] = NULL;
   return ret;
 }
+#endif
 
 /* Return an ffi_type for a type described by a
    __go_type_descriptor.  */
@@ -181,23 +188,25 @@  go_type_to_ffi (const struct __go_type_descriptor *descriptor)
 	return &ffi_type_double;
       abort ();
     case GO_COMPLEX64:
-#ifdef __alpha__
-      runtime_throw("the libffi library does not support Complex64 type with "
-		    "reflect.Call or runtime.SetFinalizer");
-#else
       if (sizeof (float) == 4)
-	return go_complex_to_ffi (&ffi_type_float);
-      abort ();
+	{
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+	  return &ffi_type_complex_float;
+#else
+	  return go_complex_to_ffi (&ffi_type_float);
 #endif
+	}
+      abort ();
     case GO_COMPLEX128:
-#ifdef __alpha__
-      runtime_throw("the libffi library does not support Complex128 type with "
-		    "reflect.Call or runtime.SetFinalizer");
-#else
       if (sizeof (double) == 8)
-	return go_complex_to_ffi (&ffi_type_double);
-      abort ();
+	{
+#ifdef FFI_TARGET_HAS_COMPLEX_TYPE
+	  return &ffi_type_complex_double;
+#else
+	  return go_complex_to_ffi (&ffi_type_double);
 #endif
+	}
+      abort ();
     case GO_INT16:
       return &ffi_type_sint16;
     case GO_INT32:
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
index dfc703e..29e814a 100644
--- a/libgo/runtime/go-reflect-call.c
+++ b/libgo/runtime/go-reflect-call.c
@@ -12,11 +12,10 @@ 
 #include "go-alloc.h"
 #include "go-assert.h"
 #include "go-type.h"
-
-#ifdef USE_LIBFFI
-
 #include "go-ffi.h"
 
+#if defined(USE_LIBFFI) && FFI_GO_CLOSURES
+
 /* The functions in this file are only called from reflect_call.  As
    reflect_call calls a libffi function, which will be compiled
    without -fsplit-stack, it will always run with a large stack.  */
@@ -202,11 +201,7 @@  go_set_results (const struct __go_func_type *func, unsigned char *call_result,
 
    If IS_METHOD is true this is a call to a method expression.  The
    first argument is the receiver.  It is described in FUNC_TYPE, but
-   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 we must pass a closure pointer via
-   __go_set_closure.  The pointer to pass is simply FUNC_VAL.  */
+   regardless of FUNC_TYPE, it is passed as a pointer.  */
 
 void
 reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
@@ -221,9 +216,7 @@  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);
+  ffi_call_go (&cif, func_val->fn, call_result, params, func_val);
 
   /* Some day we may need to free result values if RESULTS is
      NULL.  */
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
index b05c5fa..43323e2 100644
--- a/libgo/runtime/malloc.goc
+++ b/libgo/runtime/malloc.goc
@@ -84,7 +84,6 @@  runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
 	MLink *v, *next;
 	byte *tiny;
 	bool incallback;
-	void *closure;
 
 	if(size == 0) {
 		// All 0-length allocations use this pointer.
@@ -96,10 +95,6 @@  runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
 	m = runtime_m();
 	g = runtime_g();
 
-	// We should not be called in between __go_set_closure and the
-	// actual function call, but cope with it if we are.
-	closure = g->closure;
-
 	incallback = false;
 	if(m->mcache == nil && g->ncgo > 0) {
 		// For gccgo this case can occur when a cgo or SWIG function
@@ -180,7 +175,6 @@  runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
 					m->locks--;
 					if(incallback)
 						runtime_entersyscall();
-					g->closure = closure;
 					return v;
 				}
 			}
@@ -267,8 +261,6 @@  runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
 	if(incallback)
 		runtime_entersyscall();
 
-	g->closure = closure;
-
 	return v;
 }
 
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 0867abf..662dd87 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -133,8 +133,8 @@  clearpools(void)
 
 	// clear sync.Pool's
 	if(poolcleanup != nil) {
-		__go_set_closure(poolcleanup);
-		poolcleanup->fn();
+		__builtin_call_with_static_chain(poolcleanup->fn(),
+						 poolcleanup);
 	}
 
 	for(pp=runtime_allp; (p=*pp) != nil; pp++) {
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 20fbc0a..c4f27fb 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -3310,26 +3310,6 @@  runtime_proc_scan(struct Workbuf** wbufp, void (*enqueue1)(struct Workbuf**, Obj
 	enqueue1(wbufp, (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;
-}
-
 // Return whether we are waiting for a GC.  This gc toolchain uses
 // preemption instead.
 bool
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 1f1358a..515ae58 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -195,7 +195,6 @@  struct	Location
 
 struct	G
 {
-	void*	closure;	// Closure value.
 	Defer*	defer;
 	Panic*	panic;
 	void*	exception;	// current exception being thrown
@@ -833,9 +832,6 @@  int32 getproccount(void);
 
 #define PREFETCH(p) __builtin_prefetch(p)
 
-void	__go_set_closure(void*);
-void*	__go_get_closure(void);
-
 bool	runtime_gcwaiting(void);
 void	runtime_badsignal(int);
 Defer*	runtime_newdefer(void);
diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc
index ee24b9c..b77ad33 100644
--- a/libgo/runtime/time.goc
+++ b/libgo/runtime/time.goc
@@ -237,8 +237,7 @@  timerproc(void* dummy __attribute__ ((unused)))
 			arg = t->arg;
 			seq = t->seq;
 			runtime_unlock(&timers);
-			__go_set_closure(fv);
-			f(arg, seq);
+			__builtin_call_with_static_chain(f(arg, seq), fv);
 
 			// clear f and arg to avoid leak while sleeping for next timer
 			f = nil;