Alien-LibJIT

 view release on metacpan or  search on metacpan

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

/*
 * jit-compile.c - Function compilation.
 *
 * Copyright (C) 2004, 2006-2008  Southern Storm Software, Pty Ltd.
 * Copyright (C) 2012  Aleksey Demakov
 *
 * This file is part of the libjit library.
 *
 * The libjit library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * The libjit library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with the libjit library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include "jit-internal.h"
#include "jit-rules.h"
#include "jit-reg-alloc.h"
#include "jit-setjmp.h"
#ifdef _JIT_COMPILE_DEBUG
# include <jit/jit-dump.h>
# include <stdio.h>
#endif

/*
 * Misc data needed for compilation
 */
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
@*/

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

		jit_insn_iter_init(&iter, block);
		while((insn = jit_insn_iter_next(&iter)) != 0)
		{
			if(insn->dest && (insn->flags & JIT_INSN_DEST_OTHER_FLAGS) == 0)
			{
				reset_value(insn->dest);
			}
			if(insn->value1 && (insn->flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0)
			{
				reset_value(insn->value1);
			}
			if(insn->value2 && (insn->flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0)
			{
				reset_value(insn->value2);
			}
		}
	}

	/* Reset values referred to by builder */
	if(func->builder->setjmp_value)
	{
		reset_value(func->builder->setjmp_value);
	}
	if(func->builder->parent_frame)
	{
		reset_value(func->builder->parent_frame);
	}

	/* Reset the "touched" registers mask. The first time compilation
	   might have followed wrong code paths and thus allocated wrong
	   registers. */
	if(func->builder->has_tail_call)
	{
		/* For functions with tail calls _jit_regs_alloc_global()
		   does not allocate any global registers. The "permanent"
		   mask has all global registers set to prevent their use. */
		gen->touched = jit_regused_init;
	}
	else
	{
		gen->touched = gen->permanent;
	}

	/* Reset the epilog fixup list */
	gen->epilog_fixup = 0;
}

/*
 * Acquire the memory context.
 */
static void
memory_acquire(_jit_compile_t *state)
{
	/* Store the function's context as codegen context */
	state->gen.context = state->func->context;

	/* Acquire the memory context lock */
	_jit_memory_lock(state->gen.context);

	/* Remember that the lock is acquired */
	state->memory_locked = 1;

	if(!_jit_memory_ensure(state->gen.context))
	{
		jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
	}
}

/*
 * Release the memory context.
 */
static void
memory_release(_jit_compile_t *state)
{
	/* Release the lock if it was previously acquired */
	if(state->memory_locked)
	{
		_jit_memory_unlock(state->gen.context);
		state->memory_locked = 0;
	}
}

/*
 * Align the method code on a particular boundary if the
 * difference between the current position and the aligned
 * boundary is less than "diff".  The "nop" value is used
 * to pad unused bytes.
 */
static void
memory_align(_jit_compile_t *state, int align, int diff, int nop)
{
	jit_nuint p, n;

	/* Adjust the required alignment */
	if(align < 1)
	{
		align = 1;
	}

	/* Determine the location of the next alignment boundary */
	p = (jit_nuint) state->gen.ptr;
	n = (p + (jit_nuint) align - 1) & ~((jit_nuint) align - 1);
	if(p == n || (p - n) >= (jit_nuint) diff)
	{
		return;
	}

	/* Determine the actual alignment */
	align = (int) (n - p);

	/* Detect overflow of the free memory region */
	_jit_gen_check_space(&state->gen, align);

#ifdef jit_should_pad
	/* Use CPU-specific padding, because it may be more efficient */
	_jit_pad_buffer(state->gen.ptr, align);
#else
	jit_memset(state->gen.ptr, nop, align);
	state->gen.ptr += align;
#endif
}

/*
 * Prepare to start code generation with just allocated code space.
 */
static void
memory_start(_jit_compile_t *state)
{
	/* Remember the memory context state */
	state->memory_started = 1;

	/* Store the bounds of the available space */
	state->gen.mem_start = _jit_memory_get_break(state->gen.context);
	state->gen.mem_limit = _jit_memory_get_limit(state->gen.context); 

	/* Align the function code start as required */
	state->gen.ptr = state->gen.mem_start;
	memory_align(state, JIT_FUNCTION_ALIGNMENT, JIT_FUNCTION_ALIGNMENT, 0);



( run in 0.402 second using v1.01-cache-2.11-cpan-ceb78f64989 )