OSDN Git Service

runtime: Handle FFI promoting result types.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 11 Feb 2012 07:08:13 +0000 (07:08 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 11 Feb 2012 07:08:13 +0000 (07:08 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184123 138bc75d-0d04-0410-961f-82ee72b054a4

libgo/runtime/go-reflect-call.c

index 27177e2..a818dba 100644 (file)
@@ -5,6 +5,7 @@
    license that can be found in the LICENSE file.  */
 
 #include <stdio.h>
+#include <stdint.h>
 #include <stdlib.h>
 
 #include "ffi.h"
@@ -326,6 +327,28 @@ go_results_size (const struct __go_func_type *func)
 
   types = (const struct __go_type_descriptor **) func->__out.__values;
 
+  /* A single integer return value is always promoted to a full
+     word.  */
+  if (count == 1)
+    {
+      switch (types[0]->__code & GO_CODE_MASK)
+       {
+       case GO_BOOL:
+       case GO_INT8:
+       case GO_INT16:
+       case GO_INT32:
+       case GO_UINT8:
+       case GO_UINT16:
+       case GO_UINT32:
+       case GO_INT:
+       case GO_UINT:
+         return sizeof (ffi_arg);
+
+       default:
+         break;
+       }
+    }
+
   off = 0;
   maxalign = 0;
   for (i = 0; i < count; ++i)
@@ -362,6 +385,81 @@ go_set_results (const struct __go_func_type *func, unsigned char *call_result,
 
   types = (const struct __go_type_descriptor **) func->__out.__values;
 
+  /* A single integer return value is always promoted to a full
+     word.  */
+  if (count == 1)
+    {
+      switch (types[0]->__code & GO_CODE_MASK)
+       {
+       case GO_BOOL:
+       case GO_INT8:
+       case GO_INT16:
+       case GO_INT32:
+       case GO_UINT8:
+       case GO_UINT16:
+       case GO_UINT32:
+       case GO_INT:
+       case GO_UINT:
+         {
+           union
+           {
+             unsigned char buf[sizeof (ffi_arg)];
+             ffi_arg v;
+           } u;
+           ffi_arg v;
+
+           __builtin_memcpy (&u.buf, call_result, sizeof (ffi_arg));
+           v = u.v;
+
+           switch (types[0]->__size)
+             {
+             case 1:
+               {
+                 uint8_t b;
+
+                 b = (uint8_t) v;
+                 __builtin_memcpy (results[0], &b, 1);
+               }
+               break;
+
+             case 2:
+               {
+                 uint16_t s;
+
+                 s = (uint16_t) v;
+                 __builtin_memcpy (results[0], &s, 2);
+               }
+               break;
+
+             case 4:
+               {
+                 uint32_t w;
+
+                 w = (uint32_t) v;
+                 __builtin_memcpy (results[0], &w, 4);
+               }
+               break;
+
+             case 8:
+               {
+                 uint64_t d;
+
+                 d = (uint64_t) v;
+                 __builtin_memcpy (results[0], &d, 8);
+               }
+               break;
+
+             default:
+               abort ();
+             }
+         }
+         return;
+
+       default:
+         break;
+       }
+    }
+
   off = 0;
   for (i = 0; i < count; ++i)
     {
@@ -388,7 +486,7 @@ reflect_call (const struct __go_func_type *func_type, const void *func_addr,
   ffi_cif cif;
   unsigned char *call_result;
 
-  __go_assert (func_type->__common.__code == GO_FUNC);
+  __go_assert ((func_type->__common.__code & GO_CODE_MASK) == GO_FUNC);
   go_func_to_cif (func_type, is_interface, is_method, &cif);
 
   call_result = (unsigned char *) malloc (go_results_size (func_type));