]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
provide for user defined on-demand compilation drivers
authorAleksey Demakov <ademakov@gmail.com>
Sun, 4 Feb 2007 14:31:32 +0000 (14:31 +0000)
committerAleksey Demakov <ademakov@gmail.com>
Sun, 4 Feb 2007 14:31:32 +0000 (14:31 +0000)
ChangeLog
include/jit/jit-common.h
include/jit/jit-context.h
include/jit/jit-function.h
jit/jit-context.c
jit/jit-function.c
jit/jit-internal.h

index fef5ee0b11d1b5c901e821b5400dfb627a3b5fab..51f67afe805286bd95b3d27d187ac260a560e106 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2007-02-04  Aleksey Demakov  <ademakov@gmail.com>
+
+       * include/jit/jit-common.h, include/jit/jit-context.h,
+       * include/jit/jit-function.h, jit/jit-internal.h, jit/jit-context.c,
+       * jit/jit-function.c: provide for user defined on-demand compilation
+       driver and delayed function entry point setup.
+
 2007-01-28  Aleksey Demakov  <ademakov@gmail.com>
 
        * jit/jit-reg-alloc.c (_jit_regs_gen, set_regdesc_flags): fix bugs
index bb03f7be63743461b0d07f470205490b0f25c974..edd6633437a646db03ddbebd9ac87613ec00d162 100644 (file)
@@ -88,6 +88,13 @@ typedef void (*jit_meta_free_func)(void *data);
  */
 typedef int (*jit_on_demand_func)(jit_function_t func);
 
+/*
+ * Function that is used to control on demand compilation.
+ * Typically, it should take care of the context locking and unlocking,
+ * calling function's on demand compiler, and final compilation.
+ */
+typedef void *(*jit_on_demand_driver_func)(jit_function_t func);
+
 #ifdef __cplusplus
 };
 #endif
index 03159b69597475902bbfb51619db773895ed3aa2..59452a9d9cf5a335b00db12c20ad75a6da0b2d4f 100644 (file)
@@ -32,6 +32,9 @@ void jit_context_destroy(jit_context_t context) JIT_NOTHROW;
 int jit_context_supports_threads(jit_context_t context) JIT_NOTHROW;
 void jit_context_build_start(jit_context_t context) JIT_NOTHROW;
 void jit_context_build_end(jit_context_t context) JIT_NOTHROW;
+void jit_context_set_on_demand_driver(
+       jit_context_t context,
+       jit_on_demand_driver_func driver) JIT_NOTHROW;
 int jit_context_set_meta
        (jit_context_t context, int type, void *data,
         jit_meta_free_func free_data) JIT_NOTHROW;
index 7e5e7a999e6726742c415bca4ff149ed89aa57a2..b9d6db78b45ade77deee0f05a3a09dc5582f791c 100644 (file)
@@ -53,6 +53,8 @@ int jit_function_is_compiled(jit_function_t func) JIT_NOTHROW;
 void jit_function_set_recompilable(jit_function_t func) JIT_NOTHROW;
 void jit_function_clear_recompilable(jit_function_t func) JIT_NOTHROW;
 int jit_function_is_recompilable(jit_function_t func) JIT_NOTHROW;
+int jit_function_compile_entry(jit_function_t func, void **entry_point) JIT_NOTHROW;
+void jit_function_setup_entry(jit_function_t func, void *entry_point) JIT_NOTHROW;
 void *jit_function_to_closure(jit_function_t func) JIT_NOTHROW;
 jit_function_t jit_function_from_closure
        (jit_context_t context, void *closure) JIT_NOTHROW;
@@ -62,7 +64,8 @@ void *jit_function_to_vtable_pointer(jit_function_t func) JIT_NOTHROW;
 jit_function_t jit_function_from_vtable_pointer
        (jit_context_t context, void *vtable_pointer) JIT_NOTHROW;
 void jit_function_set_on_demand_compiler
-               (jit_function_t func, jit_on_demand_func on_demand) JIT_NOTHROW;
+       (jit_function_t func, jit_on_demand_func on_demand) JIT_NOTHROW;
+jit_on_demand_func jit_function_get_on_demand_compiler(jit_function_t func) JIT_NOTHROW;
 int jit_function_apply
        (jit_function_t func, void **args, void *return_area);
 int jit_function_apply_vararg
index d80ed06ee1ccb87cc15d251797be0b1697ee96a6..8e0f0f29dea1f602d047617483c1e9301f7228a2 100644 (file)
@@ -88,6 +88,7 @@ jit_context_t jit_context_create(void)
        jit_mutex_create(&(context->cache_lock));
        context->functions = 0;
        context->last_function = 0;
+       context->on_demand_driver = 0;
        return context;
 }
 
@@ -158,6 +159,54 @@ void jit_context_build_end(jit_context_t context)
        jit_mutex_unlock(&(context->builder_lock));
 }
 
+/*@
+ * @deftypefun void jit_context_set_on_demand_driver (jit_context_t context, jit_on_demand_driver_func driver)
+ * Specify the C function to be called to drive on-demand compilation.
+ *
+ * When on-demand compilation is requested the default driver provided by
+ * @code{libjit} takes the following actions:
+ *
+ * @enumerate
+ * @item
+ * The context is locked by calling @code{jit_context_build_start}.
+ *
+ * @item
+ * If the function has already been compiled, @code{libjit} unlocks
+ * the context and returns immediately.  This can happen because of race
+ * conditions between threads: some other thread may have beaten us
+ * to the on-demand compiler.
+ *
+ * @item
+ * The user's on-demand compiler is called.  It is responsible for building
+ * the instructions in the function's body.  It should return one of the
+ * result codes @code{JIT_RESULT_OK}, @code{JIT_RESULT_COMPILE_ERROR},
+ * or @code{JIT_RESULT_OUT_OF_MEMORY}.
+ *
+ * @item
+ * If the user's on-demand function hasn't already done so, @code{libjit}
+ * will call @code{jit_function_compile} to compile the function.
+ *
+ * @item
+ * The context is unlocked by calling @code{jit_context_build_end} and
+ * @code{libjit} jumps to the newly-compiled entry point.  If an error
+ * occurs, a built-in exception of type @code{JIT_RESULT_COMPILE_ERROR}
+ * or @code{JIT_RESULT_OUT_OF_MEMORY} will be thrown.
+ *
+ * @item
+ * The entry point of the compiled function is returned from the
+ * driver.
+ * @end enumerate
+ *
+ * You may need to provide your own driver if some additional actions
+ * are required.
+ *
+ * @end deftypefun
+@*/
+void jit_context_set_on_demand_driver(jit_context_t context, jit_on_demand_driver_func driver)
+{
+       context->on_demand_driver = driver;
+}
+
 /*@
  * @deftypefun int jit_context_set_meta (jit_context_t context, int type, {void *} data, jit_meta_free_func free_data)
  * Tag a context with some metadata.  Returns zero if out of memory.
index ffb84bde2102a7c7aabe64db1704682e972f9223..e166398dddd73eee867d83a902c5e7519ca901ee 100644 (file)
@@ -49,6 +49,9 @@
 jit_function_t jit_function_create(jit_context_t context, jit_type_t signature)
 {
        jit_function_t func;
+#if defined(jit_redirector_size)
+       jit_on_demand_driver_func on_demand_driver;
+#endif
 #if defined(jit_redirector_size) || defined(jit_indirector_size)
        jit_cache_t cache;
 #endif
@@ -104,20 +107,24 @@ jit_function_t jit_function_create(jit_context_t context, jit_type_t signature)
        func->context = context;
        func->signature = jit_type_copy(signature);
 
-#if defined(jit_redirector_size) && !defined(JIT_BACKEND_INTERP)
+#if defined(jit_redirector_size)
        /* If we aren't using interpretation, then point the function's
           initial entry point at the redirector, which in turn will
           invoke the on-demand compiler */
+       on_demand_driver = context->on_demand_driver;
+       if(!on_demand_driver)
+       {
+               on_demand_driver = _jit_function_compile_on_demand;
+       }
        func->entry_point = _jit_create_redirector
-               (func->redirector, (void *)_jit_function_compile_on_demand,
+               (func->redirector, (void *) on_demand_driver,
                 func, jit_type_get_abi(signature));
        jit_flush_exec(func->redirector, jit_redirector_size);
-
+#endif
 # if defined(jit_indirector_size)
        _jit_create_indirector(func->indirector, (void**) &(func->entry_point));
        jit_flush_exec(func->indirector, jit_indirector_size);
 # endif
-#endif
 
        /* Add the function to the context list */
        func->next = 0;
@@ -618,34 +625,10 @@ static void compile_block(jit_gencode_t gen, jit_function_t func,
 }
 
 /*
- * Information that is stored for an exception region in the cache.
+ * Compile a function and return its entry point.
  */
-typedef struct jit_cache_eh *jit_cache_eh_t;
-struct jit_cache_eh
-{
-       jit_label_t             handler_label;
-       unsigned char  *handler;
-       jit_cache_eh_t  previous;
-};
-
-/*@
- * @deftypefun int jit_function_compile (jit_function_t 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
-@*/
-int jit_function_compile(jit_function_t func)
+static int
+compile(jit_function_t func, void **entry_point)
 {
        struct jit_gencode gen;
        jit_cache_t cache;
@@ -657,22 +640,6 @@ int jit_function_compile(jit_function_t func)
        int have_prolog;
 #endif
 
-       /* 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;
-       }
-
        /* We need the cache lock while we are compiling the function */
        jit_mutex_lock(&(func->context->cache_lock));
 
@@ -809,7 +776,6 @@ int jit_function_compile(jit_function_t func)
                                block->fixup_absolute_list = 0;
                        }
                }
-
        }
        while(result == JIT_CACHE_END_RESTART);
 
@@ -841,18 +807,146 @@ int jit_function_compile(jit_function_t func)
                func->no_return = 1;
        }
 
-       /* Record the entry point */
-       func->entry_point = start;
-       func->is_compiled = 1;
-
        /* Free the builder structure, which we no longer require */
        _jit_function_free_builder(func);
 
        /* The function has been compiled successfully */
        jit_mutex_unlock(&(func->context->cache_lock));
+
+       /* 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;
+struct jit_cache_eh
+{
+       jit_label_t             handler_label;
+       unsigned char  *handler;
+       jit_cache_eh_t  previous;
+};
+
+/*@
+ * @deftypefun int jit_function_compile (jit_function_t 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
+@*/
+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 func, void **entry_point)
+ * 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
+@*/
+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 */
+               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 func, void *entry_point)
+ * Make a function compiled with @code{jit_function_compile_entry}
+ * available for invocation and free the resources used for
+ * compilation. If @code{entry_point} is null then it only
+ * frees the resources.
+ * @end deftypefun
+@*/
+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_recompile (jit_function_t func)
  * Force @code{func} to be recompiled, by calling its on-demand
@@ -1202,10 +1296,28 @@ jit_function_t jit_function_from_vtable_pointer(jit_context_t context, void *vta
  * just after you create it with @code{jit_function_create}.
  * @end deftypefun
 @*/
-void jit_function_set_on_demand_compiler
-               (jit_function_t func, jit_on_demand_func on_demand)
+void
+jit_function_set_on_demand_compiler(jit_function_t func, jit_on_demand_func on_demand)
+{
+       if(func)
+       {
+               func->on_demand = on_demand;
+       }
+}
+
+/*@
+ * @deftypefun jit_on_demand_func jit_function_get_on_demand_compiler (jit_function_t func)
+ * Returns function's on-demand compiler.
+ * @end deftypefun
+@*/
+jit_on_demand_func
+jit_function_get_on_demand_compiler(jit_function_t func)
 {
-       func->on_demand = on_demand;
+       if(func)
+       {
+               return func->on_demand;
+       }
+       return 0;
 }
 
 void *_jit_function_compile_on_demand(jit_function_t func)
index 409b1517cf34409751df33338b77c3c6bbd41e1c..91d1828857f6a9306cf5af31e569fc89b26993b0 100644 (file)
@@ -478,6 +478,9 @@ struct _jit_context
        /* Debugger support */
        jit_debugger_hook_func debug_hook;
        jit_debugger_t          debugger;
+
+       /* On-demand compilation driver */
+       jit_on_demand_driver_func       on_demand_driver;
 };
 
 /*