void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ #ifdef X86_WIN64 if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT && ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0)) { ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF); } #else if (rvalue == NULL && (cif->flags == FFI_TYPE_STRUCT || cif->flags == FFI_TYPE_MS_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } #endif else ecif.rvalue = rvalue; switch (cif->abi) { #ifdef X86_WIN64 case FFI_WIN64: ffi_call_win64(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #else #ifndef X86_WIN32 case FFI_SYSV: ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #else case FFI_SYSV: case FFI_MS_CDECL: #endif case FFI_STDCALL: case FFI_THISCALL: case FFI_FASTCALL: case FFI_PASCAL: case FFI_REGISTER: ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif default: FFI_ASSERT(0); break; } }
void ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { ecif.rvalue = alloca (cif->rtype->size); } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; default: FFI_ASSERT (0); break; } }
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { int ret_type = cif->flags; extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; ecif.rvalue = rvalue; /* If we don't have a return value, we need to fake one. */ if (rvalue == NULL) { if (ret_type == FFI390_RET_STRUCT) ecif.rvalue = alloca (cif->rtype->size); else ret_type = FFI390_RET_VOID; } switch (cif->abi) { case FFI_SYSV: ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args, ret_type, ecif.rvalue, fn); break; default: FFI_ASSERT (0); break; } }
void ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return value address then we need to make one. */ if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size > 8) ecif.rvalue = alloca (cif->rtype->size); else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: ffi_call_SYSV (&ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; default: FFI_ASSERT (0); break; } }
int ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { #if !defined(_WIN64) case FFI_SYSV: /*@-usedef@*/ return ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; case FFI_STDCALL: /*@-usedef@*/ return ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #else case FFI_SYSV: /*@-usedef@*/ /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #endif default: FFI_ASSERT(0); break; } return -1; /* theller: Hrm. */ }
void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return value address then we need to make one. */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { ecif.rvalue = alloca (cif->rtype->size); } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); if (cif->rtype->type == FFI_TYPE_STRUCT) { int size = cif->rtype->size; int align = cif->rtype->alignment; if (size < 4) { if (align == 1) *(unsigned long *)(ecif.rvalue) <<= (4 - size) * 8; } else if (4 < size && size < 8) { if (align == 1) { memcpy (ecif.rvalue, ecif.rvalue + 8-size, size); } else if (align == 2) { if (size & 1) size += 1; if (size != 8) memcpy (ecif.rvalue, ecif.rvalue + 8-size, size); } } } break; default: FFI_ASSERT(0); break; } }
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { /* * The final SYSV ABI says that structures smaller or equal 8 bytes * are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them * in memory. * * Just to keep things simple for the assembly code, we will always * bounce-buffer struct return values less than or equal to 8 bytes. * This allows the ASM to handle SYSV small structures by directly * writing r3 and r4 to memory without worrying about struct size. */ unsigned int smst_buffer[2]; extended_cif ecif; unsigned int rsize = 0; ecif.cif = cif; ecif.avalue = avalue; /* Ensure that we have a valid struct return value */ ecif.rvalue = rvalue; if (cif->rtype->type == FFI_TYPE_STRUCT) { rsize = cif->rtype->size; if (rsize <= 8) ecif.rvalue = smst_buffer; else if (!rvalue) ecif.rvalue = alloca(rsize); } switch (cif->abi) { #ifndef POWERPC64 # ifndef __NO_FPRS__ case FFI_SYSV: case FFI_GCC_SYSV: case FFI_LINUX: # endif case FFI_LINUX_SOFT_FLOAT: ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); break; #else case FFI_LINUX64: ffi_call_LINUX64 (&ecif, -(REALLYLONG) cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif default: FFI_ASSERT (0); break; } /* Check for a bounce-buffered return value */ if (rvalue && ecif.rvalue == smst_buffer) memcpy(rvalue, smst_buffer, rsize); }
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { /* The final SYSV ABI says that structures smaller or equal 8 bytes are returned in r3/r4. A draft ABI used by linux instead returns them in memory. We bounce-buffer SYSV small struct return values so that sysv.S can write r3 and r4 to memory without worrying about struct size. For ELFv2 ABI, use a bounce buffer for homogeneous structs too, for similar reasons. */ unsigned long smst_buffer[8]; extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; ecif.rvalue = rvalue; if ((cif->flags & FLAG_RETURNS_SMST) != 0) ecif.rvalue = smst_buffer; /* Ensure that we have a valid struct return value. FIXME: Isn't this just papering over a user problem? */ else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT) ecif.rvalue = alloca (cif->rtype->size); #ifdef POWERPC64 ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn); #else ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); #endif /* Check for a bounce-buffered return value */ if (rvalue && ecif.rvalue == smst_buffer) { unsigned int rsize = cif->rtype->size; #ifndef __LITTLE_ENDIAN__ /* The SYSV ABI returns a structure of up to 4 bytes in size left-padded in r3. */ # ifndef POWERPC64 if (rsize <= 4) memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize); else # endif /* The SYSV ABI returns a structure of up to 8 bytes in size left-padded in r3/r4, and the ELFv2 ABI similarly returns a structure of up to 8 bytes in size left-padded in r3. */ if (rsize <= 8) memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize); else #endif memcpy (rvalue, smst_buffer, rsize); } }
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ #ifdef X86_WIN64 if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT && cif->rtype->size != 1 && cif->rtype->size != 2 && cif->rtype->size != 4 && cif->rtype->size != 8) { ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF); } #else if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT) { ecif.rvalue = alloca(cif->rtype->size); } #endif else ecif.rvalue = rvalue; switch (cif->abi) { #ifdef X86_WIN64 case FFI_WIN64: ffi_call_win64(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #elif defined(X86_WIN32) case FFI_SYSV: case FFI_STDCALL: ffi_call_win32(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #else case FFI_SYSV: ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif default: FFI_ASSERT(0); break; } }
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { extended_cif ecif; int small_struct = (cif->flags == FFI_TYPE_INT && cif->rtype->type == FFI_TYPE_STRUCT); int vfp_struct = (cif->flags == FFI_TYPE_STRUCT_VFP_FLOAT || cif->flags == FFI_TYPE_STRUCT_VFP_DOUBLE); ecif.cif = cif; ecif.avalue = avalue; unsigned int temp; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->flags == FFI_TYPE_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } else if (small_struct) ecif.rvalue = &temp; else if (vfp_struct) { /* Largest case is double x 4. */ ecif.rvalue = alloca(32); } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); break; case FFI_VFP: ffi_call_VFP (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue); break; default: FFI_ASSERT(0); break; } if (small_struct) memcpy (rvalue, &temp, cif->rtype->size); else if (vfp_struct) memcpy (rvalue, ecif.rvalue, cif->rtype->size); }
void ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && retval_on_stack(cif->rtype)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ /* To avoid changing the assembly code make sure the size of the argument * block is a multiple of 16. Then add 8 to compensate for local variables * in ffi_call_SYSV. */ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #ifdef X86_WIN32 case FFI_STDCALL: /*@-usedef@*/ ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #endif /* X86_WIN32 */ default: FFI_ASSERT(0); break; } }
void ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->flags == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #ifdef X86_WIN32 case FFI_STDCALL: /*@-usedef@*/ ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #endif /* X86_WIN32 */ default: FFI_ASSERT(0); break; } }
void ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue) { extended_cif ecif; UINT64 trvalue; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if (cif->rtype->type == FFI_TYPE_STRUCT && return_type (cif->rtype) != FFI_TYPE_STRUCT) ecif.rvalue = &trvalue; else if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; default: FFI_ASSERT(0); break; } if (rvalue && cif->rtype->type == FFI_TYPE_STRUCT && return_type (cif->rtype) != FFI_TYPE_STRUCT) memcpy (rvalue, &trvalue, cif->rtype->size); }
void ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue) { extended_cif ecif; void **avalue = (void **)fake_avalue; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } else ecif.rvalue = rvalue; switch (cif->abi) { #ifdef X86_WIN32 case FFI_SYSV: case FFI_STDCALL: ffi_call_win32(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #else case FFI_SYSV: ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif default: FFI_ASSERT(0); break; } }
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } else ecif.rvalue = rvalue; switch (cif->abi) { #ifndef POWERPC64 case FFI_SYSV: case FFI_GCC_SYSV: case FFI_LINUX: case FFI_LINUX_SOFT_FLOAT: ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); break; #else case FFI_LINUX64: ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif default: FFI_ASSERT (0); break; } }
void ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue) { extended_cif ecif; void **avalue = (void **)fake_avalue; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if (rvalue == NULL && (cif->flags == FFI_TYPE_STRUCT || cif->flags == FFI_TYPE_MS_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } else ecif.rvalue = rvalue; switch (cif->abi) { #ifdef X86_WIN32 case FFI_SYSV: case FFI_STDCALL: case FFI_MS_CDECL: ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags, ecif.rvalue, fn); break; case FFI_THISCALL: case FFI_FASTCALL: { unsigned int abi = cif->abi; unsigned int i, passed_regs = 0; if (cif->flags == FFI_TYPE_STRUCT) ++passed_regs; for (i=0; i < cif->nargs && passed_regs < 2;i++) { size_t sz; if (cif->arg_types[i]->type == FFI_TYPE_FLOAT || cif->arg_types[i]->type == FFI_TYPE_STRUCT) continue; sz = (cif->arg_types[i]->size + 3) & ~3; if (sz == 0 || sz > 4) continue; ++passed_regs; } if (passed_regs < 2 && abi == FFI_FASTCALL) cif->abi = abi = FFI_THISCALL; if (passed_regs < 1 && abi == FFI_THISCALL) cif->abi = abi = FFI_STDCALL; ffi_call_win32(ffi_prep_args_raw, &ecif, abi, cif->bytes, cif->flags, ecif.rvalue, fn); } break; #else case FFI_SYSV: ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif default: FFI_ASSERT(0); break; } }
/* Call a function with the provided arguments and capture the return value. */ void ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: { struct call_context context; size_t stack_bytes; /* Figure out the total amount of stack space we need, the above call frame space needs to be 16 bytes aligned to ensure correct alignment of the first object inserted in that space hence the ALIGN applied to cif->bytes.*/ stack_bytes = ALIGN(cif->bytes, 16); memset (&context, 0, sizeof (context)); if (is_register_candidate (cif->rtype)) { ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn); switch (cif->rtype->type) { case FFI_TYPE_VOID: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: #if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE case FFI_TYPE_LONGDOUBLE: #endif case FFI_TYPE_UINT8: case FFI_TYPE_SINT8: case FFI_TYPE_UINT16: case FFI_TYPE_SINT16: case FFI_TYPE_UINT32: case FFI_TYPE_SINT32: case FFI_TYPE_POINTER: case FFI_TYPE_UINT64: case FFI_TYPE_INT: case FFI_TYPE_SINT64: { void *addr = get_basic_type_addr (cif->rtype->type, &context, 0); copy_basic_type (rvalue, addr, cif->rtype->type); break; } case FFI_TYPE_STRUCT: if (is_hfa (cif->rtype)) { int j; unsigned short type = get_homogeneous_type (cif->rtype); unsigned elems = element_count (cif->rtype); for (j = 0; j < elems; j++) { void *reg = get_basic_type_addr (type, &context, j); copy_basic_type (rvalue, reg, type); rvalue += get_basic_type_size (type); } } else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG) { size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)); memcpy (rvalue, get_x_addr (&context, 0), size); } else { FFI_ASSERT (0); } break; default: FFI_ASSERT (0); break; } } else { memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64)); ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn); } break; } default: FFI_ASSERT (0); break; } }
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ #ifdef X86_WIN64 if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT && cif->rtype->size != 1 && cif->rtype->size != 2 && cif->rtype->size != 4 && cif->rtype->size != 8) { ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF); } #else if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT) { ecif.rvalue = alloca(cif->rtype->size); } #endif else ecif.rvalue = rvalue; switch (cif->abi) { #ifdef X86_WIN64 case FFI_WIN64: { // Make copies of all struct arguments // NOTE: not sure if responsibility should be here or in caller unsigned int i; for (i=0; i < cif->nargs;i++) { size_t size = cif->arg_types[i]->size; if ((cif->arg_types[i]->type == FFI_TYPE_STRUCT && (size != 1 && size != 2 && size != 4 && size != 8)) #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE || cif->arg_types[i]->type == FFI_TYPE_LONGDOUBLE #endif ) { void *local = alloca(size); memcpy(local, avalue[i], size); avalue[i] = local; } } ffi_call_win64(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); } break; #else case FFI_SYSV: ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #ifdef X86_WIN32 case FFI_STDCALL: ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif /* X86_WIN32 */ #endif /* X86_WIN64 */ default: FFI_ASSERT(0); break; } }
static void ffi_call_int (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue, void *closure) { int flags = cif->flags; ffi_type *rtype = cif->rtype; size_t bytes, rsize, vfp_size; char *stack, *vfp_space, *new_rvalue; struct call_frame *frame; rsize = 0; if (rvalue == NULL) { /* If the return value is a struct and we don't have a return value address then we need to make one. Otherwise the return value is in registers and we can ignore them. */ if (flags == ARM_TYPE_STRUCT) rsize = rtype->size; else flags = ARM_TYPE_VOID; } else if (flags == ARM_TYPE_VFP_N) { /* Largest case is double x 4. */ rsize = 32; } else if (flags == ARM_TYPE_INT && rtype->type == FFI_TYPE_STRUCT) rsize = 4; /* Largest case. */ vfp_size = (cif->abi == FFI_VFP && cif->vfp_used ? 8*8: 0); bytes = cif->bytes; stack = alloca (vfp_size + bytes + sizeof(struct call_frame) + rsize); vfp_space = NULL; if (vfp_size) { vfp_space = stack; stack += vfp_size; } frame = (struct call_frame *)(stack + bytes); new_rvalue = rvalue; if (rsize) new_rvalue = (void *)(frame + 1); frame->rvalue = new_rvalue; frame->flags = flags; frame->closure = closure; if (vfp_space) { ffi_prep_args_VFP (cif, flags, new_rvalue, avalue, stack, vfp_space); ffi_call_VFP (vfp_space, frame, fn, cif->vfp_used); } else { ffi_prep_args_SYSV (cif, flags, new_rvalue, avalue, stack); ffi_call_SYSV (stack, frame, fn); } if (rvalue && rvalue != new_rvalue) memcpy (rvalue, new_rvalue, rtype->size); }