re PR go/91781 (r275691 breaks go test "reflect")
authorIan Lance Taylor <ian@gcc.gnu.org>
Tue, 17 Sep 2019 20:24:00 +0000 (20:24 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 17 Sep 2019 20:24:00 +0000 (20:24 +0000)
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

gcc/go/gofrontend/MERGE
libgo/go/reflect/makefunc_ffi.go
libgo/go/reflect/makefunc_ffi_c.c
libgo/runtime/go-reflect-call.c

index ab30040ce459eede96a722eeb0d14ab0dd664600..4a81caa228dd00acf880ca17255c25deed5f2cbc 100644 (file)
@@ -1,4 +1,4 @@
-ff18e041624b8c23ffcd747f51e9dda945777d2a
+7aabaf8623cf88e2378057476a034093abbe5aab
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 88ffca56ca033fd6474e11371d42bf313f3a4974..05c5bc003427e3db1e63535ecf2f73647b119e08 100644 (file)
@@ -28,7 +28,7 @@ func makeCIF(ft *funcType) unsafe.Pointer
 //
 // The ffi_callback handles __go_makefunc_can_recover, and
 // 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
        in := make([]Value, 0, len(ftyp.in))
        ap := params
@@ -42,21 +42,46 @@ func ffiCallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFunc
 
        out := impl.call(in)
 
-       off := uintptr(0)
-       for i, typ := range ftyp.out {
-               v := out[i]
+       checkValue := func(v Value, typ *rtype, addr unsafe.Pointer) {
                if v.flag&flagRO != 0 {
                        panic("reflect: function created by MakeFunc using " + funcName(impl.fn) +
                                " 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
                // of type t in the language spec.
                // See issue 28761.
                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) {
                        *(*unsafe.Pointer)(addr) = v.ptr
index e57bd512e87062eff6d344ae75b7676ac1ffaf06..f1890264d7f431776f0edccefe321b7af18b20b9 100644 (file)
@@ -25,7 +25,8 @@ void makeFuncFFI(void *cif, void *impl)
    function ffiCall with the pointer to the arguments, the results area,
    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");
 
 extern void makefuncfficanrecover(Slice)
@@ -72,7 +73,8 @@ ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
       makefuncfficanrecover (s);
     }
 
-  ffiCallbackGo(results, args, closure);
+  ffiCallbackGo(results, args, closure, sizeof(ffi_arg),
+                __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__);
 
   if (i < n)
     makefuncreturning ();
index ffae9030420c14d63c51188ad9d104c0cc085c55..4d887eb87181f137d8a7ee52d23d2ee09ff76021 100644 (file)
@@ -44,8 +44,8 @@ go_results_size (const struct functype *func)
 
   types = (const struct _type **) func->out.__values;
 
-  /* A single integer return value is always promoted to a full
-     word.  */
+  /* A single integer return value is always promoted to a full word.
+     There is similar code below and in libgo/go/reflect/makefunc_ffi.go.*/
   if (count == 1)
     {
       switch (types[0]->kind & kindMask)
@@ -57,8 +57,6 @@ go_results_size (const struct functype *func)
        case kindUint8:
        case kindUint16:
        case kindUint32:
-       case kindInt:
-       case kindUint:
          return sizeof (ffi_arg);
 
        default:
@@ -108,8 +106,8 @@ go_set_results (const struct functype *func, unsigned char *call_result,
 
   types = (const struct _type **) func->out.__values;
 
-  /* A single integer return value is always promoted to a full
-     word.  */
+  /* A single integer return value is always promoted to a full word.
+     There is similar code above and in libgo/go/reflect/makefunc_ffi.go.*/
   if (count == 1)
     {
       switch (types[0]->kind & kindMask)
@@ -121,8 +119,6 @@ go_set_results (const struct functype *func, unsigned char *call_result,
        case kindUint8:
        case kindUint16:
        case kindUint32:
-       case kindInt:
-       case kindUint:
          {
            union
            {