Commit dffa7328 by Ian Lance Taylor

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
parent 0c92e488
...@@ -444,6 +444,7 @@ runtime_files = \ ...@@ -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 ...@@ -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 = \ ...@@ -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) ...@@ -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 = ...@@ -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 \ ...@@ -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 = \ ...@@ -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 = \ ...@@ -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 = \ ...@@ -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: ...@@ -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 ...@@ -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) ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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")
} }
t := typ.common()
ftyp := (*funcType)(unsafe.Pointer(t))
var code uintptr
var ffi *ffiData
switch runtime.GOARCH { switch runtime.GOARCH {
case "amd64", "386": 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: default:
panic("reflect.MakeFunc not implemented for " + runtime.GOARCH) code, ffi = makeFuncFFI(ftyp, fn)
} }
t := typ.common() impl := &makeFuncImpl{
ftyp := (*funcType)(unsafe.Pointer(t)) code: code,
typ: ftyp,
// Indirect Go func value (dummy) to obtain fn: fn,
// actual code address. (A Go func value is a pointer method: -1,
// to a C function pointer. http://golang.org/s/go11func.) ffi: ffi,
dummy := makeFuncStub }
code := **(**uintptr)(unsafe.Pointer(&dummy))
impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn, method: -1}
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 { ...@@ -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 { ...@@ -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 { ...@@ -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")
} }
t := typ.common()
ftyp := (*funcType)(unsafe.Pointer(t))
var code uintptr
var ffi *ffiData
switch runtime.GOARCH { switch runtime.GOARCH {
case "amd64", "386": 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: 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{ 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 @@ ...@@ -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");
} }
// 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
}
}
// 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) ...@@ -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 ...@@ -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, ...@@ -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)), ...@@ -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) ...@@ -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) ...@@ -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;
......
/* 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) */
/* 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); ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -16,7 +16,7 @@ runtime_traceback () ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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() ...@@ -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"); ...@@ -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));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment