Commit 033425d0 by Ian Lance Taylor

re PR go/91781 (r275691 breaks go test "reflect")

	PR go/91781
    reflect: promote integer closure return to full word
    
    The libffi library expects an integer return type to be promoted to a
    full word.  Implement that when returning from a closure written in Go.
    This only matters on big-endian systems when returning an integer smaller
    than the pointer size, which is why we didn't notice it until now.
    
    Fixes https://gcc.gnu.org/PR91781.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/195858

From-SVN: r275813
parent 99a28ee8
ff18e041624b8c23ffcd747f51e9dda945777d2a 7aabaf8623cf88e2378057476a034093abbe5aab
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -28,7 +28,7 @@ func makeCIF(ft *funcType) unsafe.Pointer ...@@ -28,7 +28,7 @@ func makeCIF(ft *funcType) unsafe.Pointer
// //
// The ffi_callback handles __go_makefunc_can_recover, and // The ffi_callback handles __go_makefunc_can_recover, and
// then passes off the data as received from ffi here. // then passes off the data as received from ffi here.
func ffiCallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFuncImpl) { func ffiCallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFuncImpl, wordsize int32, bigEndian bool) {
ftyp := impl.typ ftyp := impl.typ
in := make([]Value, 0, len(ftyp.in)) in := make([]Value, 0, len(ftyp.in))
ap := params ap := params
...@@ -42,21 +42,46 @@ func ffiCallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFunc ...@@ -42,21 +42,46 @@ func ffiCallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFunc
out := impl.call(in) out := impl.call(in)
off := uintptr(0) checkValue := func(v Value, typ *rtype, addr unsafe.Pointer) {
for i, typ := range ftyp.out {
v := out[i]
if v.flag&flagRO != 0 { if v.flag&flagRO != 0 {
panic("reflect: function created by MakeFunc using " + funcName(impl.fn) + panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
" returned value obtained from unexported field") " returned value obtained from unexported field")
} }
off = align(off, uintptr(typ.fieldAlign))
addr := unsafe.Pointer(uintptr(results) + off)
// Convert v to type typ if v is assignable to a variable // Convert v to type typ if v is assignable to a variable
// of type t in the language spec. // of type t in the language spec.
// See issue 28761. // See issue 28761.
v = v.assignTo("reflect.MakeFunc", typ, addr) v = v.assignTo("reflect.MakeFunc", typ, addr)
}
// In libffi a single integer return value is always promoted
// to a full word. This only matters for integers whose size
// is less than the size of a full word. There is similar code
// in libgo/runtime/go-reflect-call.c.
if len(ftyp.out) == 1 {
typ := ftyp.out[0]
switch typ.Kind() {
case Bool, Int8, Int16, Int32, Uint8, Uint16, Uint32:
v := out[0]
checkValue(v, typ, nil)
if bigEndian {
results = unsafe.Pointer(uintptr(results) + uintptr(wordsize) - typ.size)
}
memmove(results, v.ptr, typ.size)
return
}
}
off := uintptr(0)
for i, typ := range ftyp.out {
v := out[i]
off = align(off, uintptr(typ.fieldAlign))
addr := unsafe.Pointer(uintptr(results) + off)
checkValue(v, typ, addr)
if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
*(*unsafe.Pointer)(addr) = v.ptr *(*unsafe.Pointer)(addr) = v.ptr
......
...@@ -25,7 +25,8 @@ void makeFuncFFI(void *cif, void *impl) ...@@ -25,7 +25,8 @@ void makeFuncFFI(void *cif, void *impl)
function ffiCall with the pointer to the arguments, the results area, function ffiCall with the pointer to the arguments, the results area,
and the closure structure. */ and the closure structure. */
extern void ffiCallbackGo(void *result, void **args, ffi_go_closure *closure) extern void ffiCallbackGo(void *result, void **args, ffi_go_closure *closure,
int32 wordsize, _Bool big_endian)
__asm__ (GOSYM_PREFIX "reflect.ffiCallbackGo"); __asm__ (GOSYM_PREFIX "reflect.ffiCallbackGo");
extern void makefuncfficanrecover(Slice) extern void makefuncfficanrecover(Slice)
...@@ -72,7 +73,8 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results, ...@@ -72,7 +73,8 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
makefuncfficanrecover (s); makefuncfficanrecover (s);
} }
ffiCallbackGo(results, args, closure); ffiCallbackGo(results, args, closure, sizeof(ffi_arg),
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
if (i < n) if (i < n)
makefuncreturning (); makefuncreturning ();
......
...@@ -44,8 +44,8 @@ go_results_size (const struct functype *func) ...@@ -44,8 +44,8 @@ go_results_size (const struct functype *func)
types = (const struct _type **) func->out.__values; types = (const struct _type **) func->out.__values;
/* A single integer return value is always promoted to a full /* A single integer return value is always promoted to a full word.
word. */ There is similar code below and in libgo/go/reflect/makefunc_ffi.go.*/
if (count == 1) if (count == 1)
{ {
switch (types[0]->kind & kindMask) switch (types[0]->kind & kindMask)
...@@ -57,8 +57,6 @@ go_results_size (const struct functype *func) ...@@ -57,8 +57,6 @@ go_results_size (const struct functype *func)
case kindUint8: case kindUint8:
case kindUint16: case kindUint16:
case kindUint32: case kindUint32:
case kindInt:
case kindUint:
return sizeof (ffi_arg); return sizeof (ffi_arg);
default: default:
...@@ -108,8 +106,8 @@ go_set_results (const struct functype *func, unsigned char *call_result, ...@@ -108,8 +106,8 @@ go_set_results (const struct functype *func, unsigned char *call_result,
types = (const struct _type **) func->out.__values; types = (const struct _type **) func->out.__values;
/* A single integer return value is always promoted to a full /* A single integer return value is always promoted to a full word.
word. */ There is similar code above and in libgo/go/reflect/makefunc_ffi.go.*/
if (count == 1) if (count == 1)
{ {
switch (types[0]->kind & kindMask) switch (types[0]->kind & kindMask)
...@@ -121,8 +119,6 @@ go_set_results (const struct functype *func, unsigned char *call_result, ...@@ -121,8 +119,6 @@ go_set_results (const struct functype *func, unsigned char *call_result,
case kindUint8: case kindUint8:
case kindUint16: case kindUint16:
case kindUint32: case kindUint32:
case kindInt:
case kindUint:
{ {
union union
{ {
......
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