diff options
-rw-r--r-- | libgo/Makefile.am | 8 | ||||
-rw-r--r-- | libgo/Makefile.in | 42 | ||||
-rw-r--r-- | libgo/go/reflect/all_test.go | 24 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc.go | 95 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc_dummy.c | 11 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc_ffi.go | 88 | ||||
-rw-r--r-- | libgo/go/reflect/makefunc_ffi_c.c | 135 | ||||
-rw-r--r-- | libgo/runtime/go-caller.c | 2 | ||||
-rw-r--r-- | libgo/runtime/go-callers.c | 8 | ||||
-rw-r--r-- | libgo/runtime/go-ffi.c | 338 | ||||
-rw-r--r-- | libgo/runtime/go-ffi.h | 16 | ||||
-rw-r--r-- | libgo/runtime/go-panic.h | 6 | ||||
-rw-r--r-- | libgo/runtime/go-recover.c | 9 | ||||
-rw-r--r-- | libgo/runtime/go-reflect-call.c | 319 | ||||
-rw-r--r-- | libgo/runtime/go-traceback.c | 2 | ||||
-rw-r--r-- | libgo/runtime/mprof.goc | 6 | ||||
-rw-r--r-- | libgo/runtime/proc.c | 6 | ||||
-rw-r--r-- | libgo/runtime/runtime.h | 2 |
18 files changed, 709 insertions, 408 deletions
diff --git a/libgo/Makefile.am b/libgo/Makefile.am index ab15e90..6d00bcc 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -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 diff --git a/libgo/Makefile.in b/libgo/Makefile.in index f11adca..1e085b7 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -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 diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 799bbea..f888d64 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -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 { diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go index a46e1d8..736ac36 100644 --- a/libgo/go/reflect/makefunc.go +++ b/libgo/go/reflect/makefunc.go @@ -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} diff --git a/libgo/go/reflect/makefunc_dummy.c b/libgo/go/reflect/makefunc_dummy.c index aba48df..8eff0c1 100644 --- a/libgo/go/reflect/makefunc_dummy.c +++ b/libgo/go/reflect/makefunc_dummy.c @@ -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 index 0000000..a13ef17 --- /dev/null +++ b/libgo/go/reflect/makefunc_ffi.go @@ -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 index 0000000..fba269d --- /dev/null +++ b/libgo/go/reflect/makefunc_ffi_c.c @@ -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 --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c index e97b850..a5c687d 100644 --- a/libgo/runtime/go-caller.c +++ b/libgo/runtime/go-caller.c @@ -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; diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c index 2136869..0470345 100644 --- a/libgo/runtime/go-callers.c +++ b/libgo/runtime/go-callers.c @@ -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 index 0000000..21879b9 --- /dev/null +++ b/libgo/runtime/go-ffi.c @@ -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 index 0000000..afae4b6 --- /dev/null +++ b/libgo/runtime/go-ffi.h @@ -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 --git a/libgo/runtime/go-panic.h b/libgo/runtime/go-panic.h index e7031d4..bcaa7e1 100644 --- a/libgo/runtime/go-panic.h +++ b/libgo/runtime/go-panic.h @@ -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) */ diff --git a/libgo/runtime/go-recover.c b/libgo/runtime/go-recover.c index ceb9b57..2d3db55 100644 --- a/libgo/runtime/go-recover.c +++ b/libgo/runtime/go-recover.c @@ -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; diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c index 07b99d7..dfc703e 100644 --- a/libgo/runtime/go-reflect-call.c +++ b/libgo/runtime/go-reflect-call.c @@ -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 @@ 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)); diff --git a/libgo/runtime/go-traceback.c b/libgo/runtime/go-traceback.c index f397f07..7b33cca 100644 --- a/libgo/runtime/go-traceback.c +++ b/libgo/runtime/go-traceback.c @@ -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); } diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc index 8bd56ba..d9c220b 100644 --- a/libgo/runtime/mprof.goc +++ b/libgo/runtime/mprof.goc @@ -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; } diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index 363cc19..4195aff 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -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; } diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index 8fc10ff..6650be1 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -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)); |