Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jit/jit-function.c  view on Meta::CPAN

		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 /* !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) */

	/* Release the memory context */
	_jit_memory_unlock(context);

	/* 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;
}

/*@
 * @deftypefun jit_function_t jit_function_create_nested (jit_context_t @var{context}, jit_type_t @var{signature}, jit_function_t @var{parent})
 * Create a new function block and associate it with a JIT context.
 * In addition, this function is nested inside the specified
 * @var{parent} function and is able to access its parent's
 * (and grandparent's) local variables.
 *
 * The front end is responsible for ensuring that the nested function can
 * never be called by anyone except its parent and sibling functions.
 * The front end is also responsible for ensuring that the nested function
 * is compiled before its parent.
 * @end deftypefun
@*/
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)
{
	/* Handle the easy cases first */
	if(!func)
	{
		return 0;
	}
	if(func->builder)
	{
		return 1;
	}

	/* Allocate memory for the builder and clear it */
	func->builder = jit_cnew(struct _jit_builder);
	if(!(func->builder))
	{
		return 0;
	}

	/* Cache the value of the JIT_OPTION_POSITION_INDEPENDENT option */
	func->builder->position_independent
		= jit_context_get_meta_numeric(
			func->context, JIT_OPTION_POSITION_INDEPENDENT);

	/* Initialize the function builder */
	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);

	/* Create the entry block */
	if(!_jit_block_init(func))
	{
		_jit_function_free_builder(func);
		return 0;
	}

	/* Create instructions to initialize the incoming arguments */
	func->builder->current_block = func->builder->entry_block;
	if(!_jit_create_entry_insns(func))
	{
		_jit_function_free_builder(func);
		return 0;
	}

	/* The current position is where initialization code will be
	   inserted by "jit_insn_move_blocks_to_start" */
	func->builder->init_block = func->builder->current_block;

	/* Start first block for function body */
	if(!jit_insn_new_block(func))
	{
		_jit_function_free_builder(func);
		return 0;
	}

	/* The builder is ready to go */
	return 1;

libjit/jit/jit-function.c  view on Meta::CPAN

}

/*@
 * @deftypefun jit_function_t jit_function_previous (jit_context_t @var{context}, jit_function_t @var{prev})
 * Iterate over the defined functions in reverse creation order.
 * @end deftypefun
@*/
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;
	}
}

/*@
 * @deftypefun jit_block_t jit_function_get_entry (jit_function_t @var{func})
 * Get the entry block for a function.  This is always the first block
 * created by @code{jit_function_create}.
 * @end deftypefun
@*/
jit_block_t jit_function_get_entry(jit_function_t func)
{
	if(func && func->builder)
	{
		return func->builder->entry_block;
	}
	else
	{
		return 0;
	}
}

/*@
 * @deftypefun jit_block_t jit_function_get_current (jit_function_t @var{func})
 * Get the current block for a function.  New blocks are created by
 * certain @code{jit_insn_xxx} calls.
 * @end deftypefun
@*/
jit_block_t jit_function_get_current(jit_function_t func)
{
	if(func && func->builder)
	{
		return func->builder->current_block;
	}
	else
	{
		return 0;
	}
}

/*@
 * @deftypefun jit_function_t jit_function_get_nested_parent (jit_function_t @var{func})
 * Get the nested parent for a function, or NULL if @var{func}
 * does not have a nested parent.
 * @end deftypefun
@*/
jit_function_t jit_function_get_nested_parent(jit_function_t func)
{
	if(func)
	{
		return func->nested_parent;
	}
	else
	{
		return 0;
	}
}

/*
 * Information that is stored for an exception region in the cache.
 */
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;
};

/*@
 * @deftypefun int jit_function_is_compiled (jit_function_t @var{func})
 * Determine if a function has already been compiled.
 * @end deftypefun
@*/
int jit_function_is_compiled(jit_function_t func)
{
	if(func)
	{
		return func->is_compiled;
	}
	else
	{
		return 0;
	}
}

/*@
 * @deftypefun int jit_function_set_recompilable (jit_function_t @var{func})
 * Mark this function as a candidate for recompilation.  That is,
 * it is possible that we may call @code{jit_function_compile}
 * more than once, to re-optimize an existing function.
 *
 * It is very important that this be called before the first time that
 * you call @code{jit_function_compile}.  Functions that are recompilable
 * are invoked in a slightly different way to non-recompilable functions.
 * If you don't set this flag, then existing invocations of the function
 * may continue to be sent to the original compiled version, not the new
 * version.
 * @end deftypefun
@*/
void jit_function_set_recompilable(jit_function_t func)
{
	if(func)
	{
		func->is_recompilable = 1;
	}
}

/*@
 * @deftypefun void jit_function_clear_recompilable (jit_function_t @var{func})
 * Clear the recompilable flag on this function.  Normally you would use

libjit/jit/jit-function.c  view on Meta::CPAN

 * is guaranteed to be supported everywhere.
 *
 * Function applications acts as an exception blocker.  If any exceptions
 * occur during the execution of @var{func}, they won't travel up the
 * stack any further than this point.  This prevents ordinary C code
 * from being accidentally presented with a situation that it cannot handle.
 * This blocking protection is not present when a function is invoked
 * via its closure.
 * @end deftypefun
 *
 * @deftypefun int jit_function_apply_vararg (jit_function_t @var{func}, jit_type_t @var{signature}, void **@var{args}, void *@var{return_area})
 * Call the function @var{func} with the supplied arguments.  There may
 * be more arguments than are specified in the function's original signature,
 * in which case the additional values are passed as variable arguments.
 * This function is otherwise identical to @code{jit_function_apply}.
 * @end deftypefun
@*/
#if !defined(JIT_BACKEND_INTERP)
/* The interpreter version is in "jit-interp.cpp" */

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;

	/* Establish a "setjmp" point here so that we can unwind the
	   stack to this point when an exception occurs and then prevent
	   the exception from propagating further up the stack */
	_jit_unwind_push_setjmp(&jbuf);
	if(setjmp(jbuf.buf))
	{
		_jit_unwind_pop_setjmp();
		return 0;
	}

	/* Create a backtrace entry that blocks exceptions from
	   flowing further than this up the stack */
	_jit_backtrace_push(&call_trace, 0);

	/* Get the function's entry point */
	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);
	}

	/* Get the default signature if necessary */
	if(!signature)
	{
		signature = func->signature;
	}

	/* Clear the exception state */
	jit_exception_clear_last();

	/* Apply the function.  If it returns, then there is no exception */
	jit_apply(signature, func->entry_point, args,
			  jit_type_num_params(func->signature), return_area);

	/* Restore the backtrace and "setjmp" contexts and exit */
	_jit_unwind_pop_setjmp();
	return 1;
}

#endif /* !JIT_BACKEND_INTERP */

/*@
 * @deftypefun void jit_function_set_optimization_level (jit_function_t @var{func}, unsigned int @var{level})
 * Set the optimization level for @var{func}.  Increasing values indicate
 * that the @code{libjit} dynamic compiler should expend more effort to
 * generate better code for this function.  Usually you would increase
 * this value just before forcing @var{func} to recompile.
 *
 * When the optimization level reaches the value returned by
 * @code{jit_function_get_max_optimization_level()}, there is usually
 * little point in continuing to recompile the function because
 * @code{libjit} may not be able to do any better.
 *
 * The front end is usually responsible for choosing candidates for
 * function inlining.  If it has identified more such candidates, then
 * it may still want to recompile @var{func} again even once it has
 * reached the maximum optimization level.
 * @end deftypefun
@*/
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)



( run in 0.357 second using v1.01-cache-2.11-cpan-4991d5b9bd9 )