Alien-LibJIT
view release on metacpan or search on metacpan
libjit/jit/jit-function.c view on Meta::CPAN
/*
* jit-function.c - Functions for manipulating function blocks.
*
* 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-apply-func.h"
#include "jit-rules.h"
#include "jit-setjmp.h"
/*@
* @deftypefun jit_function_t jit_function_create (jit_context_t @var{context}, jit_type_t @var{signature})
* Create a new function block and associate it with a JIT context.
* Returns NULL if out of memory.
*
* A function persists for the lifetime of its containing context.
* It initially starts life in the "building" state, where the user
* constructs instructions that represents the function body.
* Once the build process is complete, the user calls
* @code{jit_function_compile} to convert it into its executable form.
*
* It is recommended that you call @code{jit_context_build_start} before
* calling @code{jit_function_create}, and then call
* @code{jit_context_build_end} after you have called
* @code{jit_function_compile}. This will protect the JIT's internal
* data structures within a multi-threaded environment.
* @end deftypefun
@*/
jit_function_t
jit_function_create(jit_context_t context, jit_type_t signature)
{
jit_function_t func;
#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
unsigned char *trampoline;
#endif
/* Acquire the memory context */
_jit_memory_lock(context);
if(!_jit_memory_ensure(context))
{
_jit_memory_unlock(context);
return 0;
}
/* Allocate memory for the function and clear it */
func = _jit_memory_alloc_function(context);
if(!func)
{
_jit_memory_unlock(context);
return 0;
}
#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
trampoline = (unsigned char *) _jit_memory_alloc_trampoline(context);
if(!trampoline)
{
_jit_memory_free_function(context, func);
_jit_memory_unlock(context);
return 0;
}
# if defined(jit_redirector_size)
func->redirector = trampoline;
trampoline += jit_redirector_size;
# endif
# if defined(jit_indirector_size)
func->indirector = trampoline;
# endif
#endif /* !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size)) */
/* Release the memory context */
_jit_memory_unlock(context);
/* 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
libjit/jit/jit-function.c view on Meta::CPAN
jit_memory_pool_free(&(func->builder->edge_pool), 0);
jit_memory_pool_free(&(func->builder->value_pool), _jit_value_free);
jit_memory_pool_free(&(func->builder->meta_pool), _jit_meta_free_one);
jit_free(func->builder->param_values);
jit_free(func->builder->label_info);
jit_free(func->builder);
func->builder = 0;
func->is_optimized = 0;
}
}
void
_jit_function_destroy(jit_function_t func)
{
jit_context_t context;
if(!func)
{
return;
}
context = func->context;
if(func->next)
{
func->next->prev = func->prev;
}
else
{
context->last_function = func->prev;
}
if(func->prev)
{
func->prev->next = func->next;
}
else
{
context->functions = func->next;
}
_jit_function_free_builder(func);
_jit_varint_free_data(func->bytecode_offset);
jit_meta_destroy(&func->meta);
jit_type_free(func->signature);
_jit_memory_lock(context);
#if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
# if defined(jit_redirector_size)
_jit_memory_free_trampoline(context, func->redirector);
# else
_jit_memory_free_trampoline(context, func->indirector);
# endif
#endif
_jit_memory_free_function(context, func);
_jit_memory_unlock(context);
}
/*@
* @deftypefun void jit_function_abandon (jit_function_t @var{func})
* Abandon this function during the build process. This should be called
* when you detect a fatal error that prevents the function from being
* properly built. The @var{func} object is completely destroyed and
* detached from its owning context. The function is left alone if
* it was already compiled.
* @end deftypefun
@*/
void jit_function_abandon(jit_function_t func)
{
if(func && func->builder)
{
if(func->is_compiled)
{
/* We already compiled this function previously, but we
have tried to recompile it with new contents. Throw
away the builder, but keep the original version */
_jit_function_free_builder(func);
}
else
{
/* This function was never compiled, so abandon entirely */
_jit_function_destroy(func);
}
}
}
/*@
* @deftypefun jit_context_t jit_function_get_context (jit_function_t @var{func})
* Get the context associated with a function.
* @end deftypefun
@*/
jit_context_t jit_function_get_context(jit_function_t func)
{
if(func)
{
return func->context;
}
else
{
return 0;
}
}
/*@
* @deftypefun jit_type_t jit_function_get_signature (jit_function_t @var{func})
* Get the signature associated with a function.
* @end deftypefun
@*/
jit_type_t jit_function_get_signature(jit_function_t func)
{
if(func)
{
return func->signature;
}
else
{
return 0;
}
}
/*@
libjit/jit/jit-function.c view on Meta::CPAN
void *
jit_function_to_vtable_pointer(jit_function_t func)
{
#ifdef JIT_BACKEND_INTERP
/* In the interpreted version, the function pointer is used in vtables */
return func;
#else
/* On native platforms, the closure entry point is the vtable pointer */
if(!func)
{
return 0;
}
if(func->indirector && (!func->is_compiled || func->is_recompilable))
{
return func->indirector;
}
return func->entry_point;
#endif
}
/*@
* @deftypefun jit_function_t jit_function_from_vtable_pointer (jit_context_t @var{context}, void *@var{vtable_pointer})
* Convert a vtable_pointer back into a function. Returns NULL if the
* vtable_pointer does not correspond to a function in the specified context.
* @end deftypefun
@*/
jit_function_t
jit_function_from_vtable_pointer(jit_context_t context, void *vtable_pointer)
{
#ifdef JIT_BACKEND_INTERP
/* In the interpreted version, the function pointer is used in vtables */
jit_function_t func = (jit_function_t)vtable_pointer;
if(func && func->context == context)
{
return func;
}
return 0;
#else
void *func_info;
if(!context)
{
return 0;
}
func_info = _jit_memory_find_function_info(context, vtable_pointer);
if(!func_info)
{
return 0;
}
return _jit_memory_get_function(context, func_info);
#endif
}
/*@
* @deftypefun void jit_function_set_on_demand_compiler (jit_function_t @var{func}, jit_on_demand_func @var{on_demand})
* Specify the C function to be called when @var{func} needs to be
* compiled on-demand. This should be set just after the function
* is created, before any build or compile processes begin.
*
* You won't need an on-demand compiler if you always build and compile
* your functions before you call them. But if you can call a function
* before it is built, then you must supply an on-demand compiler.
*
* When on-demand compilation is requested, @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.
* @end enumerate
*
* Normally you will need some kind of context information to tell you
* which higher-level construct is being compiled. You can use the
* metadata facility to add this context information to the function
* 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)
{
if(func)
{
func->on_demand = on_demand;
}
}
/*@
* @deftypefun jit_on_demand_func jit_function_get_on_demand_compiler (jit_function_t @var{func})
* Returns function's on-demand compiler.
* @end deftypefun
@*/
jit_on_demand_func
jit_function_get_on_demand_compiler(jit_function_t func)
{
if(func)
{
( run in 0.953 second using v1.01-cache-2.11-cpan-5735350b133 )