Alien-LibJIT

 view release on metacpan or  search on metacpan

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

typedef struct
{
	jit_function_t		func;

	int			memory_locked;
	int 			memory_started;

	int			restart;
	int			page_factor;

	struct jit_gencode	gen;

} _jit_compile_t;

#define _JIT_RESULT_TO_OBJECT(x)	((void *) ((jit_nint) (x) - JIT_RESULT_OK))
#define _JIT_RESULT_FROM_OBJECT(x)	((jit_nint) ((void *) (x)) + JIT_RESULT_OK)

/*
 * This exception handler overrides a user-defined handler during compilation.
 */
static void *
internal_exception_handler(int exception_type)
{
	return _JIT_RESULT_TO_OBJECT(exception_type);
}

/*
 * Optimize a function.
 */
static void
optimize(jit_function_t func)
{
	if(func->is_optimized || func->optimization_level == JIT_OPTLEVEL_NONE)
	{
		/* The function is already optimized or does not need optimization */
		return;
	}

	/* Build control flow graph */
	_jit_block_build_cfg(func);

	/* Eliminate useless control flow */
	_jit_block_clean_cfg(func);

	/* Optimization is done */
	func->is_optimized = 1;
}

/*@
 * @deftypefun int jit_optimize (jit_function_t @var{func})
 * Optimize a function by analyzing and transforming its intermediate
 * representation. If the function was already compiled or optimized,
 * then do nothing.
 *
 * Returns @code{JIT_RESUlT_OK} on success, otherwise it might return
 * @code{JIT_RESULT_OUT_OF_MEMORY}, @code{JIT_RESULT_COMPILE_ERROR} or
 * possibly some other more specific @code{JIT_RESULT_} code.
 *
 * Normally this function should not be used because @code{jit_compile}
 * performs all the optimization anyway.  However it might be useful for
 * debugging to verify the effect of the @code{libjit} code optimization.
 * This might be done, for instance, by calling @code{jit_dump_function}
 * before and after @code{jit_optimize}.
 * @end deftypefun
@*/
int
jit_optimize(jit_function_t func)
{
	jit_jmp_buf jbuf;
	jit_exception_func handler;

	/* Bail out on invalid parameter */
	if(!func)
	{
		return JIT_RESULT_NULL_FUNCTION;
	}

	/* Bail out if there is nothing to do here */
	if(!func->builder)
	{
		if(func->is_compiled)
		{
			/* The function is already compiled and we can't optimize it */
			return JIT_RESULT_OK;
		}
		else
		{
			/* We don't have anything to optimize at all */
			return JIT_RESULT_NULL_FUNCTION;
		}
	}

	/* Override user's exception handler */
	handler = jit_exception_set_handler(internal_exception_handler);

	/* 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();
		jit_exception_set_handler(handler);
		return _JIT_RESULT_FROM_OBJECT(jit_exception_get_last_and_clear());
	}

	/* Perform the optimizations */
	optimize(func);

	/* Restore the "setjmp" contexts and exit */
	_jit_unwind_pop_setjmp();
	jit_exception_set_handler(handler);
	return JIT_RESULT_OK;
}

/*
 * Mark the current position with a bytecode offset value.
 */
void
mark_offset(jit_gencode_t gen, jit_function_t func, unsigned long offset)
{

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


	/* Try to allocate within the current memory limit */
	result = _jit_memory_start_function(state->gen.context, state->func);
	if(result == JIT_MEMORY_RESTART)
	{
		/* Not enough space. Request to extend the limit and retry */
		_jit_memory_extend_limit(state->gen.context, state->page_factor++);
		result = _jit_memory_start_function(state->gen.context, state->func);
	}
	if(result != JIT_MEMORY_OK)
	{
		/* Failed to allocate any space */
		jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
	}

	/* Start with with allocated space */
	memory_start(state);
}

/*
 * Finish code generation.
 */
static void
memory_flush(_jit_compile_t *state)
{
	int result;

	if(state->memory_started)
	{
		/* Reset the memory state */
		state->memory_started = 0;

		/* Let the memory context know the address we ended at */
		_jit_memory_set_break(state->gen.context, state->gen.code_end);

		/* Finally end the function */
		result = _jit_memory_end_function(state->gen.context, JIT_MEMORY_OK);
		if(result != JIT_MEMORY_OK)
		{
			if(result == JIT_MEMORY_RESTART)
			{
				/* Throw an internal exception that causes
				   a larger code space to be allocated and
				   the code generation to restart */
				jit_exception_builtin(JIT_RESULT_MEMORY_FULL);
			}
			else
			{
				/* Throw exception that indicates failure
				   to allocate enough code space */
				jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
			}
		}

#ifndef JIT_BACKEND_INTERP
		/* On success perform a CPU cache flush, to make the code executable */
		_jit_flush_exec(state->gen.code_start,
			        state->gen.code_end - state->gen.code_start);
#endif

		/* Terminate the debug information and flush it */
		if(!_jit_varint_encode_end(&state->gen.offset_encoder))
		{
			jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
		}
		state->func->bytecode_offset = _jit_varint_get_data(&state->gen.offset_encoder);
	}
}

/*
 * Give back the allocated space in case of failure to generate the code.
 */
static void
memory_abort(_jit_compile_t *state)
{
	if(state->memory_started)
	{
		state->memory_started = 0;

		/* Release the code space */
		_jit_memory_end_function(state->gen.context, JIT_MEMORY_RESTART);

		/* Free encoded bytecode offset data */
		_jit_varint_free_data(_jit_varint_get_data(&state->gen.offset_encoder));
	}
}

/*
 * Allocate more code space.
 */
static void
memory_realloc(_jit_compile_t *state)
{
	int result;

	/* Release the previously allocated code space */
	memory_abort(state);

	/* Request to extend memory limit and retry space allocation */
	_jit_memory_extend_limit(state->gen.context, state->page_factor++);
	result = _jit_memory_start_function(state->gen.context, state->func);
	if(result != JIT_MEMORY_OK)
	{
		/* Failed to allocate enough space */
		jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
	}

	/* Start with with allocated space */
	memory_start(state);
}

/*
 * Prepare function info needed for code generation.
 */
static void
codegen_prepare(_jit_compile_t *state)
{
	/* Intuit "nothrow" and "noreturn" flags for this function */
	if(!state->func->builder->may_throw)
	{
		state->func->no_throw = 1;



( run in 0.780 second using v1.01-cache-2.11-cpan-02777c243ea )