]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
reflect, runtime: Use libffi closures to implement reflect.MakeFunc.
authorIan Lance Taylor <ian@gcc.gnu.org>
Sat, 19 Jul 2014 21:36:26 +0000 (21:36 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Sat, 19 Jul 2014 21:36:26 +0000 (21:36 +0000)
Keep using the existing 386 and amd64 code on those archs,
since it is more efficient.

From-SVN: r212853

18 files changed:
libgo/Makefile.am
libgo/Makefile.in
libgo/go/reflect/all_test.go
libgo/go/reflect/makefunc.go
libgo/go/reflect/makefunc_dummy.c
libgo/go/reflect/makefunc_ffi.go [new file with mode: 0644]
libgo/go/reflect/makefunc_ffi_c.c [new file with mode: 0644]
libgo/runtime/go-caller.c
libgo/runtime/go-callers.c
libgo/runtime/go-ffi.c [new file with mode: 0644]
libgo/runtime/go-ffi.h [new file with mode: 0644]
libgo/runtime/go-panic.h
libgo/runtime/go-recover.c
libgo/runtime/go-reflect-call.c
libgo/runtime/go-traceback.c
libgo/runtime/mprof.goc
libgo/runtime/proc.c
libgo/runtime/runtime.h

index ab15e90b7bdbcafe577c0d319f606e16dc485633..6d00bcc38c6fc40fe71f68c65e3304f540987d5c 100644 (file)
@@ -444,6 +444,7 @@ runtime_files = \
        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 @@ 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 = \
+       go/reflect/makefunc_ffi_c.c
 
 go_regexp_files = \
        go/regexp/exec.go \
@@ -1849,6 +1853,7 @@ libgo_go_objs = \
        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/check: $(CHECK_DEPS)
 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
index f11adca45226b7d95c59ad69744181c9213d8651..1e085b73a73b7f23ab0c6180ae39c159a234f2ab 100644 (file)
@@ -135,17 +135,18 @@ 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 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 crypto/dsa.lo crypto/ecdsa.lo \
-       crypto/elliptic.lo crypto/hmac.lo crypto/md5.lo crypto/rand.lo \
-       crypto/rc4.lo crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo \
-       crypto/sha512.lo crypto/subtle.lo crypto/tls.lo crypto/x509.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 \
+       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 \
+       crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \
+       crypto/hmac.lo crypto/md5.lo crypto/rand.lo crypto/rc4.lo \
+       crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo crypto/sha512.lo \
+       crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
        crypto/x509/pkix.lo database/sql.lo database/sql/driver.lo \
        debug/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
        debug/pe.lo debug/plan9obj.lo encoding/ascii85.lo \
@@ -196,7 +197,7 @@ am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
        go-check-interface.lo go-construct-map.lo \
        go-convert-interface.lo go-copy.lo go-defer.lo \
        go-deferred-recover.lo go-eface-compare.lo \
-       go-eface-val-compare.lo go-fieldtrack.lo \
+       go-eface-val-compare.lo go-ffi.lo go-fieldtrack.lo \
        go-int-array-to-string.lo go-int-to-string.lo \
        go-interface-compare.lo go-interface-eface-compare.lo \
        go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \
@@ -773,6 +774,7 @@ runtime_files = \
        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 \
@@ -1121,10 +1123,14 @@ go_path_files = \
 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 \
        go/regexp/onepass.go \
@@ -1910,6 +1916,7 @@ libgo_go_objs = \
        path.lo \
        reflect-go.lo \
        reflect/makefunc.lo \
+       reflect/makefunc_ffi_c.lo \
        regexp.lo \
        runtime-go.lo \
        sort.lo \
@@ -2430,6 +2437,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-compare.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-val-compare.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-ffi.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-fieldtrack.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-iface.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-array-to-string.Plo@am__quote@
@@ -2677,6 +2685,13 @@ go-eface-val-compare.lo: runtime/go-eface-val-compare.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
 
+go-ffi.lo: runtime/go-ffi.c
+@am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-ffi.lo -MD -MP -MF $(DEPDIR)/go-ffi.Tpo -c -o go-ffi.lo `test -f 'runtime/go-ffi.c' || echo '$(srcdir)/'`runtime/go-ffi.c
+@am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-ffi.Tpo $(DEPDIR)/go-ffi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      source='runtime/go-ffi.c' object='go-ffi.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-ffi.lo `test -f 'runtime/go-ffi.c' || echo '$(srcdir)/'`runtime/go-ffi.c
+
 go-fieldtrack.lo: runtime/go-fieldtrack.c
 @am__fastdepCC_TRUE@   $(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-fieldtrack.lo -MD -MP -MF $(DEPDIR)/go-fieldtrack.Tpo -c -o go-fieldtrack.lo `test -f 'runtime/go-fieldtrack.c' || echo '$(srcdir)/'`runtime/go-fieldtrack.c
 @am__fastdepCC_TRUE@   $(am__mv) $(DEPDIR)/go-fieldtrack.Tpo $(DEPDIR)/go-fieldtrack.Plo
@@ -4585,6 +4600,9 @@ reflect/check: $(CHECK_DEPS)
 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
index 799bbea4a8a9012ad846dd97013f42d80822398f..f888d648c19b19ef8f6f6896a66cffd0d10e3e49 100644 (file)
@@ -1502,12 +1502,6 @@ func TestCallWithStruct(t *testing.T) {
 }
 
 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 TestMakeFunc(t *testing.T) {
 }
 
 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 TestMethod(t *testing.T) {
 }
 
 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 @@ type Tm4 struct {
 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 {
index a46e1d8649798eef886079f182f2b4681a0ab2a7..736ac36ade74d50c7caf9bae6d58886bf51d337b 100644 (file)
@@ -22,6 +22,10 @@ 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
@@ -51,22 +55,29 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
                panic("reflect: call of MakeFunc with non-Func type")
        }
 
+       t := typ.common()
+       ftyp := (*funcType)(unsafe.Pointer(t))
+
+       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:
-               panic("reflect.MakeFunc not implemented for " + runtime.GOARCH)
+               code, ffi = makeFuncFFI(ftyp, fn)
        }
 
-       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))
-
-       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 @@ func makeMethodValue(op string, v Value) Value {
                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 @@ func makeMethodValue(op string, v Value) Value {
        // 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 @@ func makeValueMethod(v Value) Value {
                panic("reflect: call of makeValueMethod with non-MethodFn")
        }
 
+       t := typ.common()
+       ftyp := (*funcType)(unsafe.Pointer(t))
+
+       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:
-               panic("reflect.makeValueMethod not implemented for " + runtime.GOARCH)
+               code, ffi = makeFuncFFI(ftyp,
+                       func(in []Value) []Value {
+                               return v.Call(in)
+                       })
        }
 
-       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))
-
        impl := &makeFuncImpl{
                code:   code,
                typ:    ftyp,
                method: -2,
                rcvr:   v,
+               ffi:    ffi,
        }
 
        return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
index aba48df3eb88974e93ea24864fd36aea7219004c..8eff0c1dfacd0dac7dd1c607abf1f3be7da1adbe 100644 (file)
@@ -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 --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go
new file mode 100644 (file)
index 0000000..a13ef17
--- /dev/null
@@ -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 --git a/libgo/go/reflect/makefunc_ffi_c.c b/libgo/go/reflect/makefunc_ffi_c.c
new file mode 100644 (file)
index 0000000..fba269d
--- /dev/null
@@ -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
index e97b85097bc1a2b5d0b3dc8b900b422dd5568b63..a5c687d00f49f816f7e37a0edefb68b87eeb06ec 100644 (file)
@@ -177,7 +177,7 @@ Caller (int skip)
   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;
index 213686933d9c5adb2ae3ede364c840c05183bf9b..047034539a90bebade6e3c0efaf97d26e3af0c4a 100644 (file)
@@ -26,6 +26,7 @@ struct callers_data
   int skip;
   int index;
   int max;
+  int keep_thunks;
 };
 
 /* Callback function for backtrace_full.  Just collect the locations.
@@ -63,7 +64,7 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno,
   /* 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 @@ error_callback (void *data __attribute__ ((unused)),
 /* 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 @@ runtime_callers (int32 skip, Location *locbuf, int32 m)
   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 @@ Callers (int skip, struct __go_open_array pc)
      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 --git a/libgo/runtime/go-ffi.c b/libgo/runtime/go-ffi.c
new file mode 100644 (file)
index 0000000..21879b9
--- /dev/null
@@ -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 --git a/libgo/runtime/go-ffi.h b/libgo/runtime/go-ffi.h
new file mode 100644 (file)
index 0000000..afae4b6
--- /dev/null
@@ -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
index e7031d4040a242f57626ddb289b2a1385a80b8e3..bcaa7e1ee382ab82addc6dd02eabb412c2b3aed1 100644 (file)
@@ -38,6 +38,12 @@ extern void __go_print_string (struct String);
 
 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) */
index ceb9b572582d9680d660f7906fdc72e406130eb8..2d3db55cbc95878b1d98b6291f46875eee2504d4 100644 (file)
@@ -63,7 +63,7 @@ __go_can_recover (const void *retaddr)
   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 @@ __go_can_recover (const void *retaddr)
   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;
index 07b99d7433b5cca54c44a676fcb5a551e7aef52c..dfc703eb2c827c92ba06511104228ff7a37dab03 100644 (file)
 
 #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 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
   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));
 
index f397f07523131583bc8d2591600a20cfb2bdbaa1..7b33cca86815e39a2e8b568b8ecfb3d4bebd5d43 100644 (file)
@@ -16,7 +16,7 @@ runtime_traceback ()
   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);
 }
 
index 8bd56bae1cd7e16cd950938197633443074cb392..d9c220bca23fcefcae33d73171bb7bc5ae777979 100644 (file)
@@ -186,7 +186,7 @@ runtime_MProf_Malloc(void *p, uintptr size)
        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 @@ runtime_blockevent(int64 cycles, int32 skip)
        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 @@ saveg(G *gp, TRecord *r)
        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;
        }
index 363cc191197b63ece9e9e9e9e791aa088444aec6..4195aff76a78a5f87ba1964ffaf57af449c15bdc 100644 (file)
@@ -756,7 +756,7 @@ gtraceback(G* gp)
        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 @@ mcommoninit(M *mp)
        // 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 @@ runtime_sigprof()
        }
 
        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;
        }
index 8fc10ff81f158c024c75ab6c48410ed93fd72f4e..6650be1b3d349488260b22c10bfd060aacd2a0ba 100644 (file)
@@ -609,7 +609,7 @@ void        runtime_exitsyscall(void) __asm__ (GOSYM_PREFIX "syscall.Exitsyscall");
 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));