#include "jit-internal.h"
#include "jit-apply-func.h"
#include "jit-rules.h"
#include "jit-setjmp.h"
jit_function_t
jit_function_create(jit_context_t context, jit_type_t signature)
{
jit_function_t func;
#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
unsigned char *trampoline;
#endif
_jit_memory_lock(context);
if(!_jit_memory_ensure(context))
{
_jit_memory_unlock(context);
return 0;
}
func = _jit_memory_alloc_function(context);
if(!func)
{
_jit_memory_unlock(context);
return 0;
}
#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
trampoline = (unsigned char *) _jit_memory_alloc_trampoline(context);
if(!trampoline)
{
_jit_memory_free_function(context, func);
_jit_memory_unlock(context);
return 0;
}
# if defined(jit_redirector_size)
func->redirector = trampoline;
trampoline += jit_redirector_size;
# endif
# if defined(jit_indirector_size)
func->indirector = trampoline;
# endif
#endif
_jit_memory_unlock(context);
func->context = context;
func->signature = jit_type_copy(signature);
func->optimization_level = JIT_OPTLEVEL_NORMAL;
#if !defined(JIT_BACKEND_INTERP) && defined(jit_redirector_size)
func->entry_point = _jit_create_redirector
(func->redirector, (void *) context->on_demand_driver,
func, jit_type_get_abi(signature));
_jit_flush_exec(func->redirector, jit_redirector_size);
#endif
#if !defined(JIT_BACKEND_INTERP) && defined(jit_indirector_size)
_jit_create_indirector(func->indirector, (void**) &(func->entry_point));
_jit_flush_exec(func->indirector, jit_indirector_size);
#endif
func->next = 0;
func->prev = context->last_function;
if(context->last_function)
{
context->last_function->next = func;
}
else
{
context->functions = func;
}
context->last_function = func;
return func;
}
jit_function_t jit_function_create_nested
(jit_context_t context, jit_type_t signature, jit_function_t parent)
{
jit_function_t func;
func = jit_function_create(context, signature);
if(!func)
{
return 0;
}
func->nested_parent = parent;
return func;
}
int _jit_function_ensure_builder(jit_function_t func)
{
if(!func)
{
return 0;
}
if(func->builder)
{
return 1;
}
func->builder = jit_cnew(struct _jit_builder);
if(!(func->builder))
{
return 0;
}
func->builder->position_independent
= jit_context_get_meta_numeric(
func->context, JIT_OPTION_POSITION_INDEPENDENT);
jit_memory_pool_init(&(func->builder->value_pool), struct _jit_value);
jit_memory_pool_init(&(func->builder->edge_pool), struct _jit_edge);
jit_memory_pool_init(&(func->builder->meta_pool), struct _jit_meta);
if(!_jit_block_init(func))
{
_jit_function_free_builder(func);
return 0;
}
func->builder->current_block = func->builder->entry_block;
if(!_jit_create_entry_insns(func))
{
_jit_function_free_builder(func);
return 0;
}
func->builder->init_block = func->builder->current_block;
if(!jit_insn_new_block(func))
{
_jit_function_free_builder(func);
return 0;
}
return 1;
}
void _jit_function_free_builder(jit_function_t func)
{
if(func->builder)
{
_jit_block_free(func);
jit_memory_pool_free(&(func->builder->edge_pool), 0);
jit_memory_pool_free(&(func->builder->value_pool), _jit_value_free);
jit_memory_pool_free(&(func->builder->meta_pool), _jit_meta_free_one);
jit_free(func->builder->param_values);
jit_free(func->builder->label_info);
jit_free(func->builder);
func->builder = 0;
func->is_optimized = 0;
}
}
void
_jit_function_destroy(jit_function_t func)
{
jit_context_t context;
if(!func)
{
return;
}
context = func->context;
if(func->next)
{
func->next->prev = func->prev;
}
else
{
context->last_function = func->prev;
}
if(func->prev)
{
func->prev->next = func->next;
}
else
{
context->functions = func->next;
}
_jit_function_free_builder(func);
_jit_varint_free_data(func->bytecode_offset);
jit_meta_destroy(&func->meta);
jit_type_free(func->signature);
_jit_memory_lock(context);
#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
# if defined(jit_redirector_size)
_jit_memory_free_trampoline(context, func->redirector);
# else
_jit_memory_free_trampoline(context, func->indirector);
# endif
#endif
_jit_memory_free_function(context, func);
_jit_memory_unlock(context);
}
void jit_function_abandon(jit_function_t func)
{
if(func && func->builder)
{
if(func->is_compiled)
{
_jit_function_free_builder(func);
}
else
{
_jit_function_destroy(func);
}
}
}
jit_context_t jit_function_get_context(jit_function_t func)
{
if(func)
{
return func->context;
}
else
{
return 0;
}
}
jit_type_t jit_function_get_signature(jit_function_t func)
{
if(func)
{
return func->signature;
}
else
{
return 0;
}
}
int jit_function_set_meta(jit_function_t func, int type, void *data,
jit_meta_free_func free_data, int build_only)
{
if(build_only)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
return jit_meta_set(&(func->builder->meta), type, data,
free_data, func);
}
else
{
return jit_meta_set(&(func->meta), type, data, free_data, 0);
}
}
void *jit_function_get_meta(jit_function_t func, int type)
{
void *data = jit_meta_get(func->meta, type);
if(!data && func->builder)
{
data = jit_meta_get(func->builder->meta, type);
}
return data;
}
void jit_function_free_meta(jit_function_t func, int type)
{
jit_meta_free(&(func->meta), type);
if(func->builder)
{
jit_meta_free(&(func->builder->meta), type);
}
}
jit_function_t jit_function_next(jit_context_t context, jit_function_t prev)
{
if(prev)
{
return prev->next;
}
else if(context)
{
return context->functions;
}
else
{
return 0;
}
}
jit_function_t jit_function_previous(jit_context_t context, jit_function_t prev)
{
if(prev)
{
return prev->prev;
}
else if(context)
{
return context->last_function;
}
else
{
return 0;
}
}
jit_block_t jit_function_get_entry(jit_function_t func)
{
if(func && func->builder)
{
return func->builder->entry_block;
}
else
{
return 0;
}
}
jit_block_t jit_function_get_current(jit_function_t func)
{
if(func && func->builder)
{
return func->builder->current_block;
}
else
{
return 0;
}
}
jit_function_t jit_function_get_nested_parent(jit_function_t func)
{
if(func)
{
return func->nested_parent;
}
else
{
return 0;
}
}
typedef struct jit_cache_eh *jit_cache_eh_t;
struct jit_cache_eh
{
jit_label_t handler_label;
unsigned char *handler;
jit_cache_eh_t previous;
};
int jit_function_is_compiled(jit_function_t func)
{
if(func)
{
return func->is_compiled;
}
else
{
return 0;
}
}
void jit_function_set_recompilable(jit_function_t func)
{
if(func)
{
func->is_recompilable = 1;
}
}
void jit_function_clear_recompilable(jit_function_t func)
{
if(func)
{
func->is_recompilable = 0;
}
}
int jit_function_is_recompilable(jit_function_t func)
{
if(func)
{
return func->is_recompilable;
}
else
{
return 0;
}
}
#ifdef JIT_BACKEND_INTERP
static void function_closure(jit_type_t signature, void *result,
void **args, void *user_data)
{
if(!jit_function_apply((jit_function_t)user_data, args, result))
{
jit_exception_throw(jit_exception_get_last());
}
}
#endif
void *jit_function_to_closure(jit_function_t func)
{
if(!func)
{
return 0;
}
#ifdef JIT_BACKEND_INTERP
return jit_closure_create(func->context, func->signature,
function_closure, (void *)func);
#else
if(func->indirector && (!func->is_compiled || func->is_recompilable))
{
return func->indirector;
}
return func->entry_point;
#endif
}
jit_function_t
jit_function_from_closure(jit_context_t context, void *closure)
{
void *func_info;
if(!context)
{
return 0;
}
func_info = _jit_memory_find_function_info(context, closure);
if(!func_info)
{
return 0;
}
return _jit_memory_get_function(context, func_info);
}
jit_function_t
jit_function_from_pc(jit_context_t context, void *pc, void **handler)
{
void *func_info;
jit_function_t func;
if(!context)
{
return 0;
}
func_info = _jit_memory_find_function_info(context, pc);
if(!func_info)
{
return 0;
}
func = _jit_memory_get_function(context, func_info);
if(!func)
{
return 0;
}
if(handler)
{
#if 0#else
*handler = func->cookie;
#endif
}
return func;
}
void *
jit_function_to_vtable_pointer(jit_function_t func)
{
#ifdef JIT_BACKEND_INTERP
return func;
#else
if(!func)
{
return 0;
}
if(func->indirector && (!func->is_compiled || func->is_recompilable))
{
return func->indirector;
}
return func->entry_point;
#endif
}
jit_function_t
jit_function_from_vtable_pointer(jit_context_t context, void *vtable_pointer)
{
#ifdef JIT_BACKEND_INTERP
jit_function_t func = (jit_function_t)vtable_pointer;
if(func && func->context == context)
{
return func;
}
return 0;
#else
void *func_info;
if(!context)
{
return 0;
}
func_info = _jit_memory_find_function_info(context, vtable_pointer);
if(!func_info)
{
return 0;
}
return _jit_memory_get_function(context, func_info);
#endif
}
void
jit_function_set_on_demand_compiler(jit_function_t func, jit_on_demand_func on_demand)
{
if(func)
{
func->on_demand = on_demand;
}
}
jit_on_demand_func
jit_function_get_on_demand_compiler(jit_function_t func)
{
if(func)
{
return func->on_demand;
}
return 0;
}
#if !defined(JIT_BACKEND_INTERP)
int jit_function_apply(jit_function_t func, void **args, void *return_area)
{
if(func)
{
return jit_function_apply_vararg
(func, func->signature, args, return_area);
}
else
{
return jit_function_apply_vararg(func, 0, args, return_area);
}
}
int jit_function_apply_vararg
(jit_function_t func, jit_type_t signature, void **args, void *return_area)
{
struct jit_backtrace call_trace;
void *entry;
jit_jmp_buf jbuf;
_jit_unwind_push_setjmp(&jbuf);
if(setjmp(jbuf.buf))
{
_jit_unwind_pop_setjmp();
return 0;
}
_jit_backtrace_push(&call_trace, 0);
if(!func)
{
jit_exception_builtin(JIT_RESULT_NULL_FUNCTION);
return 0;
}
if(func->nested_parent)
{
jit_exception_builtin(JIT_RESULT_CALLED_NESTED);
return 0;
}
if(func->is_compiled)
{
entry = func->entry_point;
}
else
{
entry = (*func->context->on_demand_driver)(func);
}
if(!signature)
{
signature = func->signature;
}
jit_exception_clear_last();
jit_apply(signature, func->entry_point, args,
jit_type_num_params(func->signature), return_area);
_jit_unwind_pop_setjmp();
return 1;
}
#endif
void
jit_function_set_optimization_level(jit_function_t func, unsigned int level)
{
unsigned int max_level = jit_function_get_max_optimization_level();
if(level > max_level)
{
level = max_level;
}
if(func)
{
func->optimization_level = level;
}
}
unsigned int
jit_function_get_optimization_level(jit_function_t func)
{
if(func)
{
return func->optimization_level;
}
else
{
return JIT_OPTLEVEL_NONE;
}
}
unsigned int
jit_function_get_max_optimization_level(void)
{
return JIT_OPTLEVEL_NORMAL;
}
jit_label_t
jit_function_reserve_label(jit_function_t func)
{
if(!_jit_function_ensure_builder(func))
{
return jit_label_undefined;
}
return (func->builder->next_label)++;
}
int
jit_function_labels_equal(jit_function_t func, jit_label_t label, jit_label_t label2)
{
jit_block_t block, block2;
if(func && func->builder
&& label != jit_label_undefined
&& label2 != jit_label_undefined
&& label < func->builder->max_label_info
&& label2 < func->builder->max_label_info)
{
block = func->builder->label_info[label].block;
if(block)
{
block2 = func->builder->label_info[label2].block;
return block == block2;
}
}
return 0;
}