- default:
- FFI_ASSERT(0);
- break;
- }
-}
-
-/*
- * Closures represent a pair consisting of a function pointer, and
- * some user data. A closure is invoked by reinterpreting the closure
- * as a function pointer, and branching to it. Thus we can make an
- * interpreted function callable as a C function: We turn the interpreter
- * itself, together with a pointer specifying the interpreted procedure,
- * into a closure.
- * On X86, the first few words of the closure structure actually contain code,
- * which will do the right thing. On most other architectures, this
- * would raise some Icache/Dcache coherence issues (which can be solved, but
- * often not cheaply).
- * For IA64, function pointer are already pairs consisting of a code
- * pointer, and a gp pointer. The latter is needed to access global variables.
- * Here we set up such a pair as the first two words of the closure (in
- * the "trampoline" area), but we replace the gp pointer with a pointer
- * to the closure itself. We also add the real gp pointer to the
- * closure. This allows the function entry code to both retrieve the
- * user data, and to restire the correct gp pointer.
- */
-
-static void
-ffi_prep_incoming_args_UNIX(struct ia64_args *args, void **rvalue,
- void **avalue, ffi_cif *cif);
-
-/* This function is entered with the doctored gp (r1) value.
- * This code is extremely gcc specific. There is some argument that
- * it should really be written in assembly code, since it depends on
- * gcc properties that might change over time.
- */
-
-/* ffi_closure_UNIX is an assembly routine, which copies the register */
-/* state into a struct ia64_args, and then invokes */
-/* ffi_closure_UNIX_inner. It also recovers the closure pointer */
-/* from its fake gp pointer. */
-void ffi_closure_UNIX();
-
-#ifndef __GNUC__
-# error This requires gcc
-#endif
-void
-ffi_closure_UNIX_inner (ffi_closure *closure, struct ia64_args * args)
-/* Hopefully declaring this as a varargs function will force all args */
-/* to memory. */
-{
- // this is our return value storage
- long double res;
-
- // our various things...
- ffi_cif *cif;
- unsigned short rtype;
- void *resp;
- void **arg_area;
-
- resp = (void*)&res;
- cif = closure->cif;
- arg_area = (void**) alloca (cif->nargs * sizeof (void*));
-
- /* this call will initialize ARG_AREA, such that each
- * element in that array points to the corresponding
- * value on the stack; and if the function returns
- * a structure, it will re-set RESP to point to the
- * structure return address. */
-
- ffi_prep_incoming_args_UNIX(args, (void**)&resp, arg_area, cif);
-
- (closure->fun) (cif, resp, arg_area, closure->user_data);
-
- rtype = cif->flags;
-
- /* now, do a generic return based on the value of rtype */
- if (rtype == FFI_TYPE_INT)
- {
- asm volatile ("ld8 r8=[%0]" : : "r" (resp) : "r8");
- }
- else if (rtype == FFI_TYPE_FLOAT)
- {
- asm volatile ("ldfs f8=[%0]" : : "r" (resp) : "f8");
- }
- else if (rtype == FFI_TYPE_DOUBLE)
- {
- asm volatile ("ldfd f8=[%0]" : : "r" (resp) : "f8");
- }
- else if (rtype == FFI_IS_SMALL_STRUCT2)
- {
- asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]"
- : : "r" (resp), "r" (resp+8) : "r8","r9");
- }
- else if (rtype == FFI_IS_SMALL_STRUCT3)
- {
- asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]"
- : : "r" (resp), "r" (resp+8), "r" (resp+16)
- : "r8","r9","r10");
- }
- else if (rtype == FFI_IS_SMALL_STRUCT4)
- {
- asm volatile ("ld8 r8=[%0]; ld8 r9=[%1]; ld8 r10=[%2]; ld8 r11=[%3]"
- : : "r" (resp), "r" (resp+8), "r" (resp+16), "r" (resp+24)
- : "r8","r9","r10","r11");
- }
- else if (rtype != FFI_TYPE_VOID && rtype != FFI_TYPE_STRUCT)
- {
- /* Can only happen for homogeneous FP aggregates? */
- abort();
- }
-}