Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jit/jit-context.c  view on Meta::CPAN

/*
 * jit-context.c - Functions for manipulating JIT contexts.
 *
 * Copyright (C) 2004  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"

/*@

Everything that is done with @code{libjit} is done relative to a context.
It is possible to have more than one context at a time - each acts as an
independent environment for compiling and managing code.

When you want to compile a function, you create it with
@code{jit_function_create}, and then populate its body with
calls to the value and instruction functions.  See @xref{Values}, and
@ref{Instructions} for more information on how to do this.

@section Using libjit in a multi-threaded environment

The library does not handle the creation, management, and destruction
of threads itself.  It is up to the front-end environment to take
care of that.  But the library is thread-aware, as long as you take
some very simple steps.

In a multi-threaded environment, you must ensure that only one
thread can build functions at any one time.  Otherwise the
JIT's context may become corrupted.  To protect the system,
you should call @code{jit_context_build_start} before
creating the function.  And then call @code{jit_context_build_end}
once the function has been fully compiled.

You can compile multiple functions during the one build process
if you wish, which is the normal case when compiling a class.

It is usually a good idea to suspend the finalization of
garbage-collected objects while function building is in progress.
Otherwise you may get a deadlock when the finalizer thread tries
to call the builder to compile a finalization routine.  Suspension
of finalization is the responsibility of the caller.

@section Context functions
@cindex jit-context.h

The following functions are available to create, manage, and
ultimately destroy JIT contexts:

@*/

/*@
 * @deftypefun jit_context_t jit_context_create (void)
 * Create a new context block for the JIT.  Returns NULL
 * if out of memory.
 * @end deftypefun
@*/
jit_context_t
jit_context_create(void)
{
	jit_context_t context;

	/* Make sure that the JIT is initialized */
	jit_init();

	/* Allocate memory for the context */
	context = jit_cnew(struct _jit_context);
	if(!context)
	{
		return 0;
	}

	/* Initialize the context and return it */
	jit_mutex_create(&context->memory_lock);
	jit_mutex_create(&context->builder_lock);
	context->functions = 0;
	context->last_function = 0;
	context->on_demand_driver = _jit_function_compile_on_demand;
	context->memory_manager = jit_default_memory_manager();
	return context;
}

/*@
 * @deftypefun void jit_context_destroy (jit_context_t @var{context})
 * Destroy a JIT context block and everything that is associated with it.
 * It is very important that no threads within the program are currently
 * running compiled code when this function is called.
 * @end deftypefun
@*/
void
jit_context_destroy(jit_context_t context)
{
	int sym;

	if(!context)
	{
		return;
	}

	for(sym = 0; sym < context->num_registered_symbols; ++sym)
	{
		jit_free(context->registered_symbols[sym]);
	}
	jit_free(context->registered_symbols);

	while(context->functions != 0)
	{
		_jit_function_destroy(context->functions);
	}

	_jit_memory_destroy(context);

	jit_mutex_destroy(&context->memory_lock);
	jit_mutex_destroy(&context->builder_lock);

	jit_free(context);
}

/*@
 * @deftypefun void jit_context_build_start (jit_context_t @var{context})
 * This routine should be called before you start building a function
 * to be JIT'ed.  It acquires a lock on the context to prevent other
 * threads from accessing the build process, since only one thread
 * can be performing build operations at any one time.
 * @end deftypefun
@*/
void
jit_context_build_start(jit_context_t context)
{
	jit_mutex_lock(&context->builder_lock);
}

/*@
 * @deftypefun void jit_context_build_end (jit_context_t @var{context})
 * This routine should be called once you have finished building
 * and compiling a function and are ready to resume normal execution.
 * This routine will release the build lock, allowing other threads
 * that are waiting on the builder to proceed.
 * @end deftypefun
@*/
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 @var{context}, jit_on_demand_driver_func @var{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)
{
	if (driver)
	{
		context->on_demand_driver = driver;
	}
	else
	{
		context->on_demand_driver = _jit_function_compile_on_demand;
	}
}

/*@
 * @deftypefun void jit_context_set_memory_manager (jit_context_t @var{context}, jit_memory_manager_t @var{manager})
 * Specify the memory manager plug-in.
 * @end deftypefun
@*/
void
jit_context_set_memory_manager(jit_context_t context, jit_memory_manager_t manager)
{
	/* Bail out if there is already an established memory context */
	if (context->memory_context)
	{
		return;
	}

	/* Set the context memory manager */
	if (manager)
	{
		context->memory_manager = manager;
	}
	else



( run in 0.654 second using v1.01-cache-2.11-cpan-97f6503c9c8 )