Alien-LibJIT

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

libjit/jit/jit-rules-x86-64.h
libjit/jit/jit-rules-x86-64.ins
libjit/jit/jit-rules-x86.c
libjit/jit/jit-rules-x86.h
libjit/jit/jit-rules-x86.ins
libjit/jit/jit-rules.c
libjit/jit/jit-rules.h
libjit/jit/jit-setjmp.h
libjit/jit/jit-signal.c
libjit/jit/jit-symbol.c
libjit/jit/jit-thread.c
libjit/jit/jit-thread.h
libjit/jit/jit-type.c
libjit/jit/jit-unwind.c
libjit/jit/jit-util.c
libjit/jit/jit-value.c
libjit/jit/jit-varint.c
libjit/jit/jit-varint.h
libjit/jit/jit-vmem.c
libjit/jit/jit-walk.c
libjit/jit/mklabel.sh
libjit/jitdynamic/Makefile.am

inc/Module/Build/AlienLibJIT.pm  view on Meta::CPAN

our $LIBJIT_HOME = 'libjit';
our $LIBJIT_M4 = 'm4';
our $LIBJIT_INCLUDE = File::Spec->catfile($LIBJIT_HOME, 'include');
our $LIBJIT_RESULT = File::Spec->catfile($LIBJIT_HOME, 'jit', '.libs', 'libjit'.$Config::Config{lib_ext});

sub new {
    my ($class, @args) = @_;

    return $class->SUPER::new(
        #include_dirs       => [$LIBJIT_INCLUDE],
        #extra_linker_flags => [$LIBJIT_RESULT, '-lpthread'],
        @args,
    );
}

sub ACTION_code {
    my ($self) = @_;

    $self->depends_on('libjit');

    return $self->SUPER::ACTION_code(@_);

libjit/ChangeLog  view on Meta::CPAN

	* jit/jit-cache.h, jit/jit-cache.c (_jit_cache_get_method_list):
	function removed.

2011-07-27  Aleksey Demakov  <ademakov@gmail.com>

	* jit/jit-config.h: added new file as central location for all
	platform config macros deduced from ./configure and cpp.
	* jit/Makefile.am: add jit-config.h.

	* include/jit/jit-context.h, jit/jit-context.c
	(jit_context_supports_threads): removed.
	* include/jit/jit-init.h, jit/jit-init.c (jit_supports_threads):
	added function to replace jit_context_supports_threads.

	* include/jit/jit-init.h, jit/jit-init.c
	(jit_supports_virtual_memory): added new function to check if
	the jit supports virtual memory routines.

	* include/jit/jit-vmem.h, jit/jit-vmem.c (jit_vmem_init)
	(jit_vmem_page_size, jit_vmem_round_up, jit_vmem_round_down)
	(jit_vmem_reserve, jit_vmem_reserve_committed, jit_vmem_release)
	(jit_vmem_commit, jit_vmem_decommit, jit_vmem_protect): added new
	files with virtual memory routines.

libjit/ChangeLog  view on Meta::CPAN

	register class which means all registers in the class are clobbered.
	Remove "only", "spill_before", "unary", and "binary" keywords.
	Replace "unary_note" and "binary_note" with "note". Also replace
	"unary_branch" and "binary_branch" with "branch".

	* jit/jit-rules-alpha.ins, jit/jit-rules-x86.ins: update according
	to the new rule syntax.

2006-12-20  Aleksey Demakov  <ademakov@gmail.com>

	* jit/jit-thread.h, jit/jit-thread.c: add _jit_global_lock mutex.
	* jit/jit-init.c (jit_init): make sure that initialization is done
	  only once.

2006-12-17  Klaus Treichel  <ktreichel@web.de>

	* include/jit/jit-function.h, jit/jit-function.c: Add the function
	jit_function_from_vtable_pointer to convert a vtable pointer back to
	the jit_function_t.

2006-11-29  Aleksey Demakov  <ademakov@gmail.com>

libjit/ChangeLog  view on Meta::CPAN

	destination pointers in "store_relative" instructions, because
	otherwise the register allocator gets confused.

2004-10-29  Peter Lund <firefly@diku.dk>

	* doc/libjit.3: fix manpage formatting issues. (patch attached
	to bug #10779, Gopal).

2004-10-28  Rhys Weatherley  <rweather@southern-storm.com.au>

	* configure.in, jit/jit-debugger.c, jit/jit-thread.c,
	jit/jit-thread.h: implement some of the locking code
	for the debugging API.

2004-10-12  Evin Robertson  <evin@users.sourceforge.net>

	* jit/jit-rules-x86.c (output_branch): correct the offset
	when outputting a long-form backward branch.

	* tests/Makefile.am, tests/loop.pas: test case for the
	long-form backward branch bug.

libjit/ChangeLog  view on Meta::CPAN


2004-05-20  Rhys Weatherley  <rweather@southern-storm.com.au>

	* include/jit/jit-value.h, jit/jit-insn.c, jit/jit-value.c:
	convert constant conditional branches such as "if true goto L" into
	unconditional branches.

	* jit/jit-block.c, jit/jit-internal.h, jit/jit-live.c,
	jit/jit-rules-interp.c: perform peephole optimization of
	branches to branches before live variable analysis, so that
	the back ends don't need to worry about jump threading.

	* jit/jit-block.c, jit/jit-live.c: treat dead blocks as empty
	when peepholing branches to the next block.

2004-05-15  Rhys Weatherley  <rweather@southern-storm.com.au>

	* tools/gen-apply.c: fix a macro generation bug for Win32 systems.

	* jit/jit-reg-alloc.c: fix a compile bug.

libjit/configure.ac  view on Meta::CPAN

	CXXFLAGS="/nologo /QIfist /EHs"
fi

dnl Check for file extensions.
AC_EXEEXT
AC_OBJEXT

dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(string.h strings.h memory.h stdlib.h stdarg.h varargs.h)
AC_CHECK_HEADERS(tgmath.h math.h ieeefp.h pthread.h unistd.h sys/types.h)
AC_CHECK_HEADERS(sys/mman.h fcntl.h dlfcn.h sys/cygwin.h sys/stat.h)
AC_CHECK_HEADERS(time.h sys/time.h)

dnl A macro that helps detect the size of types in a cross-compile environment.
AC_DEFUN([AC_COMPILE_CHECK_SIZEOF],
[changequote(<<, >>)dnl
dnl The name to #define.
define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
dnl The cache variable name.
define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl

libjit/configure.ac  view on Meta::CPAN

	esac
fi
AC_SUBST(libdir)

dnl Checks for library functions.
if test "x$suppress_libm" = "xno" ; then
	AC_CHECK_LIB(m, sin)
fi
if test "x$platform_win32" = "xno" ; then
	AC_CHECK_LIB(dl, dlopen)
	AC_CHECK_LIB(pthread, pthread_create)
fi
AC_FUNC_MEMCMP
AC_CHECK_FUNCS(memset memcmp memchr memcpy memmove bcopy bzero bcmp)
AC_CHECK_FUNCS(strlen strcpy strcat strncpy strcmp strncmp)
AC_CHECK_FUNCS(strchr strrchr vsprintf vsnprintf _vsnprintf getpagesize)
AC_CHECK_FUNCS(isnan isinf finite fmod remainder drem ceil floor)
AC_CHECK_FUNCS(acos asin atan atan2 cos cosh exp log log10 pow)
AC_CHECK_FUNCS(sin sinh sqrt tan tanh)
AC_CHECK_FUNCS(isnanf isinff finitef fmodf remainderf dremf ceilf floorf)
AC_CHECK_FUNCS(acosf asinf atanf atan2f cosf coshf expf logf log10f powf)

libjit/doc/libjit.texi  view on Meta::CPAN

Almost everything that is done with @code{libjit} is done relative
to a context.  In particular, a context holds all of the functions
that you have built and compiled.

You can have multiple contexts at any one time, but normally you will
only need one.  Multiple contexts may be useful if you wish to
run multiple virtual machines side by side in the same process,
without them interfering with each other.

Whenever we are constructing a function, we need to lock down the
context to prevent multiple threads from using the builder at a time:

@example
jit_context_build_start(context);
@end example

The next step is to construct the function object that will represent
our @code{mul_add} function:

@example
jit_function_t function;

libjit/doc/libjit.texi  view on Meta::CPAN

@example
jit_function_compile(function);
jit_context_build_end(context);
@end example

As a side-effect, this will discard all of the memory associated with
the values and instructions that we constructed while building the
function.  They are no longer required, because we now have the
executable form that we require.

We also unlock the context, because it is now safe for other threads
to access the function building process.

Up until this point, we haven't executed the @code{mul_add} function.
All we have done is build and compile it, ready for execution.  To execute it,
we call @code{jit_function_apply}:

@example
jit_int arg1, arg2, arg3;
void *args[3];
jit_int result;

libjit/doc/libjit.texi  view on Meta::CPAN

to take care of context locking:

@example
jit_context_build_start(context);
jit_function_get_on_demand_compiler(function)(function);
jit_function_compile(function);
jit_context_build_end(context);
@end example

After this, any existing references to the function will be redirected
to the new version.  However, if some thread is currently executing the
previous version, then it will keep doing so until the previous version
exits.  Only after that will subsequent calls go to the new version.

In this tutorial, we use the same on-demand compiler when we
recompile @code{mul_add}.  In a real program, you would probably call
@code{jit_function_set_on_demand_compiler} to set a new on-demand
compiler that performs greater levels of optimization.

If you no longer intend to recompile the function, you should call
@code{jit_function_clear_recompilable} so that @code{libjit} can

libjit/include/jit/jit-debugger.h  view on Meta::CPAN

#ifndef	_JIT_DEBUGGER_H
#define	_JIT_DEBUGGER_H

#include <jit/jit-common.h>

#ifdef	__cplusplus
extern	"C" {
#endif

typedef struct jit_debugger *jit_debugger_t;
typedef jit_nint jit_debugger_thread_id_t;
typedef jit_nint jit_debugger_breakpoint_id_t;

typedef struct jit_debugger_event
{
	int								type;
	jit_debugger_thread_id_t		thread;
	jit_function_t					function;
	jit_nint						data1;
	jit_nint						data2;
	jit_debugger_breakpoint_id_t	id;
	jit_stack_trace_t				trace;

} jit_debugger_event_t;

#define	JIT_DEBUGGER_TYPE_QUIT				0
#define	JIT_DEBUGGER_TYPE_HARD_BREAKPOINT	1
#define	JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT	2
#define	JIT_DEBUGGER_TYPE_USER_BREAKPOINT	3
#define	JIT_DEBUGGER_TYPE_ATTACH_THREAD		4
#define	JIT_DEBUGGER_TYPE_DETACH_THREAD		5

typedef struct jit_debugger_breakpoint_info
{
	int								flags;
	jit_debugger_thread_id_t		thread;
	jit_function_t					function;
	jit_nint						data1;
	jit_nint						data2;

} *jit_debugger_breakpoint_info_t;

#define	JIT_DEBUGGER_FLAG_THREAD		(1 << 0)
#define	JIT_DEBUGGER_FLAG_FUNCTION		(1 << 1)
#define	JIT_DEBUGGER_FLAG_DATA1			(1 << 2)
#define	JIT_DEBUGGER_FLAG_DATA2			(1 << 3)

libjit/include/jit/jit-debugger.h  view on Meta::CPAN

	(jit_function_t func, jit_nint data1, jit_nint data2);

int jit_debugging_possible(void) JIT_NOTHROW;

jit_debugger_t jit_debugger_create(jit_context_t context) JIT_NOTHROW;
void jit_debugger_destroy(jit_debugger_t dbg) JIT_NOTHROW;

jit_context_t jit_debugger_get_context(jit_debugger_t dbg) JIT_NOTHROW;
jit_debugger_t jit_debugger_from_context(jit_context_t context) JIT_NOTHROW;

jit_debugger_thread_id_t jit_debugger_get_self(jit_debugger_t dbg) JIT_NOTHROW;
jit_debugger_thread_id_t jit_debugger_get_thread
		(jit_debugger_t dbg, const void *native_thread) JIT_NOTHROW;
int jit_debugger_get_native_thread
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread,
		 void *native_thread) JIT_NOTHROW;
void jit_debugger_set_breakable
		(jit_debugger_t dbg, const void *native_thread, int flag) JIT_NOTHROW;

void jit_debugger_attach_self
		(jit_debugger_t dbg, int stop_immediately) JIT_NOTHROW;
void jit_debugger_detach_self(jit_debugger_t dbg) JIT_NOTHROW;

int jit_debugger_wait_event
		(jit_debugger_t dbg, jit_debugger_event_t *event,
		 jit_int timeout) JIT_NOTHROW;

jit_debugger_breakpoint_id_t jit_debugger_add_breakpoint
		(jit_debugger_t dbg, jit_debugger_breakpoint_info_t info) JIT_NOTHROW;
void jit_debugger_remove_breakpoint
		(jit_debugger_t dbg, jit_debugger_breakpoint_id_t id) JIT_NOTHROW;
void jit_debugger_remove_all_breakpoints(jit_debugger_t dbg) JIT_NOTHROW;

int jit_debugger_is_alive
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
int jit_debugger_is_running
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
void jit_debugger_run
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
void jit_debugger_step
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
void jit_debugger_next
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;
void jit_debugger_finish
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread) JIT_NOTHROW;

void jit_debugger_break(jit_debugger_t dbg) JIT_NOTHROW;

void jit_debugger_quit(jit_debugger_t dbg) JIT_NOTHROW;

jit_debugger_hook_func jit_debugger_set_hook
		(jit_context_t context, jit_debugger_hook_func hook);

#ifdef	__cplusplus
};

libjit/include/jit/jit-init.h  view on Meta::CPAN

#include <jit/jit-defs.h>

#ifdef	__cplusplus
extern	"C" {
#endif

void jit_init(void) JIT_NOTHROW;

int jit_uses_interpreter(void) JIT_NOTHROW;

int jit_supports_threads(void) JIT_NOTHROW;

int jit_supports_virtual_memory(void) JIT_NOTHROW;

int jit_supports_closures(void);

unsigned int jit_get_closure_size(void);
unsigned int jit_get_closure_alignment(void);
unsigned int jit_get_trampoline_size(void);
unsigned int jit_get_trampoline_alignment(void);

libjit/jit/Makefile.am  view on Meta::CPAN

	jit-rules-interp.h \
	jit-rules-arm.h \
	jit-rules-arm.c \
	jit-rules-x86.h \
	jit-rules-x86.c \
	jit-rules-x86-64.h \
	jit-rules-x86-64.c \
	jit-setjmp.h \
	jit-signal.c \
	jit-symbol.c \
	jit-thread.c \
	jit-thread.h \
	jit-type.c \
	jit-unwind.c \
	jit-util.c \
	jit-value.c \
	jit-varint.h \
	jit-varint.c \
	jit-vmem.c \
	jit-walk.c

EXTRA_DIST = \

libjit/jit/jit-config.h  view on Meta::CPAN

#elif defined(_WIN32) || defined(WIN32)
# define JIT_WIN32_NATIVE	1
# define JIT_WIN32_PLATFORM	1
#elif defined(__APPLE__) && defined(__MACH__)
# define JIT_DARWIN_PLATFORM	1
#elif defined(__linux__)
# define JIT_LINUX_PLATFORM	1
#endif

/*
 * Determine the type of threading library that we are using.
 */
#if defined(HAVE_PTHREAD_H) && defined(HAVE_LIBPTHREAD)
# define JIT_THREADS_SUPPORTED	1
# define JIT_THREADS_PTHREAD	1
#elif defined(JIT_WIN32_PLATFORM)
# define JIT_THREADS_SUPPORTED	1
# define JIT_THREADS_WIN32	1
#else
# define JIT_THREADS_SUPPORTED	0
#endif

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


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:

@*/

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

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

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

	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);
}

/*@

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

 * 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}

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

function exit, etc).
@end deftypefun

There are two ways for a front end to receive notification about breakpoints.
The bulk of this chapter describes the @code{jit_debugger_t} interface,
which handles most of the ugly details.  In addition, a low-level "debug hook
mechanism" is provided for front ends that wish more control over the
process.  The debug hook mechanism is described below, under the
@code{jit_debugger_set_hook} function.

This debugger implementation requires a threading system to work
successfully.  At least two threads are required, in addition to those of
the program being debugged:

@enumerate
@item
Event thread which calls @code{jit_debugger_wait_event} to receive
notifications of breakpoints and other interesting events.

@item
User interface thread which calls functions like @code{jit_debugger_run},
@code{jit_debugger_step}, etc, to control the debug process.
@end enumerate

These two threads should be set to "unbreakable" with a call to
@code{jit_debugger_set_breakable}.  This prevents them from accidentally
stopping at a breakpoint, which would cause a system deadlock.
Other housekeeping threads, such as a finalization thread, should
also be set to "unbreakable" for the same reason.

@noindent
Events have the following members:

@table @code
@item type
The type of event (see the next table for details).

@item thread
The thread that the event occurred on.

@item function
The function that the breakpoint occurred within.

@item data1
@itemx data2
The data values at the breakpoint.  These values are inserted into
the function's code with @code{jit_insn_mark_breakpoint}.

@item id

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

occurred.  This value is automatically freed upon the next call
to @code{jit_debugger_wait_event}.  If you wish to preserve the
value, then you must call @code{jit_stack_trace_copy}.
@end table

@noindent
The following event types are currently supported:

@table @code
@item JIT_DEBUGGER_TYPE_QUIT
A thread called @code{jit_debugger_quit}, indicating that it wanted the
event thread to terminate.

@item JIT_DEBUGGER_TYPE_HARD_BREAKPOINT
A thread stopped at a hard breakpoint.  That is, a breakpoint defined
by a call to @code{jit_debugger_add_breakpoint}.

@item JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT
A thread stopped at a breakpoint that wasn't explicitly defined by
a call to @code{jit_debugger_add_breakpoint}.  This typicaly results
from a call to a "step" function like @code{jit_debugger_step}, where
execution stopped at the next line but there isn't an explicit breakpoint
on that line.

@item JIT_DEBUGGER_TYPE_USER_BREAKPOINT
A thread stopped because of a call to @code{jit_debugger_break}.

@item JIT_DEBUGGER_TYPE_ATTACH_THREAD
A thread called @code{jit_debugger_attach_self}.  The @code{data1} field
of the event is set to the value of @code{stop_immediately} for the call.

@item JIT_DEBUGGER_TYPE_DETACH_THREAD
A thread called @code{jit_debugger_detach_self}.
@end table

@deftypefun int jit_insn_mark_breakpoint_variable (jit_function_t @var{func}, jit_value_t @var{data1}, jit_value_t @var{data2})
This function is similar to @code{jit_insn_mark_breakpoint} except that values
in @var{data1} and @var{data2} can be computed at runtime. You can use this
function for example to get address of local variable.
@end deftypefun

@*/

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

 * Run types.
 */
#define	JIT_RUN_TYPE_STOPPED		0
#define	JIT_RUN_TYPE_CONTINUE		1
#define	JIT_RUN_TYPE_STEP			2
#define	JIT_RUN_TYPE_NEXT			3
#define	JIT_RUN_TYPE_FINISH			4
#define	JIT_RUN_TYPE_DETACHED		5

/*
 * Information about a thread that is under the control of the debugger.
 */
typedef struct jit_debugger_thread
{
	struct jit_debugger_thread *next;
	jit_debugger_thread_id_t	id;
	jit_thread_id_t				native_id;
	int				   volatile	run_type;
	jit_function_t				find_func;
	jit_nint					last_data1;
	jit_nint					last_func_data1;
	int							breakable;

} *jit_debugger_thread_t;

/*
 * Structure of a debugger instance.
 */
struct jit_debugger
{
	jit_monitor_t				  queue_lock;
	jit_monitor_t				  run_lock;
	jit_context_t				  context;
	jit_debugger_linked_event_t * volatile events;

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

 * Lock the debugger object.
 */
#define	lock_debugger(dbg)		jit_monitor_lock(&((dbg)->run_lock))

/*
 * Unlock the debugger object.
 */
#define	unlock_debugger(dbg)	jit_monitor_unlock(&((dbg)->run_lock))

/*
 * Suspend the current thread until it is marked as running again.
 * It is assumed that the debugger's monitor lock has been acquired.
 */
static void suspend_thread(jit_debugger_t dbg, jit_debugger_thread_t thread)
{
	while(thread->run_type == JIT_RUN_TYPE_STOPPED)
	{
		jit_monitor_wait(&(dbg->run_lock), -1);
	}
}

/*
 * Wake all threads that are waiting on the debugger's monitor.
 */
#define	wakeup_all(dbg)		jit_monitor_signal_all(&((dbg)->run_lock))

/*
 * Get the information block for the current thread.
 */
static jit_debugger_thread_t get_current_thread(jit_debugger_t dbg)
{
	/* TODO */
	return 0;
}

/*
 * Get the information block for a specific thread.
 */
static jit_debugger_thread_t get_specific_thread
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
{
	/* TODO */
	return 0;
}

/*
 * Allocate space for a new event on the event queue.
 */
#define	alloc_event()		\
		((jit_debugger_event_t *)jit_cnew(jit_debugger_linked_event_t))

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

	{
		dbg->events = event;
	}
	dbg->last_event = event;
	jit_monitor_signal(&(dbg->queue_lock));
	jit_monitor_unlock(&(dbg->queue_lock));
}

/*@
 * @deftypefun int jit_debugging_possible (void)
 * Determine if debugging is possible.  i.e. that threading is available
 * and compatible with the debugger's requirements.
 * @end deftypefun
@*/
int jit_debugging_possible(void)
{
	return JIT_THREADS_SUPPORTED;
}

/*@
 * @deftypefun jit_debugger_t jit_debugger_create (jit_context_t @var{context})

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

	{
		return context->debugger;
	}
	else
	{
		return 0;
	}
}

/*@
 * @deftypefun jit_debugger_thread_id_t jit_debugger_get_self (jit_debugger_t @var{dbg})
 * Get the thread identifier associated with the current thread.
 * The return values are normally values like 1, 2, 3, etc, allowing
 * the user interface to report messages like "thread 3 has stopped
 * at a breakpoint".
 * @end deftypefun
@*/
jit_debugger_thread_id_t jit_debugger_get_self(jit_debugger_t dbg)
{
	jit_thread_id_t id = jit_thread_self();
	jit_debugger_thread_id_t thread;
	thread = jit_debugger_get_thread(dbg, &id);
	jit_thread_release_self(id);
	return thread;
}

/*@
 * @deftypefun jit_debugger_thread_id_t jit_debugger_get_thread (jit_debugger_t @var{dbg}, const void *@var{native_thread})
 * Get the thread identifier for a specific native thread.  The
 * @var{native_thread} pointer is assumed to point at a block
 * of memory containing a native thread handle.  This would be a
 * @code{pthread_t} on Pthreads platforms or a @code{HANDLE}
 * on Win32 platforms.  If the native thread has not been seen
 * previously, then a new thread identifier is allocated.
 * @end deftypefun
@*/
jit_debugger_thread_id_t jit_debugger_get_thread
		(jit_debugger_t dbg, const void *native_thread)
{
	/* TODO */
	return 0;
}

/*@
 * @deftypefun int jit_debugger_get_native_thread (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread}, void *@var{native_thread})
 * Get the native thread handle associated with a debugger thread identifier.
 * Returns non-zero if OK, or zero if the debugger thread identifier is not
 * yet associated with a native thread handle.
 * @end deftypefun
@*/
int jit_debugger_get_native_thread
		(jit_debugger_t dbg, jit_debugger_thread_id_t thread,
		 void *native_thread)
{
	jit_debugger_thread_t th;
	lock_debugger(dbg);
	th = get_specific_thread(dbg, thread);
	if(th)
	{
		jit_memcpy(native_thread, &(th->native_id), sizeof(th->native_id));
		unlock_debugger(dbg);
		return 1;
	}
	else
	{
		unlock_debugger(dbg);
		return 0;
	}
}

/*@
 * @deftypefun void jit_debugger_set_breakable (jit_debugger_t @var{dbg}, const void *@var{native_thread}, int @var{flag})
 * Set a flag that indicates if a native thread can stop at breakpoints.
 * If set to 1 (the default), breakpoints will be active on the thread.
 * If set to 0, breakpoints will be ignored on the thread.  Typically
 * this is used to mark threads associated with the debugger's user
 * interface, or the virtual machine's finalization thread, so that they
 * aren't accidentally suspended by the debugger (which might cause a
 * deadlock).
 * @end deftypefun
@*/
void jit_debugger_set_breakable
		(jit_debugger_t dbg, const void *native_thread, int flag)
{
	jit_debugger_thread_t th;
	jit_debugger_thread_id_t id;
	id = jit_debugger_get_thread(dbg, native_thread);
	lock_debugger(dbg);
	th = get_specific_thread(dbg, id);
	if(th)
	{
		th->breakable = flag;
	}
	unlock_debugger(dbg);
}

/*@
 * @deftypefun void jit_debugger_attach_self (jit_debugger_t @var{dbg}, int @var{stop_immediately})
 * Attach the current thread to a debugger.  If @var{stop_immediately}
 * is non-zero, then the current thread immediately suspends, waiting for
 * the user to start it with @code{jit_debugger_run}.  This function is
 * typically called in a thread's startup code just before any "real work"
 * is performed.
 * @end deftypefun
@*/
void jit_debugger_attach_self(jit_debugger_t dbg, int stop_immediately)
{
	jit_debugger_event_t *event;
	jit_debugger_thread_t th;
	lock_debugger(dbg);
	th = get_current_thread(dbg);
	if(th)
	{
		event = alloc_event();
		if(event)
		{
			event->type = JIT_DEBUGGER_TYPE_ATTACH_THREAD;
			event->thread = th->id;
			event->data1 = (jit_nint)stop_immediately;
			add_event(dbg, event);
			th->find_func = 0;
			th->last_data1 = 0;
			th->last_func_data1 = 0;
			if(stop_immediately)
			{
				th->run_type = JIT_RUN_TYPE_STOPPED;
				suspend_thread(dbg, th);
			}
			else
			{
				th->run_type = JIT_RUN_TYPE_CONTINUE;
			}
		}
	}
	unlock_debugger(dbg);
}

/*@
 * @deftypefun void jit_debugger_detach_self (jit_debugger_t @var{dbg})
 * Detach the current thread from the debugger.  This is typically
 * called just before the thread exits.
 * @end deftypefun
@*/
void jit_debugger_detach_self(jit_debugger_t dbg)
{
	jit_debugger_event_t *event;
	jit_debugger_thread_t th;
	lock_debugger(dbg);
	th = get_current_thread(dbg);
	if(th)
	{
		event = alloc_event();
		if(event)
		{
			event->type = JIT_DEBUGGER_TYPE_DETACH_THREAD;
			event->thread = th->id;
			add_event(dbg, event);
			th->run_type = JIT_RUN_TYPE_DETACHED;
		}
	}
	unlock_debugger(dbg);
}

/*@
 * @deftypefun int jit_debugger_wait_event (jit_debugger_t @var{dbg}, jit_debugger_event_t *@var{event}, jit_nint @var{timeout})
 * Wait for the next debugger event to arrive.  Debugger events typically

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

 * The fields of @var{info} are as follows:
 *
 * @table @code
 * @item flags
 * Flags that indicate which of the following fields should be matched.
 * If a flag is not present, then all possible values of the field will match.
 * Valid flags are @code{JIT_DEBUGGER_FLAG_THREAD},
 * @code{JIT_DEBUGGER_FLAG_FUNCTION}, @code{JIT_DEBUGGER_FLAG_DATA1},
 * and @code{JIT_DEBUGGER_FLAG_DATA2}.
 *
 * @item thread
 * The thread to match against, if @code{JIT_DEBUGGER_FLAG_THREAD} is set.
 *
 * @item function
 * The function to match against, if @code{JIT_DEBUGGER_FLAG_FUNCTION} is set.
 *
 * @item data1
 * The @code{data1} value to match against, if @code{JIT_DEBUGGER_FLAG_DATA1}
 * is set.
 *
 * @item data2
 * The @code{data2} value to match against, if @code{JIT_DEBUGGER_FLAG_DATA2}

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

 * @deftypefun void jit_debugger_remove_all_breakpoints (jit_debugger_t @var{dbg})
 * Remove all breakpoints from a debugger instance.
 * @end deftypefun
@*/
void jit_debugger_remove_all_breakpoints(jit_debugger_t dbg)
{
	/* TODO */
}

/*@
 * @deftypefun int jit_debugger_is_alive (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread})
 * Determine if a particular thread is still alive.
 * @end deftypefun
@*/
int jit_debugger_is_alive(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
{
	/* TODO */
	return 1;
}

/*@
 * @deftypefun int jit_debugger_is_running (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread})
 * Determine if a particular thread is currently running (non-zero) or
 * stopped (zero).
 * @end deftypefun
@*/
int jit_debugger_is_running(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
{
	jit_debugger_thread_t th;
	int flag = 0;
	lock_debugger(dbg);
	th = get_specific_thread(dbg, thread);
	if(th)
	{
		flag = (th->run_type != JIT_RUN_TYPE_STOPPED);
	}
	unlock_debugger(dbg);
	return flag;
}

/*@
 * @deftypefun void jit_debugger_run (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread})
 * Start the specified thread running, or continue from the last breakpoint.
 *
 * This function, and the others that follow, sends a request to the specified
 * thread and then returns to the caller immediately.
 * @end deftypefun
@*/
void jit_debugger_run(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
{
	jit_debugger_thread_t th;
	lock_debugger(dbg);
	th = get_specific_thread(dbg, thread);
	if(th && th->run_type == JIT_RUN_TYPE_STOPPED)
	{
		th->run_type = JIT_RUN_TYPE_CONTINUE;
		wakeup_all(dbg);
	}
	unlock_debugger(dbg);
}

/*@
 * @deftypefun void jit_debugger_step (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread})
 * Step over a single line of code.  If the line performs a method call,
 * then this will step into the call.  The request will be ignored if
 * the thread is currently running.
 * @end deftypefun
@*/
void jit_debugger_step(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
{
	jit_debugger_thread_t th;
	lock_debugger(dbg);
	th = get_specific_thread(dbg, thread);
	if(th && th->run_type == JIT_RUN_TYPE_STOPPED)
	{
		th->run_type = JIT_RUN_TYPE_STEP;
		wakeup_all(dbg);
	}
	unlock_debugger(dbg);
}

/*@
 * @deftypefun void jit_debugger_next (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread})
 * Step over a single line of code but do not step into method calls.
 * The request will be ignored if the thread is currently running.
 * @end deftypefun
@*/
void jit_debugger_next(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
{
	jit_debugger_thread_t th;
	lock_debugger(dbg);
	th = get_specific_thread(dbg, thread);
	if(th && th->run_type == JIT_RUN_TYPE_STOPPED)
	{
		th->run_type = JIT_RUN_TYPE_NEXT;
		wakeup_all(dbg);
	}
	unlock_debugger(dbg);
}

/*@
 * @deftypefun void jit_debugger_finish (jit_debugger_t @var{dbg}, jit_debugger_thread_id_t @var{thread})
 * Keep running until the end of the current function.  The request will
 * be ignored if the thread is currently running.
 * @end deftypefun
@*/
void jit_debugger_finish(jit_debugger_t dbg, jit_debugger_thread_id_t thread)
{
	jit_debugger_thread_t th;
	lock_debugger(dbg);
	th = get_specific_thread(dbg, thread);
	if(th && th->run_type == JIT_RUN_TYPE_STOPPED)
	{
		th->run_type = JIT_RUN_TYPE_FINISH;
		wakeup_all(dbg);
	}
	unlock_debugger(dbg);
}

/*@
 * @deftypefun void jit_debugger_break (jit_debugger_t @var{dbg})
 * Force an explicit user breakpoint at the current location within the
 * current thread.  Control returns to the caller when the debugger
 * calls one of the above "run" or "step" functions in another thread.
 * @end deftypefun
@*/
void jit_debugger_break(jit_debugger_t dbg)
{
	jit_debugger_event_t *event;
	jit_debugger_thread_t th;
	lock_debugger(dbg);
	th = get_current_thread(dbg);
	if(th && th->breakable)
	{
		event = alloc_event();
		if(event)
		{
			th->run_type = JIT_RUN_TYPE_STOPPED;
			th->find_func = 0;
			th->last_data1 = 0;
			th->last_func_data1 = 0;
			event->type = JIT_DEBUGGER_TYPE_USER_BREAKPOINT;
			event->thread = th->id;
			event->trace = jit_exception_get_stack_trace();
			add_event(dbg, event);
			suspend_thread(dbg, th);
		}
	}
	unlock_debugger(dbg);
}

/*@
 * @deftypefun void jit_debugger_quit (jit_debugger_t @var{dbg})
 * Sends a request to the thread that called @code{jit_debugger_wait_event}
 * indicating that the debugger should quit.
 * @end deftypefun
@*/
void jit_debugger_quit(jit_debugger_t dbg)
{
	jit_debugger_event_t *event;
	lock_debugger(dbg);
	event = alloc_event();
	if(event)
	{

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

	else
	{
		return 0;
	}
}

void _jit_debugger_hook(jit_function_t func, jit_nint data1, jit_nint data2)
{
	jit_context_t context;
	jit_debugger_t dbg;
	jit_debugger_thread_t th;
	jit_debugger_event_t *event;
	int stop;

	/* Find the context and look for a user-supplied debug hook */
	context = func->context;
	if(context->debug_hook)
	{
		(*(context->debug_hook))(func, data1, data2);
	}

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

	/* Determine if there is a debugger attached to the context */
	dbg = context->debugger;
	if(!dbg)
	{
		return;
	}

	/* Lock down the debugger while we do this */
	lock_debugger(dbg);

	/* Get the current thread's information block */
	th = get_current_thread(dbg);
	if(!th || !(th->breakable))
	{
		unlock_debugger(dbg);
		return;
	}

	/* Determine if there is a hard breakpoint at this location */
	/* TODO */

	/* Determine if we are looking for a soft breakpoint */

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

			   th->last_data1 == JIT_DEBUGGER_DATA1_THROW ||
			   th->find_func == 0)
			{
				stop = 1;
			}
		}
		break;
	}
	th->last_data1 = data1;

	/* Do we need to stop the thread at this breakpoint? */
	if(stop)
	{
		event = alloc_event();
		if(event)
		{
			th->run_type = JIT_RUN_TYPE_STOPPED;
			th->find_func = func;
			th->last_func_data1 = data1;
			event->type = JIT_DEBUGGER_TYPE_SOFT_BREAKPOINT;
			event->thread = th->id;
			event->function = func;
			event->data1 = data1;
			event->data2 = data2;
			event->trace = jit_exception_get_stack_trace();
			add_event(dbg, event);
			suspend_thread(dbg, th);
		}
	}

	/* Unlock and exit */
	unlock_debugger(dbg);
}

libjit/jit/jit-elf-defs.h  view on Meta::CPAN

#define SHF_WRITE	     (1 << 0)	/* Writable */
#define SHF_ALLOC	     (1 << 1)	/* Occupies memory during execution */
#define SHF_EXECINSTR	     (1 << 2)	/* Executable */
#define SHF_MERGE	     (1 << 4)	/* Might be merged */
#define SHF_STRINGS	     (1 << 5)	/* Contains nul-terminated strings */
#define SHF_INFO_LINK	     (1 << 6)	/* `sh_info' contains SHT index */
#define SHF_LINK_ORDER	     (1 << 7)	/* Preserve order after combining */
#define SHF_OS_NONCONFORMING (1 << 8)	/* Non-standard OS specific handling
					   required */
#define SHF_GROUP	     (1 << 9)	/* Section is member of a group.  */
#define SHF_TLS		     (1 << 10)	/* Section hold thread-local data.  */
#define SHF_MASKOS	     0x0ff00000	/* OS-specific.  */
#define SHF_MASKPROC	     0xf0000000	/* Processor-specific */

/* Section group handling.  */
#define GRP_COMDAT	0x1		/* Mark group as COMDAT.  */

/* Symbol table entry.  */

typedef struct
{

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

#include "jit-setjmp.h"

/*@

@cindex jit-except.h

@*/

/*@
 * @deftypefun {void *} jit_exception_get_last (void)
 * Get the last exception object that occurred on this thread, or NULL
 * if there is no exception object on this thread.  As far as @code{libjit}
 * is concerned, an exception is just a pointer.  The precise meaning of the
 * data at the pointer is determined by the front end.
 * @end deftypefun
@*/
void *jit_exception_get_last(void)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		return control->last_exception;
	}
	else
	{
		return 0;
	}
}

/*@
 * @deftypefun {void *} jit_exception_get_last_and_clear (void)
 * Get the last exception object that occurred on this thread and also
 * clear the exception state to NULL.  This combines the effect of
 * both @code{jit_exception_get_last} and @code{jit_exception_clear_last}.
 * @end deftypefun
@*/
void *jit_exception_get_last_and_clear(void)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		void *obj = control->last_exception;
		control->last_exception = 0;
		return obj;
	}
	else
	{
		return 0;
	}
}

/*@
 * @deftypefun void jit_exception_set_last (void *@var{object})
 * Set the last exception object that occurred on this thread, so that
 * it can be retrieved by a later call to @code{jit_exception_get_last}.
 * This is normally used by @code{jit_function_apply} to save the
 * exception object before returning to regular code.
 * @end deftypefun
@*/
void jit_exception_set_last(void *object)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		control->last_exception = object;
	}
}

/*@
 * @deftypefun void jit_exception_clear_last (void)
 * Clear the last exception object that occurred on this thread.
 * This is equivalent to calling @code{jit_exception_set_last}
 * with a parameter of NULL.
 * @end deftypefun
@*/
void jit_exception_clear_last(void)
{
	jit_exception_set_last(0);
}

/*@
 * @deftypefun void jit_exception_throw (void *@var{object})
 * Throw an exception object within the current thread.  As far as
 * @code{libjit} is concerned, the exception object is just a pointer.
 * The precise meaning of the data at the pointer is determined
 * by the front end.
 *
 * Note: as an exception object works its way back up the stack,
 * it may be temporarily stored in memory that is not normally visible
 * to a garbage collector.  The front-end is responsible for taking steps
 * to "pin" the object so that it is uncollectable until explicitly
 * copied back into a location that is visible to the collector once more.
 * @end deftypefun
@*/
void jit_exception_throw(void *object)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		control->last_exception = object;
		if(control->setjmp_head)
		{
			control->backtrace_head = control->setjmp_head->trace;
			longjmp(control->setjmp_head->buf, 1);
		}
	}
}

/*@
 * @deftypefun void jit_exception_builtin (int @var{exception_type})
 * This function is called to report a builtin exception.
 * The JIT will automatically embed calls to this function wherever a
 * builtin exception needs to be reported.
 *
 * When a builtin exception occurs, the current thread's exception
 * handler is called to construct an appropriate object, which is
 * then thrown.
 *
 * If there is no exception handler set, or the handler returns NULL,
 * then @code{libjit} will print an error message to stderr and cause
 * the program to exit with a status of 1.  You normally don't want
 * this behavior and you should override it if possible.
 *
 * The following builtin exception types are currently supported:
 *

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

		"Error during function compilation",
		"Out of memory",
		"Null pointer dereferenced",
		"Null function pointer called",
		"Nested function called from non-nested context",
		"Array index out of bounds",
		"Undefined label"
	};
	#define	num_messages	(sizeof(messages) / sizeof(const char *))

	/* Get the exception handler for this thread */
	handler = jit_exception_get_handler();

	/* Invoke the exception handler to create an appropriate object */
	if(handler)
	{
		object = (*handler)(exception_type);
		if(object)
		{
			jit_exception_throw(object);
		}

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

	{
		fprintf(stderr, "Unknown builtin exception %d",
				(-exception_type) + 1);
	}
	putc('\n', stderr);
	exit(1);
}

/*@
 * @deftypefun jit_exception_func jit_exception_set_handler (jit_exception_func @var{handler})
 * Set the builtin exception handler for the current thread.
 * Returns the previous exception handler.
 * @end deftypefun
@*/
jit_exception_func jit_exception_set_handler
	(jit_exception_func handler)
{
	jit_exception_func previous;
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		previous = control->exception_handler;
		control->exception_handler = handler;
		return previous;
	}
	else
	{
		return 0;
	}
}

/*@
 * @deftypefun jit_exception_func jit_exception_get_handler (void)
 * Get the builtin exception handler for the current thread.
 * @end deftypefun
@*/
jit_exception_func jit_exception_get_handler(void)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		return control->exception_handler;
	}
	else
	{
		return 0;
	}
}

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

 * Returns NULL if a stack trace is not available, or there is
 * insufficient memory to create it.
 * @end deftypefun
@*/
jit_stack_trace_t jit_exception_get_stack_trace(void)
{
	jit_stack_trace_t trace;
	unsigned int size;
	jit_unwind_context_t unwind;

	/* Count the number of items in the current thread's call stack */
	size = 0;
	if(jit_unwind_init(&unwind, NULL))
	{
		do
		{
			size++;
		}
		while(jit_unwind_next_pc(&unwind));
		jit_unwind_free(&unwind);
	}

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

void jit_stack_trace_free(jit_stack_trace_t trace)
{
	if(trace)
	{
		jit_free(trace);
	}
}

void _jit_backtrace_push(jit_backtrace_t trace, void *pc)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		trace->parent = control->backtrace_head;
		trace->pc = pc;
		trace->security_object = 0;
		trace->free_security_object = 0;
		control->backtrace_head = trace;
	}
	else
	{
		trace->parent = 0;
		trace->pc = pc;
		trace->security_object = 0;
		trace->free_security_object = 0;
	}
}

void _jit_backtrace_pop(void)
{
	jit_thread_control_t control = _jit_thread_get_control();
	jit_backtrace_t trace;
	if(control)
	{
		trace = control->backtrace_head;
		if(trace)
		{
			control->backtrace_head = trace->parent;
			if(trace->security_object && trace->free_security_object)
			{
				(*(trace->free_security_object))(trace->security_object);
			}
		}
	}
}

void _jit_backtrace_set(jit_backtrace_t trace)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		control->backtrace_head = trace;
	}
}

void _jit_unwind_push_setjmp(jit_jmp_buf *jbuf)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control)
	{
		jbuf->trace = control->backtrace_head;
		jbuf->catch_pc = 0;
		jbuf->parent = control->setjmp_head;
		control->setjmp_head = jbuf;
	}
}

void _jit_unwind_pop_setjmp(void)
{
	jit_thread_control_t control = _jit_thread_get_control();
	if(control && control->setjmp_head)
	{
		control->backtrace_head = control->setjmp_head->trace;
		control->setjmp_head = control->setjmp_head->parent;
	}
}

void _jit_unwind_pop_and_rethrow(void)
{
	_jit_unwind_pop_setjmp();

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

 * 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

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

 * 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}

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

 *
 * It is safe to initialize the JIT multiple times.  Subsequent
 * initializations are quietly ignored.
 * @end deftypefun
@*/
void
jit_init(void)
{
	static int init_done = 0;

	/* Make sure that the thread subsystem is initialized */
	_jit_thread_init();

	/* Make sure that the initialization is done only once
	   (requires the global lock initialized above) */
	jit_mutex_lock(&_jit_global_lock);
	if(init_done)
	{
		goto done;
	}
	init_done = 1;

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

jit_uses_interpreter(void)
{
#if defined(JIT_BACKEND_INTERP)
	return 1;
#else
	return 0;
#endif
}

/*@
 * @deftypefun int jit_supports_threads (void)
 * Determine if the JIT supports threads.
 * @end deftypefun
@*/
int
jit_supports_threads(void)
{
	return JIT_THREADS_SUPPORTED;
}

/*@
 * @deftypefun int jit_supports_virtual_memory (void)
 * Determine if the JIT supports virtual memory.
 * @end deftypefun
@*/
int

libjit/jit/jit-internal.h  view on Meta::CPAN

#if defined(HAVE_MEMCHR)
# define jit_memchr(s, c, len)		(memchr((s), (c), (len)))
#endif

/*
 * We need the apply rules for "jit_redirector_size".
 */
#include "jit-apply-func.h"

/*
 * Include the thread routines.
 */
#include "jit-thread.h"

/*
 * Include varint encoding for bytecode offset data.
 */
#include "jit-varint.h"

#ifdef	__cplusplus
extern	"C" {
#endif

libjit/jit/jit-internal.h  view on Meta::CPAN

 */
void _jit_backtrace_pop(void);

/*
 * Reset the backtrace stack to "trace".  Used in exception catch
 * blocks to fix up the backtrace information.
 */
void _jit_backtrace_set(jit_backtrace_t trace);

/*
 * Control information that is associated with a thread.
 */
struct jit_thread_control
{
	void			*last_exception;
	jit_exception_func	exception_handler;
	jit_backtrace_t		backtrace_head;
	struct jit_jmp_buf	*setjmp_head;
};

/*
 * Initialize the block list for a function.
 */

libjit/jit/jit-memory-cache.c  view on Meta::CPAN


Each method can also have offset information associated with it, to map
between native code addresses and offsets within the original bytecode.
This is typically used to support debugging.  Offset information is stored
as auxiliary data, attached to the jit_cache_method block.

Threading issues
----------------

Writing a method to the cache, querying a method by address, or querying
offset information for a method, are not thread-safe.  The caller should
arrange for a cache lock to be acquired prior to performing these
operations.

Executing methods from the cache is thread-safe, as the method code is
fixed in place once it has been written.

Note: some CPU's require that a special cache flush instruction be
performed before executing method code that has just been written.
This is especially important in SMP environments.  It is the caller's
responsibility to perform this flush operation.

We do not provide locking or CPU flush capabilities in the cache
implementation itself, because the caller may need to perform other
duties before flushing the CPU cache or releasing the lock.

The following is the recommended way to map an "jit_function_t" pointer
to a starting address for execution:

	Look in "jit_function_t" to see if we already have a starting address.
		If so, then bail out.
	Acquire the cache lock.
	Check again to see if we already have a starting address, just
		in case another thread got here first.  If so, then release
		the cache lock and bail out.
	Translate the method.
	Update the "jit_function_t" structure to contain the starting address.
	Force a CPU cache line flush.
	Release the cache lock.

Why aren't methods flushed when the cache fills up?
---------------------------------------------------

In this cache implementation, methods are never "flushed" when the
cache becomes full.  Instead, all translation stops.  This is not a bug.
It is a feature.

In a multi-threaded environment, it is impossible to know if some
other thread is executing the code of a method that may be a candidate
for flushing.  Impossible that is unless one introduces a huge number
of read-write locks, one per method, to prevent a method from being
flushed.  The read locks must be acquired on entry to a method, and
released on exit.  The write locks are acquired prior to translation.

The overhead of introducing all of these locks and the associated cache
data structures is very high.  The only safe thing to do is to assume
that once a method has been translated, its code must be fixed in place
for all time.

libjit/jit/jit-setjmp.h  view on Meta::CPAN

	jmp_buf				buf;
	jit_backtrace_t		trace;
	void			   *catch_pc;
	struct jit_jmp_buf *parent;

} jit_jmp_buf;
#define	jit_jmp_catch_pc_offset	\
			((jit_nint)&(((jit_jmp_buf *)0)->catch_pc))

/*
 * Push a "setjmp" buffer onto the current thread's unwind stck.
 */
void _jit_unwind_push_setjmp(jit_jmp_buf *jbuf);

/*
 * Pop the top-most "setjmp" buffer from the current thread's unwind stack.
 */
void _jit_unwind_pop_setjmp(void);

/*
 * Pop the top-most "setjmp" buffer and rethrow the current exception.
 */
void _jit_unwind_pop_and_rethrow(void);

#ifdef	__cplusplus
};

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

/*
 * jit-thread.c - Internal thread management routines for libjit.
 *
 * 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.
 *

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

#include <errno.h>

/*
 * Mutex that synchronizes global data initialization.
 */
jit_mutex_t _jit_global_lock;

#if defined(JIT_THREADS_PTHREAD)

/*
 * The thread-specific key to use to fetch the control object.
 */
static pthread_key_t control_key;

/*
 * Initialize the pthread support routines.  Only called once.
 */
static void init_pthread(void)
{
	jit_mutex_create(&_jit_global_lock);

	/* Allocate a thread-specific variable for the JIT's thread
	   control object, and arrange for it to be freed when the
	   thread exits or is otherwise terminated */
	pthread_key_create(&control_key, jit_free);
}

#elif defined(JIT_THREADS_WIN32)

/*
 * The thread-specific key to use to fetch the control object.
 */
static DWORD control_key;

/*
 * Initialize the Win32 thread support routines.  Only called once.
 */
static void init_win32_thread(void)
{
	jit_mutex_create(&_jit_global_lock);

	control_key = TlsAlloc();
}

jit_thread_id_t _jit_thread_self(void)
{
	HANDLE new_handle;
	DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
					GetCurrentProcess(), &new_handle,
					0, 0, DUPLICATE_SAME_ACCESS);
	return new_handle;
}

#else /* No thread package */

/*
 * The control object for the only thread in the system.
 */
static void *control_object = 0;

#endif /* No thread package */

void _jit_thread_init(void)
{
#if defined(JIT_THREADS_PTHREAD)
	static pthread_once_t once_control = PTHREAD_ONCE_INIT;
	pthread_once(&once_control, init_pthread);
#elif defined(JIT_THREADS_WIN32)
	static LONG volatile once_control = 0;
	if(!InterlockedExchange((PLONG)&once_control, 1))
	{
		init_win32_thread();
	}
#endif
}

static void *get_raw_control(void)
{
	_jit_thread_init();
#if defined(JIT_THREADS_PTHREAD)
	return pthread_getspecific(control_key);
#elif defined(JIT_THREADS_WIN32)
	return (void *)(TlsGetValue(control_key));
#else
	return control_object;
#endif
}

static void set_raw_control(void *obj)
{
	_jit_thread_init();
#if defined(JIT_THREADS_PTHREAD)
	pthread_setspecific(control_key, obj);
#elif defined(JIT_THREADS_WIN32)
	TlsSetValue(control_key, obj);
#else
	control_object = obj;
#endif
}

jit_thread_control_t _jit_thread_get_control(void)
{
	jit_thread_control_t control;
	control = (jit_thread_control_t)get_raw_control();
	if(!control)
	{
		control = jit_cnew(struct jit_thread_control);
		if(control)
		{
			set_raw_control(control);
		}
	}
	return control;
}

jit_thread_id_t _jit_thread_current_id(void)
{
#if defined(JIT_THREADS_PTHREAD)
	return pthread_self();
#elif defined(JIT_THREADS_WIN32)
	return GetCurrentThread();
#else
	/* There is only one thread, so lets give it an identifier of 1 */
	return 1;
#endif
}

int _jit_monitor_wait(jit_monitor_t *mon, jit_int timeout)
{
#if defined(JIT_THREADS_PTHREAD)
	if(timeout < 0)
	{
		pthread_cond_wait(&(mon->_cond), &(mon->_mutex));
		return 1;
	}
	else
	{
		struct timeval tv;
		struct timespec ts;
		int result;

		gettimeofday(&tv, 0);
		ts.tv_sec = tv.tv_sec + (long)(timeout / 1000);
		ts.tv_nsec = (tv.tv_usec + (long)((timeout % 1000) * 1000)) * 1000L;
		if(ts.tv_nsec >= 1000000000L)
		{
			++(ts.tv_sec);
			ts.tv_nsec -= 1000000000L;
		}

		/* Wait until we are signalled or the timeout expires */
		do
		{
			result = pthread_cond_timedwait(&(mon->_cond), &(mon->_mutex), &ts);
		}
		while(result == EINTR);
		return ((result == 0) ? 1 : 0);
	}
#elif defined(JIT_THREADS_WIN32)
	DWORD result;
	++(mon->_waiting);
	if(timeout >= 0)
	{
		result = SignalObjectAndWait(mon->_mutex, mon->_cond,

libjit/jit/jit-thread.h  view on Meta::CPAN

/*
 * jit-thread.h - Internal thread management routines for libjit.
 *
 * 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.
 *

libjit/jit/jit-thread.h  view on Meta::CPAN

 * <http://www.gnu.org/licenses/>.
 */

#ifndef	_JIT_THREAD_H
#define	_JIT_THREAD_H

#include <jit/jit-defs.h>
#include "jit-config.h"

#if defined(JIT_THREADS_PTHREAD)
# include <pthread.h>
#elif defined(JIT_THREADS_WIN32)
# include <windows.h>
#endif

#ifdef	__cplusplus
extern	"C" {
#endif

/*
 * Type that describes a thread's identifier, and the id comparison function.
 */
#if defined(JIT_THREADS_PTHREAD)
typedef pthread_t jit_thread_id_t;
#define	jit_thread_id_equal(x,y)	(pthread_equal((x), (y)))
#define	jit_thread_self()			(pthread_self())
#define	jit_thread_release_self(t)	do { ; } while (0)
#elif defined(JIT_THREADS_WIN32)
typedef HANDLE jit_thread_id_t;
#define	jit_thread_id_equal(x,y)	((x) == (y))
jit_thread_id_t _jit_thread_self(void);
#define	jit_thread_self()			_jit_thread_self()
#define	jit_thread_release_self(t)	CloseHandle((t))
#else
typedef int jit_thread_id_t;
#define	jit_thread_id_equal(x,y)	((x) == (y))
#define	jit_thread_self()			1
#define	jit_thread_release_self(t)	do { ; } while (0)
#endif

/*
 * Control information that is associated with a thread.
 */
typedef struct jit_thread_control *jit_thread_control_t;

/*
 * Initialize the thread routines.  Ignored if called multiple times.
 */
void _jit_thread_init(void);

/*
 * Get the JIT control object for the current thread.
 */
jit_thread_control_t _jit_thread_get_control(void);

/*
 * Get the identifier for the current thread.
 */
jit_thread_id_t _jit_thread_current_id(void);

/*
 * Define the primitive mutex operations.
 */
#if defined(JIT_THREADS_PTHREAD)

typedef pthread_mutex_t jit_mutex_t;
#define	jit_mutex_create(mutex)		(pthread_mutex_init((mutex), 0))
#define	jit_mutex_destroy(mutex)	(pthread_mutex_destroy((mutex)))
#define	jit_mutex_lock(mutex)		(pthread_mutex_lock((mutex)))
#define	jit_mutex_unlock(mutex)		(pthread_mutex_unlock((mutex)))

#elif defined(JIT_THREADS_WIN32)

typedef CRITICAL_SECTION jit_mutex_t;
#define	jit_mutex_create(mutex)		(InitializeCriticalSection((mutex)))
#define	jit_mutex_destroy(mutex)	(DeleteCriticalSection((mutex)))
#define	jit_mutex_lock(mutex)		(EnterCriticalSection((mutex)))
#define	jit_mutex_unlock(mutex)		(LeaveCriticalSection((mutex)))

#else

libjit/jit/jit-thread.h  view on Meta::CPAN

extern jit_mutex_t _jit_global_lock;

/*
 * Define the primitive monitor operations.
 */

#if defined(JIT_THREADS_PTHREAD)

typedef struct
{
	pthread_mutex_t	_mutex;
	pthread_cond_t	_cond;

} jit_monitor_t;
#define	jit_monitor_create(mon)	\
		do { \
			pthread_mutex_init(&((mon)->_mutex), 0); \
			pthread_cond_init(&((mon)->_cond), 0); \
		} while (0)
#define	jit_monitor_destroy(mon)	\
		do { \
			pthread_cond_destroy(&((mon)->_cond)); \
			pthread_mutex_destroy(&((mon)->_mutex)); \
		} while (0)
#define	jit_monitor_lock(mon)			\
		do { \
			pthread_mutex_lock(&((mon)->_mutex)); \
		} while (0)
#define	jit_monitor_unlock(mon)			\
		do { \
			pthread_mutex_unlock(&((mon)->_mutex)); \
		} while (0)
#define	jit_monitor_signal(mon)			\
		do { \
			pthread_cond_signal(&((mon)->_cond)); \
		} while (0)
#define	jit_monitor_signal_all(mon)		\
		do { \
			pthread_cond_broadcast(&((mon)->_cond)); \
		} while (0)

#elif defined(JIT_THREADS_WIN32)

typedef struct
{
	HANDLE	_mutex;
	HANDLE	_cond;
	LONG volatile _waiting;
} jit_monitor_t;

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

#include "jit-internal.h"
#include "jit-rules.h"
#include "jit-apply-rules.h"
#include <jit/jit-unwind.h>
#include <jit/jit-walk.h>

int
jit_unwind_init(jit_unwind_context_t *unwind, jit_context_t context)
{
#if defined(JIT_BACKEND_INTERP) || JIT_APPLY_BROKEN_FRAME_BUILTINS != 0
	jit_thread_control_t control;

	control = _jit_thread_get_control();
	if(!control)
	{
		return 0;
	}

	unwind->frame = control->backtrace_head;
#elif JIT_FAST_GET_CURRENT_FRAME != 0
	unwind->frame = jit_get_next_frame_address(jit_get_current_frame());
#else
	unwind->frame = jit_get_frame_address(1);

libjit/jitruby/ext/method_data.c.rpp  view on Meta::CPAN


#ifdef HAVE_ENV_H
/* pre-YARV */
#include <env.h>
#endif

#ifdef RUBY_VM

/* YARV */

struct rb_thread_struct
{   
    VALUE self;
    void *vm;
    VALUE *stack;
    unsigned long stack_size;
    VALUE *cfp;
    /* ... */
};

typedef struct rb_thread_struct rb_thread_t;

#define CFP_DATA_MEMO_NODE_AND_PC cfp[0]
#define CFP_METHOD_CLASS cfp[11]

/* On YARV, we store the method data on the stack.  We don't have to pop
 * it off the stack, because the stack pointer will be reset to the
 * previous frame's stack pointer when the function returns.
 */
static void fix_frame()
{
  do {
    extern rb_thread_t * ruby_current_thread;
    VALUE * cfp = ruby_current_thread->cfp;
    CFP_DATA_MEMO_NODE_AND_PC = RBASIC(CFP_METHOD_CLASS)->klass;

    if(rb_type(CFP_DATA_MEMO_NODE_AND_PC) != T_NODE)
    {
      /* This can happen for module functions that are created after
       * the stub function */
      rb_raise(
          rb_eRuntimeError,
          "Cannot find method data for module function");
    }

libjit/jitruby/ext/method_data.c.rpp  view on Meta::CPAN

      CFP_METHOD_CLASS = RCLASS_SUPER(CFP_METHOD_CLASS);
    }
  } while(0);
}

#define FIX_FRAME() \
  fix_frame()

static NODE * data_memo_node()
{
  extern rb_thread_t * ruby_current_thread;
  VALUE * cfp = ruby_current_thread->cfp;
  return (NODE *)CFP_DATA_MEMO_NODE_AND_PC;
}

#else

/* pre-YARV */

/* Okay to not pop this temporary frame, since it will be popped by the
 * caller
 */

libjit/jitruby/ext/method_data.c.rpp  view on Meta::CPAN

 *   |  +- ...
 *   +- ...
 *
 * The method data is then accessible via
 * ruby_frame->prev->last_class->rval.
 *
 * On YARV, the current frame is not duplicated; rather, the method data
 * is placed on the stack and is referenced by one of the unused members
 * of the control frame (the program counter):
 *
 * ruby_current_thread->cfp
 *   |- pc - NODE_MEMO
 *   |  |- (u1) cfnc - actual C function to call
 *   |  |- (u2) rval - stored data
 *   |  +- (u3) 0
 *   |- method_class - klass
 *   +- ...
 *
 */
void define_method_with_data(
    VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data)



( run in 0.488 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )