[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[dotgnu-pnet-commits] libjit ChangeLog jit/jit-internal.h jit/jit-fun...
From: |
Aleksey Demakov |
Subject: |
[dotgnu-pnet-commits] libjit ChangeLog jit/jit-internal.h jit/jit-fun... |
Date: |
Fri, 05 Jun 2009 23:31:51 +0000 |
CVSROOT: /sources/dotgnu-pnet
Module name: libjit
Changes by: Aleksey Demakov <avd> 09/06/05 23:31:51
Modified files:
. : ChangeLog
jit : jit-internal.h jit-function.c Makefile.am
jit-block.c
Added files:
jit : jit-compile.c
Log message:
move compile functions from jit-function.c to a new file jit-compile.c;
handle internal exceptions during compilation;
optimize CFG by default but add possibility to turn optimization off;
add jit_optimize function.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libjit/ChangeLog?cvsroot=dotgnu-pnet&r1=1.433&r2=1.434
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-internal.h?cvsroot=dotgnu-pnet&r1=1.36&r2=1.37
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-function.c?cvsroot=dotgnu-pnet&r1=1.43&r2=1.44
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/Makefile.am?cvsroot=dotgnu-pnet&r1=1.28&r2=1.29
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-block.c?cvsroot=dotgnu-pnet&r1=1.13&r2=1.14
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-compile.c?cvsroot=dotgnu-pnet&rev=1.1
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/ChangeLog,v
retrieving revision 1.433
retrieving revision 1.434
diff -u -b -r1.433 -r1.434
--- ChangeLog 5 Jun 2009 17:03:10 -0000 1.433
+++ ChangeLog 5 Jun 2009 23:31:50 -0000 1.434
@@ -1,7 +1,28 @@
2009-06-05 Aleksey Demakov <address@hidden>
+ * jit/jit-compile.c (jit_function_compile)
+ (jit_function_compile_entry, jit_function_setup_entry)
+ (_jit_function_compile_on_demand): new file, move all compile
+ functions here from jit-function.c.
+
+ * jit/jit-compile.c (jit_compile, jit_compile_entry): add new
+ functions that do exactly the same as jit_function_compile and
+ jit_function_compile_entry but return JIT_RESULT_ error code.
+
+ * jit/jit-compile.c (jit_optimize): add function to optimize IR.
+
* include/jit/jit-function.h: add optimization level constants
- JIT_OPTLEVEL_NONE and JIT_OPTLEVEL_NORMAL,
+ JIT_OPTLEVEL_NONE and JIT_OPTLEVEL_NORMAL.
+ * jit/jit-function.c (jit_function_create) set JIT_OPTLEVEL_NORMAL
+ optimization level by default.
+ * jit/jit-function.c (jit_function_get_max_optimization_level):
+ return JIT_OPTLEVEL_NORMAL.
+ * jit/jit-internal.h (struct _jit_function): add is_optimized field
+ to _jit_function struct.
+
+ * jit/jit-compile.c (compile): catch internal exceptions.
+ * jit/jit-block.c: use internal exceptions instead of return codes
+ for CFG error handling.
2009-05-10 Aleksey Demakov <address@hidden>
Index: jit/jit-internal.h
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-internal.h,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -b -r1.36 -r1.37
--- jit/jit-internal.h 9 May 2009 21:54:33 -0000 1.36
+++ jit/jit-internal.h 5 Jun 2009 23:31:50 -0000 1.37
@@ -441,6 +441,7 @@
/* Flag bits for this function */
unsigned is_recompilable : 1;
+ unsigned is_optimized : 1;
unsigned no_throw : 1;
unsigned no_return : 1;
unsigned has_try : 1;
@@ -601,12 +602,12 @@
* Build control flow graph edges for all blocks associated with a
* function.
*/
-int _jit_block_build_cfg(jit_function_t func);
+void _jit_block_build_cfg(jit_function_t func);
/*
* Eliminate useless control flow between blocks in a function.
*/
-int _jit_block_clean_cfg(jit_function_t func);
+void _jit_block_clean_cfg(jit_function_t func);
/*
* Compute block postorder for control flow graph depth first traversal.
Index: jit/jit-function.c
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-function.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -b -r1.43 -r1.44
--- jit/jit-function.c 9 May 2009 21:54:32 -0000 1.43
+++ jit/jit-function.c 5 Jun 2009 23:31:50 -0000 1.44
@@ -21,14 +21,10 @@
*/
#include "jit-internal.h"
-#include "jit-memory.h"
-#include "jit-rules.h"
-#include "jit-reg-alloc.h"
#include "jit-apply-func.h"
+#include "jit-cache.h"
+#include "jit-rules.h"
#include "jit-setjmp.h"
-#ifdef _JIT_COMPILE_DEBUG
-#include <stdio.h>
-#endif
/*@
* @deftypefun jit_function_t jit_function_create (jit_context_t
@var{context}, jit_type_t @var{signature})
@@ -105,6 +101,7 @@
/* 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
@@ -234,6 +231,7 @@
jit_free(func->builder->label_info);
jit_free(func->builder);
func->builder = 0;
+ func->is_optimized = 0;
}
}
@@ -495,433 +493,6 @@
}
/*
- * Compile a single basic block within a function.
- */
-static void
-compile_block(jit_gencode_t gen, jit_function_t func, jit_block_t block)
-{
- jit_insn_iter_t iter;
- jit_insn_t insn;
-
-#ifdef _JIT_COMPILE_DEBUG
- printf("Block #%d: %d\n", func->builder->block_count++, block->label);
-#endif
-
- /* Iterate over all blocks in the function */
- jit_insn_iter_init(&iter, block);
- while((insn = jit_insn_iter_next(&iter)) != 0)
- {
-#ifdef _JIT_COMPILE_DEBUG
- unsigned char *p1, *p2;
- p1 = gen->posn.ptr;
- printf("Insn: %5d, Opcode: 0x%04x\n",
func->builder->insn_count++, insn->opcode);
- printf("Start of binary code: 0x%08x\n", p1);
-#endif
-
- switch(insn->opcode)
- {
- case JIT_OP_NOP:
- /* Ignore NOP's */
- break;
-
- case JIT_OP_CHECK_NULL:
- /* Determine if we can optimize the null check away */
- if(!_jit_insn_check_is_redundant(&iter))
- {
- _jit_gen_insn(gen, func, block, insn);
- }
- break;
-
- case JIT_OP_CALL:
- case JIT_OP_CALL_TAIL:
- case JIT_OP_CALL_INDIRECT:
- case JIT_OP_CALL_INDIRECT_TAIL:
- case JIT_OP_CALL_VTABLE_PTR:
- case JIT_OP_CALL_VTABLE_PTR_TAIL:
- case JIT_OP_CALL_EXTERNAL:
- case JIT_OP_CALL_EXTERNAL_TAIL:
- /* Spill all caller-saved registers before a call */
- _jit_regs_spill_all(gen);
- _jit_gen_insn(gen, func, block, insn);
- break;
-
-#ifndef JIT_BACKEND_INTERP
- case JIT_OP_INCOMING_REG:
- /* Assign a register to an incoming value */
- _jit_regs_set_incoming(gen,
-
(int)jit_value_get_nint_constant(insn->value2),
- insn->value1);
- _jit_gen_insn(gen, func, block, insn);
- break;
-#endif
-
- case JIT_OP_INCOMING_FRAME_POSN:
- /* Set the frame position for an incoming value */
- insn->value1->frame_offset =
jit_value_get_nint_constant(insn->value2);
- insn->value1->in_register = 0;
- insn->value1->has_frame_offset = 1;
- if(insn->value1->has_global_register)
- {
- insn->value1->in_global_register = 1;
- _jit_gen_load_global(gen,
insn->value1->global_reg, insn->value1);
- }
- else
- {
- insn->value1->in_frame = 1;
- }
- break;
-
-#ifndef JIT_BACKEND_INTERP
- case JIT_OP_OUTGOING_REG:
- /* Copy a value into an outgoing register */
- _jit_regs_set_outgoing(gen,
-
(int)jit_value_get_nint_constant(insn->value2),
- insn->value1);
- break;
-#endif
-
- case JIT_OP_OUTGOING_FRAME_POSN:
- /* Set the frame position for an outgoing value */
- insn->value1->frame_offset =
jit_value_get_nint_constant(insn->value2);
- insn->value1->in_register = 0;
- insn->value1->in_global_register = 0;
- insn->value1->in_frame = 0;
- insn->value1->has_frame_offset = 1;
- insn->value1->has_global_register = 0;
- break;
-
-#ifndef JIT_BACKEND_INTERP
- case JIT_OP_RETURN_REG:
- /* Assign a register to a return value */
- _jit_regs_set_incoming(gen,
-
(int)jit_value_get_nint_constant(insn->value2),
- insn->value1);
- _jit_gen_insn(gen, func, block, insn);
- break;
-#endif
-
- case JIT_OP_MARK_OFFSET:
- /* Mark the current code position as corresponding
- to a particular bytecode offset */
- _jit_cache_mark_bytecode(&gen->posn,
- (unsigned long)(long)
-
jit_value_get_nint_constant(insn->value1));
- break;
-
- default:
- /* Generate code for the instruction with the back end
*/
- _jit_gen_insn(gen, func, block, insn);
- break;
- }
-
-#ifdef _JIT_COMPILE_DEBUG
- p2 = gen->posn.ptr;
- printf("Length of binary code: %d\n\n", p2 - p1);
- fflush(stdout);
-#endif
- }
-}
-
-/*
- * Reset value on restart.
- */
-static void
-reset_value(jit_value_t value)
-{
- value->reg = -1;
- value->in_register = 0;
- value->in_global_register = 0;
- value->in_frame = 0;
-}
-
-/*
- * Clean up the compilation state on restart.
- */
-static void
-cleanup_on_restart(jit_gencode_t gen, jit_function_t func)
-{
- jit_block_t block;
- jit_insn_iter_t iter;
- jit_insn_t insn;
-
- block = 0;
- while((block = jit_block_next(func, block)) != 0)
- {
- /* Clear the block addresses and fixup lists */
- block->address = 0;
- block->fixup_list = 0;
- block->fixup_absolute_list = 0;
-
- /* Reset values referred to by block instructions */
- 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;
-}
-
-/*
- * Compile a function and return its entry point.
- */
-static int
-compile(jit_function_t func, void **entry_point)
-{
- struct jit_gencode gen;
- jit_cache_t cache;
- unsigned char *start;
- unsigned char *end;
- jit_block_t block;
- int page_factor;
- int result;
-
- /* Initialize the code generation state */
- jit_memzero(&gen, sizeof(gen));
- page_factor = 0;
- start = 0;
- end = 0;
-
- /* Intuit "nothrow" and "noreturn" flags for this function */
- if(!(func->builder->may_throw))
- {
- func->no_throw = 1;
- }
- if(!(func->builder->ordinary_return))
- {
- func->no_return = 1;
- }
-
- /* Build control flow graph */
- if(!_jit_block_build_cfg(func))
- {
- return 0;
- }
-
- /* Eliminate useless control flow */
- if(!_jit_block_clean_cfg(func))
- {
- return 0;
- }
-
- /* Compute liveness and "next use" information for this function */
- _jit_function_compute_liveness(func);
-
- /* Allocate global registers to variables within the function */
-#ifndef JIT_BACKEND_INTERP
- _jit_regs_alloc_global(&gen, func);
-#endif
-
- /* We need the cache lock while we are compiling the function */
- jit_mutex_lock(&(func->context->cache_lock));
-
-#ifdef _JIT_COMPILE_DEBUG
- printf("\n*** Start compilation ***\n\n");
- func->builder->block_count = 0;
- func->builder->insn_count = 0;
-#endif
-
- /* Get the method cache */
- cache = _jit_context_get_cache(func->context);
- if(!cache)
- {
- jit_mutex_unlock(&(func->context->cache_lock));
- return 0;
- }
-
- /* Start function output to the cache */
- result = _jit_cache_start_method(cache, &(gen.posn),
- page_factor++,
- JIT_FUNCTION_ALIGNMENT, func);
- if (result == JIT_CACHE_RESTART)
- {
- /* No space left on the current cache page. Allocate a new
one. */
- result = _jit_cache_start_method(cache, &(gen.posn),
- page_factor++,
- JIT_FUNCTION_ALIGNMENT, func);
- }
- if (result != JIT_CACHE_OK)
- {
- /* Failed to allocate any cache space */
- jit_mutex_unlock(&(func->context->cache_lock));
- return 0;
- }
-
- for(;;)
- {
- start = gen.posn.ptr;
-
-#ifdef jit_extra_gen_init
- /* Initialize information that may need to be reset each loop */
- jit_extra_gen_init(&gen);
-#endif
-
-#ifdef JIT_PROLOG_SIZE
- /* Output space for the function prolog */
- if(!jit_cache_check_for_n(&(gen.posn), JIT_PROLOG_SIZE))
- {
- /* No space left on the current cache page. Restart. */
- jit_cache_mark_full(&(gen.posn));
- goto restart;
- }
- gen.posn.ptr += JIT_PROLOG_SIZE;
-#endif
-
- /* Generate code for the blocks in the function */
- block = 0;
- while((block = jit_block_next(func, block)) != 0)
- {
- /* Notify the back end that the block is starting */
- _jit_gen_start_block(&gen, block);
-
-#ifndef JIT_BACKEND_INTERP
- /* Clear the local register assignments */
- _jit_regs_init_for_block(&gen);
-#endif
-
- /* Generate the block's code */
- compile_block(&gen, func, block);
-
-#ifndef JIT_BACKEND_INTERP
- /* Spill all live register values back to their frame
positions */
- _jit_regs_spill_all(&gen);
-#endif
-
- /* Notify the back end that the block is finished */
- _jit_gen_end_block(&gen, block);
-
- /* Stop code generation if the cache page is full */
- if(_jit_cache_is_full(cache, &(gen.posn)))
- {
- /* No space left on the current cache page.
Restart. */
- goto restart;
- }
- }
-
- /* Output the function epilog. All return paths will jump to
here */
- _jit_gen_epilog(&gen, func);
- end = gen.posn.ptr;
-
-#ifdef JIT_PROLOG_SIZE
- /* Back-patch the function prolog and get the real entry point
*/
- start = _jit_gen_prolog(&gen, func, start);
-#endif
-
-#if !defined(JIT_BACKEND_INTERP) && (!defined(jit_redirector_size) ||
!defined(jit_indirector_size))
- /* If the function is recompilable, then we need an extra entry
- point to properly redirect previous references to the
function */
- if(func->is_recompilable && !func->indirector)
- {
- /* TODO: use _jit_create_indirector() instead of
- _jit_gen_redirector() as both do the same. */
- func->indirector = _jit_gen_redirector(&gen, func);
- }
-#endif
-
- restart:
- /* End the function's output process */
- result = _jit_cache_end_method(&(gen.posn));
- if(result != JIT_CACHE_RESTART)
- {
- break;
- }
-
- /* Clean up the compilation state before restart */
- cleanup_on_restart(&gen, func);
-
-#ifdef _JIT_COMPILE_DEBUG
- printf("\n*** Restart compilation ***\n\n");
- func->builder->block_count = 0;
- func->builder->insn_count = 0;
-#endif
-
- /* Restart function output to the cache */
- result = _jit_cache_start_method(cache, &(gen.posn),
- page_factor,
- JIT_FUNCTION_ALIGNMENT, func);
- if(result != JIT_CACHE_OK)
- {
-#ifdef jit_extra_gen_cleanup
- /* Clean up the extra code generation state */
- jit_extra_gen_cleanup(gen);
-#endif
- jit_mutex_unlock(&(func->context->cache_lock));
- return 0;
- }
- page_factor *= 2;
- }
-
-#ifdef jit_extra_gen_cleanup
- /* Clean up the extra code generation state */
- jit_extra_gen_cleanup(gen);
-#endif
-
- /* Bail out if we ran out of memory while translating the function */
- if(result != JIT_CACHE_OK)
- {
- jit_mutex_unlock(&(func->context->cache_lock));
- return 0;
- }
-
-#ifndef JIT_BACKEND_INTERP
- /* Perform a CPU cache flush, to make the code executable */
- jit_flush_exec(start, (unsigned int)(end - start));
-#endif
-
- /* The function has been compiled successfully */
- jit_mutex_unlock(&(func->context->cache_lock));
-
- /* Free the builder structure, which we no longer require */
- _jit_function_free_builder(func);
-
- /* Record the entry point */
- if(entry_point)
- {
- *entry_point = start;
- }
-
- return 1;
-}
-
-/*
* Information that is stored for an exception region in the cache.
*/
typedef struct jit_cache_eh *jit_cache_eh_t;
@@ -933,122 +504,6 @@
};
/*@
- * @deftypefun int jit_function_compile (jit_function_t @var{func})
- * Compile a function to its executable form. If the function was
- * already compiled, then do nothing. Returns zero on error.
- *
- * If an error occurs, you can use @code{jit_function_abandon} to
- * completely destroy the function. Once the function has been compiled
- * successfully, it can no longer be abandoned.
- *
- * Sometimes you may wish to recompile a function, to apply greater
- * levels of optimization the second time around. You must call
- * @code{jit_function_set_recompilable} before you compile the function
- * the first time. On the second time around, build the function's
- * instructions again, and call @code{jit_function_compile}
- * a second time.
- * @end deftypefun
address@hidden/
-int
-jit_function_compile(jit_function_t func)
-{
- int result;
- void *entry_point;
-
- /* Bail out if we have nothing to do */
- if(!func)
- {
- return 0;
- }
- if(func->is_compiled && !(func->builder))
- {
- /* The function is already compiled, and we don't need to
recompile */
- return 1;
- }
- if(!(func->builder))
- {
- /* We don't have anything to compile at all */
- return 0;
- }
-
- /* Compile and record the entry point. */
- result = compile(func, &entry_point);
- if(result)
- {
- func->entry_point = entry_point;
- func->is_compiled = 1;
- }
-
- return result;
-}
-
-/*@
- * @deftypefun int jit_function_compile_entry (jit_function_t @var{func}, void
address@hidden)
- * Compile a function to its executable form but do not make it
- * available for invocation yet. It may be made available later
- * with @code{jit_function_setup_entry}.
- * @end deftypefun
address@hidden/
-int
-jit_function_compile_entry(jit_function_t func, void **entry_point)
-{
- /* Init entry_point */
- if(entry_point)
- {
- *entry_point = 0;
- }
- else
- {
- return 0;
- }
-
- /* Bail out if we have nothing to do */
- if(!func)
- {
- return 0;
- }
- if(func->is_compiled && !(func->builder))
- {
- /* The function is already compiled, and we don't need to
recompile */
- *entry_point = func->entry_point;
- return 1;
- }
- if(!(func->builder))
- {
- /* We don't have anything to compile at all */
- return 0;
- }
-
- /* Compile and return the entry point. */
- return compile(func, entry_point);
-}
-
-/*@
- * @deftypefun int jit_function_setup_entry (jit_function_t @var{func}, void
address@hidden)
- * Make a function compiled with @code{jit_function_compile_entry}
- * available for invocation and free the resources used for
- * compilation. If @var{entry_point} is null then it only
- * frees the resources.
- * @end deftypefun
address@hidden/
-void
-jit_function_setup_entry(jit_function_t func, void *entry_point)
-{
- /* Bail out if we have nothing to do */
- if(!func)
- {
- return;
- }
- /* Record the entry point */
- if(entry_point)
- {
- func->entry_point = entry_point;
- func->is_compiled = 1;
- }
- _jit_function_free_builder(func);
-}
-
-/*@
* @deftypefun int jit_function_is_compiled (jit_function_t @var{func})
* Determine if a function has already been compiled.
* @end deftypefun
@@ -1369,62 +824,6 @@
return 0;
}
-void *_jit_function_compile_on_demand(jit_function_t func)
-{
- void *entry = 0;
- int result = JIT_RESULT_OK;
-
- /* Lock down the context */
- jit_context_build_start(func->context);
-
- /* If we are already compiled, then bail out */
- if(func->is_compiled)
- {
- entry = func->entry_point;
- jit_context_build_end(func->context);
- return entry;
- }
-
- /* Call the user's on-demand compiler. Bail out with an error
- if the user didn't supply an on-demand compiler */
- if(func->on_demand)
- {
- result = (*(func->on_demand))(func);
- if(result == JIT_RESULT_OK)
- {
- /* Compile the function if the user didn't do so */
- if(!(func->is_compiled))
- {
- if(jit_function_compile(func))
- {
- entry = func->entry_point;
- }
- else
- {
- result = JIT_RESULT_OUT_OF_MEMORY;
- }
- }
- else
- {
- entry = func->entry_point;
- }
- }
- _jit_function_free_builder(func);
- }
- else
- {
- result = JIT_RESULT_COMPILE_ERROR;
- }
-
- /* Unlock the context and report the result */
- jit_context_build_end(func->context);
- if(result != JIT_RESULT_OK)
- {
- jit_exception_builtin(result);
- }
- return entry;
-}
-
/*@
* @deftypefun int jit_function_apply (jit_function_t @var{func}, void
address@hidden, void address@hidden)
* Call the function @var{func} with the supplied arguments. Each element
@@ -1547,8 +946,8 @@
* reached the maximum optimization level.
* @end deftypefun
@*/
-void jit_function_set_optimization_level
- (jit_function_t func, unsigned int level)
+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)
@@ -1557,7 +956,7 @@
}
if(func)
{
- func->optimization_level = (int)level;
+ func->optimization_level = level;
}
}
@@ -1566,15 +965,16 @@
* Get the current optimization level for @var{func}.
* @end deftypefun
@*/
-unsigned int jit_function_get_optimization_level(jit_function_t func)
+unsigned int
+jit_function_get_optimization_level(jit_function_t func)
{
if(func)
{
- return (unsigned int)(func->optimization_level);
+ return func->optimization_level;
}
else
{
- return 0;
+ return JIT_OPTLEVEL_NONE;
}
}
@@ -1583,10 +983,10 @@
* Get the maximum optimization level that is supported by @code{libjit}.
* @end deftypefun
@*/
-unsigned int jit_function_get_max_optimization_level(void)
+unsigned int
+jit_function_get_max_optimization_level(void)
{
- /* TODO - implement more than basic optimization */
- return 0;
+ return JIT_OPTLEVEL_NORMAL;
}
/*@
Index: jit/Makefile.am
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/Makefile.am,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -b -r1.28 -r1.29
--- jit/Makefile.am 28 Apr 2009 22:42:42 -0000 1.28
+++ jit/Makefile.am 5 Jun 2009 23:31:50 -0000 1.29
@@ -18,6 +18,7 @@
jit-block.c \
jit-cache.h \
jit-cache.c \
+ jit-compile.c \
jit-context.c \
jit-cpuid-x86.h \
jit-cpuid-x86.c \
Index: jit/jit-block.c
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-block.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -b -r1.13 -r1.14
--- jit/jit-block.c 9 May 2009 21:54:32 -0000 1.13
+++ jit/jit-block.c 5 Jun 2009 23:31:50 -0000 1.14
@@ -37,7 +37,7 @@
} _jit_block_stack_entry_t;
-static int
+static void
create_edge(jit_function_t func, jit_block_t src, jit_block_t dst, int flags,
int create)
{
_jit_edge_t edge;
@@ -49,7 +49,7 @@
edge = jit_memory_pool_alloc(&func->builder->edge_pool, struct
_jit_edge);
if(!edge)
{
- return 0;
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
/* Initialize edge fields */
@@ -65,11 +65,9 @@
/* Count it */
++(src->num_succs);
++(dst->num_preds);
-
- return 1;
}
-static int
+static void
build_edges(jit_function_t func, int create)
{
jit_block_t src, dst;
@@ -97,7 +95,7 @@
if(!dst)
{
/* Bail out on undefined label */
- return 0;
+
jit_exception_builtin(JIT_RESULT_UNDEFINED_LABEL);
}
}
else if(opcode > JIT_OP_BR && opcode <= JIT_OP_BR_NFGE_INV)
@@ -107,7 +105,7 @@
if(!dst)
{
/* Bail out on undefined label */
- return 0;
+
jit_exception_builtin(JIT_RESULT_UNDEFINED_LABEL);
}
}
else if(opcode == JIT_OP_THROW || opcode == JIT_OP_RETHROW)
@@ -126,7 +124,7 @@
if(!dst)
{
/* Bail out on undefined label */
- return 0;
+
jit_exception_builtin(JIT_RESULT_UNDEFINED_LABEL);
}
}
else if(opcode >= JIT_OP_CALL && opcode <=
JIT_OP_CALL_EXTERNAL_TAIL)
@@ -148,12 +146,9 @@
if(!dst)
{
/* Bail out on undefined label */
- return 0;
- }
- if(!create_edge(func, src, dst,
_JIT_EDGE_BRANCH, create))
- {
- return 0;
+
jit_exception_builtin(JIT_RESULT_UNDEFINED_LABEL);
}
+ create_edge(func, src, dst, _JIT_EDGE_BRANCH,
create);
}
dst = 0;
}
@@ -165,25 +160,17 @@
/* create a branch or exception edge if appropriate */
if(dst)
{
- if(!create_edge(func, src, dst, flags, create))
- {
- return 0;
- }
+ create_edge(func, src, dst, flags, create);
}
/* create a fall-through edge if appropriate */
if(!src->ends_in_dead)
{
- if(!create_edge(func, src, src->next,
_JIT_EDGE_FALLTHRU, create))
- {
- return 0;
+ create_edge(func, src, src->next, _JIT_EDGE_FALLTHRU,
create);
}
}
- }
-
- return 1;
}
-static int
+static void
alloc_edges(jit_function_t func)
{
jit_block_t block;
@@ -200,7 +187,7 @@
block->succs = jit_calloc(block->num_succs,
sizeof(_jit_edge_t));
if(!block->succs)
{
- return 0;
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
/* Reset edge count for the next build pass */
block->num_succs = 0;
@@ -216,14 +203,12 @@
block->preds = jit_calloc(block->num_preds,
sizeof(_jit_edge_t));
if(!block->preds)
{
- return 0;
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
/* Reset edge count for the next build pass */
block->num_preds = 0;
}
}
-
- return 1;
}
static void
@@ -351,7 +336,7 @@
}
/* Merge empty block with its successor */
-static int
+static void
merge_empty(jit_function_t func, jit_block_t block, int *changed)
{
_jit_edge_t succ_edge, pred_edge, fallthru_edge;
@@ -379,7 +364,7 @@
*changed = 1;
if(!attach_edge_dst(pred_edge, succ_block))
{
- return 0;
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
}
}
@@ -394,7 +379,7 @@
*changed = 1;
if(!attach_edge_dst(pred_edge, succ_block))
{
- return 0;
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
fallthru_edge = 0;
}
@@ -414,8 +399,6 @@
_jit_block_detach(block, block);
delete_block(block);
}
-
- return 1;
}
/* Delete block along with references to it */
@@ -571,28 +554,20 @@
func->builder->exit_block = 0;
}
-int
+void
_jit_block_build_cfg(jit_function_t func)
{
/* Count the edges */
- if(!build_edges(func, 0))
- {
- return 0;
- }
+ build_edges(func, 0);
+
/* Allocate memory for edges */
- if(!alloc_edges(func))
- {
- return 0;
- }
+ alloc_edges(func);
+
/* Actually build the edges */
- if(!build_edges(func, 1))
- {
- return 0;
- }
- return 1;
+ build_edges(func, 1);
}
-int
+void
_jit_block_clean_cfg(jit_function_t func)
{
int index, changed;
@@ -612,7 +587,7 @@
if(!_jit_block_compute_postorder(func))
{
- return 0;
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
eliminate_unreachable(func);
@@ -671,10 +646,7 @@
if(is_empty_block(block))
{
/* Remove empty block */
- if(!merge_empty(func, block, &changed))
- {
- return 0;
- }
+ merge_empty(func, block, &changed);
}
}
@@ -685,13 +657,11 @@
{
if(!_jit_block_compute_postorder(func))
{
- return 0;
+ jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
}
clear_visited(func);
goto loop;
}
-
- return 1;
}
int
Index: jit/jit-compile.c
===================================================================
RCS file: jit/jit-compile.c
diff -N jit/jit-compile.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ jit/jit-compile.c 5 Jun 2009 23:31:50 -0000 1.1
@@ -0,0 +1,809 @@
+/*
+ * jit-compile.c - Function compilation.
+ *
+ * Copyright (C) 2004, 2006-2008 Southern Storm Software, Pty Ltd.
+ *
+ * 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-memory.h"
+#include "jit-rules.h"
+#include "jit-reg-alloc.h"
+#include "jit-setjmp.h"
+#ifdef _JIT_COMPILE_DEBUG
+# include <stdio.h>
+#endif
+
+#define _JIT_RESULT_TO_OBJECT(x) ((void *) ((int) (x) - JIT_RESULT_OK))
+#define _JIT_RESULT_FROM_OBJECT(x) ((int) ((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 */
+ 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
address@hidden/
+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;
+}
+
+/*
+ * Compile a single basic block within a function.
+ */
+static void
+compile_block(jit_gencode_t gen, jit_function_t func, jit_block_t block)
+{
+ jit_insn_iter_t iter;
+ jit_insn_t insn;
+
+#ifdef _JIT_COMPILE_DEBUG
+ printf("Block #%d: %d\n", func->builder->block_count++, block->label);
+#endif
+
+ /* Iterate over all blocks in the function */
+ jit_insn_iter_init(&iter, block);
+ while((insn = jit_insn_iter_next(&iter)) != 0)
+ {
+#ifdef _JIT_COMPILE_DEBUG
+ unsigned char *p1, *p2;
+ p1 = gen->posn.ptr;
+ printf("Insn: %5d, Opcode: 0x%04x\n",
func->builder->insn_count++, insn->opcode);
+ printf("Start of binary code: 0x%08x\n", p1);
+#endif
+
+ switch(insn->opcode)
+ {
+ case JIT_OP_NOP:
+ /* Ignore NOP's */
+ break;
+
+ case JIT_OP_CHECK_NULL:
+ /* Determine if we can optimize the null check away */
+ if(!_jit_insn_check_is_redundant(&iter))
+ {
+ _jit_gen_insn(gen, func, block, insn);
+ }
+ break;
+
+ case JIT_OP_CALL:
+ case JIT_OP_CALL_TAIL:
+ case JIT_OP_CALL_INDIRECT:
+ case JIT_OP_CALL_INDIRECT_TAIL:
+ case JIT_OP_CALL_VTABLE_PTR:
+ case JIT_OP_CALL_VTABLE_PTR_TAIL:
+ case JIT_OP_CALL_EXTERNAL:
+ case JIT_OP_CALL_EXTERNAL_TAIL:
+ /* Spill all caller-saved registers before a call */
+ _jit_regs_spill_all(gen);
+ _jit_gen_insn(gen, func, block, insn);
+ break;
+
+#ifndef JIT_BACKEND_INTERP
+ case JIT_OP_INCOMING_REG:
+ /* Assign a register to an incoming value */
+ _jit_regs_set_incoming(gen,
+
(int)jit_value_get_nint_constant(insn->value2),
+ insn->value1);
+ _jit_gen_insn(gen, func, block, insn);
+ break;
+#endif
+
+ case JIT_OP_INCOMING_FRAME_POSN:
+ /* Set the frame position for an incoming value */
+ insn->value1->frame_offset =
jit_value_get_nint_constant(insn->value2);
+ insn->value1->in_register = 0;
+ insn->value1->has_frame_offset = 1;
+ if(insn->value1->has_global_register)
+ {
+ insn->value1->in_global_register = 1;
+ _jit_gen_load_global(gen,
insn->value1->global_reg, insn->value1);
+ }
+ else
+ {
+ insn->value1->in_frame = 1;
+ }
+ break;
+
+#ifndef JIT_BACKEND_INTERP
+ case JIT_OP_OUTGOING_REG:
+ /* Copy a value into an outgoing register */
+ _jit_regs_set_outgoing(gen,
+
(int)jit_value_get_nint_constant(insn->value2),
+ insn->value1);
+ break;
+#endif
+
+ case JIT_OP_OUTGOING_FRAME_POSN:
+ /* Set the frame position for an outgoing value */
+ insn->value1->frame_offset =
jit_value_get_nint_constant(insn->value2);
+ insn->value1->in_register = 0;
+ insn->value1->in_global_register = 0;
+ insn->value1->in_frame = 0;
+ insn->value1->has_frame_offset = 1;
+ insn->value1->has_global_register = 0;
+ break;
+
+#ifndef JIT_BACKEND_INTERP
+ case JIT_OP_RETURN_REG:
+ /* Assign a register to a return value */
+ _jit_regs_set_incoming(gen,
+
(int)jit_value_get_nint_constant(insn->value2),
+ insn->value1);
+ _jit_gen_insn(gen, func, block, insn);
+ break;
+#endif
+
+ case JIT_OP_MARK_OFFSET:
+ /* Mark the current code position as corresponding
+ to a particular bytecode offset */
+ _jit_cache_mark_bytecode(&gen->posn,
+ (unsigned long)(long)
+
jit_value_get_nint_constant(insn->value1));
+ break;
+
+ default:
+ /* Generate code for the instruction with the back end
*/
+ _jit_gen_insn(gen, func, block, insn);
+ break;
+ }
+
+#ifdef _JIT_COMPILE_DEBUG
+ p2 = gen->posn.ptr;
+ printf("Length of binary code: %d\n\n", p2 - p1);
+ fflush(stdout);
+#endif
+ }
+}
+
+/*
+ * Reset value on restart.
+ */
+static void
+reset_value(jit_value_t value)
+{
+ value->reg = -1;
+ value->in_register = 0;
+ value->in_global_register = 0;
+ value->in_frame = 0;
+}
+
+/*
+ * Clean up the compilation state on restart.
+ */
+static void
+cleanup_on_restart(jit_gencode_t gen, jit_function_t func)
+{
+ jit_block_t block;
+ jit_insn_iter_t iter;
+ jit_insn_t insn;
+
+ block = 0;
+ while((block = jit_block_next(func, block)) != 0)
+ {
+ /* Clear the block addresses and fixup lists */
+ block->address = 0;
+ block->fixup_list = 0;
+ block->fixup_absolute_list = 0;
+
+ /* Reset values referred to by block instructions */
+ 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;
+}
+
+static void
+prepare(jit_function_t func)
+{
+ /* Intuit "nothrow" and "noreturn" flags for this function */
+ if(!func->builder->may_throw)
+ {
+ func->no_throw = 1;
+ }
+ if(!func->builder->ordinary_return)
+ {
+ func->no_return = 1;
+ }
+
+ /* Compute liveness and "next use" information for this function */
+ _jit_function_compute_liveness(func);
+}
+
+static int
+codegen(jit_function_t func, void **entry_point)
+{
+ struct jit_gencode gen;
+ jit_cache_t cache;
+ unsigned char *start;
+ unsigned char *end;
+ jit_block_t block;
+ int page_factor;
+ int result;
+
+ /* Initialize the code generation state */
+ jit_memzero(&gen, sizeof(gen));
+ page_factor = 0;
+ start = 0;
+ end = 0;
+
+ /* Allocate global registers to variables within the function */
+#ifndef JIT_BACKEND_INTERP
+ _jit_regs_alloc_global(&gen, func);
+#endif
+
+#ifdef _JIT_COMPILE_DEBUG
+ printf("\n*** Start compilation ***\n\n");
+ func->builder->block_count = 0;
+ func->builder->insn_count = 0;
+#endif
+
+ /* Get the method cache */
+ cache = _jit_context_get_cache(func->context);
+ if(!cache)
+ {
+ return JIT_RESULT_OUT_OF_MEMORY;
+ }
+
+ /* Start function output to the cache */
+ result = _jit_cache_start_method(cache, &(gen.posn),
+ page_factor++,
+ JIT_FUNCTION_ALIGNMENT, func);
+ if (result == JIT_CACHE_RESTART)
+ {
+ /* No space left on the current cache page. Allocate a new
one. */
+ result = _jit_cache_start_method(cache, &(gen.posn),
+ page_factor++,
+ JIT_FUNCTION_ALIGNMENT, func);
+ }
+ if (result != JIT_CACHE_OK)
+ {
+ /* Failed to allocate any cache space */
+ return JIT_RESULT_OUT_OF_MEMORY;
+ }
+
+ for(;;)
+ {
+ start = gen.posn.ptr;
+
+#ifdef jit_extra_gen_init
+ /* Initialize information that may need to be reset each loop */
+ jit_extra_gen_init(&gen);
+#endif
+
+#ifdef JIT_PROLOG_SIZE
+ /* Output space for the function prolog */
+ if(!jit_cache_check_for_n(&(gen.posn), JIT_PROLOG_SIZE))
+ {
+ /* No space left on the current cache page. Restart. */
+ jit_cache_mark_full(&(gen.posn));
+ goto restart;
+ }
+ gen.posn.ptr += JIT_PROLOG_SIZE;
+#endif
+
+ /* Generate code for the blocks in the function */
+ block = 0;
+ while((block = jit_block_next(func, block)) != 0)
+ {
+ /* Notify the back end that the block is starting */
+ _jit_gen_start_block(&gen, block);
+
+#ifndef JIT_BACKEND_INTERP
+ /* Clear the local register assignments */
+ _jit_regs_init_for_block(&gen);
+#endif
+
+ /* Generate the block's code */
+ compile_block(&gen, func, block);
+
+#ifndef JIT_BACKEND_INTERP
+ /* Spill all live register values back to their frame
positions */
+ _jit_regs_spill_all(&gen);
+#endif
+
+ /* Notify the back end that the block is finished */
+ _jit_gen_end_block(&gen, block);
+
+ /* Stop code generation if the cache page is full */
+ if(_jit_cache_is_full(cache, &(gen.posn)))
+ {
+ /* No space left on the current cache page.
Restart. */
+ goto restart;
+ }
+ }
+
+ /* Output the function epilog. All return paths will jump to
here */
+ _jit_gen_epilog(&gen, func);
+ end = gen.posn.ptr;
+
+#ifdef JIT_PROLOG_SIZE
+ /* Back-patch the function prolog and get the real entry point
*/
+ start = _jit_gen_prolog(&gen, func, start);
+#endif
+
+#if !defined(JIT_BACKEND_INTERP) && (!defined(jit_redirector_size) ||
!defined(jit_indirector_size))
+ /* If the function is recompilable, then we need an extra entry
+ point to properly redirect previous references to the
function */
+ if(func->is_recompilable && !func->indirector)
+ {
+ /* TODO: use _jit_create_indirector() instead of
+ _jit_gen_redirector() as both do the same. */
+ func->indirector = _jit_gen_redirector(&gen, func);
+ }
+#endif
+
+ restart:
+ /* End the function's output process */
+ result = _jit_cache_end_method(&(gen.posn));
+ if(result != JIT_CACHE_RESTART)
+ {
+ break;
+ }
+
+ /* Clean up the compilation state before restart */
+ cleanup_on_restart(&gen, func);
+
+#ifdef _JIT_COMPILE_DEBUG
+ printf("\n*** Restart compilation ***\n\n");
+ func->builder->block_count = 0;
+ func->builder->insn_count = 0;
+#endif
+
+ /* Restart function output to the cache */
+ result = _jit_cache_start_method(cache, &(gen.posn),
+ page_factor,
+ JIT_FUNCTION_ALIGNMENT, func);
+ if(result != JIT_CACHE_OK)
+ {
+#ifdef jit_extra_gen_cleanup
+ /* Clean up the extra code generation state */
+ jit_extra_gen_cleanup(gen);
+#endif
+ return JIT_RESULT_OUT_OF_MEMORY;
+ }
+ page_factor *= 2;
+ }
+
+#ifdef jit_extra_gen_cleanup
+ /* Clean up the extra code generation state */
+ jit_extra_gen_cleanup(gen);
+#endif
+
+ /* Bail out if we ran out of memory while translating the function */
+ if(result != JIT_CACHE_OK)
+ {
+ return JIT_RESULT_OUT_OF_MEMORY;
+ }
+
+#ifndef JIT_BACKEND_INTERP
+ /* Perform a CPU cache flush, to make the code executable */
+ jit_flush_exec(start, (unsigned int)(end - start));
+#endif
+
+ /* Record the entry point */
+ *entry_point = start;
+
+ return JIT_RESULT_OK;
+}
+
+/*
+ * Compile a function and return its entry point.
+ */
+static int
+compile(jit_function_t func, void **entry_point)
+{
+ jit_jmp_buf jbuf;
+ jit_exception_func handler;
+ volatile int unlock = 0;
+
+ /* 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))
+ {
+ if(unlock)
+ {
+ jit_mutex_unlock(&func->context->cache_lock);
+ }
+ _jit_unwind_pop_setjmp();
+ jit_exception_set_handler(handler);
+ return
_JIT_RESULT_FROM_OBJECT(jit_exception_get_last_and_clear());
+ }
+
+ /* Perform machine-independent optimizations */
+ optimize(func);
+
+ /* Prepare the data needed for code generation */
+ prepare(func);
+
+ /* We need the cache lock while we are generating the code */
+ jit_mutex_lock(&func->context->cache_lock);
+ unlock = 1;
+
+ /* Perform code generation */
+ codegen(func, entry_point);
+
+ /* Unlock the cache */
+ jit_mutex_unlock(&func->context->cache_lock);
+
+ /* Restore the "setjmp" contexts and exit */
+ _jit_unwind_pop_setjmp();
+ jit_exception_set_handler(handler);
+ return JIT_RESULT_OK;
+}
+
+/*@
+ * @deftypefun int jit_compile (jit_function_t @var{func})
+ * Compile a function to its executable form. If the function was
+ * already compiled, then do nothing. Returns zero on error.
+ *
+ * If an error occurs, you can use @code{jit_function_abandon} to
+ * completely destroy the function. Once the function has been compiled
+ * successfully, it can no longer be abandoned.
+ *
+ * Sometimes you may wish to recompile a function, to apply greater
+ * levels of optimization the second time around. You must call
+ * @code{jit_function_set_recompilable} before you compile the function
+ * the first time. On the second time around, build the function's
+ * instructions again, and call @code{jit_compile} a second time.
+ * @end deftypefun
address@hidden/
+int
+jit_compile(jit_function_t func)
+{
+ int result;
+ void *entry_point;
+
+ /* 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 don't need
to recompile */
+ return JIT_RESULT_OK;
+ }
+ else
+ {
+ /* We don't have anything to compile at all */
+ return JIT_RESULT_NULL_FUNCTION;
+ }
+ }
+
+ /* Compile and record the entry point. */
+ result = compile(func, &entry_point);
+ if(result == JIT_RESULT_OK)
+ {
+ func->entry_point = entry_point;
+ func->is_compiled = 1;
+
+ /* Free the builder structure, which we no longer require */
+ _jit_function_free_builder(func);
+ }
+
+ return result;
+}
+
+/*@
+ * @deftypefun int jit_compile_entry (jit_function_t @var{func}, void
address@hidden)
+ * Compile a function to its executable form but do not make it
+ * available for invocation yet. It may be made available later
+ * with @code{jit_function_setup_entry}.
+ * @end deftypefun
address@hidden/
+int
+jit_compile_entry(jit_function_t func, void **entry_point)
+{
+ /* Init entry_point */
+ if(entry_point)
+ {
+ *entry_point = 0;
+ }
+ else
+ {
+ return JIT_RESULT_NULL_REFERENCE;
+ }
+
+ /* 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 don't need
to recompile */
+ *entry_point = func->entry_point;
+ return JIT_RESULT_OK;
+ }
+ else
+ {
+ /* We don't have anything to compile at all */
+ return JIT_RESULT_NULL_FUNCTION;
+ }
+ }
+
+
+ if(func->is_compiled && !func->builder)
+ {
+ /* The function is already compiled, and we don't need to
recompile */
+ *entry_point = func->entry_point;
+ return 1;
+ }
+ if(!func->builder)
+ {
+ /* We don't have anything to compile at all */
+ return 0;
+ }
+
+ /* Compile and return the entry point. */
+ return compile(func, entry_point);
+}
+
+/*@
+ * @deftypefun int jit_function_setup_entry (jit_function_t @var{func}, void
address@hidden)
+ * Make a function compiled with @code{jit_function_compile_entry}
+ * available for invocation and free the resources used for
+ * compilation. If @var{entry_point} is null then it only
+ * frees the resources.
+ * @end deftypefun
address@hidden/
+void
+jit_function_setup_entry(jit_function_t func, void *entry_point)
+{
+ /* Bail out if we have nothing to do */
+ if(!func)
+ {
+ return;
+ }
+ /* Record the entry point */
+ if(entry_point)
+ {
+ func->entry_point = entry_point;
+ func->is_compiled = 1;
+ }
+ _jit_function_free_builder(func);
+}
+
+/*@
+ * @deftypefun int jit_function_compile (jit_function_t @var{func})
+ * Compile a function to its executable form. If the function was
+ * already compiled, then do nothing. Returns zero on error.
+ *
+ * If an error occurs, you can use @code{jit_function_abandon} to
+ * completely destroy the function. Once the function has been compiled
+ * successfully, it can no longer be abandoned.
+ *
+ * Sometimes you may wish to recompile a function, to apply greater
+ * levels of optimization the second time around. You must call
+ * @code{jit_function_set_recompilable} before you compile the function
+ * the first time. On the second time around, build the function's
+ * instructions again, and call @code{jit_function_compile}
+ * a second time.
+ * @end deftypefun
address@hidden/
+int
+jit_function_compile(jit_function_t func)
+{
+ return (JIT_RESULT_OK == jit_compile(func));
+}
+
+/*@
+ * @deftypefun int jit_function_compile_entry (jit_function_t @var{func}, void
address@hidden)
+ * Compile a function to its executable form but do not make it
+ * available for invocation yet. It may be made available later
+ * with @code{jit_function_setup_entry}.
+ * @end deftypefun
address@hidden/
+int
+jit_function_compile_entry(jit_function_t func, void **entry_point)
+{
+ return (JIT_RESULT_OK == jit_compile_entry(func, entry_point));
+}
+
+void *
+_jit_function_compile_on_demand(jit_function_t func)
+{
+ int result;
+ void *entry;
+
+ /* Lock down the context */
+ jit_context_build_start(func->context);
+
+ /* Fast return if we are already compiled */
+ if(func->is_compiled)
+ {
+ jit_context_build_end(func->context);
+ return func->entry_point;
+ }
+
+ if(!func->on_demand)
+ {
+ /* Bail out with an error if the user didn't supply an
+ on-demand compiler */
+ result = JIT_RESULT_COMPILE_ERROR;
+ }
+ else
+ {
+ /* Call the user's on-demand compiler. */
+ result = (func->on_demand)(func);
+ if(result == JIT_RESULT_OK && !func->is_compiled)
+ {
+ /* Compile the function if the user didn't do so */
+ result = compile(func, &entry);
+ if(result == JIT_RESULT_OK)
+ {
+ func->entry_point = entry;
+ func->is_compiled = 1;
+ }
+ }
+ _jit_function_free_builder(func);
+ }
+
+ /* Unlock the context and report the result */
+ jit_context_build_end(func->context);
+ if(result != JIT_RESULT_OK)
+ {
+ jit_exception_builtin(result);
+ /* Normally this should be unreachable but just in case... */
+ return 0;
+ }
+
+ return func->entry_point;
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [dotgnu-pnet-commits] libjit ChangeLog jit/jit-internal.h jit/jit-fun...,
Aleksey Demakov <=