summaryrefslogtreecommitdiffstats
path: root/js/src/ctypes/libffi/src/sparc/ffi64.c
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/ctypes/libffi/src/sparc/ffi64.c')
-rw-r--r--js/src/ctypes/libffi/src/sparc/ffi64.c608
1 files changed, 608 insertions, 0 deletions
diff --git a/js/src/ctypes/libffi/src/sparc/ffi64.c b/js/src/ctypes/libffi/src/sparc/ffi64.c
new file mode 100644
index 0000000000..9e04061a42
--- /dev/null
+++ b/js/src/ctypes/libffi/src/sparc/ffi64.c
@@ -0,0 +1,608 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2011, 2013 Anthony Green
+ Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
+
+ SPARC Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+#include <stdlib.h>
+#include "internal.h"
+
+/* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
+ all further uses in this file will refer to the 128-bit type. */
+#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+# if FFI_TYPE_LONGDOUBLE != 4
+# error FFI_TYPE_LONGDOUBLE out of date
+# endif
+#else
+# undef FFI_TYPE_LONGDOUBLE
+# define FFI_TYPE_LONGDOUBLE 4
+#endif
+
+#ifdef SPARC64
+
+/* Flatten the contents of a structure to the parts that are passed in
+ floating point registers. The return is a bit mask wherein bit N
+ set means bytes [4*n, 4*n+3] are passed in %fN.
+
+ We encode both the (running) size (maximum 32) and mask (maxumum 255)
+ into one integer. The size is placed in the low byte, so that align
+ and addition work correctly. The mask is placed in the second byte. */
+
+static int
+ffi_struct_float_mask (ffi_type *outer_type, int size_mask)
+{
+ ffi_type **elts;
+ ffi_type *t;
+
+ if (outer_type->type == FFI_TYPE_COMPLEX)
+ {
+ int m = 0, tt = outer_type->elements[0]->type;
+ size_t z = outer_type->size;
+
+ if (tt == FFI_TYPE_FLOAT
+ || tt == FFI_TYPE_DOUBLE
+ || tt == FFI_TYPE_LONGDOUBLE)
+ m = (1 << (z / 4)) - 1;
+ return (m << 8) | z;
+ }
+ FFI_ASSERT (outer_type->type == FFI_TYPE_STRUCT);
+
+ for (elts = outer_type->elements; (t = *elts) != NULL; elts++)
+ {
+ size_t z = t->size;
+ int o, m, tt;
+
+ size_mask = FFI_ALIGN(size_mask, t->alignment);
+ switch (t->type)
+ {
+ case FFI_TYPE_STRUCT:
+ size_mask = ffi_struct_float_mask (t, size_mask);
+ continue;
+ case FFI_TYPE_COMPLEX:
+ tt = t->elements[0]->type;
+ if (tt != FFI_TYPE_FLOAT
+ && tt != FFI_TYPE_DOUBLE
+ && tt != FFI_TYPE_LONGDOUBLE)
+ break;
+ /* FALLTHRU */
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ m = (1 << (z / 4)) - 1; /* compute mask for type */
+ o = (size_mask >> 2) & 0x3f; /* extract word offset */
+ size_mask |= m << (o + 8); /* insert mask into place */
+ break;
+ }
+ size_mask += z;
+ }
+
+ size_mask = FFI_ALIGN(size_mask, outer_type->alignment);
+ FFI_ASSERT ((size_mask & 0xff) == outer_type->size);
+
+ return size_mask;
+}
+
+/* Merge floating point data into integer data. If the structure is
+ entirely floating point, simply return a pointer to the fp data. */
+
+static void *
+ffi_struct_float_merge (int size_mask, void *vi, void *vf)
+{
+ int size = size_mask & 0xff;
+ int mask = size_mask >> 8;
+ int n = size >> 2;
+
+ if (mask == 0)
+ return vi;
+ else if (mask == (1 << n) - 1)
+ return vf;
+ else
+ {
+ unsigned int *wi = vi, *wf = vf;
+ int i;
+
+ for (i = 0; i < n; ++i)
+ if ((mask >> i) & 1)
+ wi[i] = wf[i];
+
+ return vi;
+ }
+}
+
+/* Similar, but place the data into VD in the end. */
+
+void FFI_HIDDEN
+ffi_struct_float_copy (int size_mask, void *vd, void *vi, void *vf)
+{
+ int size = size_mask & 0xff;
+ int mask = size_mask >> 8;
+ int n = size >> 2;
+
+ if (mask == 0)
+ ;
+ else if (mask == (1 << n) - 1)
+ vi = vf;
+ else
+ {
+ unsigned int *wd = vd, *wi = vi, *wf = vf;
+ int i;
+
+ for (i = 0; i < n; ++i)
+ wd[i] = ((mask >> i) & 1 ? wf : wi)[i];
+ return;
+ }
+ memcpy (vd, vi, size);
+}
+
+/* Perform machine dependent cif processing */
+
+static ffi_status
+ffi_prep_cif_machdep_core(ffi_cif *cif)
+{
+ ffi_type *rtype = cif->rtype;
+ int rtt = rtype->type;
+ size_t bytes = 0;
+ int i, n, flags;
+
+ /* Set the return type flag */
+ switch (rtt)
+ {
+ case FFI_TYPE_VOID:
+ flags = SPARC_RET_VOID;
+ break;
+ case FFI_TYPE_FLOAT:
+ flags = SPARC_RET_F_1;
+ break;
+ case FFI_TYPE_DOUBLE:
+ flags = SPARC_RET_F_2;
+ break;
+ case FFI_TYPE_LONGDOUBLE:
+ flags = SPARC_RET_F_4;
+ break;
+
+ case FFI_TYPE_COMPLEX:
+ case FFI_TYPE_STRUCT:
+ if (rtype->size > 32)
+ {
+ flags = SPARC_RET_VOID | SPARC_FLAG_RET_IN_MEM;
+ bytes = 8;
+ }
+ else
+ {
+ int size_mask = ffi_struct_float_mask (rtype, 0);
+ int word_size = (size_mask >> 2) & 0x3f;
+ int all_mask = (1 << word_size) - 1;
+ int fp_mask = size_mask >> 8;
+
+ flags = (size_mask << SPARC_SIZEMASK_SHIFT) | SPARC_RET_STRUCT;
+
+ /* For special cases of all-int or all-fp, we can return
+ the value directly without popping through a struct copy. */
+ if (fp_mask == 0)
+ {
+ if (rtype->alignment >= 8)
+ {
+ if (rtype->size == 8)
+ flags = SPARC_RET_INT64;
+ else if (rtype->size == 16)
+ flags = SPARC_RET_INT128;
+ }
+ }
+ else if (fp_mask == all_mask)
+ switch (word_size)
+ {
+ case 1: flags = SPARC_RET_F_1; break;
+ case 2: flags = SPARC_RET_F_2; break;
+ case 3: flags = SP_V9_RET_F_3; break;
+ case 4: flags = SPARC_RET_F_4; break;
+ /* 5 word structures skipped; handled via RET_STRUCT. */
+ case 6: flags = SPARC_RET_F_6; break;
+ /* 7 word structures skipped; handled via RET_STRUCT. */
+ case 8: flags = SPARC_RET_F_8; break;
+ }
+ }
+ break;
+
+ case FFI_TYPE_SINT8:
+ flags = SPARC_RET_SINT8;
+ break;
+ case FFI_TYPE_UINT8:
+ flags = SPARC_RET_UINT8;
+ break;
+ case FFI_TYPE_SINT16:
+ flags = SPARC_RET_SINT16;
+ break;
+ case FFI_TYPE_UINT16:
+ flags = SPARC_RET_UINT16;
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ flags = SP_V9_RET_SINT32;
+ break;
+ case FFI_TYPE_UINT32:
+ flags = SPARC_RET_UINT32;
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ flags = SPARC_RET_INT64;
+ break;
+
+ default:
+ abort();
+ }
+
+ bytes = 0;
+ for (i = 0, n = cif->nargs; i < n; ++i)
+ {
+ ffi_type *ty = cif->arg_types[i];
+ size_t z = ty->size;
+ size_t a = ty->alignment;
+
+ switch (ty->type)
+ {
+ case FFI_TYPE_COMPLEX:
+ case FFI_TYPE_STRUCT:
+ /* Large structs passed by reference. */
+ if (z > 16)
+ {
+ a = z = 8;
+ break;
+ }
+ /* Small structs may be passed in integer or fp regs or both. */
+ if (bytes >= 16*8)
+ break;
+ if ((ffi_struct_float_mask (ty, 0) & 0xff00) == 0)
+ break;
+ /* FALLTHRU */
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_DOUBLE:
+ case FFI_TYPE_LONGDOUBLE:
+ flags |= SPARC_FLAG_FP_ARGS;
+ break;
+ }
+ bytes = FFI_ALIGN(bytes, a);
+ bytes += FFI_ALIGN(z, 8);
+ }
+
+ /* Sparc call frames require that space is allocated for 6 args,
+ even if they aren't used. Make that space if necessary. */
+ if (bytes < 6 * 8)
+ bytes = 6 * 8;
+
+ /* The stack must be 2 word aligned, so round bytes up appropriately. */
+ bytes = FFI_ALIGN(bytes, 16);
+
+ /* Include the call frame to prep_args. */
+ bytes += 8*16 + 8*8;
+
+ cif->bytes = bytes;
+ cif->flags = flags;
+ return FFI_OK;
+}
+
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep(ffi_cif *cif)
+{
+ cif->nfixedargs = cif->nargs;
+ return ffi_prep_cif_machdep_core(cif);
+}
+
+ffi_status FFI_HIDDEN
+ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned nfixedargs, unsigned ntotalargs)
+{
+ cif->nfixedargs = nfixedargs;
+ return ffi_prep_cif_machdep_core(cif);
+}
+
+extern void ffi_call_v9(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+int FFI_HIDDEN
+ffi_prep_args_v9(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
+{
+ ffi_type **p_arg;
+ int flags = cif->flags;
+ int i, nargs;
+
+ if (rvalue == NULL)
+ {
+ if (flags & SPARC_FLAG_RET_IN_MEM)
+ {
+ /* Since we pass the pointer to the callee, we need a value.
+ We allowed for this space in ffi_call, before ffi_call_v8
+ alloca'd the space. */
+ rvalue = (char *)argp + cif->bytes;
+ }
+ else
+ {
+ /* Otherwise, we can ignore the return value. */
+ flags = SPARC_RET_VOID;
+ }
+ }
+
+#ifdef USING_PURIFY
+ /* Purify will probably complain in our assembly routine,
+ unless we zero out this memory. */
+ memset(argp, 0, 6*8);
+#endif
+
+ if (flags & SPARC_FLAG_RET_IN_MEM)
+ *argp++ = (unsigned long)rvalue;
+
+ p_arg = cif->arg_types;
+ for (i = 0, nargs = cif->nargs; i < nargs; i++)
+ {
+ ffi_type *ty = p_arg[i];
+ void *a = avalue[i];
+ size_t z;
+
+ switch (ty->type)
+ {
+ case FFI_TYPE_SINT8:
+ *argp++ = *(SINT8 *)a;
+ break;
+ case FFI_TYPE_UINT8:
+ *argp++ = *(UINT8 *)a;
+ break;
+ case FFI_TYPE_SINT16:
+ *argp++ = *(SINT16 *)a;
+ break;
+ case FFI_TYPE_UINT16:
+ *argp++ = *(UINT16 *)a;
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_SINT32:
+ *argp++ = *(SINT32 *)a;
+ break;
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_FLOAT:
+ *argp++ = *(UINT32 *)a;
+ break;
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_POINTER:
+ case FFI_TYPE_DOUBLE:
+ *argp++ = *(UINT64 *)a;
+ break;
+
+ case FFI_TYPE_LONGDOUBLE:
+ case FFI_TYPE_COMPLEX:
+ case FFI_TYPE_STRUCT:
+ z = ty->size;
+ if (z > 16)
+ {
+ /* For structures larger than 16 bytes we pass reference. */
+ *argp++ = (unsigned long)a;
+ break;
+ }
+ if (((unsigned long)argp & 15) && ty->alignment > 8)
+ argp++;
+ memcpy(argp, a, z);
+ argp += FFI_ALIGN(z, 8) / 8;
+ break;
+
+ default:
+ abort();
+ }
+ }
+
+ return flags;
+}
+
+static void
+ffi_call_int(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ size_t bytes = cif->bytes;
+
+ FFI_ASSERT (cif->abi == FFI_V9);
+
+ if (rvalue == NULL && (cif->flags & SPARC_FLAG_RET_IN_MEM))
+ bytes += FFI_ALIGN (cif->rtype->size, 16);
+
+ ffi_call_v9(cif, fn, rvalue, avalue, -bytes, closure);
+}
+
+void
+ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, NULL);
+}
+
+void
+ffi_call_go(ffi_cif *cif, void (*fn)(void), void *rvalue,
+ void **avalue, void *closure)
+{
+ ffi_call_int(cif, fn, rvalue, avalue, closure);
+}
+
+#ifdef __GNUC__
+static inline void
+ffi_flush_icache (void *p)
+{
+ asm volatile ("flush %0; flush %0+8" : : "r" (p) : "memory");
+}
+#else
+extern void ffi_flush_icache (void *) FFI_HIDDEN;
+#endif
+
+extern void ffi_closure_v9(void) FFI_HIDDEN;
+extern void ffi_go_closure_v9(void) FFI_HIDDEN;
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data,
+ void *codeloc)
+{
+ unsigned int *tramp = (unsigned int *) &closure->tramp[0];
+ unsigned long fn;
+
+ if (cif->abi != FFI_V9)
+ return FFI_BAD_ABI;
+
+ /* Trampoline address is equal to the closure address. We take advantage
+ of that to reduce the trampoline size by 8 bytes. */
+ fn = (unsigned long) ffi_closure_v9;
+ tramp[0] = 0x83414000; /* rd %pc, %g1 */
+ tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */
+ tramp[2] = 0x81c14000; /* jmp %g5 */
+ tramp[3] = 0x01000000; /* nop */
+ *((unsigned long *) &tramp[4]) = fn;
+
+ closure->cif = cif;
+ closure->fun = fun;
+ closure->user_data = user_data;
+
+ ffi_flush_icache (closure);
+
+ return FFI_OK;
+}
+
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure, ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
+{
+ if (cif->abi != FFI_V9)
+ return FFI_BAD_ABI;
+
+ closure->tramp = ffi_go_closure_v9;
+ closure->cif = cif;
+ closure->fun = fun;
+
+ return FFI_OK;
+}
+
+int FFI_HIDDEN
+ffi_closure_sparc_inner_v9(ffi_cif *cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data, void *rvalue,
+ unsigned long *gpr, unsigned long *fpr)
+{
+ ffi_type **arg_types;
+ void **avalue;
+ int i, argn, argx, nargs, flags, nfixedargs;
+
+ arg_types = cif->arg_types;
+ nargs = cif->nargs;
+ flags = cif->flags;
+ nfixedargs = cif->nfixedargs;
+
+ avalue = alloca(nargs * sizeof(void *));
+
+ /* Copy the caller's structure return address so that the closure
+ returns the data directly to the caller. */
+ if (flags & SPARC_FLAG_RET_IN_MEM)
+ {
+ rvalue = (void *) gpr[0];
+ /* Skip the structure return address. */
+ argn = 1;
+ }
+ else
+ argn = 0;
+
+ /* Grab the addresses of the arguments from the stack frame. */
+ for (i = 0; i < nargs; i++, argn = argx)
+ {
+ int named = i < nfixedargs;
+ ffi_type *ty = arg_types[i];
+ void *a = &gpr[argn];
+ size_t z;
+
+ argx = argn + 1;
+ switch (ty->type)
+ {
+ case FFI_TYPE_COMPLEX:
+ case FFI_TYPE_STRUCT:
+ z = ty->size;
+ if (z > 16)
+ a = *(void **)a;
+ else
+ {
+ argx = argn + FFI_ALIGN (z, 8) / 8;
+ if (named && argn < 16)
+ {
+ int size_mask = ffi_struct_float_mask (ty, 0);
+ int argn_mask = (0xffff00 >> argn) & 0xff00;
+
+ /* Eliminate fp registers off the end. */
+ size_mask = (size_mask & 0xff) | (size_mask & argn_mask);
+ a = ffi_struct_float_merge (size_mask, gpr+argn, fpr+argn);
+ }
+ }
+ break;
+
+ case FFI_TYPE_LONGDOUBLE:
+ argn = FFI_ALIGN (argn, 2);
+ a = (named && argn < 16 ? fpr : gpr) + argn;
+ argx = argn + 2;
+ break;
+ case FFI_TYPE_DOUBLE:
+ if (named && argn < 16)
+ a = fpr + argn;
+ break;
+ case FFI_TYPE_FLOAT:
+ if (named && argn < 16)
+ a = fpr + argn;
+ a += 4;
+ break;
+
+ case FFI_TYPE_UINT64:
+ case FFI_TYPE_SINT64:
+ case FFI_TYPE_POINTER:
+ break;
+ case FFI_TYPE_INT:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_SINT32:
+ a += 4;
+ break;
+ case FFI_TYPE_UINT16:
+ case FFI_TYPE_SINT16:
+ a += 6;
+ break;
+ case FFI_TYPE_UINT8:
+ case FFI_TYPE_SINT8:
+ a += 7;
+ break;
+
+ default:
+ abort();
+ }
+ avalue[i] = a;
+ }
+
+ /* Invoke the closure. */
+ fun (cif, rvalue, avalue, user_data);
+
+ /* Tell ffi_closure_sparc how to perform return type promotions. */
+ return flags;
+}
+#endif /* SPARC64 */