view release on metacpan or search on metacpan
inc/Module/Build/AlienLibJIT.pm view on Meta::CPAN
and die "Failed to configure libjit!";
$self->log_info("Running make\n");
system('make') and die "Failed to build libjit!";
$self->log_info("Returning to our original directory\n");
1;
} or do {
my $err = $@ || 'Zombie error';
chdir($orig);
die $err; # rethrow
};
chdir($orig);
if (-f $LIBJIT_RESULT) {
$self->log_info("Built libjit successfully\n");
}
else {
die "We built libjit, but the lib isn't where I wanted it: $LIBJIT_RESULT";
}
}
libjit/ChangeLog view on Meta::CPAN
2009-04-24 Michele Tartara <mikyt@users.sourceforge.net>
* jit/jit-gen-arm.h (arm_mov_reg_float): fix typo.
* jit/jit-rules-arm.c (_jit_gen_load_value): fix load logic.
2009-04-22 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-insn.c (jit_insn_call, jit_insn_call_indirect)
(jit_insn_call_indirect_vtable, jit_insn_call_native): don't end
basic block before a function call, rather end it after the call if
the call may throw some exception.
* jit/jit-function.c (compile_block): spill all registers before
calls.
2009-04-21 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-dump.c (jit_dump_insn): fix "call_finally" dump.
2009-04-16 Michele Tartara <mikyt@users.sourceforge.net>
* jit/jit-rules-arm.c: ARM backend fixes.
libjit/ChangeLog view on Meta::CPAN
constant positive power of two.
2008-03-29 Klaus Treichel <ktreichel@web.de>
* jit/jit-apply.c, tools/gen-apply.c: changes to apply needed for
x86-64 support.
2008-03-25 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-interp.c (jit_function_apply_vararg): fix return code if
exception is thrown.
2008-03-24 Klaus Treichel <ktreichel@web.de>
* jit/jit-function.c (cleanup_on_restart): Reset the epilog_fixup.
* jit/jit-apply-x86-64.c: Move parameter passing handling from
jit-rules-x86-64.c to this file because they are needed by apply too.
* jit/jit-apply-x86-64.h: Add declarations needed for parameter passing.
libjit/ChangeLog view on Meta::CPAN
* jit/jit-apply-x86-64.h: define the sizes for indirector and
redirector.
* jit/jit-apply-x86-64.c: do either a memory indirect, RIP relative
or register relative jump in the redirector whatever is appropriate
for the address location in _jit_create_indirector.
* jit/jit-gen-x86-64.h: add lots of additional code generation
macros and fix some bugs.
* jit/jit-insn.c: don't mark the current block dead after throwing
an exception in jit_insn_call_intrinsic because this is handled in
jit_insn_call_native if the flag JIT_CALL_NORETURN is specified.
* jit/Makefile.am: Add the new files jit-rules-x86-64.c,
jit-rules-x86-64.h and jit-rules-x86-64.ins to the sources.
* jit/jit-rules.h: add the native backend for X86_64.
* jit/jit-rules-x86-64.c, jit/jit-rules-x86-64.h,
jit/jit-rules-x86-64.ins: add the first native code generation for
libjit/ChangeLog view on Meta::CPAN
jit_function_from_vtable_pointer to convert a vtable pointer back to
the jit_function_t.
2006-11-29 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-reg-alloc.c (save_value): fix bug freeing stack register
that is not on the stack top.
2006-11-27 Kirill Kononenko <Kirill.Kononenko@gmail.com>
* jit/jit-rules-x86.c (throw_builtin):
* jit/jit-rules-x86.ins (JIT_OP_THROW, JIT_OP_LOAD_PC): directly use
the inst variable to get current PC value for the position-dependent
code case (patch #5503).
2006-11-27 Aleksey Demakov <ademakov@gmail.com>
* include/jit/jit-context.h: add JIT_OPTION_POSITION_INDEPENDENT
option.
* jit/jit-internal.h (struct _jit_builder): add position_independent
field.
* jit/jit-function.c (_jit_function_ensure_builder): initialize
position_independent field.
* jit/jit-rules-x86.c (throw_builtin):
* jit/jit-rules-x86.ins (JIT_OP_ADDRESS_OF_LABEL, JIT_OP_JUMP_TABLE)
(JIT_OP_THROW, JIT_OP_LOAD_PC): add position_independent check and
stub missing cases.
2006-11-26 Kirill Kononenko <Kirill.Kononenko@gmail.com>
* jit/jit-rules-x86.ins: if JIT_USE_SIGNALS is defined do not emit
explicit division by zero check (patch #5278).
2006-11-26 Aleksey Demakov <ademakov@gmail.com>
libjit/ChangeLog view on Meta::CPAN
* jit/jit-rules-arm.c:
* jit/jit-rules-interp.c:
* jit/jit-rules-x86.c: add _jit_gen_exch_top and _jit_gen_spill_top
functions used by new allocator to handle stack registers. Add reg
argument to _jit_gen_spill_global and_jit_gen_load_global
functions.
2006-04-11 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-insn.c (jit_insn_start_catcher): initialize
thrown_exception (the problem was found by Klaus).
2006-04-08 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-opcode.c: add jump table into jit_opcodes array.
* tools/gen-rules-parser.y: extend pattern syntax to allow mark
registers as clobbered. Fix bugs.
2006-04-07 Klaus Treichel <ktreichel@web.de>
libjit/ChangeLog view on Meta::CPAN
This fixes builds with gcc 4.0.2.
2005-12-28 Aleksey Demakov <ademakov@gmail.com>
* jit/jit-rules-x86.sel: implement JIT_OP_MEMMOVE rule. Get rid of
compiler warnings in JIT_OP_MEMSET.
2005-12-24 Avinash Atreya <avinashatreya@gmail.com>
* dpas/dpas-parser.y: implement array expressions (committed by Aleksey
Demakov, jit_insn_throw replaced with throw_builtin_exception)
2005-12-24 Aleksey Demakov <ademakov@gmail.com>
* include/jit/jit-except.h, jit/jit-except.c (jit_exception_builtin):
add JIT_RESULT_OUT_OF_BOUNDS builtin exception type code.
* dpas/dpas-parser.y (throw_builtin_exception): add static function
that makes jit_exception_builtin call.
* jit/jit-cache.c (_jit_cache_get_start_method): add function that
for an address in cache returns the start address of the block that
contains it.
* jit/jit-except.c (jit_stack_trace_get_offset): use
_jit_cache_get_start_method function instead of cache_start field.
* jit/jit-internal.h, jit/jit-function.c (jit_function_compile):
remove cache_start field to the jit_function struct.
libjit/ChangeLog view on Meta::CPAN
* jit/jit-insn.c (jit_insn_store): use the destination type
to determine the store opcode, not the source value type.
2004-11-02 Evin Robertson <evin@users.sourceforge.net>
* jit/jit-function.c (jit_function_compile): clear block addresses
and fixup lists if we need to restart on a new cache page (minor
alterations by Rhys).
* jit/jit-function.c (jit_function_apply_vararg): return 0 when a
sub-function throws an exception, not 1.
2004-10-31 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-rules-x86.sel: handle the special case of constant
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
libjit/ChangeLog view on Meta::CPAN
2004-06-24 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-reg-alloc.c, jit/jit-rules-arm.h, jit/jit-rules-interp.c,
jit/jit-rules-interp.h, jit/jit-rules-x86.h, jit/jit-rules.h:
use separate JIT_REG_xxx flags for float32, float64, and nfloat
because some platforms need to put these values in different
types of registers (e.g. x86-64).
2004-06-22 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-insn.c: properly set the "may_throw" flag for opcodes
that throw exceptions and which are also supported by the back end.
2004-06-21 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-rules-x86.c, jit/jit-rules-x86.sel: move the code
for loading/storing small structures into a central location.
2004-06-18 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-dump.c, jit/jit-reg-alloc.c, jit/jit-rules-arm.c,
jit/jit-rules-arm.h, jit/jit-rules-x86.c, jit/jit-rules-x86.h,
libjit/ChangeLog view on Meta::CPAN
default on platforms where it makes sense, and add the option
"--enable-interpreter" to "configure".
2004-05-31 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-rules-x86.sel: optimize multiplications for x86.
* jit/jit-rules-x86.c, jit/jit-rules-x86.sel, tools/gen-sel-parser.y,
tools/gen-sel-scanner.l: inline and optimize divisions for x86.
* jit/jit-rules-x86.sel: throw exceptions correctly for "check_null".
2004-05-30 Rhys Weatherley <rweather@southern-storm.com.au>
* doc/libjit.texi: clarify the text that describes LLVM, at the
request of Chris Lattner, LLVM's author.
* jit/jit-insn.c (jit_insn_convert): use intrinsic functions
for conversions when the back end doesn't support the opcode.
* jit/jit-rules-x86.sel, tools/gen-sel-parser.y,
libjit/ChangeLog view on Meta::CPAN
2004-04-27 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-dump.c, jit/jit-reg-alloc.c: fix a register stack bug
in "_jit_regs_set_value"; add some more debug code.
* include/jit/jit-opcode.h, jit/jit-insn.c, jit/jit-internal.h,
jit/jit-interp.cpp, jit/jit-opcode.c: wrap function calls
with code to set up and remove exception frame information.
* jit/jit-function.c, jit/jit-insn.c, jit/jit-internal.h:
intuit "nothrow" and "noreturn" flags for compiled functions.
* include/jit/jit-insn.h, include/jit/jit-plus.h, jit/jit-insn.c,
jitplus/jit-plus-function.cpp: add "jit_insn_throw",
"jit_insn_rethrow", and "jit_insn_get_call_stack" to assist
with throwing exceptions.
* include/jit/jit-insn.h, jit/jit-block.c, jit/jit-insn.c,
jit/jit-internal.h: add some instructions for managing "try" blocks.
* include/jit/jit-opcode.h, jit/jit-block.c, jit/jit-insn.c,
jit/jit-internal.h, jit/jit-opcode.c: more work on "try" blocks.
2004-04-26 Rhys Weatherley <rweather@southern-storm.com.au>
* jit/jit-reg-alloc.c, jit/jit-reg-alloc.h: add functions to
libjit/ChangeLog view on Meta::CPAN
* jitplus/jit-plus-function.cpp: initialization errors in
the C++ binding.
* jit/jit-function.c, jit/jit-insn.c, jit/jit-interp.cpp,
jit/jit-rules-interp.c: work on code generation for function calls.
* doc/libjit.texi, include/jit/jit-insn.h, include/jit/jit-plus.h,
jit/jit-insn.c, jitplus/jit-plus-function.cpp, tutorial/t2.c:
add a "flags" parmeter to "jit_insn_call" and friends, so that
"nothrow", "noreturn", and "tail" options can be supplied.
* jit/jit-dump.c, jit/jit-interp.cpp, jit/jit-interp.h,
jit/jit-opcode.c, jit/jit-rules-interp.c: dump the translated
native code from "jit_dump_function" are compilation.
* jit/jit-interp.cpp, jit/jit-rules-interp.c: argument variable
offsets should in item units, not byte units.
* jit/jit-insn.c, jit/jit-reg-alloc.c, jit/jit-reg-alloc.h,
jit/jit-rules-interp.c: improve register allocation in stacks.
libjit/NEWS view on Meta::CPAN
Alpha:
* Add Alpha backend (not yet fully functional) (Thomas Cort).
x86:
* Update x86 instruction selector for new register allocator and rules
syntax. Take advantage of their new features to generate better code
and/or simplify rules (Aleksey Demakov).
* optimize code generated by throw_builtin, JIT_OP_THROW, JIT_OP_LOAD_PC
if the position-independent option is not set (Kirill Kononenko).
* Implement JIT_OP_IMIN_UN, JIT_OP_ISIGN, JIT_OP_LSIGN, JIT_OP_IABS,
JIT_OP_LABS, JIT_OP_LOW_WORD, JIT_OP_EXPAND_INT, JIT_OP_EXPAND_UINT,
JIT_OP_INT_TO_NFLOAT, JIT_OP_UINT_TO_NFLOAT, JIT_OP_LONG_TO_NFLOAT,
JIT_OP_ULONG_TO_NFLOAT rules (Aleksey Demakov, Kirill Kononenko).
* optimize loading of zero constants. (Aleksey Demakov).
Interpreter:
* The interpreter backend does not use register stack and register
libjit/README view on Meta::CPAN
--------------
It is highly recommended that you build libjit with gcc and not
some other C compiler, even if you plan to use some other C
compiler to access the library. We make use of a number of gcc
builtins to assist with stack walking, dynamic function calls,
and closures.
It is also recommended that you don't use the "-fomit-frame-pointer"
option when compiling programs that use libjit. Otherwise stack walking
may not work correctly, leading to problems when throwing exceptions.
The configure script for libjit will detect the presence of this
option in CFLAGS and remove it when building libjit itself.
Contacting the authors
----------------------
The primary author is Rhys Weatherley at Southern Storm Software, Pty Ltd.
He can be reached via e-mail at "rweather@southern-storm.com.au".
The latest version of libjit will always be available from the Southern
libjit/TODO view on Meta::CPAN
Target release: 0.1.4
=====================
* CFG-based liveness analysis and dead code elimination
* global copy and constant propagation
* jitruby (in case copyright issues are resolved)
* sync jitplus with jit (jump tables, compile driver, debug)
* fix catch/throw within finally
* get rid of manual rules
* add direct conversion opcodes to/from float32 and float64
* add rounding towards zero
* try to be smarter with %rax for variadic functions on x86-64
Target Release: 0.2.0
=====================
* linear scan register allocation
* improve exception handling
libjit/configure.ac view on Meta::CPAN
dnl Add "-fno-omit-frame-pointer" to the CFLAGS because current gcc versions
dnl have no frame pointers by default on some archs.
if test x$GCC = xyes ; then
CFLAGS="$CFLAGS -fno-omit-frame-pointer"
CXXFLAGS="$CXXFLAGS -fno-omit-frame-pointer"
fi
dnl Find the option to use to turn on C++ exception handling.
AC_CACHE_CHECK(for C++ exception handling option, ac_cv_prog_cxx_exceptions,
[echo 'int main(int argc, char **argv){try { throw 1; } catch(int i) { return i; } return 0;}' > conftest.c
if test -z "`${CXX-c++} -o conftest conftest.c 2>&1`"; then
ac_cv_prog_cxx_exceptions='none needed'
else
if test -z "`${CXX-c++} -fexceptions -o conftest conftest.c 2>&1`"; then
ac_cv_prog_cxx_exceptions=-fexceptions
else
if test -z "`${CXX-c++} -fhandle-exceptions -o conftest conftest.c 2>&1`"; then
ac_cv_prog_cxx_exceptions=-fhandle-exceptions
else
ac_cv_prog_cxx_exceptions='none needed'
fi
fi
fi
rm -f conftest*
])
if test "x$ac_cv_prog_cxx_exceptions" != "xnone needed" ; then
CXXFLAGS="$ac_cv_prog_cxx_exceptions $CXXFLAGS"
fi
dnl Determine if the C++ compiler understands the "throw()" idiom.
AC_CACHE_CHECK(for C++ throw() idiom, ac_cv_prog_cxx_throw_idiom,
[echo 'extern "C" void func(void) throw(); int main(int argc, char **argv){return 0;}' > conftest.c
if test -z "`${CXX-c++} -o conftest conftest.c 2>&1`"; then
ac_cv_prog_cxx_throw_idiom=yes
else
ac_cv_prog_cxx_throw_idiom=no
fi
rm -f conftest*
])
AC_SUBST(JITTHROWIDIOM)
if test "x$ac_cv_prog_cxx_throw_idiom" = "xyes" ; then
JITTHROWIDIOM='throw()'
else
JITTHROWIDIOM=''
fi
dnl Determine if the C compiler understands the "-fno-gcse" option.
dnl We will get better code in the interpreter if we use this option.
AC_CACHE_CHECK(for -fno-gcse option, ac_cv_prog_no_gcse,
[echo 'int main(int argc, char **argv){ return 0;}' > conftest.c
if test -z "`${CC-cc} -fno-gcse -o conftest conftest.c 2>&1`"; then
ac_cv_prog_no_gcse=yes
libjit/doc/libjit.texi view on Meta::CPAN
@example
function puts (str : String) : SysInt; import ("libc")
function printf (format : String; ..) : SysInt; import ("libc")
@end example
Functions that are imported in this manner have case-sensitive names.
i.e. using @code{Printf} above will fail.
@item
The @code{throw} keyword can be used to throw an exception. The argument
must be a pointer. The @code{try}, @code{catch}, and @code{finally}
keywords are used to manage such exceptions further up the stack. e.g.
@example
try
...
catch Name : Type
...
finally
...
end
@end example
The @code{catch} block will be invoked with the exception pointer that was
supplied to @code{throw}, after casting it to @code{Type} (which must
be a pointer type). Specifying @code{throw} on its own without an argument
will rethrow the current exception pointer, and can only be used inside a
@code{catch} block.
Dynamic Pascal does not actually check the type of the thrown pointer.
If you have multiple kinds of exceptions, then you must store some kind
of type indicator in the block that is thrown and then inspect @code{^Name}
to see what the indicator says.
@item
The @code{exit} keyword can be used to break out of a loop.
@item
Function calls can be used as procedure calls. The return value is ignored.
@item
Hexadecimal constants can be expressed as @code{XXH}. The first digit
libjit/dpas/dpas-function.c view on Meta::CPAN
main_list[main_list_size++] = func;
}
int dpas_run_main_functions(void)
{
int index;
for(index = 0; index < main_list_size; ++index)
{
if(!jit_function_apply(main_list[index], 0, 0))
{
fprintf(stderr, "Exception 0x%lx thrown past top level\n",
(long)(jit_nint)(jit_exception_get_last()));
return 0;
}
}
return 1;
}
libjit/dpas/dpas-parser.y view on Meta::CPAN
{
dpas_sem_set_void(rvalue);
}
else
{
dpas_sem_set_rvalue(rvalue, type, return_value);
}
return rvalue;
}
static int throw_builtin_exception(jit_function_t func, int exception_type)
{
jit_type_t signature;
jit_type_t param_types[1];
jit_value_t param_values[1];
/* Call the "jit_exception_builtin" function to report the exception */
param_types[0] = jit_type_int;
signature = jit_type_create_signature
(jit_abi_cdecl, jit_type_void, param_types, 1, 1);
if(!signature)
libjit/dpas/dpas-parser.y view on Meta::CPAN
%token K_PROCEDURE "`procedure'"
%token K_PROGRAM "`program'"
%token K_RECORD "`record'"
%token K_REPEAT "`repeat'"
%token K_SET "`set'"
%token K_SHL "`shl'"
%token K_SHR "`shr'"
%token K_SIZEOF "`sizeof'"
%token K_STDCALL "`stdcall'"
%token K_THEN "`then'"
%token K_THROW "`throw'"
%token K_TO "`to'"
%token K_TRY "`try'"
%token K_TYPE "`type'"
%token K_UNTIL "`until'"
%token K_VAR "`var'"
%token K_VA_ARG "`va_arg'"
%token K_WITH "`with'"
%token K_WHILE "`while'"
%token K_XOR "`xor'"
libjit/dpas/dpas-parser.y view on Meta::CPAN
| WhileStatement
| RepeatStatement
| ForStatement
| CaseStatement
| K_WITH VariableList K_DO Statement {
/* TODO */
dpas_error("`with' statements not yet implemented");
}
| K_THROW Expression {
/* TODO */
dpas_error("`throw' statements not yet implemented");
}
| K_THROW {
/* TODO */
dpas_error("`throw' statements not yet implemented");
}
| TryStatement
| K_EXIT {
/* Exit from the current loop level */
if(loop_stack_size > 0)
{
if(!jit_insn_branch
(dpas_current_function(),
&(loop_stack[loop_stack_size - 1].exit_label)))
{
libjit/dpas/dpas-parser.y view on Meta::CPAN
jit_insn_store(func,total_offset,index);
}
}
if ( bounds )
{
/* if anything went wrong in the loop, we would be in out_of_bounds.
so jump to all_is_well */
jit_insn_branch(func,&all_is_well);
/* if we are here, out_of_bounds, throw an exception */
jit_insn_label(func,&out_of_bounds);
throw_builtin_exception(func, JIT_RESULT_OUT_OF_BOUNDS);
/* if we we are here, all_is_well */
jit_insn_label(func,&all_is_well);
}
/* compute effective address and set lvalue_ea*/
lvalue_ea = jit_insn_load_elem_address(func,array,total_offset,elem_type);
dpas_sem_set_lvalue_ea($$,elem_type,lvalue_ea);
/* clean-up : we aren't allocating anything here */
libjit/dpas/dpas-scanner.l view on Meta::CPAN
"procedure" { RETURNTOK(K_PROCEDURE); }
"program" { RETURNTOK(K_PROGRAM); }
"record" { RETURNTOK(K_RECORD); }
"repeat" { RETURNTOK(K_REPEAT); }
"set" { RETURNTOK(K_SET); }
"shl" { RETURNTOK(K_SHL); }
"shr" { RETURNTOK(K_SHR); }
"sizeof" { RETURNTOK(K_SIZEOF); }
"stdcall" { RETURNTOK(K_STDCALL); }
"then" { RETURNTOK(K_THEN); }
"throw" { RETURNTOK(K_THROW); }
"to" { RETURNTOK(K_TO); }
"try" { RETURNTOK(K_TRY); }
"type" { RETURNTOK(K_TYPE); }
"until" { RETURNTOK(K_UNTIL); }
"var" { RETURNTOK(K_VAR); }
"va_arg" { RETURNTOK(K_VA_ARG); }
"with" { RETURNTOK(K_WITH); }
"while" { RETURNTOK(K_WHILE); }
"xor" { RETURNTOK(K_XOR); }
libjit/include/jit/jit-except.h view on Meta::CPAN
*/
typedef void *(*jit_exception_func)(int exception_type);
/*
* External function declarations.
*/
void *jit_exception_get_last(void);
void *jit_exception_get_last_and_clear(void);
void jit_exception_set_last(void *object);
void jit_exception_clear_last(void);
void jit_exception_throw(void *object);
void jit_exception_builtin(int exception_type);
jit_exception_func jit_exception_set_handler(jit_exception_func handler);
jit_exception_func jit_exception_get_handler(void);
jit_stack_trace_t jit_exception_get_stack_trace(void);
unsigned int jit_stack_trace_get_size(jit_stack_trace_t trace);
jit_function_t jit_stack_trace_get_function(jit_context_t context,
jit_stack_trace_t trace,
unsigned int posn);
void *jit_stack_trace_get_pc(jit_stack_trace_t trace, unsigned int posn);
unsigned int jit_stack_trace_get_offset(jit_context_t context,
libjit/include/jit/jit-insn.h view on Meta::CPAN
int jit_insn_push_return_area_ptr(jit_function_t func) JIT_NOTHROW;
int jit_insn_pop_stack(jit_function_t func, jit_nint num_items) JIT_NOTHROW;
int jit_insn_defer_pop_stack
(jit_function_t func, jit_nint num_items) JIT_NOTHROW;
int jit_insn_flush_defer_pop
(jit_function_t func, jit_nint num_items) JIT_NOTHROW;
int jit_insn_return(jit_function_t func, jit_value_t value) JIT_NOTHROW;
int jit_insn_return_ptr
(jit_function_t func, jit_value_t value, jit_type_t type) JIT_NOTHROW;
int jit_insn_default_return(jit_function_t func) JIT_NOTHROW;
int jit_insn_throw(jit_function_t func, jit_value_t value) JIT_NOTHROW;
jit_value_t jit_insn_get_call_stack(jit_function_t func) JIT_NOTHROW;
jit_value_t jit_insn_thrown_exception(jit_function_t func) JIT_NOTHROW;
int jit_insn_uses_catcher(jit_function_t func) JIT_NOTHROW;
jit_value_t jit_insn_start_catcher(jit_function_t func) JIT_NOTHROW;
int jit_insn_branch_if_pc_not_in_range
(jit_function_t func, jit_label_t start_label,
jit_label_t end_label, jit_label_t *label) JIT_NOTHROW;
int jit_insn_rethrow_unhandled(jit_function_t func) JIT_NOTHROW;
int jit_insn_start_finally
(jit_function_t func, jit_label_t *finally_label) JIT_NOTHROW;
int jit_insn_return_from_finally(jit_function_t func) JIT_NOTHROW;
int jit_insn_call_finally
(jit_function_t func, jit_label_t *finally_label) JIT_NOTHROW;
jit_value_t jit_insn_start_filter
(jit_function_t func, jit_label_t *label, jit_type_t type) JIT_NOTHROW;
int jit_insn_return_from_filter
(jit_function_t func, jit_value_t value) JIT_NOTHROW;
jit_value_t jit_insn_call_filter
libjit/include/jit/jit-plus.h view on Meta::CPAN
void insn_push(const jit_value& value);
void insn_push_ptr(const jit_value& value, jit_type_t type);
void insn_set_param(const jit_value& value, jit_nint offset);
void insn_set_param_ptr
(const jit_value& value, jit_type_t type, jit_nint offset);
void insn_push_return_area_ptr();
void insn_return(const jit_value& value);
void insn_return();
void insn_return_ptr(const jit_value& value, jit_type_t type);
void insn_default_return();
void insn_throw(const jit_value& value);
jit_value insn_get_call_stack();
jit_value insn_thrown_exception();
void insn_uses_catcher();
jit_value insn_start_catcher();
void insn_branch_if_pc_not_in_range
(const jit_label& start_label, const jit_label& end_label,
jit_label& label);
void insn_rethrow_unhandled();
void insn_start_finally(jit_label& label);
void insn_return_from_finally();
void insn_call_finally(jit_label& label);
jit_value insn_start_filter(jit_label& label, jit_type_t type);
void insn_return_from_filter(const jit_value& value);
jit_value insn_call_filter
(jit_label& label, const jit_value& value, jit_type_t type);
void insn_memcpy
(const jit_value& dest, const jit_value& src, const jit_value& size);
void insn_memmove
libjit/jit/jit-compile.c view on Meta::CPAN
/* Start with with allocated space */
memory_start(state);
}
/*
* Prepare function info needed for code generation.
*/
static void
codegen_prepare(_jit_compile_t *state)
{
/* Intuit "nothrow" and "noreturn" flags for this function */
if(!state->func->builder->may_throw)
{
state->func->no_throw = 1;
}
if(!state->func->builder->ordinary_return)
{
state->func->no_return = 1;
}
/* Compute liveness and "next use" information for this function */
_jit_function_compute_liveness(state->func);
/* Allocate global registers to variables within the function */
libjit/jit/jit-context.c view on Meta::CPAN
* 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
@*/
libjit/jit/jit-debugger.c view on Meta::CPAN
*
* @item JIT_DEBUGGER_DATA1_ENTER
* Breakpoint location that corresponds to the start of a function.
*
* @item JIT_DEBUGGER_DATA1_LEAVE
* Breakpoint location that corresponds to the end of a function, just
* prior to a @code{return} statement. This is used to determine where
* to continue to upon a "finish".
*
* @item JIT_DEBUGGER_DATA1_THROW
* Breakpoint location that corresponds to an exception throw.
* @end table
* @end deftypefun
@*/
jit_debugger_breakpoint_id_t jit_debugger_add_breakpoint
(jit_debugger_t dbg, jit_debugger_breakpoint_info_t info)
{
/* TODO */
return 0;
}
libjit/jit/jit-except.c view on Meta::CPAN
* 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);
}
libjit/jit/jit-except.c view on Meta::CPAN
}
/*@
* @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:
*
* @table @code
* @vindex JIT_RESULT_OK
libjit/jit/jit-except.c view on Meta::CPAN
/* 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);
}
}
/* We don't have an exception handler, so print a message and exit */
fputs("A builtin JIT exception could not be handled:\n", stderr);
exception_type = -(exception_type - 1);
if(exception_type >= 0 && exception_type < (int)num_messages)
{
fputs(messages[exception_type], stderr);
}
libjit/jit/jit-except.c view on Meta::CPAN
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();
jit_exception_throw(jit_exception_get_last());
}
libjit/jit/jit-function.c view on Meta::CPAN
/*
* Closure handling function for "jit_function_to_closure".
*/
static void function_closure(jit_type_t signature, void *result,
void **args, void *user_data)
{
if(!jit_function_apply((jit_function_t)user_data, args, result))
{
/* We cannot report the exception through the closure,
so we have no choice but to rethrow it up the stack */
jit_exception_throw(jit_exception_get_last());
}
}
#endif /* JIT_BACKEND_INTERP */
/*@
* @deftypefun {void *} jit_function_to_closure (jit_function_t @var{func})
* Convert a compiled function into a closure that can called directly
* from C. Returns NULL if out of memory, or if closures are not
* supported on this platform.
libjit/jit/jit-function.c view on Meta::CPAN
* 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)
libjit/jit/jit-insn.c view on Meta::CPAN
oper = descr->doper;
desc = descr->ddesc;
}
else
{
oper = descr->nfoper;
desc = descr->nfdesc;
}
if(desc && desc->ptr_result_type)
{
func->builder->may_throw = 1;
}
value1 = jit_insn_convert(func, value1, result_type, overflow_check);
if(_jit_opcode_is_supported(oper))
{
return apply_unary(func, oper, value1, result_type);
}
else
{
return apply_intrinsic(func, descr, value1, 0, result_type);
}
libjit/jit/jit-insn.c view on Meta::CPAN
oper = descr->doper;
desc = descr->ddesc;
}
else
{
oper = descr->nfoper;
desc = descr->nfdesc;
}
if(desc && desc->ptr_result_type)
{
func->builder->may_throw = 1;
}
value1 = jit_insn_convert(func, value1, result_type, overflow_check);
value2 = jit_insn_convert(func, value2, result_type, overflow_check);
if(_jit_opcode_is_supported(oper))
{
return apply_binary(func, oper, value1, value2, result_type);
}
else
{
return apply_intrinsic(func, descr, value1, value2, result_type);
libjit/jit/jit-insn.c view on Meta::CPAN
/* Calculate the effective address and then use a relative store */
base_addr = jit_insn_add(func, base_addr,
jit_insn_mul(func, index,
jit_value_create_nint_constant
(func, jit_type_nint, size)));
return jit_insn_store_relative(func, base_addr, 0, value);
}
/*@
* @deftypefun int jit_insn_check_null (jit_function_t @var{func}, jit_value_t @var{value})
* Check @var{value} to see if it is NULL. If it is, then throw the
* built-in @code{JIT_RESULT_NULL_REFERENCE} exception.
* @end deftypefun
@*/
int jit_insn_check_null(jit_function_t func, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
/* Do the check only if the value is no not Null constant */
if(value->is_nint_constant && (value->address != 0))
{
return 1;
}
func->builder->may_throw = 1;
return create_unary_note(func, JIT_OP_CHECK_NULL, value);
}
int _jit_insn_check_is_redundant(const jit_insn_iter_t *iter)
{
jit_insn_iter_t new_iter = *iter;
jit_insn_t insn;
jit_value_t value;
/* Back up to find the "check_null" instruction of interest */
libjit/jit/jit-insn.c view on Meta::CPAN
jit_value_set_addressable(value1);
result = apply_unary(func, JIT_OP_ADDRESS_OF, value1, type);
jit_type_free(type);
return result;
}
/*@
* @deftypefun jit_value_t jit_insn_address_of_label (jit_function_t @var{func}, jit_label_t *@var{label})
* Get the address of @var{label} into a new temporary. This is typically
* used for exception handling, to track where in a function an exception
* was actually thrown.
* @end deftypefun
@*/
jit_value_t jit_insn_address_of_label(jit_function_t func, jit_label_t *label)
{
jit_value_t dest;
jit_insn_t insn;
if(!_jit_function_ensure_builder(func) || !label)
{
return 0;
}
libjit/jit/jit-insn.c view on Meta::CPAN
CVT_INTRINSIC(jit_float64_to_nfloat, float64, nfloat)
};
/*
* Apply a unary conversion operator.
*/
static jit_value_t apply_unary_conversion
(jit_function_t func, int oper, jit_value_t value1,
jit_type_t result_type)
{
/* Set the "may_throw" flag if the conversion may throw an exception */
if(convert_intrinsics[oper - 1].descr.ptr_result_type)
{
func->builder->may_throw = 1;
}
/* Bail out early if the conversion opcode is supported by the back end */
if(_jit_opcode_is_supported(oper))
{
return apply_unary(func, oper, value1, result_type);
}
/* Call the appropriate intrinsic method */
return jit_insn_call_intrinsic
libjit/jit/jit-insn.c view on Meta::CPAN
if(!type)
{
return 0;
}
jit_insn_call_native
(func, "_jit_unwind_pop_setjmp",
(void *)_jit_unwind_pop_setjmp, type, 0, 0, JIT_CALL_NOTHROW);
jit_type_free(type);
}
/* If "nothrow" or "tail" is set, then there is no more to do */
if((flags & (JIT_CALL_NOTHROW | JIT_CALL_TAIL)) != 0)
{
return 1;
}
/* This function may throw an exception */
func->builder->may_throw = 1;
#if JIT_APPLY_BROKEN_FRAME_BUILTINS != 0
{
jit_value_t eh_frame_info;
jit_type_t params[2];
/* Get the value that holds the exception frame information */
if((eh_frame_info = func->builder->eh_frame_info) == 0)
{
type = jit_type_create_struct(0, 0, 0);
libjit/jit/jit-insn.c view on Meta::CPAN
return 0;
}
}
/* We are now ready to make the actual function call */
return 1;
#else /* JIT_BACKEND_INTERP */
/* The interpreter handles exception frames for us */
if((flags & (JIT_CALL_NOTHROW | JIT_CALL_TAIL)) == 0)
{
func->builder->may_throw = 1;
}
return 1;
#endif
}
/*
* Restore the exception handling frame after a function call.
*/
static int restore_eh_frame_after_call(jit_function_t func, int flags)
{
#if !defined(JIT_BACKEND_INTERP)
jit_value_t value;
/* If the "nothrow", "noreturn", or "tail" flags are set, then we
don't need to worry about this */
if((flags & (JIT_CALL_NOTHROW | JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
{
return 1;
}
#if JIT_APPLY_BROKEN_FRAME_BUILTINS != 0
{
jit_type_t type;
libjit/jit/jit-insn.c view on Meta::CPAN
jit_value_t return_value)
{
/* If the function does not return, then end the current block.
The next block does not have "entered_via_top" set so that
it will be eliminated during later code generation */
if((flags & (JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
{
func->builder->current_block->ends_in_dead = 1;
}
/* If the function may throw an exceptions then end the current
basic block to account for exceptional control flow */
if((flags & JIT_CALL_NOTHROW) == 0)
{
if(!jit_insn_new_block(func))
{
return 0;
}
}
/* Create space for the return value, if we don't already have one */
libjit/jit/jit-insn.c view on Meta::CPAN
* is used in its place. This is the usual case. However, if the function
* takes a variable number of arguments, then you may need to construct
* an explicit signature for the non-fixed argument values.
*
* The @var{flags} parameter specifies additional information about the
* type of call to perform:
*
* @table @code
* @vindex JIT_CALL_NOTHROW
* @item JIT_CALL_NOTHROW
* The function never throws exceptions.
*
* @vindex JIT_CALL_NORETURN
* @item JIT_CALL_NORETURN
* The function will never return directly to its caller. It may however
* return to the caller indirectly by throwing an exception that the
* caller catches.
*
* @vindex JIT_CALL_TAIL
* @item JIT_CALL_TAIL
* Apply tail call optimizations, as the result of this function
* call will be immediately returned from the containing function.
* Tail calls are only appropriate when the signature of the called
* function matches the callee, and none of the parameters point
* to local variables.
* @end table
libjit/jit/jit-insn.c view on Meta::CPAN
{
return 0;
}
}
else
{
new_args = args;
}
/* Intuit additional flags from "jit_func" if it was already compiled */
if(func->no_throw)
{
flags |= JIT_CALL_NOTHROW;
}
if(func->no_return)
{
flags |= JIT_CALL_NORETURN;
}
/* Set up exception frame information for the call */
if(!setup_eh_frame_for_call(func, flags))
libjit/jit/jit-insn.c view on Meta::CPAN
if(jit_block_current_is_dead(func))
{
return 2;
}
/* Add a simple "void" return to terminate the function */
return jit_insn_return(func, 0);
}
/*@
* @deftypefun int jit_insn_throw (jit_function_t @var{func}, jit_value_t @var{value})
* Throw a pointer @var{value} as an exception object. This can also
* be used to "rethrow" an object from a catch handler that is not
* interested in handling the exception.
* @end deftypefun
@*/
int jit_insn_throw(jit_function_t func, jit_value_t value)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
func->builder->may_throw = 1;
func->builder->non_leaf = 1; /* May have to call out to throw */
if(!create_unary_note(func, JIT_OP_THROW, value))
{
return 0;
}
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
/*@
* @deftypefun jit_value_t jit_insn_get_call_stack (jit_function_t @var{func})
* Get an object that represents the current position in the code,
* and all of the functions that are currently on the call stack.
* This is equivalent to calling @code{jit_exception_get_stack_trace},
* and is normally used just prior to @code{jit_insn_throw} to record
* the location of the exception that is being thrown.
* @end deftypefun
@*/
jit_value_t jit_insn_get_call_stack(jit_function_t func)
{
jit_type_t type;
jit_value_t value;
/* Create a signature prototype for "void *()" */
type = jit_type_create_signature
(jit_abi_cdecl, jit_type_void_ptr, 0, 0, 1);
libjit/jit/jit-insn.c view on Meta::CPAN
value = jit_insn_call_native
(func, "jit_exception_get_stack_trace",
(void *)jit_exception_get_stack_trace, type, 0, 0, 0);
/* Clean up and exit */
jit_type_free(type);
return value;
}
/*@
* @deftypefun jit_value_t jit_insn_thrown_exception (jit_function_t @var{func})
* Get the value that holds the most recent thrown exception. This is
* typically used in @code{catch} clauses.
* @end deftypefun
@*/
jit_value_t jit_insn_thrown_exception(jit_function_t func)
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!(func->builder->thrown_exception))
{
func->builder->thrown_exception =
jit_value_create(func, jit_type_void_ptr);
}
return func->builder->thrown_exception;
}
/*
* Initialize the "setjmp" setup block that is needed to catch exceptions
* thrown back to this level of execution. The block looks like this:
*
* jit_jmp_buf jbuf;
* void *catcher;
*
* _jit_unwind_push_setjmp(&jbuf);
* if(setjmp(&jbuf.buf))
* {
* catch_pc = jbuf.catch_pc;
* if(catch_pc)
* {
* jbuf.catch_pc = 0;
* goto *catcher;
* }
* else
* {
* _jit_unwind_pop_and_rethrow();
* }
* }
*
* The field "jbuf.catch_pc" will be set to the address of the relevant
* "catch" block just before a subroutine call that may involve exceptions.
* It will be reset to NULL after such subroutine calls.
*
* Native back ends are responsible for outputting a call to the function
* "_jit_unwind_pop_setjmp()" just before "return" instructions if the
* "has_try" flag is set on the function.
*/
static int initialize_setjmp_block(jit_function_t func)
{
#if !defined(JIT_BACKEND_INTERP)
jit_label_t start_label = jit_label_undefined;
jit_label_t end_label = jit_label_undefined;
jit_label_t code_label = jit_label_undefined;
jit_label_t rethrow_label = jit_label_undefined;
jit_type_t type;
jit_value_t args[2];
jit_value_t value;
/* Bail out if we have already done this before */
if(func->builder->setjmp_value)
{
return 1;
}
func->builder->catcher_label = jit_label_undefined;
libjit/jit/jit-insn.c view on Meta::CPAN
return 0;
}
#endif /* !HAVE_SIGSETJMP */
/* Branch to the end of the init code if "setjmp" returned zero */
if(!jit_insn_branch_if_not(func, value, &code_label))
{
return 0;
}
/* We need a value to hold the location of the thrown exception */
if((func->builder->thrown_pc =
jit_value_create(func, jit_type_void_ptr)) == 0)
{
return 0;
}
/* Get the value of "catch_pc" from within "setjmp_value" and store it
into the current frame. This indicates where the exception occurred */
value = jit_insn_load_relative
(func, jit_insn_address_of(func, func->builder->setjmp_value),
jit_jmp_catch_pc_offset, jit_type_void_ptr);
if(!value)
{
return 0;
}
if(!jit_insn_store(func, func->builder->thrown_pc, value))
{
return 0;
}
if(!jit_insn_branch_if_not(func, value, &rethrow_label))
{
return 0;
}
/* Clear the original "catch_pc" value within "setjmp_value" */
if(!jit_insn_store_relative
(func, jit_insn_address_of(func, func->builder->setjmp_value),
jit_jmp_catch_pc_offset, jit_value_create_nint_constant
(func, jit_type_void_ptr, 0)))
{
return 0;
}
/* Jump to this function's exception catcher */
if(!jit_insn_branch(func, &(func->builder->catcher_label)))
{
return 0;
}
/* Mark the position of the rethrow label */
if(!jit_insn_label(func, &rethrow_label))
{
return 0;
}
/* Call "_jit_unwind_pop_and_rethrow" to pop the current
"setjmp" context and then rethrow the current exception */
type = jit_type_create_signature
(jit_abi_cdecl, jit_type_void, 0, 0, 1);
if(!type)
{
return 0;
}
jit_insn_call_native
(func, "_jit_unwind_pop_and_rethrow",
(void *)_jit_unwind_pop_and_rethrow, type, 0, 0,
JIT_CALL_NOTHROW | JIT_CALL_NORETURN);
jit_type_free(type);
/* Insert the target to jump to the normal code. */
if(!jit_insn_label(func, &code_label))
{
return 0;
}
/* Force the start of a new block to mark the end of the init code */
libjit/jit/jit-insn.c view on Meta::CPAN
{
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(func->has_try)
{
return 1;
}
func->has_try = 1;
func->builder->may_throw = 1;
func->builder->non_leaf = 1;
return initialize_setjmp_block(func);
}
/*@
* @deftypefun jit_value_t jit_insn_start_catcher (jit_function_t @var{func})
* Start the catcher block for @var{func}. There should be exactly one
* catcher block for any function that involves a @code{try}. All
* exceptions that are thrown within the function will cause control
* to jump to this point. Returns a value that holds the exception
* that was thrown.
* @end deftypefun
@*/
jit_value_t jit_insn_start_catcher(jit_function_t func)
{
jit_value_t value;
#if !defined(JIT_BACKEND_INTERP)
jit_value_t last_exception;
jit_type_t type;
#endif
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_label(func, &(func->builder->catcher_label)))
{
return 0;
}
value = jit_insn_thrown_exception(func);
if(!value)
{
return 0;
}
#if defined(JIT_BACKEND_INTERP)
/* In the interpreter, the exception object will be on the top of
the operand stack when control reaches the catcher */
if(!jit_insn_incoming_reg(func, value, 0))
{
return 0;
libjit/jit/jit-insn.c view on Meta::CPAN
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
/* Get the location where the exception occurred in this function */
#if defined(JIT_BACKEND_INTERP)
value1 = create_dest_note
(func, JIT_OP_LOAD_EXCEPTION_PC, jit_type_void_ptr);
#else
value1 = func->builder->thrown_pc;
#endif
if(!value1)
{
return 0;
}
/* Compare the location against the start and end labels */
value2 = jit_insn_address_of_label(func, &start_label);
if(!value2)
{
libjit/jit/jit-insn.c view on Meta::CPAN
if(!jit_insn_branch_if(func, jit_insn_ge(func, value1, value2), label))
{
return 0;
}
/* If control gets here, then we have a location match */
return 1;
}
/*@
* @deftypefun int jit_insn_rethrow_unhandled (jit_function_t @var{func})
* Rethrow the current exception because it cannot be handled by
* any of the @code{catch} blocks in the current function.
*
* Note: this is intended for use within catcher blocks. It should not
* be used to rethrow exceptions in response to programmer requests
* (e.g. @code{throw;} in C#). The @code{jit_insn_throw} function
* should be used for that purpose.
* @end deftypefun
@*/
int jit_insn_rethrow_unhandled(jit_function_t func)
{
jit_value_t value;
#if !defined(JIT_BACKEND_INTERP)
jit_type_t type;
#endif
/* Ensure that we have a function builder */
if(!_jit_function_ensure_builder(func))
{
return 0;
}
/* Get the current exception value to be thrown */
value = jit_insn_thrown_exception(func);
if(!value)
{
return 0;
}
#if defined(JIT_BACKEND_INTERP)
/* Rethrow the current exception (interpreter version) */
if(!create_unary_note(func, JIT_OP_RETHROW, value))
{
return 0;
}
#else /* !JIT_BACKEND_INTERP */
/* Call "_jit_unwind_pop_setjmp" to remove the current exception catcher */
if(!_jit_function_ensure_builder(func))
{
libjit/jit/jit-insn.c view on Meta::CPAN
(jit_abi_cdecl, jit_type_void, 0, 0, 1);
if(!type)
{
return 0;
}
jit_insn_call_native
(func, "_jit_unwind_pop_setjmp",
(void *)_jit_unwind_pop_setjmp, type, 0, 0, JIT_CALL_NOTHROW);
jit_type_free(type);
/* Call the "jit_exception_throw" function to effect the rethrow */
type = jit_type_void_ptr;
type = jit_type_create_signature
(jit_abi_cdecl, jit_type_void, &type, 1, 1);
if(!type)
{
return 0;
}
jit_insn_call_native
(func, "jit_exception_throw",
(void *)jit_exception_throw, type, &value, 1,
JIT_CALL_NOTHROW | JIT_CALL_NORETURN);
jit_type_free(type);
#endif /* !JIT_BACKEND_INTERP */
/* The current block ends in dead and we need to start a new block */
func->builder->current_block->ends_in_dead = 1;
return jit_insn_new_block(func);
}
libjit/jit/jit-internal.h view on Meta::CPAN
/* The next block label to be allocated */
jit_label_t next_label;
/* Mapping from label numbers to blocks */
_jit_label_info_t *label_info;
jit_label_t max_label_info;
/* Exception handling definitions for the function */
jit_value_t setjmp_value;
jit_value_t thrown_exception;
jit_value_t thrown_pc;
jit_label_t catcher_label;
jit_value_t eh_frame_info;
/* Flag that is set to indicate that this function is not a leaf */
unsigned non_leaf : 1;
/* Flag that indicates if we've seen code that may throw an exception */
unsigned may_throw : 1;
/* Flag that indicates if the function has an ordinary return */
unsigned ordinary_return : 1;
/* Flag that indicates that the current function contains a tail call */
unsigned has_tail_call : 1;
/* Generate position-independent code */
unsigned position_independent : 1;
libjit/jit/jit-internal.h view on Meta::CPAN
/* Debug information for this function */
jit_varint_data_t bytecode_offset;
/* Cookie value for this function */
void *cookie;
/* Flag bits for this function */
unsigned is_recompilable : 1;
unsigned is_optimized : 1;
unsigned no_throw : 1;
unsigned no_return : 1;
unsigned has_try : 1;
unsigned optimization_level : 8;
/* Flag set once the function is compiled */
int volatile is_compiled;
/* The entry point for the function's compiled code */
void * volatile entry_point;
libjit/jit/jit-interp.c view on Meta::CPAN
* 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/>.
*/
/*
This file must be compiled with a C++ compiler, because it uses
C++ exceptions to manage JIT exception throws. It is otherwise
straight vanilla ANSI C.
*/
#include "jit-interp.h"
#include "jit-rules.h"
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_ALLOCA_H
libjit/jit/jit-interp.c view on Meta::CPAN
pc = jit_function_interp_entry_pc(func);
/* Create a "setjmp" point if this function has a "try" block.
This is used to catch exceptions on their way up the stack */
if(func->func->has_try)
{
jbuf = (jit_jmp_buf *)alloca(sizeof(jit_jmp_buf));
_jit_unwind_push_setjmp(jbuf);
if(setjmp(jbuf->buf))
{
/* An exception has been thrown by lower-level code */
exception_object = jit_exception_get_last_and_clear();
exception_pc = pc - 1;
goto handle_exception;
}
}
else
{
jbuf = 0;
}
libjit/jit/jit-interp.c view on Meta::CPAN
stacktop = frame;
VM_R0_PTR = exception_object;
}
else
{
/* Throw the exception up to the next level */
if(jbuf)
{
_jit_unwind_pop_setjmp();
}
jit_exception_throw(exception_object);
}
}
VMBREAK;
VMCASE(JIT_OP_RETHROW):
{
/* Rethrow an exception to the caller */
if(jbuf)
{
_jit_unwind_pop_setjmp();
}
jit_exception_throw(VM_R1_PTR);
}
VMBREAK;
VMCASE(JIT_OP_LOAD_PC):
{
/* Load the current program counter onto the stack */
VM_R0_PTR = (void *)pc;
VM_MODIFY_PC(1);
}
VMBREAK;
libjit/jit/jit-interp.c view on Meta::CPAN
******************************************************************/
VMCASE(JIT_OP_ALLOCA):
{
/* Allocate memory from the stack */
VM_R0_PTR = (void *)alloca(VM_R1_NUINT);
VM_MODIFY_PC(1);
/* We need to reset the "setjmp" point for this function
because the saved stack pointer is no longer the same.
If we don't do this, then an exception throw will pop
the alloca'ed memory, causing dangling pointer problems */
if(jbuf)
{
if(setjmp(jbuf->buf))
{
exception_object = jit_exception_get_last_and_clear();
exception_pc = pc - 1;
goto handle_exception;
}
}
libjit/jit/jit-interp.c view on Meta::CPAN
jit_function_interp_t entry;
jit_item interp_return_area;
jit_item *arg_buffer;
jit_item *temp_arg;
jit_type_t type;
unsigned int num_params;
unsigned int param;
jit_jmp_buf jbuf;
/* Push a "setjmp" context onto the stack, so that we can catch
any exceptions that are thrown up to this level and prevent
them from propagating further */
_jit_unwind_push_setjmp(&jbuf);
if(setjmp(jbuf.buf))
{
_jit_unwind_pop_setjmp();
return 0;
}
/* Initialize the backtrace information */
_jit_backtrace_push(&call_trace, 0);
libjit/jit/jit-intrinsic.c view on Meta::CPAN
floating-point emulation routines). The back end code generator may choose
to use either the system-supplied intrinsics or the ones supplied by
this library. We supply all of them in our library just in case a
particular platform lacks an appropriate intrinsic.
Some intrinsics have no equivalent in existing system libraries;
particularly those that deal with overflow checking.
Functions that perform overflow checking or which divide integer operands
return a built-in exception code to indicate the type of exception
to be thrown (the caller is responsible for throwing the actual
exception). @xref{Exceptions}, for a list of built-in exception codes.
The following functions are defined in @code{<jit/jit-intrinsic.h>}:
@*/
/*
* Special values that indicate "not a number" for floating-point types.
* Visual C++ won't let us compute NaN's at compile time, so we have to
* work around it with a run-time hack.
libjit/jit/jit-opcodes.ops view on Meta::CPAN
op_def("return_float32") { op_values(empty, float32) }
op_def("return_float64") { op_values(empty, float64) }
op_def("return_nfloat") { op_values(empty, nfloat) }
op_def("return_small_struct") { op_values(empty, ptr, ptr), "NINT_ARG" }
op_def("setup_for_nested") { op_values(empty, int) }
op_def("setup_for_sibling") { op_values(empty, int, int), "NINT_ARG" }
op_def("import") { op_values(ptr, any, int) }
/*
* Exception handling.
*/
op_def("throw") { op_values(empty, ptr) }
op_def("rethrow") { op_values(empty, ptr) }
op_def("load_pc") { op_values(ptr) }
op_def("load_exception_pc") { op_values(ptr) }
op_def("enter_finally") { }
op_def("leave_finally") { }
op_def("call_finally") { op_type(branch) }
op_def("enter_filter") { op_values(any) }
op_def("leave_filter") { op_values(empty, any) }
op_def("call_filter") { op_type(branch), op_values(empty, any) }
op_def("call_filter_return") { op_values(any) }
op_def("address_of_label") { op_type(address_of_label), op_values(ptr) }
libjit/jit/jit-reg-alloc.c view on Meta::CPAN
void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func)
{
#if JIT_NUM_GLOBAL_REGS != 0
jit_value_t candidates[JIT_NUM_GLOBAL_REGS];
int num_candidates = 0;
int index, reg, posn, num;
jit_pool_block_t block;
jit_value_t value, temp;
/* If the function has a "try" block, then don't do global allocation
as the "longjmp" for exception throws will wipe out global registers */
if(func->has_try)
{
return;
}
/* If the current function involves a tail call, then we don't do
global register allocation and we also prevent the code generator
from using any of the callee-saved registers. This simplifies
tail calls, which don't have to worry about restoring such registers */
if(func->builder->has_tail_call)
libjit/jit/jit-rules-arm.c view on Meta::CPAN
offset = 0;
}
arm_branch_imm(*inst, cond, offset);
block->fixup_list = (void *)(arm_inst_get_posn(*inst) - 1);
}
}
/*
* Throw a builtin exception.
*/
static void throw_builtin
(arm_inst_buf *inst, jit_function_t func, int cond, int type)
{
arm_inst_word *patch;
/* Branch past the following code if "cond" is not true */
patch = arm_inst_get_posn(*inst);
arm_branch_imm(*inst, cond ^ 0x01, 0);
/* We need to update "catch_pc" if we have a "try" block */
if(func->builder->setjmp_value != 0)
libjit/jit/jit-rules-arm.ins view on Meta::CPAN
else
{
/* Cannot use the same register for both arguments */
arm_mov_reg_reg(inst, ARM_WORK, $2);
arm_mul_reg_reg(inst, $1, $1, ARM_WORK);
}
}
JIT_OP_IDIV:
[any, immzero] -> {
throw_builtin(&inst, func, ARM_CC_AL, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, immu8, if("$2 == 1")] -> {
/* Division by 1. Return the value itself */
}
[reg, immu8, if("($2 > 0) && (((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* Handle special cases of small immediate divides: divisions by positive powers of two */
/* NB: (n & (n-1)) == 0 if and only if n is a power of 2 */
/* Move the dividend in the work register, setting the codes (in order to know if it's positive or negative) */
arm_alu_cc_reg(inst, ARM_MOV, ARM_WORK, $1);
libjit/jit/jit-rules-arm.ins view on Meta::CPAN
break;
}
/* If the dividend was negative, make it negative again (0-x = -x)*/
arm_alu_reg_imm8_cond(inst, ARM_RSB, $1, $1, 0, ARM_CC_MI);
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 simply negates */
/*TODO: if the value to be divided by -1 is jit_min_int,
an exception (JIT_RESULT_ARITHMETIC) should probably be thrown */
arm_alu_reg(inst, ARM_MVN, $1, $1);
}
[reg, imm, clobber("r0", "r1")] -> {
/* Every other immediate division:
ARM does not have an integer division operation. It's emulated via software. */
//Put the dividend in the right position
if ($1 != ARM_R0)
arm_mov_reg_reg(inst, ARM_R0, $1);
libjit/jit/jit-rules-arm.ins view on Meta::CPAN
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN);
}
/*
* Pointer check opcodes.
*/
JIT_OP_CHECK_NULL: note
[reg] -> {
arm_test_reg_imm8(inst, ARM_CMP, $1, 0);
throw_builtin(&inst, func, ARM_CC_EQ, JIT_RESULT_NULL_REFERENCE);
}
/*
* Function calls.
*/
JIT_OP_CALL:
[] -> {
jit_function_t func = (jit_function_t)(insn->dest);
arm_call(inst, jit_function_to_closure(func));
libjit/jit/jit-rules-arm.ins view on Meta::CPAN
/*
* Exception handling
*/
JIT_OP_THROW: branch
[reg] -> {
arm_push_reg(inst, $1);
if(func->builder->setjmp_value != 0)
{
/* We have a "setjmp" block in the current function,
so we must record the location of the throw first */
jit_nint pc_offset;
_jit_gen_fix_value(func->builder->setjmp_value);
pc_offset = func->builder->setjmp_value->frame_offset +
jit_jmp_catch_pc_offset;
if(func->builder->position_independent)
{
arm_call_imm(inst, 0);
arm_pop_membase(inst, ARM_FP, pc_offset);
}
else
{
int pc = (int) (unsigned char *) arm_inst_get_posn(inst);
arm_mov_membase_imm(inst, ARM_FP, pc_offset, pc, 4, ARM_WORK);
}
}
arm_call(inst, (void *)jit_exception_throw);
}
JIT_OP_LOAD_PC:
[=reg] -> {
if(func->builder->position_independent)
{
arm_call_imm(inst, 0);
arm_pop_reg(inst, $1);
}
else
libjit/jit/jit-rules-x86-64.c view on Meta::CPAN
x86_64_mov_reg_imm_size(inst, X86_64_SCRATCH, func, 8);
x86_64_jmp_reg(inst, X86_64_SCRATCH);
}
return inst;
}
/*
* Throw a builtin exception.
*/
static unsigned char *
throw_builtin(unsigned char *inst, jit_function_t func, int type)
{
/* We need to update "catch_pc" if we have a "try" block */
if(func->builder->setjmp_value != 0)
{
_jit_gen_fix_value(func->builder->setjmp_value);
x86_64_lea_membase_size(inst, X86_64_RDI, X86_64_RIP, 0, 8);
x86_64_mov_membase_reg_size(inst, X86_64_RBP,
func->builder->setjmp_value->frame_offset
+ jit_jmp_catch_pc_offset, X86_64_RDI, 8);
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
}
[reg, local] -> {
x86_64_imul_reg_membase_size(inst, $1, X86_64_RBP, $2, 4);
}
[reg, reg] -> {
x86_64_imul_reg_reg_size(inst, $1, $2, 4);
}
JIT_OP_IDIV: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 gives an exception if the argument
is minint, or simply negates for other values */
jit_int min_int = jit_min_int;
unsigned char *patch;
x86_64_cmp_reg_imm_size(inst, $1, min_int, 4);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_64_neg_reg_size(inst, $1, 4);
}
[reg, imm, scratch reg, if("$2 == 2")] -> {
/* move the value to be divided to the temporary */
x86_64_mov_reg_reg_size(inst, $3, $1, 4);
/* shift the temporary to the 31 bits right */
/* The result is 1 for negative values and 0 for zero or */
/* positive values. (corrective value for negatives) */
x86_64_shr_reg_imm_size(inst, $3, 0x1f, 4);
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
x86_64_cdq(inst);
x86_64_idiv_reg_size(inst, $3, 4);
}
[reg("rax"), dreg, scratch reg("rdx")] -> {
jit_int min_int = jit_min_int;
unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
x86_64_test_reg_reg_size(inst, $2, $2, 4);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_64_cmp_reg_imm_size(inst, $2, -1, 4);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
x86_64_cmp_reg_imm_size(inst, $1, min_int, 4);
patch2 = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_patch(patch2, inst);
x86_64_cdq(inst);
x86_64_idiv_reg_size(inst, $2, 4);
}
JIT_OP_IDIV_UN: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
}
[reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
jit_nuint shift, value = $2 >> 1;
for(shift = 0; value; value >>= 1)
{
++shift;
}
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
x86_64_mov_reg_imm_size(inst, $3, $2, 4);
x86_64_clear_reg(inst, X86_64_RDX);
x86_64_div_reg_size(inst, $3, 4);
}
[reg("rax"), dreg, scratch reg("rdx")] -> {
#ifndef JIT_USE_SIGNALS
unsigned char *patch;
x86_64_test_reg_reg_size(inst, $2, $2, 4);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_64_clear_reg(inst, X86_64_RDX);
x86_64_div_reg_size(inst, $2, 4);
}
JIT_OP_IREM: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
x86_64_clear_reg(inst, $1);
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 gives an exception if the argument
is minint, or simply gives a remainder of zero */
jit_int min_int = jit_min_int;
unsigned char *patch;
x86_64_cmp_reg_imm_size(inst, $1, min_int, 4);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_64_clear_reg(inst, $1);
}
[=reg("rdx"), *reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
x86_64_mov_reg_imm_size(inst, $4, $3, 4);
x86_64_cdq(inst);
x86_64_idiv_reg_size(inst, $4, 4);
}
[=reg("rdx"), *reg("rax"), dreg, scratch reg("rdx")] -> {
jit_int min_int = jit_min_int;
unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
x86_64_test_reg_reg_size(inst, $3, $3, 4);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_64_cmp_reg_imm_size(inst, $3, -1, 4);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
x86_64_cmp_reg_imm_size(inst, $2, min_int, 4);
patch2 = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_patch(patch2, inst);
x86_64_cdq(inst);
x86_64_idiv_reg_size(inst, $3, 4);
}
JIT_OP_IREM_UN: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
x86_64_clear_reg(inst, $1);
}
[reg, imm, if("($2 & ($2 - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
x86_64_and_reg_imm_size(inst, $1, $2 - 1, 4);
}
[=reg("rdx"), *reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
x86_64_mov_reg_imm_size(inst, $4, $3, 4);
x86_64_clear_reg(inst, X86_64_RDX);
x86_64_div_reg_size(inst, $4, 4);
}
[=reg("rdx"), *reg("rax"), dreg, scratch reg("rdx")] -> {
#ifndef JIT_USE_SIGNALS
unsigned char *patch;
x86_64_test_reg_reg_size(inst, $3, $3, 4);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_64_clear_reg(inst, X86_64_RDX);
x86_64_div_reg_size(inst, $3, 4);
}
/*
* 8 byte integer versions
*/
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
}
[reg, local] -> {
x86_64_imul_reg_membase_size(inst, $1, X86_64_RBP, $2, 8);
}
[reg, reg] -> {
x86_64_imul_reg_reg_size(inst, $1, $2, 8);
}
JIT_OP_LDIV: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
}
[reg, imm, scratch reg, if("$2 == -1")] -> {
/* Dividing by -1 gives an exception if the argument
is minint, or simply negates for other values */
jit_long min_long = jit_min_long;
unsigned char *patch;
x86_64_mov_reg_imm_size(inst, $3, min_long, 8);
x86_64_cmp_reg_reg_size(inst, $1, $3, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_64_neg_reg_size(inst, $1, 8);
}
[reg, imm, scratch reg, if("$2 == 2")] -> {
/* move the value to be divided to the temporary */
x86_64_mov_reg_reg_size(inst, $3, $1, 8);
/* shift the temporary to the 63 bits right */
/* The result is 1 for negative values and 0 for zero or */
/* positive values. (corrective value for negatives) */
x86_64_shr_reg_imm_size(inst, $3, 0x3f, 8);
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
x86_64_cqo(inst);
x86_64_idiv_reg_size(inst, $3, 8);
}
[reg("rax"), dreg, scratch reg("rdx")] -> {
jit_long min_long = jit_min_long;
unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
x86_64_or_reg_reg_size(inst, $2, $2, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_64_cmp_reg_imm_size(inst, $2, -1, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
x86_64_mov_reg_imm_size(inst, $3, min_long, 8);
x86_64_cmp_reg_reg_size(inst, $1, $3, 8);
patch2 = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_patch(patch2, inst);
x86_64_cqo(inst);
x86_64_idiv_reg_size(inst, $2, 8);
}
JIT_OP_LDIV_UN: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
}
[reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
jit_nuint shift, value = $2 >> 1;
for(shift = 0; value; value >>= 1)
{
++shift;
}
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
x86_64_mov_reg_imm_size(inst, $3, $2, 8);
x86_64_clear_reg(inst, X86_64_RDX);
x86_64_div_reg_size(inst, $3, 8);
}
[reg("rax"), dreg, scratch reg("rdx")] -> {
#ifndef JIT_USE_SIGNALS
unsigned char *patch;
x86_64_test_reg_reg_size(inst, $2, $2, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_64_clear_reg(inst, X86_64_RDX);
x86_64_div_reg_size(inst, $2, 8);
}
JIT_OP_LREM: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
x86_64_clear_reg(inst, $1);
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 gives an exception if the argument
is minint, or simply gives a remainder of zero */
jit_long min_long = jit_min_long;
unsigned char *patch;
x86_64_cmp_reg_imm_size(inst, $1, min_long, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_64_clear_reg(inst, $1);
}
[=reg("rdx"), *reg("rax"), imm, scratch dreg, scratch reg("rdx")] -> {
x86_64_mov_reg_imm_size(inst, $4, $3, 8);
x86_64_cqo(inst);
x86_64_idiv_reg_size(inst, $4, 8);
}
[=reg("rdx"), *reg("rax"), dreg, scratch reg("rdx")] -> {
jit_long min_long = jit_min_long;
unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
x86_64_test_reg_reg_size(inst, $3, $3, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_64_mov_reg_imm_size(inst, $1, min_long, 8);
x86_64_cmp_reg_imm_size(inst, $3, -1, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
x86_64_cmp_reg_reg_size(inst, $2, $1, 8);
patch2 = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_patch(patch2, inst);
x86_64_cqo(inst);
x86_64_idiv_reg_size(inst, $3, 8);
}
JIT_OP_LREM_UN: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
x86_64_clear_reg(inst, $1);
}
[reg, imm, scratch reg, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
if(($2 >= jit_min_int) && ($2 <= jit_max_int))
{
x86_64_and_reg_imm_size(inst, $1, $2 - 1, 8);
}
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
x86_64_mov_reg_imm_size(inst, $4, $3, 8);
x86_64_clear_reg(inst, X86_64_RDX);
x86_64_div_reg_size(inst, $4, 8);
}
[=reg("rdx"), *reg("rax"), dreg, scratch reg("rdx")] -> {
#ifndef JIT_USE_SIGNALS
unsigned char *patch;
x86_64_test_reg_reg_size(inst, $3, $3, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_64_clear_reg(inst, X86_64_RDX);
x86_64_div_reg_size(inst, $3, 8);
}
/*
* single precision float versions
*/
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
*/
/*
* Pointer check opcodes.
*/
JIT_OP_CHECK_NULL: note
[reg] -> {
#if 0 && defined(JIT_USE_SIGNALS)
/* if $1 contains NULL this generates SEGV and the signal
handler will throw the exception */
x86_64_cmp_reg_membase_size(inst, $1, $1, 0, 8);
#else
unsigned char *patch;
x86_64_test_reg_reg_size(inst, $1, $1, 8);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_NULL_REFERENCE);
x86_patch(patch, inst);
#endif
}
/*
* Function calls.
*/
JIT_OP_CALL:
[] -> {
libjit/jit/jit-rules-x86-64.ins view on Meta::CPAN
*/
JIT_OP_THROW: branch
[reg] -> {
x86_64_mov_reg_reg_size(inst, X86_64_RDI, $1, 8);
if(func->builder->setjmp_value != 0)
{
jit_nint pc_offset;
/* We have a "setjmp" block in the current function,
so we must record the location of the throw first */
_jit_gen_fix_value(func->builder->setjmp_value);
pc_offset = func->builder->setjmp_value->frame_offset +
jit_jmp_catch_pc_offset;
x86_64_lea_membase_size(inst, X86_64_SCRATCH, X86_64_RIP, 0, 8);
x86_64_mov_membase_reg_size(inst, X86_64_RBP, pc_offset,
X86_64_SCRATCH, 8);
}
inst = x86_64_call_code(inst, (jit_nint)jit_exception_throw);
}
JIT_OP_RETHROW: manual
[] -> { /* Not used in native code back ends */ }
JIT_OP_LOAD_PC:
[=reg] -> {
x86_64_lea_membase_size(inst, $1, X86_64_RIP, 0, 8);
}
libjit/jit/jit-rules-x86.c view on Meta::CPAN
*inst++ = (unsigned char)0xE9;
x86_imm_emit32(inst, (int)(gen->epilog_fixup));
gen->epilog_fixup = (void *)(inst - 4);
return inst;
}
/*
* Throw a builtin exception.
*/
static unsigned char *
throw_builtin(unsigned char *inst, jit_function_t func, int type)
{
/* We need to update "catch_pc" if we have a "try" block */
if(func->builder->setjmp_value != 0)
{
_jit_gen_fix_value(func->builder->setjmp_value);
if(func->builder->position_independent)
{
x86_call_imm(inst, 0);
x86_pop_membase(inst, X86_EBP,
func->builder->setjmp_value->frame_offset
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
[reg] -> {
unsigned char *patch1;
unsigned char *patch2;
x86_alu_reg_imm(inst, X86_CMP, $1, -128);
patch1 = inst;
x86_branch8(inst, X86_CC_LE, 0, 1);
x86_alu_reg_imm(inst, X86_CMP, $1, 127);
patch2 = inst;
x86_branch8(inst, X86_CC_LE, 0, 1);
x86_patch(patch1, inst);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch2, inst);
}
JIT_OP_CHECK_UBYTE: more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 256);
patch1 = inst;
x86_branch8(inst, X86_CC_LT, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch1, inst);
}
JIT_OP_CHECK_SHORT: more_space
[reg] -> {
unsigned char *patch1;
unsigned char *patch2;
x86_alu_reg_imm(inst, X86_CMP, $1, -32768);
patch1 = inst;
x86_branch8(inst, X86_CC_LE, 0, 1);
x86_alu_reg_imm(inst, X86_CMP, $1, 32767);
patch2 = inst;
x86_branch8(inst, X86_CC_LE, 0, 1);
x86_patch(patch1, inst);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch2, inst);
}
JIT_OP_CHECK_USHORT: more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 65536);
patch1 = inst;
x86_branch8(inst, X86_CC_LT, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch1, inst);
}
JIT_OP_CHECK_INT, JIT_OP_CHECK_UINT: copy, more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 0);
patch1 = inst;
x86_branch8(inst, X86_CC_GE, 0, 1);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch1, inst);
}
JIT_OP_LOW_WORD:
[=reg, imm] -> {
jit_uint value = ((jit_uint *)($2))[0];
x86_mov_reg_imm(inst, $1, value);
}
[=reg, local] -> {
x86_mov_reg_membase(inst, $1, X86_EBP, $2, 4);
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
}
[reg, local] -> {
x86_imul_reg_membase(inst, $1, X86_EBP, $2);
}
[reg, reg] -> {
x86_imul_reg_reg(inst, $1, $2);
}
JIT_OP_IDIV: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 gives an exception if the argument
is minint, or simply negates for other values */
unsigned char *patch;
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_neg_reg(inst, $1);
}
[reg, imm, scratch reg, if("$2 == 2")] -> {
x86_mov_reg_reg(inst, $3, $1, 4);
x86_shift_reg_imm(inst, X86_SHR, $3, 0x1f);
x86_alu_reg_reg(inst, X86_ADD, $1, $3);
x86_shift_reg_imm(inst, X86_SAR, $1, 1);
}
[reg, imm, scratch reg, if("($2 > 0) && (((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
x86_mov_reg_imm(inst, $3, $2);
x86_cdq(inst);
x86_div_reg(inst, $3, 1);
}
[reg("eax"), reg, scratch reg("edx")] -> {
unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
x86_alu_reg_reg(inst, X86_OR, $2, $2);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_alu_reg_imm(inst, X86_CMP, $2, -1);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
patch2 = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_patch(patch2, inst);
x86_cdq(inst);
x86_div_reg(inst, $2, 1);
}
JIT_OP_IDIV_UN: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
}
[reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
jit_nuint shift, value = $2 >> 1;
for(shift = 0; value; value >>= 1)
{
++shift;
}
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
x86_mov_reg_imm(inst, $3, $2);
x86_clear_reg(inst, X86_EDX);
x86_div_reg(inst, $3, 0);
}
[reg("eax"), reg, scratch reg("edx")] -> {
#ifndef JIT_USE_SIGNALS
unsigned char *patch;
x86_alu_reg_reg(inst, X86_OR, $2, $2);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_clear_reg(inst, X86_EDX);
x86_div_reg(inst, $2, 0);
}
JIT_OP_IREM: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
x86_clear_reg(inst, $1);
}
[reg, imm, if("$2 == -1")] -> {
/* Dividing by -1 gives an exception if the argument
is minint, or simply gives a remainder of zero */
unsigned char *patch;
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_clear_reg(inst, $1);
}
[=reg("edx"), *reg("eax"), imm, scratch reg, scratch reg("edx")] -> {
x86_mov_reg_imm(inst, $4, $3);
x86_cdq(inst);
x86_div_reg(inst, $4, 1);
}
[=reg("edx"), *reg("eax"), reg, scratch reg("edx")] -> {
unsigned char *patch, *patch2;
#ifndef JIT_USE_SIGNALS
x86_alu_reg_reg(inst, X86_OR, $3, $3);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_alu_reg_imm(inst, X86_CMP, $3, -1);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
x86_alu_reg_imm(inst, X86_CMP, $2, jit_min_int);
patch2 = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
x86_patch(patch, inst);
x86_patch(patch2, inst);
x86_cdq(inst);
x86_div_reg(inst, $3, 1);
}
JIT_OP_IREM_UN: more_space
[any, immzero] -> {
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
}
[reg, imm, if("$2 == 1")] -> {
x86_clear_reg(inst, $1);
}
[reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> {
/* x & (x - 1) is equal to zero if x is a power of 2 */
x86_alu_reg_imm(inst, X86_AND, $1, $2 - 1);
}
[=reg("edx"), *reg("eax"), imm, scratch reg, scratch reg("edx")] -> {
x86_mov_reg_imm(inst, $4, $3);
x86_clear_reg(inst, X86_EDX);
x86_div_reg(inst, $4, 0);
}
[=reg("edx"), *reg("eax"), reg, scratch reg("edx")] -> {
#ifndef JIT_USE_SIGNALS
unsigned char *patch;
x86_alu_reg_reg(inst, X86_OR, $3, $3);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
x86_patch(patch, inst);
#endif
x86_clear_reg(inst, X86_EDX);
x86_div_reg(inst, $3, 0);
}
JIT_OP_INEG:
[reg] -> {
x86_neg_reg(inst, $1);
}
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
}
/*
* Pointer check opcodes.
*/
JIT_OP_CHECK_NULL: note
[reg] -> {
#if 0 && defined(JIT_USE_SIGNALS)
/* if $1 contains NULL this generates SEGV and the signal
handler will throw the exception */
x86_alu_reg_membase(inst, X86_CMP, $1, $1, 0);
#else
unsigned char *patch;
x86_alu_reg_reg(inst, X86_OR, $1, $1);
patch = inst;
x86_branch8(inst, X86_CC_NE, 0, 0);
inst = throw_builtin(inst, func, JIT_RESULT_NULL_REFERENCE);
x86_patch(patch, inst);
#endif
}
/*
* Function calls.
*/
JIT_OP_CALL:
[] -> {
libjit/jit/jit-rules-x86.ins view on Meta::CPAN
/*
* Exception handling.
*/
JIT_OP_THROW: branch
[reg] -> {
x86_push_reg(inst, $1);
if(func->builder->setjmp_value != 0)
{
/* We have a "setjmp" block in the current function,
so we must record the location of the throw first */
_jit_gen_fix_value(func->builder->setjmp_value);
if(func->builder->position_independent)
{
x86_call_imm(inst, 0);
x86_pop_membase(inst, X86_EBP,
func->builder->setjmp_value->frame_offset
+ jit_jmp_catch_pc_offset);
}
else
{
int pc = (int) inst;
x86_mov_membase_imm(inst, X86_EBP,
func->builder->setjmp_value->frame_offset
+ jit_jmp_catch_pc_offset, pc, 4);
}
}
x86_call_code(inst, (void *)jit_exception_throw);
}
JIT_OP_RETHROW: manual
[] -> { /* Not used in native code back ends */ }
JIT_OP_LOAD_PC:
[=reg] -> {
if(func->builder->position_independent)
{
x86_call_imm(inst, 0);