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


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

libgo patch committed: Use libffi closures


This patch finally adds support to libgo to use libffi closures to
implement reflect.MakeFunc.  This should let reflect.MakeFunc work for
any processor, or, at least, any processor that supports libffi
closures.  On x86 and x86_64 the code will continue to use the special
purpose code I wrote earlier before I knew about libffi closures, since
that code is more efficient and does not require calling mmap to make a
new function.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu, using both the regular libgo and a version
tweaked to use closures even for x86 and x86_64.  Committed to mainline.

Ian

diff -r afeebc699bab libgo/Makefile.am
--- a/libgo/Makefile.am	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/Makefile.am	Sat Jul 19 14:20:16 2014 -0700
@@ -444,6 +444,7 @@
 	runtime/go-deferred-recover.c \
 	runtime/go-eface-compare.c \
 	runtime/go-eface-val-compare.c \
+	runtime/go-ffi.c \
 	runtime/go-fieldtrack.c \
 	runtime/go-int-array-to-string.c \
 	runtime/go-int-to-string.c \
@@ -951,9 +952,12 @@
 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 = \
+	go/reflect/makefunc_ffi_c.c
 
 go_regexp_files = \
 	go/regexp/exec.go \
@@ -1849,6 +1853,7 @@
 	path.lo \
 	reflect-go.lo \
 	reflect/makefunc.lo \
+	reflect/makefunc_ffi_c.lo \
 	regexp.lo \
 	runtime-go.lo \
 	sort.lo \
@@ -2252,6 +2257,9 @@
 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 $@ $<
 .PHONY: reflect/check
 
 @go_include@ regexp.lo.dep
diff -r afeebc699bab libgo/go/reflect/all_test.go
--- a/libgo/go/reflect/all_test.go	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/go/reflect/all_test.go	Sat Jul 19 14:20:16 2014 -0700
@@ -1502,12 +1502,6 @@
 }
 
 func TestMakeFunc(t *testing.T) {
-	switch runtime.GOARCH {
-	case "amd64", "386":
-	default:
-		t.Skip("MakeFunc not implemented for " + runtime.GOARCH)
-	}
-
 	f := dummy
 	fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
 	ValueOf(&f).Elem().Set(fv)
@@ -1526,12 +1520,6 @@
 }
 
 func TestMakeFuncInterface(t *testing.T) {
-	switch runtime.GOARCH {
-	case "amd64", "386":
-	default:
-		t.Skip("MakeFunc not implemented for " + runtime.GOARCH)
-	}
-
 	fn := func(i int) int { return i }
 	incr := func(in []Value) []Value {
 		return []Value{ValueOf(int(in[0].Int() + 1))}
@@ -1676,12 +1664,6 @@
 }
 
 func TestMethodValue(t *testing.T) {
-	switch runtime.GOARCH {
-	case "amd64", "386":
-	default:
-		t.Skip("reflect method values not implemented for " + runtime.GOARCH)
-	}
-
 	p := Point{3, 4}
 	var i int64
 
@@ -1853,12 +1835,6 @@
 func (t4 Tm4) M(x int, b byte) (byte, int) { return b, x + 40 }
 
 func TestMethod5(t *testing.T) {
-	switch runtime.GOARCH {
-	case "amd64", "386":
-	default:
-		t.Skip("reflect method values not implemented for " + runtime.GOARCH)
-	}
-
 	CheckF := func(name string, f func(int, byte) (byte, int), inc int) {
 		b, x := f(1000, 99)
 		if b != 99 || x != 1000+inc {
diff -r afeebc699bab libgo/go/reflect/makefunc.go
--- a/libgo/go/reflect/makefunc.go	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/go/reflect/makefunc.go	Sat Jul 19 14:20:16 2014 -0700
@@ -22,6 +22,10 @@
 	// 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
@@ -51,22 +55,29 @@
 		panic("reflect: call of MakeFunc with non-Func type")
 	}
 
-	switch runtime.GOARCH {
-	case "amd64", "386":
-	default:
-		panic("reflect.MakeFunc not implemented for " + runtime.GOARCH)
-	}
-
 	t := typ.common()
 	ftyp := (*funcType)(unsafe.Pointer(t))
 
-	// 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))
+	var code uintptr
+	var ffi *ffiData
+	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
+		code = **(**uintptr)(unsafe.Pointer(&dummy))
+	default:
+		code, ffi = makeFuncFFI(ftyp, fn)
+	}
 
-	impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn, method: -1}
+	impl := &makeFuncImpl{
+		code: code,
+		typ: ftyp,
+		fn: fn,
+		method: -1,
+		ffi: ffi,
+	}
 
 	return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
 }
@@ -90,12 +101,6 @@
 		panic("reflect: internal error: invalid use of makeMethodValue")
 	}
 
-	switch runtime.GOARCH {
-	case "amd64", "386":
-	default:
-		panic("reflect.makeMethodValue not implemented for " + runtime.GOARCH)
-	}
-
 	// Ignoring the flagMethod bit, v describes the receiver, not the method type.
 	fl := v.flag & (flagRO | flagAddr | flagIndir)
 	fl |= flag(v.typ.Kind()) << flagKindShift
@@ -104,22 +109,37 @@
 	// v.Type returns the actual type of the method value.
 	ft := v.Type().(*rtype)
 
-	// 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))
-
 	// Cause panic if method is not appropriate.
 	// The panic would still happen during the call if we omit this,
 	// but we want Interface() and other operations to fail early.
 	_, t, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
 
+	ftyp := (*funcType)(unsafe.Pointer(t))
+	method := int(v.flag) >> flagMethodShift
+
+	var code uintptr
+	var ffi *ffiData
+	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
+		code = **(**uintptr)(unsafe.Pointer(&dummy))
+	default:
+		code, ffi = makeFuncFFI(ftyp,
+			func(in []Value) []Value {
+				m := rcvr.Method(method)
+				return m.Call(in)
+			})
+	}
+
 	fv := &makeFuncImpl{
 		code:   code,
-		typ:    (*funcType)(unsafe.Pointer(t)),
-		method: int(v.flag) >> flagMethodShift,
+		typ:    ftyp,
+		method: method,
 		rcvr:   rcvr,
+		ffi:    ffi,
 	}
 
 	return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func)<<flagKindShift | flagIndir}
@@ -137,26 +157,31 @@
 		panic("reflect: call of makeValueMethod with non-MethodFn")
 	}
 
-	switch runtime.GOARCH {
-	case "amd64", "386":
-	default:
-		panic("reflect.makeValueMethod not implemented for " + runtime.GOARCH)
-	}
-
 	t := typ.common()
 	ftyp := (*funcType)(unsafe.Pointer(t))
 
-	// 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))
+	var code uintptr
+	var ffi *ffiData
+	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
+		code = **(**uintptr)(unsafe.Pointer(&dummy))
+	default:
+		code, ffi = makeFuncFFI(ftyp,
+			func(in []Value) []Value {
+				return v.Call(in)
+			})
+	}
 
 	impl := &makeFuncImpl{
 		code:   code,
 		typ:    ftyp,
 		method: -2,
 		rcvr:   v,
+		ffi:    ffi,
 	}
 
 	return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
diff -r afeebc699bab libgo/go/reflect/makefunc_dummy.c
--- a/libgo/go/reflect/makefunc_dummy.c	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/go/reflect/makefunc_dummy.c	Sat Jul 19 14:20:16 2014 -0700
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64
+#include "runtime.h"
 
-// Dummy function for processors without makefunc support.
+/* Dummy function for processors that implement MakeFunc using FFI
+   rather than having builtin support.  */
 
-void makeFuncStub () __asm__ ("reflect.makeFuncStub");
-void makeFuncStub ()
+void makeFuncStub (void) __asm__ ("reflect.makeFuncStub");
+
+void makeFuncStub (void)
 {
+  runtime_throw ("impossible call to makeFuncStub");
 }
diff -r afeebc699bab libgo/go/reflect/makefunc_ffi.go
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/go/reflect/makefunc_ffi.go	Sat Jul 19 14:20:16 2014 -0700
@@ -0,0 +1,88 @@
+// 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.
+
+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) {
+	in := make([]Value, 0, len(ftyp.in))
+	ap := params
+	for _, rt := range ftyp.in {
+		p := unsafe_New(rt)
+		memmove(p, *(*unsafe.Pointer)(ap), rt.size)
+		v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
+		in = append(in, v)
+		ap = (unsafe.Pointer)(uintptr(ap) + ptrSize)
+	}
+
+	out := fn(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) +
+				" 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) +
+				" returned value obtained from unexported field")
+		}
+
+		off = align(off, uintptr(typ.fieldAlign))
+		addr := unsafe.Pointer(uintptr(results) + 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
+	}
+}
diff -r afeebc699bab libgo/go/reflect/makefunc_ffi_c.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/go/reflect/makefunc_ffi_c.c	Sat Jul 19 14:20:16 2014 -0700
@@ -0,0 +1,135 @@
+// 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-type.h"
+#include "go-panic.h"
+
+#ifdef USE_LIBFFI
+
+#include "go-ffi.h"
+
+#if FFI_CLOSURES
+#define USE_LIBFFI_CLOSURES
+#endif
+
+#endif /* defined(USE_LIBFFI) */
+
+/* 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");
+
+#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.  */
+
+static void
+ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
+	      void **args, void *user_data)
+{
+  Location locs[6];
+  int n;
+  int i;
+  const void *pc;
+  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 pass the PC of the Go
+     function to makefunc_can_recover.  Look up the stack for a
+     function that is definitely not an FFI function.  */
+  n = runtime_callers (1, &locs[0], sizeof locs / sizeof locs[0], true);
+  for (i = 0; i < n; i++)
+    {
+      const byte *name;
+
+      if (locs[i].function.len == 0)
+	continue;
+      if (locs[i].function.len < 4)
+	break;
+      name = locs[i].function.str;
+      if (*name == '_')
+	{
+	  if (locs[i].function.len < 5)
+	    break;
+	  ++name;
+	}
+      if (name[0] != 'f' || name[1] != 'f' || name[2] != 'i' || name[3] != '_')
+	break;
+    }
+  if (i < n)
+    pc = (const void *) locs[i].pc;
+  else
+    pc = __builtin_return_address (0);
+
+  __go_makefunc_can_recover (pc);
+
+  fv = (FuncVal *) user_data;
+  __go_set_closure (fv);
+  f = (void *) fv->fn;
+  f (args, results);
+
+  __go_makefunc_returning ();
+}
+
+/* Allocate an FFI closure and arrange to call ffi_callback.  */
+
+struct ffi_ret
+ffi (const struct __go_func_type *ftyp, FuncVal *callback)
+{
+  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);
+}
+
+#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)
+{
+  runtime_panicstring ("libgo built without FFI does not support "
+		       "reflect.MakeFunc");
+}
+
+#endif
diff -r afeebc699bab libgo/runtime/go-caller.c
--- a/libgo/runtime/go-caller.c	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/go-caller.c	Sat Jul 19 14:20:16 2014 -0700
@@ -177,7 +177,7 @@
   int32 n;
 
   runtime_memclr (&ret, sizeof ret);
-  n = runtime_callers (skip + 1, &loc, 1);
+  n = runtime_callers (skip + 1, &loc, 1, false);
   if (n < 1)
     return ret;
   ret.pc = loc.pc;
diff -r afeebc699bab libgo/runtime/go-callers.c
--- a/libgo/runtime/go-callers.c	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/go-callers.c	Sat Jul 19 14:20:16 2014 -0700
@@ -26,6 +26,7 @@
   int skip;
   int index;
   int max;
+  int keep_thunks;
 };
 
 /* Callback function for backtrace_full.  Just collect the locations.
@@ -63,7 +64,7 @@
   /* Skip thunks and recover functions.  There is no equivalent to
      these functions in the gc toolchain, so returning them here means
      significantly different results for runtime.Caller(N).  */
-  if (function != NULL)
+  if (function != NULL && !arg->keep_thunks)
     {
       const char *p;
 
@@ -136,7 +137,7 @@
 /* Gather caller PC's.  */
 
 int32
-runtime_callers (int32 skip, Location *locbuf, int32 m)
+runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
 {
   struct callers_data data;
 
@@ -144,6 +145,7 @@
   data.skip = skip + 1;
   data.index = 0;
   data.max = m;
+  data.keep_thunks = keep_thunks;
   runtime_xadd (&runtime_in_callers, 1);
   backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
 		  &data);
@@ -167,7 +169,7 @@
      which we can not correct because it would break backward
      compatibility.  Normally we would add 1 to SKIP here, but we
      don't so that we are compatible.  */
-  ret = runtime_callers (skip, locbuf, pc.__count);
+  ret = runtime_callers (skip, locbuf, pc.__count, false);
 
   for (i = 0; i < ret; i++)
     ((uintptr *) pc.__values)[i] = locbuf[i].pc;
diff -r afeebc699bab libgo/runtime/go-ffi.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-ffi.c	Sat Jul 19 14:20:16 2014 -0700
@@ -0,0 +1,338 @@
+/* go-ffi.c -- convert Go type description to libffi.
+
+   Copyright 2009 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "runtime.h"
+#include "go-alloc.h"
+#include "go-assert.h"
+#include "go-type.h"
+
+#ifdef USE_LIBFFI
+
+#include "ffi.h"
+
+/* The functions in this file are only called from reflect_call and
+   reflect.ffi.  As these functions call libffi functions, which will
+   be compiled without -fsplit-stack, they will always run with a
+   large stack.  */
+
+static ffi_type *go_array_to_ffi (const struct __go_array_type *)
+  __attribute__ ((no_split_stack));
+static ffi_type *go_slice_to_ffi (const struct __go_slice_type *)
+  __attribute__ ((no_split_stack));
+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 *)
+  __attribute__ ((no_split_stack));
+
+/* Return an ffi_type for a Go array type.  The libffi library does
+   not have any builtin support for passing arrays as values.  We work
+   around this by pretending that the array is a struct.  */
+
+static ffi_type *
+go_array_to_ffi (const struct __go_array_type *descriptor)
+{
+  ffi_type *ret;
+  uintptr_t len;
+  ffi_type *element;
+  uintptr_t i;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  len = descriptor->__len;
+  ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
+  element = go_type_to_ffi (descriptor->__element_type);
+  for (i = 0; i < len; ++i)
+    ret->elements[i] = element;
+  ret->elements[len] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go slice type.  This describes the
+   __go_open_array type defines in array.h.  */
+
+static ffi_type *
+go_slice_to_ffi (
+    const struct __go_slice_type *descriptor __attribute__ ((unused)))
+{
+  ffi_type *ret;
+  ffi_type *ffi_intgo;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *));
+  ret->elements[0] = &ffi_type_pointer;
+  ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
+  ret->elements[1] = ffi_intgo;
+  ret->elements[2] = ffi_intgo;
+  ret->elements[3] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go struct type.  */
+
+static ffi_type *
+go_struct_to_ffi (const struct __go_struct_type *descriptor)
+{
+  ffi_type *ret;
+  int field_count;
+  const struct __go_struct_field *fields;
+  int i;
+
+  field_count = descriptor->__fields.__count;
+  if (field_count == 0) {
+    return &ffi_type_void;
+  }
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  fields = (const struct __go_struct_field *) descriptor->__fields.__values;
+  ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
+					    * sizeof (ffi_type *));
+  for (i = 0; i < field_count; ++i)
+    ret->elements[i] = go_type_to_ffi (fields[i].__type);
+  ret->elements[field_count] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go string type.  This describes the String
+   struct.  */
+
+static ffi_type *
+go_string_to_ffi (void)
+{
+  ffi_type *ret;
+  ffi_type *ffi_intgo;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+  ret->elements[0] = &ffi_type_pointer;
+  ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
+  ret->elements[1] = ffi_intgo;
+  ret->elements[2] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go interface type.  This describes the
+   __go_interface and __go_empty_interface structs.  */
+
+static ffi_type *
+go_interface_to_ffi (void)
+{
+  ffi_type *ret;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+  ret->elements[0] = &ffi_type_pointer;
+  ret->elements[1] = &ffi_type_pointer;
+  ret->elements[2] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a Go complex type.  */
+
+static ffi_type *
+go_complex_to_ffi (ffi_type *float_type)
+{
+  ffi_type *ret;
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
+  ret->elements[0] = float_type;
+  ret->elements[1] = float_type;
+  ret->elements[2] = NULL;
+  return ret;
+}
+
+/* Return an ffi_type for a type described by a
+   __go_type_descriptor.  */
+
+static ffi_type *
+go_type_to_ffi (const struct __go_type_descriptor *descriptor)
+{
+  switch (descriptor->__code & GO_CODE_MASK)
+    {
+    case GO_BOOL:
+      if (sizeof (_Bool) == 1)
+	return &ffi_type_uint8;
+      else if (sizeof (_Bool) == sizeof (int))
+	return &ffi_type_uint;
+      abort ();
+    case GO_FLOAT32:
+      if (sizeof (float) == 4)
+	return &ffi_type_float;
+      abort ();
+    case GO_FLOAT64:
+      if (sizeof (double) == 8)
+	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 ();
+#endif
+    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 ();
+#endif
+    case GO_INT16:
+      return &ffi_type_sint16;
+    case GO_INT32:
+      return &ffi_type_sint32;
+    case GO_INT64:
+      return &ffi_type_sint64;
+    case GO_INT8:
+      return &ffi_type_sint8;
+    case GO_INT:
+      return sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
+    case GO_UINT16:
+      return &ffi_type_uint16;
+    case GO_UINT32:
+      return &ffi_type_uint32;
+    case GO_UINT64:
+      return &ffi_type_uint64;
+    case GO_UINT8:
+      return &ffi_type_uint8;
+    case GO_UINT:
+      return sizeof (uintgo) == 4 ? &ffi_type_uint32 : &ffi_type_uint64;
+    case GO_UINTPTR:
+      if (sizeof (void *) == 2)
+	return &ffi_type_uint16;
+      else if (sizeof (void *) == 4)
+	return &ffi_type_uint32;
+      else if (sizeof (void *) == 8)
+	return &ffi_type_uint64;
+      abort ();
+    case GO_ARRAY:
+      return go_array_to_ffi ((const struct __go_array_type *) descriptor);
+    case GO_SLICE:
+      return go_slice_to_ffi ((const struct __go_slice_type *) descriptor);
+    case GO_STRUCT:
+      return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
+    case GO_STRING:
+      return go_string_to_ffi ();
+    case GO_INTERFACE:
+      return go_interface_to_ffi ();
+    case GO_CHAN:
+    case GO_FUNC:
+    case GO_MAP:
+    case GO_PTR:
+    case GO_UNSAFE_POINTER:
+      /* These types are always pointers, and for FFI purposes nothing
+	 else matters.  */
+      return &ffi_type_pointer;
+    default:
+      abort ();
+    }
+}
+
+/* Return the return type for a function, given the number of out
+   parameters and their types.  */
+
+static ffi_type *
+go_func_return_ffi (const struct __go_func_type *func)
+{
+  int count;
+  const struct __go_type_descriptor **types;
+  ffi_type *ret;
+  int i;
+
+  count = func->__out.__count;
+  if (count == 0)
+    return &ffi_type_void;
+
+  types = (const struct __go_type_descriptor **) func->__out.__values;
+
+  if (count == 1)
+    {
+
+#if defined (__i386__) && !defined (__x86_64__)
+      /* FFI does not support complex types.  On 32-bit x86, a
+	 complex64 will be returned in %eax/%edx.  We normally tell
+	 FFI that a complex64 is a struct of two floats.  On 32-bit
+	 x86 a struct of two floats is returned via a hidden first
+	 pointer parameter.  Fortunately we can make everything work
+	 by pretending that complex64 is int64.  */
+      if ((types[0]->__code & GO_CODE_MASK) == GO_COMPLEX64)
+	return &ffi_type_sint64;
+#endif
+
+      return go_type_to_ffi (types[0]);
+    }
+
+  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
+  ret->type = FFI_TYPE_STRUCT;
+  ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *));
+  for (i = 0; i < count; ++i)
+    ret->elements[i] = go_type_to_ffi (types[i]);
+  ret->elements[count] = NULL;
+  return ret;
+}
+
+/* Build an ffi_cif structure for a function described by a
+   __go_func_type structure.  */
+
+void
+__go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
+		_Bool is_method, ffi_cif *cif)
+{
+  int num_params;
+  const struct __go_type_descriptor **in_types;
+  size_t num_args;
+  ffi_type **args;
+  int off;
+  int i;
+  ffi_type *rettype;
+  ffi_status status;
+
+  num_params = func->__in.__count;
+  in_types = ((const struct __go_type_descriptor **)
+	      func->__in.__values);
+
+  num_args = num_params + (is_interface ? 1 : 0);
+  args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
+  i = 0;
+  off = 0;
+  if (is_interface)
+    {
+      args[0] = &ffi_type_pointer;
+      off = 1;
+    }
+  else if (is_method)
+    {
+      args[0] = &ffi_type_pointer;
+      i = 1;
+    }
+  for (; i < num_params; ++i)
+    args[i + off] = go_type_to_ffi (in_types[i]);
+
+  rettype = go_func_return_ffi (func);
+
+  status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
+  __go_assert (status == FFI_OK);
+}
+
+#endif /* defined(USE_LIBFFI) */
diff -r afeebc699bab libgo/runtime/go-ffi.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgo/runtime/go-ffi.h	Sat Jul 19 14:20:16 2014 -0700
@@ -0,0 +1,16 @@
+/* go-ffi.c -- convert Go type description to libffi.
+
+   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 "config.h"
+#include "go-type.h"
+
+#ifdef USE_LIBFFI
+
+#include "ffi.h"
+
+void __go_func_to_cif (const struct __go_func_type *, _Bool, _Bool, ffi_cif *);
+
+#endif
diff -r afeebc699bab libgo/runtime/go-panic.h
--- a/libgo/runtime/go-panic.h	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/go-panic.h	Sat Jul 19 14:20:16 2014 -0700
@@ -38,6 +38,12 @@
 
 extern struct __go_empty_interface __go_recover (void);
 
+extern _Bool __go_can_recover (const void *);
+
+extern void __go_makefunc_can_recover (const void *retaddr);
+
+extern void __go_makefunc_returning (void);
+
 extern void __go_unwind_stack (void);
 
 #endif /* !defined(LIBGO_GO_PANIC_H) */
diff -r afeebc699bab libgo/runtime/go-recover.c
--- a/libgo/runtime/go-recover.c	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/go-recover.c	Sat Jul 19 14:20:16 2014 -0700
@@ -63,7 +63,7 @@
   if (!d->__makefunc_can_recover)
     return 0;
 
-  if (runtime_callers (2, &loc, 1) < 1)
+  if (runtime_callers (2, &loc, 1, false) < 1)
     return 0;
 
   /* If we have no function name, then we weren't called by Go code.
@@ -84,9 +84,10 @@
   if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_')
     return 1;
 
-  /* We may also be called by reflect.makeFuncImpl.call, for a
-     function created by reflect.MakeFunc.  */
-  if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL)
+  /* We may also be called by reflect.makeFuncImpl.call or
+     reflect.ffiCall, for a function created by reflect.MakeFunc.  */
+  if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL
+      || __builtin_strcmp ((const char *) name, "reflect.ffiCall") == 0)
     return 1;
 
   return 0;
diff -r afeebc699bab libgo/runtime/go-reflect-call.c
--- a/libgo/runtime/go-reflect-call.c	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/go-reflect-call.c	Sat Jul 19 14:20:16 2014 -0700
@@ -15,333 +15,18 @@
 
 #ifdef USE_LIBFFI
 
-#include "ffi.h"
+#include "go-ffi.h"
 
 /* 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.  */
 
-static ffi_type *go_array_to_ffi (const struct __go_array_type *)
-  __attribute__ ((no_split_stack));
-static ffi_type *go_slice_to_ffi (const struct __go_slice_type *)
-  __attribute__ ((no_split_stack));
-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 *)
-  __attribute__ ((no_split_stack));
-static void go_func_to_cif (const struct __go_func_type *, _Bool, _Bool,
-			    ffi_cif *)
-  __attribute__ ((no_split_stack));
 static size_t go_results_size (const struct __go_func_type *)
   __attribute__ ((no_split_stack));
 static void go_set_results (const struct __go_func_type *, unsigned char *,
 			    void **)
   __attribute__ ((no_split_stack));
 
-/* Return an ffi_type for a Go array type.  The libffi library does
-   not have any builtin support for passing arrays as values.  We work
-   around this by pretending that the array is a struct.  */
-
-static ffi_type *
-go_array_to_ffi (const struct __go_array_type *descriptor)
-{
-  ffi_type *ret;
-  uintptr_t len;
-  ffi_type *element;
-  uintptr_t i;
-
-  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
-  ret->type = FFI_TYPE_STRUCT;
-  len = descriptor->__len;
-  ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
-  element = go_type_to_ffi (descriptor->__element_type);
-  for (i = 0; i < len; ++i)
-    ret->elements[i] = element;
-  ret->elements[len] = NULL;
-  return ret;
-}
-
-/* Return an ffi_type for a Go slice type.  This describes the
-   __go_open_array type defines in array.h.  */
-
-static ffi_type *
-go_slice_to_ffi (
-    const struct __go_slice_type *descriptor __attribute__ ((unused)))
-{
-  ffi_type *ret;
-  ffi_type *ffi_intgo;
-
-  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
-  ret->type = FFI_TYPE_STRUCT;
-  ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *));
-  ret->elements[0] = &ffi_type_pointer;
-  ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
-  ret->elements[1] = ffi_intgo;
-  ret->elements[2] = ffi_intgo;
-  ret->elements[3] = NULL;
-  return ret;
-}
-
-/* Return an ffi_type for a Go struct type.  */
-
-static ffi_type *
-go_struct_to_ffi (const struct __go_struct_type *descriptor)
-{
-  ffi_type *ret;
-  int field_count;
-  const struct __go_struct_field *fields;
-  int i;
-
-  field_count = descriptor->__fields.__count;
-  if (field_count == 0) {
-    return &ffi_type_void;
-  }
-  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
-  ret->type = FFI_TYPE_STRUCT;
-  fields = (const struct __go_struct_field *) descriptor->__fields.__values;
-  ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
-					    * sizeof (ffi_type *));
-  for (i = 0; i < field_count; ++i)
-    ret->elements[i] = go_type_to_ffi (fields[i].__type);
-  ret->elements[field_count] = NULL;
-  return ret;
-}
-
-/* Return an ffi_type for a Go string type.  This describes the String
-   struct.  */
-
-static ffi_type *
-go_string_to_ffi (void)
-{
-  ffi_type *ret;
-  ffi_type *ffi_intgo;
-
-  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
-  ret->type = FFI_TYPE_STRUCT;
-  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
-  ret->elements[0] = &ffi_type_pointer;
-  ffi_intgo = sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
-  ret->elements[1] = ffi_intgo;
-  ret->elements[2] = NULL;
-  return ret;
-}
-
-/* Return an ffi_type for a Go interface type.  This describes the
-   __go_interface and __go_empty_interface structs.  */
-
-static ffi_type *
-go_interface_to_ffi (void)
-{
-  ffi_type *ret;
-
-  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
-  ret->type = FFI_TYPE_STRUCT;
-  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
-  ret->elements[0] = &ffi_type_pointer;
-  ret->elements[1] = &ffi_type_pointer;
-  ret->elements[2] = NULL;
-  return ret;
-}
-
-/* Return an ffi_type for a Go complex type.  */
-
-static ffi_type *
-go_complex_to_ffi (ffi_type *float_type)
-{
-  ffi_type *ret;
-
-  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
-  ret->type = FFI_TYPE_STRUCT;
-  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
-  ret->elements[0] = float_type;
-  ret->elements[1] = float_type;
-  ret->elements[2] = NULL;
-  return ret;
-}
-
-/* Return an ffi_type for a type described by a
-   __go_type_descriptor.  */
-
-static ffi_type *
-go_type_to_ffi (const struct __go_type_descriptor *descriptor)
-{
-  switch (descriptor->__code & GO_CODE_MASK)
-    {
-    case GO_BOOL:
-      if (sizeof (_Bool) == 1)
-	return &ffi_type_uint8;
-      else if (sizeof (_Bool) == sizeof (int))
-	return &ffi_type_uint;
-      abort ();
-    case GO_FLOAT32:
-      if (sizeof (float) == 4)
-	return &ffi_type_float;
-      abort ();
-    case GO_FLOAT64:
-      if (sizeof (double) == 8)
-	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 ();
-#endif
-    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 ();
-#endif
-    case GO_INT16:
-      return &ffi_type_sint16;
-    case GO_INT32:
-      return &ffi_type_sint32;
-    case GO_INT64:
-      return &ffi_type_sint64;
-    case GO_INT8:
-      return &ffi_type_sint8;
-    case GO_INT:
-      return sizeof (intgo) == 4 ? &ffi_type_sint32 : &ffi_type_sint64;
-    case GO_UINT16:
-      return &ffi_type_uint16;
-    case GO_UINT32:
-      return &ffi_type_uint32;
-    case GO_UINT64:
-      return &ffi_type_uint64;
-    case GO_UINT8:
-      return &ffi_type_uint8;
-    case GO_UINT:
-      return sizeof (uintgo) == 4 ? &ffi_type_uint32 : &ffi_type_uint64;
-    case GO_UINTPTR:
-      if (sizeof (void *) == 2)
-	return &ffi_type_uint16;
-      else if (sizeof (void *) == 4)
-	return &ffi_type_uint32;
-      else if (sizeof (void *) == 8)
-	return &ffi_type_uint64;
-      abort ();
-    case GO_ARRAY:
-      return go_array_to_ffi ((const struct __go_array_type *) descriptor);
-    case GO_SLICE:
-      return go_slice_to_ffi ((const struct __go_slice_type *) descriptor);
-    case GO_STRUCT:
-      return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
-    case GO_STRING:
-      return go_string_to_ffi ();
-    case GO_INTERFACE:
-      return go_interface_to_ffi ();
-    case GO_CHAN:
-    case GO_FUNC:
-    case GO_MAP:
-    case GO_PTR:
-    case GO_UNSAFE_POINTER:
-      /* These types are always pointers, and for FFI purposes nothing
-	 else matters.  */
-      return &ffi_type_pointer;
-    default:
-      abort ();
-    }
-}
-
-/* Return the return type for a function, given the number of out
-   parameters and their types.  */
-
-static ffi_type *
-go_func_return_ffi (const struct __go_func_type *func)
-{
-  int count;
-  const struct __go_type_descriptor **types;
-  ffi_type *ret;
-  int i;
-
-  count = func->__out.__count;
-  if (count == 0)
-    return &ffi_type_void;
-
-  types = (const struct __go_type_descriptor **) func->__out.__values;
-
-  if (count == 1)
-    {
-
-#if defined (__i386__) && !defined (__x86_64__)
-      /* FFI does not support complex types.  On 32-bit x86, a
-	 complex64 will be returned in %eax/%edx.  We normally tell
-	 FFI that a complex64 is a struct of two floats.  On 32-bit
-	 x86 a struct of two floats is returned via a hidden first
-	 pointer parameter.  Fortunately we can make everything work
-	 by pretending that complex64 is int64.  */
-      if ((types[0]->__code & GO_CODE_MASK) == GO_COMPLEX64)
-	return &ffi_type_sint64;
-#endif
-
-      return go_type_to_ffi (types[0]);
-    }
-
-  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
-  ret->type = FFI_TYPE_STRUCT;
-  ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *));
-  for (i = 0; i < count; ++i)
-    ret->elements[i] = go_type_to_ffi (types[i]);
-  ret->elements[count] = NULL;
-  return ret;
-}
-
-/* Build an ffi_cif structure for a function described by a
-   __go_func_type structure.  */
-
-static void
-go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
-		_Bool is_method, ffi_cif *cif)
-{
-  int num_params;
-  const struct __go_type_descriptor **in_types;
-  size_t num_args;
-  ffi_type **args;
-  int off;
-  int i;
-  ffi_type *rettype;
-  ffi_status status;
-
-  num_params = func->__in.__count;
-  in_types = ((const struct __go_type_descriptor **)
-	      func->__in.__values);
-
-  num_args = num_params + (is_interface ? 1 : 0);
-  args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
-  i = 0;
-  off = 0;
-  if (is_interface)
-    {
-      args[0] = &ffi_type_pointer;
-      off = 1;
-    }
-  else if (is_method)
-    {
-      args[0] = &ffi_type_pointer;
-      i = 1;
-    }
-  for (; i < num_params; ++i)
-    args[i + off] = go_type_to_ffi (in_types[i]);
-
-  rettype = go_func_return_ffi (func);
-
-  status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
-  __go_assert (status == FFI_OK);
-}
-
 /* Get the total size required for the result parameters of a
    function.  */
 
@@ -532,7 +217,7 @@
   unsigned char *call_result;
 
   __go_assert ((func_type->__common.__code & GO_CODE_MASK) == GO_FUNC);
-  go_func_to_cif (func_type, is_interface, is_method, &cif);
+  __go_func_to_cif (func_type, is_interface, is_method, &cif);
 
   call_result = (unsigned char *) malloc (go_results_size (func_type));
 
diff -r afeebc699bab libgo/runtime/go-traceback.c
--- a/libgo/runtime/go-traceback.c	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/go-traceback.c	Sat Jul 19 14:20:16 2014 -0700
@@ -16,7 +16,7 @@
   Location locbuf[100];
   int32 c;
 
-  c = runtime_callers (1, locbuf, nelem (locbuf));
+  c = runtime_callers (1, locbuf, nelem (locbuf), false);
   runtime_printtrace (locbuf, c, true);
 }
 
diff -r afeebc699bab libgo/runtime/mprof.goc
--- a/libgo/runtime/mprof.goc	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/mprof.goc	Sat Jul 19 14:20:16 2014 -0700
@@ -186,7 +186,7 @@
 	Bucket *b;
 	int32 nstk;
 
-	nstk = runtime_callers(1, stk, nelem(stk));
+	nstk = runtime_callers(1, stk, nelem(stk), false);
 	runtime_lock(&proflock);
 	b = stkbucket(MProf, size, stk, nstk, true);
 	b->recent_allocs++;
@@ -249,7 +249,7 @@
 	if(rate <= 0 || (rate > cycles && runtime_fastrand1()%rate > cycles))
 		return;
 
-	nstk = runtime_callers(skip, stk, nelem(stk));
+	nstk = runtime_callers(skip, stk, nelem(stk), false);
 	runtime_lock(&proflock);
 	b = stkbucket(BProf, 0, stk, nstk, true);
 	b->count++;
@@ -449,7 +449,7 @@
 	Location locstk[nelem(r->stk)];
 
 	if(gp == runtime_g()) {
-		n = runtime_callers(0, locstk, nelem(r->stk));
+		n = runtime_callers(0, locstk, nelem(r->stk), false);
 		for(i = 0; i < n; i++)
 			r->stk[i] = locstk[i].pc;
 	}
diff -r afeebc699bab libgo/runtime/proc.c
--- a/libgo/runtime/proc.c	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/proc.c	Sat Jul 19 14:20:16 2014 -0700
@@ -756,7 +756,7 @@
 	traceback = gp->traceback;
 	gp->traceback = nil;
 	traceback->c = runtime_callers(1, traceback->locbuf,
-		sizeof traceback->locbuf / sizeof traceback->locbuf[0]);
+		sizeof traceback->locbuf / sizeof traceback->locbuf[0], false);
 	runtime_gogo(traceback->gp);
 }
 
@@ -766,7 +766,7 @@
 	// If there is no mcache runtime_callers() will crash,
 	// and we are most likely in sysmon thread so the stack is senseless anyway.
 	if(m->mcache)
-		runtime_callers(1, mp->createstack, nelem(mp->createstack));
+		runtime_callers(1, mp->createstack, nelem(mp->createstack), false);
 
 	mp->fastrand = 0x49f6428aUL + mp->id + runtime_cputicks();
 
@@ -2584,7 +2584,7 @@
 	}
 
 	if(traceback) {
-		n = runtime_callers(0, prof.locbuf, nelem(prof.locbuf));
+		n = runtime_callers(0, prof.locbuf, nelem(prof.locbuf), false);
 		for(i = 0; i < n; i++)
 			prof.pcbuf[i] = prof.locbuf[i].pc;
 	}
diff -r afeebc699bab libgo/runtime/runtime.h
--- a/libgo/runtime/runtime.h	Sat Jul 19 03:11:29 2014 -0700
+++ b/libgo/runtime/runtime.h	Sat Jul 19 14:20:16 2014 -0700
@@ -609,7 +609,7 @@
 G*	__go_go(void (*pfn)(void*), void*);
 void	siginit(void);
 bool	__go_sigsend(int32 sig);
-int32	runtime_callers(int32, Location*, int32);
+int32	runtime_callers(int32, Location*, int32, bool keep_callers);
 int64	runtime_nanotime(void);	// monotonic time
 int64	runtime_unixnanotime(void); // real time, can skip
 void	runtime_dopanic(int32) __attribute__ ((noreturn));

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