Example #1
0
void
_jit_memory_lock(jit_context_t context)
{
	jit_mutex_lock(&context->memory_lock);
}
Example #2
0
/*@
 * @deftypefun jit_function_t jit_function_create (jit_context_t @var{context}, jit_type_t @var{signature})
 * Create a new function block and associate it with a JIT context.
 * Returns NULL if out of memory.
 *
 * A function persists for the lifetime of its containing context.
 * It initially starts life in the "building" state, where the user
 * constructs instructions that represents the function body.
 * Once the build process is complete, the user calls
 * @code{jit_function_compile} to convert it into its executable form.
 *
 * It is recommended that you call @code{jit_context_build_start} before
 * calling @code{jit_function_create}, and then call
 * @code{jit_context_build_end} after you have called
 * @code{jit_function_compile}.  This will protect the JIT's internal
 * data structures within a multi-threaded environment.
 * @end deftypefun
@*/
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))
	jit_cache_t cache;
#endif

	/* Allocate memory for the function and clear it */
	func = jit_cnew(struct _jit_function);
	if(!func)
	{
		return 0;
	}

#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
	/* TODO: if the function is destroyed the redirector and indirector memory
	   is leaked */

	/* We need the cache lock while we are allocating redirector and indirector */
	jit_mutex_lock(&(context->cache_lock));

	/* Get the method cache */
	cache = _jit_context_get_cache(context);
	if(!cache)
	{
		jit_mutex_unlock(&(context->cache_lock));
		jit_free(func);
		return 0;
	}
    func->compilation_success_callback = 0;
    func->insn_compilation_callback = 0;
    func->current_code_location_start_column = 0;
    func->current_code_location_end_column = 0;
    func->current_code_location_start_line = 0;
    func->current_code_location_end_line = 0;

# if defined(jit_redirector_size)
	/* Allocate redirector buffer */
	func->redirector = _jit_cache_alloc_no_method(cache, jit_redirector_size, 1);
	if(!func->redirector)
	{
		jit_mutex_unlock(&(context->cache_lock));
		jit_free(func);
		return 0;
	}
# endif
# if defined(jit_indirector_size)
	/* Allocate indirector buffer */
	func->indirector = _jit_cache_alloc_no_method(cache, jit_indirector_size, 1);
	if(!func->indirector)
	{
		jit_mutex_unlock(&(context->cache_lock));
		jit_free(func);
		return 0;
	}
# endif

	jit_mutex_unlock(&(context->cache_lock));
#endif /* !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) */

	/* Initialize the function block */
	func->context = context;
	func->signature = jit_type_copy(signature);
	func->optimization_level = JIT_OPTLEVEL_NORMAL;

#if !defined(JIT_BACKEND_INTERP) && defined(jit_redirector_size)
	/* If we aren't using interpretation, then point the function's
	   initial entry point at the redirector, which in turn will
	   invoke the on-demand compiler */
	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

	/* Add the function to the context list */
	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 the function to the caller */
	return func;
}