Browse Source

provide for user defined on-demand compilation drivers

cache-refactoring
Aleksey Demakov 18 years ago
parent
commit
e5446328c2
  1. 7
      ChangeLog
  2. 7
      include/jit/jit-common.h
  3. 3
      include/jit/jit-context.h
  4. 5
      include/jit/jit-function.h
  5. 49
      jit/jit-context.c
  6. 222
      jit/jit-function.c
  7. 3
      jit/jit-internal.h

7
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

7
include/jit/jit-common.h

@ -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

3
include/jit/jit-context.h

@ -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;

5
include/jit/jit-function.h

@ -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

49
jit/jit-context.c

@ -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.

222
jit/jit-function.c

@ -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)

3
jit/jit-internal.h

@ -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;
};
/*

Loading…
Cancel
Save