dotgnu-pnet-commits
[Top][All Lists]
Advanced

[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;
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]