summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-02-11 07:08:13 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-02-11 07:08:13 +0000
commitc2e397da783df9052a075fd58f19c1b82afa5c8e (patch)
tree31c8010941b678ef4c108a0a4499982d3d32d72e /libgo
parent4f89e4fb1ced634afc8f576dc73abbea3ea003bb (diff)
downloadgcc-c2e397da783df9052a075fd58f19c1b82afa5c8e.tar.gz
runtime: Handle FFI promoting result types.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184123 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo')
-rw-r--r--libgo/runtime/go-reflect-call.c100
1 files changed, 99 insertions, 1 deletions
diff --git a/libgo/runtime/go-reflect-call.c b/libgo/runtime/go-reflect-call.c
index 27177e2fc73..a818dba438e 100644
--- a/libgo/runtime/go-reflect-call.c
+++ b/libgo/runtime/go-reflect-call.c
@@ -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));