#include "jit-internal.h"
#include "jit-apply-rules.h"
#include "jit-apply-func.h"
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_ALLOCA_H
#include <alloca.h>
#endif
#ifdef JIT_WIN32_PLATFORM
#include <malloc.h>
#ifndef alloca
#define alloca _alloca
#endif
#endif
typedef enum
{
_JIT_APPLY_RETURN_TYPE_OTHER = 0,
_JIT_APPLY_RETURN_TYPE_FLOAT32 = 1,
_JIT_APPLY_RETURN_TYPE_FLOAT64 = 2,
_JIT_APPLY_RETURN_TYPE_NFLOAT = 3
} _jit_apply_return_type;
unsigned char const _jit_apply_return_in_reg[] =
JIT_APPLY_STRUCT_RETURN_IN_REG_INIT;
static unsigned int jit_type_get_max_arg_size(jit_type_t signature)
{
unsigned int size;
unsigned int typeSize;
unsigned int param;
jit_type_t type;
if(signature->size)
{
return signature->size;
}
size = 0;
param = jit_type_num_params(signature);
while(param > 0)
{
--param;
type = jit_type_normalize(jit_type_get_param(signature, param));
switch(type->kind)
{
case JIT_TYPE_SBYTE:
case JIT_TYPE_UBYTE:
case JIT_TYPE_SHORT:
case JIT_TYPE_USHORT:
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
case JIT_TYPE_NINT:
case JIT_TYPE_NUINT:
case JIT_TYPE_PTR:
case JIT_TYPE_SIGNATURE:
{
size += sizeof(jit_nint);
}
break;
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
{
#ifdef JIT_NATIVE_INT32
size += sizeof(jit_long) + sizeof(jit_nint);
#else
size += sizeof(jit_nint);
#endif
}
break;
case JIT_TYPE_FLOAT32:
case JIT_TYPE_FLOAT64:
case JIT_TYPE_NFLOAT:
{
size += (sizeof(jit_nfloat) + sizeof(jit_nint) * 2 - 1) &
~(sizeof(jit_nint) - 1);
}
break;
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
{
typeSize = jit_type_get_size(type);
size += (typeSize + sizeof(jit_nint) * 2 - 1) &
~(sizeof(jit_nint) - 1);
}
break;
}
}
type = jit_type_get_return(signature);
if(jit_type_is_struct(type) || jit_type_is_union(type))
{
size += sizeof(jit_nint);
}
signature->size = size;
return size;
}
static void jit_apply_builder_add_arguments
(jit_apply_builder *builder, jit_type_t signature,
void **args, unsigned int index, unsigned int num_args)
{
unsigned int param;
jit_type_t type;
for(param = 0; param < num_args; ++param)
{
type = jit_type_normalize
(jit_type_get_param(signature, index + param));
switch(type->kind)
{
case JIT_TYPE_SBYTE:
{
jit_apply_builder_add_sbyte
(builder, *((jit_sbyte *)(args[param])));
}
break;
case JIT_TYPE_UBYTE:
{
jit_apply_builder_add_ubyte
(builder, *((jit_ubyte *)(args[param])));
}
break;
case JIT_TYPE_SHORT:
{
jit_apply_builder_add_short
(builder, *((jit_short *)(args[param])));
}
break;
case JIT_TYPE_USHORT:
{
jit_apply_builder_add_ushort
(builder, *((jit_ushort *)(args[param])));
}
break;
case JIT_TYPE_INT:
{
jit_apply_builder_add_int
(builder, *((jit_int *)(args[param])));
}
break;
case JIT_TYPE_UINT:
{
jit_apply_builder_add_uint
(builder, *((jit_uint *)(args[param])));
}
break;
case JIT_TYPE_NINT:
case JIT_TYPE_PTR:
case JIT_TYPE_SIGNATURE:
{
jit_apply_builder_add_nint
(builder, *((jit_nint *)(args[param])));
}
break;
case JIT_TYPE_NUINT:
{
jit_apply_builder_add_nuint
(builder, *((jit_nuint *)(args[param])));
}
break;
case JIT_TYPE_LONG:
{
jit_apply_builder_add_long
(builder, *((jit_long *)(args[param])));
}
break;
case JIT_TYPE_ULONG:
{
jit_apply_builder_add_ulong
(builder, *((jit_ulong *)(args[param])));
}
break;
case JIT_TYPE_FLOAT32:
{
jit_apply_builder_add_float32
(builder, *((jit_float32 *)(args[param])));
}
break;
case JIT_TYPE_FLOAT64:
{
jit_apply_builder_add_float64
(builder, *((jit_float64 *)(args[param])));
}
break;
case JIT_TYPE_NFLOAT:
{
jit_apply_builder_add_nfloat
(builder, *((jit_nfloat *)(args[param])));
}
break;
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
{
#ifdef HAVE_JIT_BUILTIN_APPLY_STRUCT
_jit_builtin_apply_add_struct(builder, args[param], type);
#else
jit_apply_builder_add_struct(builder, args[param],
jit_type_get_size(type),
jit_type_get_alignment(type));
#endif
}
break;
}
}
}
static void jit_apply_builder_get_return
(jit_apply_builder *builder, void *return_value,
jit_type_t type, jit_apply_return *result)
{
switch(type->kind)
{
case JIT_TYPE_SBYTE:
{
*((jit_sbyte *)return_value) =
jit_apply_return_get_sbyte(result);
}
break;
case JIT_TYPE_UBYTE:
{
*((jit_ubyte *)return_value) =
jit_apply_return_get_ubyte(result);
}
break;
case JIT_TYPE_SHORT:
{
*((jit_short *)return_value) =
jit_apply_return_get_short(result);
}
break;
case JIT_TYPE_USHORT:
{
*((jit_ushort *)return_value) =
jit_apply_return_get_ushort(result);
}
break;
case JIT_TYPE_INT:
{
*((jit_int *)return_value) =
jit_apply_return_get_int(result);
}
break;
case JIT_TYPE_UINT:
{
*((jit_uint *)return_value) =
jit_apply_return_get_uint(result);
}
break;
case JIT_TYPE_NINT:
case JIT_TYPE_PTR:
case JIT_TYPE_SIGNATURE:
{
*((jit_nint *)return_value) =
jit_apply_return_get_nint(result);
}
break;
case JIT_TYPE_NUINT:
{
*((jit_nuint *)return_value) =
jit_apply_return_get_nuint(result);
}
break;
case JIT_TYPE_LONG:
{
*((jit_long *)return_value) =
jit_apply_return_get_long(result);
}
break;
case JIT_TYPE_ULONG:
{
*((jit_ulong *)return_value) =
jit_apply_return_get_ulong(result);
}
break;
case JIT_TYPE_FLOAT32:
{
*((jit_float32 *)return_value) =
jit_apply_return_get_float32(result);
}
break;
case JIT_TYPE_FLOAT64:
{
*((jit_float64 *)return_value) =
jit_apply_return_get_float64(result);
}
break;
case JIT_TYPE_NFLOAT:
{
*((jit_nfloat *)return_value) =
jit_apply_return_get_nfloat(result);
}
break;
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
{
#ifdef HAVE_JIT_BUILTIN_APPLY_STRUCT_RETURN
_jit_builtin_apply_get_struct_return(builder, return_value, result, type);
#else
unsigned int size = jit_type_get_size(type);
jit_apply_builder_get_struct_return(builder, size, return_value, result);
#endif
}
break;
}
}
void jit_apply(jit_type_t signature, void *func,
void **args, unsigned int num_fixed_args,
void *return_value)
{
jit_apply_builder builder;
unsigned int size;
jit_apply_return *apply_return;
jit_type_t type;
jit_apply_builder_init(&builder, signature);
type = jit_type_normalize(jit_type_get_return(signature));
if(jit_type_is_struct(type) || jit_type_is_union(type))
{
size = jit_type_get_size(type);
jit_apply_builder_add_struct_return(&builder, size, return_value);
}
jit_apply_builder_add_arguments
(&builder, signature, args, 0, num_fixed_args);
jit_apply_builder_start_varargs(&builder);
jit_apply_builder_add_arguments
(&builder, signature, args + num_fixed_args, num_fixed_args,
jit_type_num_params(signature) - num_fixed_args);
if(type->kind < JIT_TYPE_FLOAT32 || type->kind > JIT_TYPE_NFLOAT)
{
jit_builtin_apply(func, builder.apply_args,
builder.stack_used, 0, apply_return);
}
else
{
jit_builtin_apply(func, builder.apply_args,
builder.stack_used, 1, apply_return);
}
if(return_value != 0 && type != jit_type_void)
{
jit_apply_builder_get_return
(&builder, return_value, type, apply_return);
}
}
void jit_apply_raw(jit_type_t signature, void *func,
void *args, void *return_value)
{
jit_apply_return *apply_return;
unsigned int size;
jit_type_t type;
type = jit_type_normalize(jit_type_get_return(signature));
size = jit_type_num_params(signature) * sizeof(jit_nint);
if(type->kind < JIT_TYPE_FLOAT32 || type->kind > JIT_TYPE_NFLOAT)
{
jit_builtin_apply(func, args, size, 0, apply_return);
}
else
{
jit_builtin_apply(func, args, size, 1, apply_return);
}
if(return_value != 0 && type != jit_type_void)
{
jit_apply_builder_get_return
(0, return_value, type, apply_return);
}
}
int jit_raw_supported(jit_type_t signature)
{
#if JIT_APPLY_NUM_WORD_REGS == 0 && JIT_APPLY_NUM_FLOAT_REGS == 0 && \
JIT_APPLY_STRUCT_RETURN_SPECIAL_REG == 0
unsigned int param;
jit_type_t type;
#if JIT_APPLY_X86_FASTCALL != 0
if(jit_type_get_abi(signature) == jit_abi_fastcall)
{
return 0;
}
#endif
param = jit_type_num_params(signature);
while(param > 0)
{
--param;
type = jit_type_normalize(jit_type_get_param(signature, param));
if(type->kind < JIT_TYPE_SBYTE || type->kind > JIT_TYPE_NUINT)
{
return 0;
}
}
type = jit_type_get_return(signature);
if(jit_type_is_struct(type) || jit_type_is_union(type))
{
return 0;
}
return 1;
#else
return 0;
#endif
}
struct jit_closure_va_list
{
jit_apply_builder builder;
};
#ifdef jit_closure_size
typedef struct jit_closure *jit_closure_t;
struct jit_closure
{
unsigned char buf[jit_closure_size];
jit_type_t signature;
jit_closure_func func;
void *user_data;
};
static void closure_handler(jit_closure_t closure, void *apply_args)
{
jit_type_t signature = closure->signature;
jit_type_t type;
jit_apply_builder parser;
void *return_buffer;
void **args;
void *temp_arg;
unsigned int num_params;
unsigned int param;
jit_apply_return apply_return;
_jit_apply_return_type return_type;
jit_apply_parser_init(&parser, closure->signature, apply_args);
type = jit_type_normalize(jit_type_get_return(signature));
if(!type || type == jit_type_void)
{
return_buffer = 0;
}
else if(jit_type_return_via_pointer(type))
{
jit_apply_parser_get_struct_return(&parser, return_buffer);
}
else
{
return_buffer = alloca(jit_type_get_size(type));
}
num_params = jit_type_num_params(signature);
args = (void **)alloca((num_params + 1) * sizeof(void *));
for(param = 0; param < num_params; ++param)
{
type = jit_type_normalize(jit_type_get_param(signature, param));
if(!type)
{
args[param] = 0;
continue;
}
temp_arg = alloca(jit_type_get_size(type));
args[param] = temp_arg;
switch(type->kind)
{
case JIT_TYPE_SBYTE:
{
jit_apply_parser_get_sbyte
(&parser, *((jit_sbyte *)temp_arg));
}
break;
case JIT_TYPE_UBYTE:
{
jit_apply_parser_get_ubyte
(&parser, *((jit_ubyte *)temp_arg));
}
break;
case JIT_TYPE_SHORT:
{
jit_apply_parser_get_short
(&parser, *((jit_short *)temp_arg));
}
break;
case JIT_TYPE_USHORT:
{
jit_apply_parser_get_ushort
(&parser, *((jit_ushort *)temp_arg));
}
break;
case JIT_TYPE_INT:
{
jit_apply_parser_get_int
(&parser, *((jit_int *)temp_arg));
}
break;
case JIT_TYPE_UINT:
{
jit_apply_parser_get_uint
(&parser, *((jit_uint *)temp_arg));
}
break;
case JIT_TYPE_LONG:
{
jit_apply_parser_get_long
(&parser, *((jit_long *)temp_arg));
}
break;
case JIT_TYPE_ULONG:
{
jit_apply_parser_get_ulong
(&parser, *((jit_ulong *)temp_arg));
}
break;
case JIT_TYPE_FLOAT32:
{
jit_apply_parser_get_float32
(&parser, *((jit_float32 *)temp_arg));
}
break;
case JIT_TYPE_FLOAT64:
{
jit_apply_parser_get_float64
(&parser, *((jit_float64 *)temp_arg));
}
break;
case JIT_TYPE_NFLOAT:
{
jit_apply_parser_get_nfloat
(&parser, *((jit_nfloat *)temp_arg));
}
break;
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
{
#ifdef HAVE_JIT_BUILTIN_APPLY_STRUCT
_jit_builtin_apply_get_struct(&parser, temp_arg, type);
#else
jit_apply_parser_get_struct(&parser, jit_type_get_size(type),
jit_type_get_alignment(type), temp_arg);
#endif
}
break;
}
}
jit_apply_parser_start_varargs(&parser);
args[num_params] = &parser;
(*(closure->func))(signature, return_buffer, args, closure->user_data);
jit_memzero(&apply_return, sizeof(apply_return));
type = jit_type_normalize(jit_type_get_return(signature));
return_type = _JIT_APPLY_RETURN_TYPE_OTHER;
if(type)
{
switch(type->kind)
{
case JIT_TYPE_SBYTE:
{
jit_apply_return_set_sbyte
(&apply_return, *((jit_sbyte *)return_buffer));
}
break;
case JIT_TYPE_UBYTE:
{
jit_apply_return_set_ubyte
(&apply_return, *((jit_ubyte *)return_buffer));
}
break;
case JIT_TYPE_SHORT:
{
jit_apply_return_set_short
(&apply_return, *((jit_short *)return_buffer));
}
break;
case JIT_TYPE_USHORT:
{
jit_apply_return_set_ushort
(&apply_return, *((jit_ushort *)return_buffer));
}
break;
case JIT_TYPE_INT:
{
jit_apply_return_set_int
(&apply_return, *((jit_int *)return_buffer));
}
break;
case JIT_TYPE_UINT:
{
jit_apply_return_set_uint
(&apply_return, *((jit_uint *)return_buffer));
}
break;
case JIT_TYPE_LONG:
{
jit_apply_return_set_long
(&apply_return, *((jit_long *)return_buffer));
}
break;
case JIT_TYPE_ULONG:
{
jit_apply_return_set_ulong
(&apply_return, *((jit_ulong *)return_buffer));
}
break;
case JIT_TYPE_FLOAT32:
{
jit_apply_return_set_float32
(&apply_return, *((jit_float32 *)return_buffer));
return_type = _JIT_APPLY_RETURN_TYPE_FLOAT32;
}
break;
case JIT_TYPE_FLOAT64:
{
jit_apply_return_set_float64
(&apply_return, *((jit_float64 *)return_buffer));
return_type = _JIT_APPLY_RETURN_TYPE_FLOAT64;
}
break;
case JIT_TYPE_NFLOAT:
{
jit_apply_return_set_nfloat
(&apply_return, *((jit_nfloat *)return_buffer));
return_type = _JIT_APPLY_RETURN_TYPE_NFLOAT;
}
break;
case JIT_TYPE_STRUCT:
case JIT_TYPE_UNION:
{
if(!jit_type_return_via_pointer(type))
{
jit_memcpy(&apply_return, return_buffer,
jit_type_get_size(type));
}
}
break;
}
}
switch(return_type)
{
case _JIT_APPLY_RETURN_TYPE_FLOAT32:
{
jit_builtin_return_float(&apply_return);
}
break;
case _JIT_APPLY_RETURN_TYPE_FLOAT64:
{
jit_builtin_return_double(&apply_return);
}
break;
case _JIT_APPLY_RETURN_TYPE_NFLOAT:
{
jit_builtin_return_nfloat(&apply_return);
}
break;
default:
{
jit_builtin_return_int(&apply_return);
}
}
}
#endif
void *
jit_closure_create(jit_context_t context, jit_type_t signature, jit_closure_func func, void *user_data)
{
#ifdef jit_closure_size
jit_closure_t closure;
if(!context || !signature || !func)
{
return 0;
}
_jit_memory_lock(context);
if(!_jit_memory_ensure(context))
{
_jit_memory_unlock(context);
return 0;
}
closure = (jit_closure_t) _jit_memory_alloc_closure(context);
if(!closure)
{
_jit_memory_unlock(context);
return 0;
}
_jit_create_closure(closure->buf, (void *)closure_handler, closure, signature);
closure->signature = signature;
closure->func = func;
closure->user_data = user_data;
_jit_memory_unlock(context);
_jit_flush_exec(closure->buf, sizeof(closure->buf));
return closure;
#else
return 0;
#endif
}
int
jit_supports_closures(void)
{
#ifdef jit_closure_size
return 1;
#else
return 0;
#endif
}
unsigned int
jit_get_closure_size(void)
{
#ifdef jit_closure_size
return jit_closure_size;
#else
return 0;
#endif
}
unsigned int
jit_get_closure_alignment(void)
{
#ifdef jit_closure_size
return jit_closure_align;
#else
return 0;
#endif
}
unsigned int
jit_get_trampoline_size(void)
{
int size = 0;
#if defined(jit_redirector_size)
size += jit_redirector_size;
#endif
#if defined(jit_indirector_size)
size += jit_indirector_size;
#endif
return size;
}
unsigned int
jit_get_trampoline_alignment(void)
{
#if defined(jit_redirector_size) || defined(jit_indirector_size)
return 1;
#else
return 0;
#endif
}
jit_nint jit_closure_va_get_nint(jit_closure_va_list_t va)
{
jit_nint value;
jit_apply_parser_get_nint(&(va->builder), value);
return value;
}
jit_nuint jit_closure_va_get_nuint(jit_closure_va_list_t va)
{
jit_nuint value;
jit_apply_parser_get_nuint(&(va->builder), value);
return value;
}
jit_long jit_closure_va_get_long(jit_closure_va_list_t va)
{
jit_long value;
jit_apply_parser_get_long(&(va->builder), value);
return value;
}
jit_ulong jit_closure_va_get_ulong(jit_closure_va_list_t va)
{
jit_ulong value;
jit_apply_parser_get_ulong(&(va->builder), value);
return value;
}
jit_float32 jit_closure_va_get_float32(jit_closure_va_list_t va)
{
jit_float32 value;
jit_apply_parser_get_float32(&(va->builder), value);
return value;
}
jit_float64 jit_closure_va_get_float64(jit_closure_va_list_t va)
{
jit_float64 value;
jit_apply_parser_get_float64(&(va->builder), value);
return value;
}
jit_nfloat jit_closure_va_get_nfloat(jit_closure_va_list_t va)
{
jit_nfloat value;
jit_apply_parser_get_nfloat(&(va->builder), value);
return value;
}
void *jit_closure_va_get_ptr(jit_closure_va_list_t va)
{
jit_nint value;
jit_apply_parser_get_nint(&(va->builder), value);
return (void *)value;
}
void
jit_closure_va_get_struct(jit_closure_va_list_t va, void *buf, jit_type_t type)
{
#ifdef HAVE_JIT_BUILTIN_APPLY_STRUCT
_jit_builtin_apply_get_struct(&(va->builder), buf, type);
#else
jit_apply_parser_get_struct
(&(va->builder), jit_type_get_size(type),
jit_type_get_alignment(type), buf);
#endif
}