mirror of git://gcc.gnu.org/git/gcc.git
reflect, runtime: Use libffi closures to implement reflect.MakeFunc.
Keep using the existing 386 and amd64 code on those archs, since it is more efficient. From-SVN: r212853
This commit is contained in:
parent
0c92e4881a
commit
dffa732835
|
|
@ -444,6 +444,7 @@ runtime_files = \
|
||||||
runtime/go-deferred-recover.c \
|
runtime/go-deferred-recover.c \
|
||||||
runtime/go-eface-compare.c \
|
runtime/go-eface-compare.c \
|
||||||
runtime/go-eface-val-compare.c \
|
runtime/go-eface-val-compare.c \
|
||||||
|
runtime/go-ffi.c \
|
||||||
runtime/go-fieldtrack.c \
|
runtime/go-fieldtrack.c \
|
||||||
runtime/go-int-array-to-string.c \
|
runtime/go-int-array-to-string.c \
|
||||||
runtime/go-int-to-string.c \
|
runtime/go-int-to-string.c \
|
||||||
|
|
@ -951,9 +952,12 @@ endif
|
||||||
go_reflect_files = \
|
go_reflect_files = \
|
||||||
go/reflect/deepequal.go \
|
go/reflect/deepequal.go \
|
||||||
go/reflect/makefunc.go \
|
go/reflect/makefunc.go \
|
||||||
|
go/reflect/makefunc_ffi.go \
|
||||||
$(go_reflect_makefunc_file) \
|
$(go_reflect_makefunc_file) \
|
||||||
go/reflect/type.go \
|
go/reflect/type.go \
|
||||||
go/reflect/value.go
|
go/reflect/value.go
|
||||||
|
go_reflect_makefunc_c_file = \
|
||||||
|
go/reflect/makefunc_ffi_c.c
|
||||||
|
|
||||||
go_regexp_files = \
|
go_regexp_files = \
|
||||||
go/regexp/exec.go \
|
go/regexp/exec.go \
|
||||||
|
|
@ -1849,6 +1853,7 @@ libgo_go_objs = \
|
||||||
path.lo \
|
path.lo \
|
||||||
reflect-go.lo \
|
reflect-go.lo \
|
||||||
reflect/makefunc.lo \
|
reflect/makefunc.lo \
|
||||||
|
reflect/makefunc_ffi_c.lo \
|
||||||
regexp.lo \
|
regexp.lo \
|
||||||
runtime-go.lo \
|
runtime-go.lo \
|
||||||
sort.lo \
|
sort.lo \
|
||||||
|
|
@ -2252,6 +2257,9 @@ reflect/check: $(CHECK_DEPS)
|
||||||
reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
|
reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
|
||||||
@$(MKDIR_P) reflect
|
@$(MKDIR_P) reflect
|
||||||
$(LTCOMPILE) -c -o $@ $<
|
$(LTCOMPILE) -c -o $@ $<
|
||||||
|
reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file)
|
||||||
|
@$(MKDIR_P) reflect
|
||||||
|
$(LTCOMPILE) -c -o $@ $<
|
||||||
.PHONY: reflect/check
|
.PHONY: reflect/check
|
||||||
|
|
||||||
@go_include@ regexp.lo.dep
|
@go_include@ regexp.lo.dep
|
||||||
|
|
|
||||||
|
|
@ -135,17 +135,18 @@ am__DEPENDENCIES_1 =
|
||||||
am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
|
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 \
|
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 \
|
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 \
|
reflect-go.lo reflect/makefunc.lo reflect/makefunc_ffi_c.lo \
|
||||||
sort.lo strconv.lo strings.lo strings/index.lo sync.lo \
|
regexp.lo runtime-go.lo sort.lo strconv.lo strings.lo \
|
||||||
syscall.lo syscall/errno.lo syscall/signame.lo syscall/wait.lo \
|
strings/index.lo sync.lo syscall.lo syscall/errno.lo \
|
||||||
testing.lo time-go.lo unicode.lo archive/tar.lo archive/zip.lo \
|
syscall/signame.lo syscall/wait.lo testing.lo time-go.lo \
|
||||||
compress/bzip2.lo compress/flate.lo compress/gzip.lo \
|
unicode.lo archive/tar.lo archive/zip.lo compress/bzip2.lo \
|
||||||
compress/lzw.lo compress/zlib.lo container/heap.lo \
|
compress/flate.lo compress/gzip.lo compress/lzw.lo \
|
||||||
container/list.lo container/ring.lo crypto/aes.lo \
|
compress/zlib.lo container/heap.lo container/list.lo \
|
||||||
crypto/cipher.lo crypto/des.lo crypto/dsa.lo crypto/ecdsa.lo \
|
container/ring.lo crypto/aes.lo crypto/cipher.lo crypto/des.lo \
|
||||||
crypto/elliptic.lo crypto/hmac.lo crypto/md5.lo crypto/rand.lo \
|
crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \
|
||||||
crypto/rc4.lo crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo \
|
crypto/hmac.lo crypto/md5.lo crypto/rand.lo crypto/rc4.lo \
|
||||||
crypto/sha512.lo crypto/subtle.lo crypto/tls.lo crypto/x509.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 \
|
crypto/x509/pkix.lo database/sql.lo database/sql/driver.lo \
|
||||||
debug/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
|
debug/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
|
||||||
debug/pe.lo debug/plan9obj.lo encoding/ascii85.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-check-interface.lo go-construct-map.lo \
|
||||||
go-convert-interface.lo go-copy.lo go-defer.lo \
|
go-convert-interface.lo go-copy.lo go-defer.lo \
|
||||||
go-deferred-recover.lo go-eface-compare.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-int-array-to-string.lo go-int-to-string.lo \
|
||||||
go-interface-compare.lo go-interface-eface-compare.lo \
|
go-interface-compare.lo go-interface-eface-compare.lo \
|
||||||
go-interface-val-compare.lo go-make-slice.lo go-map-delete.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-deferred-recover.c \
|
||||||
runtime/go-eface-compare.c \
|
runtime/go-eface-compare.c \
|
||||||
runtime/go-eface-val-compare.c \
|
runtime/go-eface-val-compare.c \
|
||||||
|
runtime/go-ffi.c \
|
||||||
runtime/go-fieldtrack.c \
|
runtime/go-fieldtrack.c \
|
||||||
runtime/go-int-array-to-string.c \
|
runtime/go-int-array-to-string.c \
|
||||||
runtime/go-int-to-string.c \
|
runtime/go-int-to-string.c \
|
||||||
|
|
@ -1121,10 +1123,14 @@ go_path_files = \
|
||||||
go_reflect_files = \
|
go_reflect_files = \
|
||||||
go/reflect/deepequal.go \
|
go/reflect/deepequal.go \
|
||||||
go/reflect/makefunc.go \
|
go/reflect/makefunc.go \
|
||||||
|
go/reflect/makefunc_ffi.go \
|
||||||
$(go_reflect_makefunc_file) \
|
$(go_reflect_makefunc_file) \
|
||||||
go/reflect/type.go \
|
go/reflect/type.go \
|
||||||
go/reflect/value.go
|
go/reflect/value.go
|
||||||
|
|
||||||
|
go_reflect_makefunc_c_file = \
|
||||||
|
go/reflect/makefunc_ffi_c.c
|
||||||
|
|
||||||
go_regexp_files = \
|
go_regexp_files = \
|
||||||
go/regexp/exec.go \
|
go/regexp/exec.go \
|
||||||
go/regexp/onepass.go \
|
go/regexp/onepass.go \
|
||||||
|
|
@ -1910,6 +1916,7 @@ libgo_go_objs = \
|
||||||
path.lo \
|
path.lo \
|
||||||
reflect-go.lo \
|
reflect-go.lo \
|
||||||
reflect/makefunc.lo \
|
reflect/makefunc.lo \
|
||||||
|
reflect/makefunc_ffi_c.lo \
|
||||||
regexp.lo \
|
regexp.lo \
|
||||||
runtime-go.lo \
|
runtime-go.lo \
|
||||||
sort.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-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-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-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-fieldtrack.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-iface.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@
|
@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@
|
@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
|
@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
|
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@ $(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
|
@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)
|
reflect/makefunc.lo: $(go_reflect_makefunc_s_file)
|
||||||
@$(MKDIR_P) reflect
|
@$(MKDIR_P) reflect
|
||||||
$(LTCOMPILE) -c -o $@ $<
|
$(LTCOMPILE) -c -o $@ $<
|
||||||
|
reflect/makefunc_ffi_c.lo: $(go_reflect_makefunc_c_file)
|
||||||
|
@$(MKDIR_P) reflect
|
||||||
|
$(LTCOMPILE) -c -o $@ $<
|
||||||
.PHONY: reflect/check
|
.PHONY: reflect/check
|
||||||
|
|
||||||
@go_include@ regexp.lo.dep
|
@go_include@ regexp.lo.dep
|
||||||
|
|
|
||||||
|
|
@ -1502,12 +1502,6 @@ func TestCallWithStruct(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMakeFunc(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
|
f := dummy
|
||||||
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
|
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
|
||||||
ValueOf(&f).Elem().Set(fv)
|
ValueOf(&f).Elem().Set(fv)
|
||||||
|
|
@ -1526,12 +1520,6 @@ func TestMakeFunc(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMakeFuncInterface(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 }
|
fn := func(i int) int { return i }
|
||||||
incr := func(in []Value) []Value {
|
incr := func(in []Value) []Value {
|
||||||
return []Value{ValueOf(int(in[0].Int() + 1))}
|
return []Value{ValueOf(int(in[0].Int() + 1))}
|
||||||
|
|
@ -1676,12 +1664,6 @@ func TestMethod(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMethodValue(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}
|
p := Point{3, 4}
|
||||||
var i int64
|
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 (t4 Tm4) M(x int, b byte) (byte, int) { return b, x + 40 }
|
||||||
|
|
||||||
func TestMethod5(t *testing.T) {
|
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) {
|
CheckF := func(name string, f func(int, byte) (byte, int), inc int) {
|
||||||
b, x := f(1000, 99)
|
b, x := f(1000, 99)
|
||||||
if b != 99 || x != 1000+inc {
|
if b != 99 || x != 1000+inc {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ type makeFuncImpl struct {
|
||||||
// method values.
|
// method values.
|
||||||
method int
|
method int
|
||||||
rcvr Value
|
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
|
// 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")
|
panic("reflect: call of MakeFunc with non-Func type")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "amd64", "386":
|
|
||||||
default:
|
|
||||||
panic("reflect.MakeFunc not implemented for " + runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
t := typ.common()
|
t := typ.common()
|
||||||
ftyp := (*funcType)(unsafe.Pointer(t))
|
ftyp := (*funcType)(unsafe.Pointer(t))
|
||||||
|
|
||||||
// Indirect Go func value (dummy) to obtain
|
var code uintptr
|
||||||
// actual code address. (A Go func value is a pointer
|
var ffi *ffiData
|
||||||
// to a C function pointer. http://golang.org/s/go11func.)
|
switch runtime.GOARCH {
|
||||||
dummy := makeFuncStub
|
case "amd64", "386":
|
||||||
code := **(**uintptr)(unsafe.Pointer(&dummy))
|
// Indirect Go func value (dummy) to obtain actual
|
||||||
|
// code address. (A Go func value is a pointer to a C
|
||||||
|
// function pointer. http://golang.org/s/go11func.)
|
||||||
|
dummy := makeFuncStub
|
||||||
|
code = **(**uintptr)(unsafe.Pointer(&dummy))
|
||||||
|
default:
|
||||||
|
code, ffi = makeFuncFFI(ftyp, fn)
|
||||||
|
}
|
||||||
|
|
||||||
impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn, method: -1}
|
impl := &makeFuncImpl{
|
||||||
|
code: code,
|
||||||
|
typ: ftyp,
|
||||||
|
fn: fn,
|
||||||
|
method: -1,
|
||||||
|
ffi: ffi,
|
||||||
|
}
|
||||||
|
|
||||||
return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
|
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")
|
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.
|
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
|
||||||
fl := v.flag & (flagRO | flagAddr | flagIndir)
|
fl := v.flag & (flagRO | flagAddr | flagIndir)
|
||||||
fl |= flag(v.typ.Kind()) << flagKindShift
|
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.
|
// v.Type returns the actual type of the method value.
|
||||||
ft := v.Type().(*rtype)
|
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.
|
// Cause panic if method is not appropriate.
|
||||||
// The panic would still happen during the call if we omit this,
|
// The panic would still happen during the call if we omit this,
|
||||||
// but we want Interface() and other operations to fail early.
|
// but we want Interface() and other operations to fail early.
|
||||||
_, t, _ := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
|
_, 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{
|
fv := &makeFuncImpl{
|
||||||
code: code,
|
code: code,
|
||||||
typ: (*funcType)(unsafe.Pointer(t)),
|
typ: ftyp,
|
||||||
method: int(v.flag) >> flagMethodShift,
|
method: method,
|
||||||
rcvr: rcvr,
|
rcvr: rcvr,
|
||||||
|
ffi: ffi,
|
||||||
}
|
}
|
||||||
|
|
||||||
return Value{ft, unsafe.Pointer(&fv), v.flag&flagRO | flag(Func)<<flagKindShift | flagIndir}
|
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")
|
panic("reflect: call of makeValueMethod with non-MethodFn")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "amd64", "386":
|
|
||||||
default:
|
|
||||||
panic("reflect.makeValueMethod not implemented for " + runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
t := typ.common()
|
t := typ.common()
|
||||||
ftyp := (*funcType)(unsafe.Pointer(t))
|
ftyp := (*funcType)(unsafe.Pointer(t))
|
||||||
|
|
||||||
// Indirect Go func value (dummy) to obtain
|
var code uintptr
|
||||||
// actual code address. (A Go func value is a pointer
|
var ffi *ffiData
|
||||||
// to a C function pointer. http://golang.org/s/go11func.)
|
switch runtime.GOARCH {
|
||||||
dummy := makeFuncStub
|
case "amd64", "386":
|
||||||
code := **(**uintptr)(unsafe.Pointer(&dummy))
|
// Indirect Go func value (dummy) to obtain actual
|
||||||
|
// code address. (A Go func value is a pointer to a C
|
||||||
|
// function pointer. http://golang.org/s/go11func.)
|
||||||
|
dummy := makeFuncStub
|
||||||
|
code = **(**uintptr)(unsafe.Pointer(&dummy))
|
||||||
|
default:
|
||||||
|
code, ffi = makeFuncFFI(ftyp,
|
||||||
|
func(in []Value) []Value {
|
||||||
|
return v.Call(in)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl := &makeFuncImpl{
|
impl := &makeFuncImpl{
|
||||||
code: code,
|
code: code,
|
||||||
typ: ftyp,
|
typ: ftyp,
|
||||||
method: -2,
|
method: -2,
|
||||||
rcvr: v,
|
rcvr: v,
|
||||||
|
ffi: ffi,
|
||||||
}
|
}
|
||||||
|
|
||||||
return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
|
return Value{t, unsafe.Pointer(&impl), flag(Func<<flagKindShift) | flagIndir}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// 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) __asm__ ("reflect.makeFuncStub");
|
||||||
void makeFuncStub ()
|
|
||||||
|
void makeFuncStub (void)
|
||||||
{
|
{
|
||||||
|
runtime_throw ("impossible call to makeFuncStub");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -177,7 +177,7 @@ Caller (int skip)
|
||||||
int32 n;
|
int32 n;
|
||||||
|
|
||||||
runtime_memclr (&ret, sizeof ret);
|
runtime_memclr (&ret, sizeof ret);
|
||||||
n = runtime_callers (skip + 1, &loc, 1);
|
n = runtime_callers (skip + 1, &loc, 1, false);
|
||||||
if (n < 1)
|
if (n < 1)
|
||||||
return ret;
|
return ret;
|
||||||
ret.pc = loc.pc;
|
ret.pc = loc.pc;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ struct callers_data
|
||||||
int skip;
|
int skip;
|
||||||
int index;
|
int index;
|
||||||
int max;
|
int max;
|
||||||
|
int keep_thunks;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Callback function for backtrace_full. Just collect the locations.
|
/* 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
|
/* Skip thunks and recover functions. There is no equivalent to
|
||||||
these functions in the gc toolchain, so returning them here means
|
these functions in the gc toolchain, so returning them here means
|
||||||
significantly different results for runtime.Caller(N). */
|
significantly different results for runtime.Caller(N). */
|
||||||
if (function != NULL)
|
if (function != NULL && !arg->keep_thunks)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
|
|
@ -136,7 +137,7 @@ error_callback (void *data __attribute__ ((unused)),
|
||||||
/* Gather caller PC's. */
|
/* Gather caller PC's. */
|
||||||
|
|
||||||
int32
|
int32
|
||||||
runtime_callers (int32 skip, Location *locbuf, int32 m)
|
runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
|
||||||
{
|
{
|
||||||
struct callers_data data;
|
struct callers_data data;
|
||||||
|
|
||||||
|
|
@ -144,6 +145,7 @@ runtime_callers (int32 skip, Location *locbuf, int32 m)
|
||||||
data.skip = skip + 1;
|
data.skip = skip + 1;
|
||||||
data.index = 0;
|
data.index = 0;
|
||||||
data.max = m;
|
data.max = m;
|
||||||
|
data.keep_thunks = keep_thunks;
|
||||||
runtime_xadd (&runtime_in_callers, 1);
|
runtime_xadd (&runtime_in_callers, 1);
|
||||||
backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
|
backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
|
||||||
&data);
|
&data);
|
||||||
|
|
@ -167,7 +169,7 @@ Callers (int skip, struct __go_open_array pc)
|
||||||
which we can not correct because it would break backward
|
which we can not correct because it would break backward
|
||||||
compatibility. Normally we would add 1 to SKIP here, but we
|
compatibility. Normally we would add 1 to SKIP here, but we
|
||||||
don't so that we are compatible. */
|
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++)
|
for (i = 0; i < ret; i++)
|
||||||
((uintptr *) pc.__values)[i] = locbuf[i].pc;
|
((uintptr *) pc.__values)[i] = locbuf[i].pc;
|
||||||
|
|
|
||||||
|
|
@ -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) */
|
||||||
|
|
@ -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
|
||||||
|
|
@ -38,6 +38,12 @@ extern void __go_print_string (struct String);
|
||||||
|
|
||||||
extern struct __go_empty_interface __go_recover (void);
|
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);
|
extern void __go_unwind_stack (void);
|
||||||
|
|
||||||
#endif /* !defined(LIBGO_GO_PANIC_H) */
|
#endif /* !defined(LIBGO_GO_PANIC_H) */
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ __go_can_recover (const void *retaddr)
|
||||||
if (!d->__makefunc_can_recover)
|
if (!d->__makefunc_can_recover)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (runtime_callers (2, &loc, 1) < 1)
|
if (runtime_callers (2, &loc, 1, false) < 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If we have no function name, then we weren't called by Go code.
|
/* 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] == '_')
|
if (name[0] == 'f' && name[1] == 'f' && name[2] == 'i' && name[3] == '_')
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* We may also be called by reflect.makeFuncImpl.call, for a
|
/* We may also be called by reflect.makeFuncImpl.call or
|
||||||
function created by reflect.MakeFunc. */
|
reflect.ffiCall, for a function created by reflect.MakeFunc. */
|
||||||
if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL)
|
if (__builtin_strstr ((const char *) name, "makeFuncImpl") != NULL
|
||||||
|
|| __builtin_strcmp ((const char *) name, "reflect.ffiCall") == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -15,333 +15,18 @@
|
||||||
|
|
||||||
#ifdef USE_LIBFFI
|
#ifdef USE_LIBFFI
|
||||||
|
|
||||||
#include "ffi.h"
|
#include "go-ffi.h"
|
||||||
|
|
||||||
/* The functions in this file are only called from reflect_call. As
|
/* The functions in this file are only called from reflect_call. As
|
||||||
reflect_call calls a libffi function, which will be compiled
|
reflect_call calls a libffi function, which will be compiled
|
||||||
without -fsplit-stack, it will always run with a large stack. */
|
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 *)
|
static size_t go_results_size (const struct __go_func_type *)
|
||||||
__attribute__ ((no_split_stack));
|
__attribute__ ((no_split_stack));
|
||||||
static void go_set_results (const struct __go_func_type *, unsigned char *,
|
static void go_set_results (const struct __go_func_type *, unsigned char *,
|
||||||
void **)
|
void **)
|
||||||
__attribute__ ((no_split_stack));
|
__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
|
/* Get the total size required for the result parameters of a
|
||||||
function. */
|
function. */
|
||||||
|
|
||||||
|
|
@ -532,7 +217,7 @@ reflect_call (const struct __go_func_type *func_type, FuncVal *func_val,
|
||||||
unsigned char *call_result;
|
unsigned char *call_result;
|
||||||
|
|
||||||
__go_assert ((func_type->__common.__code & GO_CODE_MASK) == GO_FUNC);
|
__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));
|
call_result = (unsigned char *) malloc (go_results_size (func_type));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ runtime_traceback ()
|
||||||
Location locbuf[100];
|
Location locbuf[100];
|
||||||
int32 c;
|
int32 c;
|
||||||
|
|
||||||
c = runtime_callers (1, locbuf, nelem (locbuf));
|
c = runtime_callers (1, locbuf, nelem (locbuf), false);
|
||||||
runtime_printtrace (locbuf, c, true);
|
runtime_printtrace (locbuf, c, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ runtime_MProf_Malloc(void *p, uintptr size)
|
||||||
Bucket *b;
|
Bucket *b;
|
||||||
int32 nstk;
|
int32 nstk;
|
||||||
|
|
||||||
nstk = runtime_callers(1, stk, nelem(stk));
|
nstk = runtime_callers(1, stk, nelem(stk), false);
|
||||||
runtime_lock(&proflock);
|
runtime_lock(&proflock);
|
||||||
b = stkbucket(MProf, size, stk, nstk, true);
|
b = stkbucket(MProf, size, stk, nstk, true);
|
||||||
b->recent_allocs++;
|
b->recent_allocs++;
|
||||||
|
|
@ -249,7 +249,7 @@ runtime_blockevent(int64 cycles, int32 skip)
|
||||||
if(rate <= 0 || (rate > cycles && runtime_fastrand1()%rate > cycles))
|
if(rate <= 0 || (rate > cycles && runtime_fastrand1()%rate > cycles))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nstk = runtime_callers(skip, stk, nelem(stk));
|
nstk = runtime_callers(skip, stk, nelem(stk), false);
|
||||||
runtime_lock(&proflock);
|
runtime_lock(&proflock);
|
||||||
b = stkbucket(BProf, 0, stk, nstk, true);
|
b = stkbucket(BProf, 0, stk, nstk, true);
|
||||||
b->count++;
|
b->count++;
|
||||||
|
|
@ -449,7 +449,7 @@ saveg(G *gp, TRecord *r)
|
||||||
Location locstk[nelem(r->stk)];
|
Location locstk[nelem(r->stk)];
|
||||||
|
|
||||||
if(gp == runtime_g()) {
|
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++)
|
for(i = 0; i < n; i++)
|
||||||
r->stk[i] = locstk[i].pc;
|
r->stk[i] = locstk[i].pc;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -756,7 +756,7 @@ gtraceback(G* gp)
|
||||||
traceback = gp->traceback;
|
traceback = gp->traceback;
|
||||||
gp->traceback = nil;
|
gp->traceback = nil;
|
||||||
traceback->c = runtime_callers(1, traceback->locbuf,
|
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);
|
runtime_gogo(traceback->gp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -766,7 +766,7 @@ mcommoninit(M *mp)
|
||||||
// If there is no mcache runtime_callers() will crash,
|
// If there is no mcache runtime_callers() will crash,
|
||||||
// and we are most likely in sysmon thread so the stack is senseless anyway.
|
// and we are most likely in sysmon thread so the stack is senseless anyway.
|
||||||
if(m->mcache)
|
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();
|
mp->fastrand = 0x49f6428aUL + mp->id + runtime_cputicks();
|
||||||
|
|
||||||
|
|
@ -2584,7 +2584,7 @@ runtime_sigprof()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(traceback) {
|
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++)
|
for(i = 0; i < n; i++)
|
||||||
prof.pcbuf[i] = prof.locbuf[i].pc;
|
prof.pcbuf[i] = prof.locbuf[i].pc;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -609,7 +609,7 @@ void runtime_exitsyscall(void) __asm__ (GOSYM_PREFIX "syscall.Exitsyscall");
|
||||||
G* __go_go(void (*pfn)(void*), void*);
|
G* __go_go(void (*pfn)(void*), void*);
|
||||||
void siginit(void);
|
void siginit(void);
|
||||||
bool __go_sigsend(int32 sig);
|
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_nanotime(void); // monotonic time
|
||||||
int64 runtime_unixnanotime(void); // real time, can skip
|
int64 runtime_unixnanotime(void); // real time, can skip
|
||||||
void runtime_dopanic(int32) __attribute__ ((noreturn));
|
void runtime_dopanic(int32) __attribute__ ((noreturn));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue