Alien-LibJIT
view release on metacpan or search on metacpan
libjit/jit/jit-interp.c view on Meta::CPAN
/*
* jit-interp.c - Fallback interpreter implementation.
*
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
*
* This file is part of the libjit library.
*
* The libjit library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 2.1 of
* the License, or (at your option) any later version.
*
* The libjit library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the libjit library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/*
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
#include <alloca.h>
#endif
#ifdef JIT_WIN32_PLATFORM
#include <malloc.h>
#ifndef alloca
#define alloca _alloca
#endif
#endif
#include "jit-setjmp.h"
#if defined(JIT_BACKEND_INTERP)
/*
* Determine what kind of interpreter dispatch to use.
*/
#ifdef HAVE_COMPUTED_GOTO
#if defined(PIC) && defined(HAVE_PIC_COMPUTED_GOTO)
#define JIT_INTERP_TOKEN_PIC 1
#elif defined(PIC)
#define JIT_INTERP_SWITCH 1
#else
#define JIT_INTERP_TOKEN 1
#endif
#else /* !HAVE_COMPUTED_GOTO */
#define JIT_INTERP_SWITCH 1
#endif /* !HAVE_COMPUTED_GOTO */
/*
* Modify the program counter and stack pointer.
*/
#define VM_MODIFY_PC_AND_STACK(pcmod,stkmod) \
do { \
pc += (jit_nint)(int)(pcmod); \
stacktop += (jit_nint)(int)(stkmod); \
} while (0)
#define VM_MODIFY_PC(pcmod) \
do { \
pc += (jit_nint)(int)(pcmod); \
} while (0)
#define VM_MODIFY_STACK(stkmod) \
do { \
stacktop += (jit_nint)(int)(stkmod); \
} while (0)
/*
* Fetch arguments of various types from the instruction stream.
*/
#define VM_NINT_ARG (((jit_nint *)(pc))[1])
#define VM_NINT_ARG2 (((jit_nint *)(pc))[2])
#define VM_NINT_ARG3 (((jit_nint *)(pc))[3])
libjit/jit/jit-interp.c view on Meta::CPAN
apply_args[param] = args;
args += JIT_NUM_ITEMS_IN_STRUCT(jit_type_get_size(type));
}
break;
default:
{
/* Shouldn't happen, but do something sane */
apply_args[param] = args;
}
break;
}
}
/* Apply the function */
jit_apply(signature, func, apply_args, num_fixed_args, return_area);
}
void _jit_run_function(jit_function_interp_t func, jit_item *args,
jit_item *return_area)
{
jit_item *frame_base;
jit_item *frame;
jit_item *stacktop;
jit_item r0, r1, r2;
void **pc;
jit_int builtin_exception;
jit_nint temparg;
void *tempptr;
void *tempptr2;
jit_function_t call_func;
struct jit_backtrace call_trace;
void *entry;
void *exception_object = 0;
void *exception_pc = 0;
void *handler;
jit_jmp_buf *jbuf;
jit_nint current_frame_size;
/* Define the label table for computed goto dispatch */
#include "jit-interp-labels.h"
/* Set up the stack frame for this function */
current_frame_size = func->frame_size;
frame_base = (jit_item *)alloca(current_frame_size);
stacktop = frame_base + func->working_area;
frame = stacktop;
/* Get the initial program counter */
restart_tail:
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;
}
/* Enter the instruction dispatch loop */
VMSWITCH(pc)
{
/******************************************************************
* Simple opcodes.
******************************************************************/
VMCASE(JIT_OP_NOP):
{
/* Nothing to do except move on to the next instruction */
VM_MODIFY_PC(1);
}
VMBREAK;
/******************************************************************
* Conversion opcodes.
******************************************************************/
VMCASE(JIT_OP_TRUNC_SBYTE):
{
/* Truncate an integer to a signed 8-bit value */
VM_R0_INT = (jit_int)(jit_sbyte)VM_R1_INT;
VM_MODIFY_PC(1);
}
VMBREAK;
VMCASE(JIT_OP_TRUNC_UBYTE):
{
/* Truncate an integer to an unsigned 8-bit value */
VM_R0_INT = (jit_int)(jit_ubyte)VM_R1_INT;
VM_MODIFY_PC(1);
}
VMBREAK;
VMCASE(JIT_OP_TRUNC_SHORT):
{
/* Truncate an integer to a signed 16-bit value */
VM_R0_INT = (jit_int)(jit_short)VM_R1_INT;
VM_MODIFY_PC(1);
}
VMBREAK;
VMCASE(JIT_OP_TRUNC_USHORT):
{
/* Truncate an integer to an unsigned 16-bit value */
VM_R0_INT = (jit_int)(jit_ushort)VM_R1_INT;
VM_MODIFY_PC(1);
}
VMBREAK;
libjit/jit/jit-interp.c view on Meta::CPAN
VMBREAK;
VMCASE(JIT_OP_PUSH_FLOAT64):
{
VM_STK_FLOAT64P = VM_R1_FLOAT64;
VM_MODIFY_PC_AND_STACK(1, -1);
}
VMBREAK;
VMCASE(JIT_OP_PUSH_NFLOAT):
{
VM_STK_NFLOATP = VM_R1_NFLOAT;
VM_MODIFY_PC_AND_STACK(1, -1);
}
VMBREAK;
VMCASE(JIT_OP_PUSH_STRUCT):
{
/* Push a structure value onto the stack, given a pointer to it */
temparg = VM_NINT_ARG;
stacktop -= JIT_NUM_ITEMS_IN_STRUCT(temparg);
jit_memcpy(stacktop, VM_R1_PTR, (unsigned int)temparg);
VM_MODIFY_PC(2);
}
VMBREAK;
VMCASE(JIT_OP_FLUSH_SMALL_STRUCT):
{
#if JIT_APPLY_MAX_STRUCT_IN_REG != 0
jit_memcpy(VM_R0_PTR, return_area->struct_value, VM_NINT_ARG);
#endif
VM_MODIFY_PC(2);
}
VMBREAK;
/******************************************************************
* Exception handling.
******************************************************************/
VMCASE(JIT_OP_THROW):
{
/* Throw an exception, which may be handled in this function */
exception_object = VM_R1_PTR;
exception_pc = pc;
handle_exception:
tempptr = jit_function_from_pc(func->func->context, pc, &handler);
if(tempptr == func->func && handler != 0)
{
/* We have an appropriate "catch" handler in this function */
pc = (void **)handler;
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;
VMCASE(JIT_OP_LOAD_EXCEPTION_PC):
{
/* Load the address where the exception occurred onto the stack */
VM_R0_PTR = (void *)exception_pc;
VM_MODIFY_PC(1);
}
VMBREAK;
VMCASE(JIT_OP_LEAVE_FINALLY):
{
/* Return from a "finally" handler */
pc = (void **)VM_STK_PTR0;
VM_MODIFY_STACK(1);
}
VMBREAK;
VMCASE(JIT_OP_LEAVE_FILTER):
{
/* Return from a "filter" handler: pc on stack */
pc = (void **)(stacktop[0].ptr_value);
VM_MODIFY_STACK(1);
}
VMBREAK;
VMCASE(JIT_OP_CALL_FILTER):
{
/* Call a "filter" handler with pc and value on stack */
stacktop[-1].ptr_value = (void *)(pc + 2);
VM_MODIFY_STACK(-1);
pc = VM_BR_TARGET;
}
VMBREAK;
VMCASE(JIT_OP_CALL_FINALLY):
{
/* Call a "finally" handler */
VM_STK_PTRP = (void *)(pc + 2);
VM_MODIFY_STACK(-1);
pc = VM_BR_TARGET;
}
VMBREAK;
VMCASE(JIT_OP_ADDRESS_OF_LABEL):
{
/* Load the address of a label onto the stack */
VM_R0_PTR = VM_BR_TARGET;
VM_MODIFY_PC(2);
}
VMBREAK;
libjit/jit/jit-interp.c view on Meta::CPAN
VM_MODIFY_PC(1);
}
VMBREAK;
VMCASE(JIT_OP_STORE_ELEMENT_FLOAT64):
{
/* Store a 64-bit float value to an array */
VM_STORE_ELEM(jit_float64, VM_R2_FLOAT64);
VM_MODIFY_PC(1);
}
VMBREAK;
VMCASE(JIT_OP_STORE_ELEMENT_NFLOAT):
{
/* Store a native float value to an array */
VM_STORE_ELEM(jit_nfloat, VM_R2_NFLOAT);
VM_MODIFY_PC(1);
}
VMBREAK;
/******************************************************************
* Block operations.
******************************************************************/
VMCASE(JIT_OP_MEMCPY):
{
/* Copy a block of memory */
jit_memcpy(VM_R0_PTR, VM_R1_PTR, VM_R2_NUINT);
VM_MODIFY_PC(1);
}
VMBREAK;
VMCASE(JIT_OP_MEMMOVE):
{
/* Move a block of memory */
jit_memmove(VM_R0_PTR, VM_R1_PTR, VM_R2_NUINT);
VM_MODIFY_PC(1);
}
VMBREAK;
VMCASE(JIT_OP_MEMSET):
{
/* Set a block of memory to a value */
jit_memset(VM_R0_PTR, (int)VM_R1_INT, VM_R2_NUINT);
VM_MODIFY_PC(1);
}
VMBREAK;
/******************************************************************
* Allocate memory from the stack.
******************************************************************/
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;
}
}
}
VMBREAK;
/******************************************************************
* Argument variable access opcodes.
******************************************************************/
VMCASE(JIT_INTERP_OP_LDA_0_SBYTE):
{
/* Load a signed 8-bit integer argument into the register 0 */
VM_R0_INT = *VM_ARG(jit_sbyte);
VM_MODIFY_PC(2);
}
VMBREAK;
VMCASE(JIT_INTERP_OP_LDA_0_UBYTE):
{
/* Load an unsigned 8-bit integer argument into the register 0 */
VM_R0_INT = *VM_ARG(jit_ubyte);
VM_MODIFY_PC(2);
}
VMBREAK;
VMCASE(JIT_INTERP_OP_LDA_0_SHORT):
{
/* Load a signed 16-bit integer argument into the register 0 */
VM_R0_INT = *VM_ARG(jit_short);
VM_MODIFY_PC(2);
}
VMBREAK;
VMCASE(JIT_INTERP_OP_LDA_0_USHORT):
{
/* Load am unsigned 16-bit argument local into the register 0 */
VM_R0_INT = *VM_ARG(jit_ushort);
VM_MODIFY_PC(2);
}
VMBREAK;
VMCASE(JIT_INTERP_OP_LDA_0_INT):
{
/* Load a 32-bit integer argument into the register 0 */
VM_R0_INT = *VM_ARG(jit_int);
VM_MODIFY_PC(2);
}
VMBREAK;
VMCASE(JIT_INTERP_OP_LDA_0_LONG):
{
/* Load a 64-bit integer argument into the register 0 */
libjit/jit/jit-interp.c view on Meta::CPAN
VMCASE(JIT_OP_INCOMING_REG):
VMCASE(JIT_OP_INCOMING_FRAME_POSN):
VMCASE(JIT_OP_OUTGOING_REG):
VMCASE(JIT_OP_OUTGOING_FRAME_POSN):
VMCASE(JIT_OP_RETURN_REG):
VMCASE(JIT_OP_SET_PARAM_INT):
VMCASE(JIT_OP_SET_PARAM_LONG):
VMCASE(JIT_OP_SET_PARAM_FLOAT32):
VMCASE(JIT_OP_SET_PARAM_FLOAT64):
VMCASE(JIT_OP_SET_PARAM_NFLOAT):
VMCASE(JIT_OP_SET_PARAM_STRUCT):
VMCASE(JIT_OP_ENTER_FINALLY):
VMCASE(JIT_OP_ENTER_FILTER):
VMCASE(JIT_OP_CALL_FILTER_RETURN):
VMCASE(JIT_OP_MARK_OFFSET):
{
/* Shouldn't happen, but skip the instruction anyway */
VM_MODIFY_PC_AND_STACK(1, 0);
}
VMBREAK;
}
VMSWITCHEND
handle_builtin: ;
jit_exception_builtin(builtin_exception);
}
int jit_function_apply
(jit_function_t func, void **args, void *return_area)
{
if(func)
{
return jit_function_apply_vararg
(func, func->signature, args, return_area);
}
else
{
return jit_function_apply_vararg(func, 0, args, return_area);
}
}
/* Imported from "jit-rules-interp.c" */
unsigned int _jit_interp_calculate_arg_size
(jit_function_t func, jit_type_t signature);
int jit_function_apply_vararg
(jit_function_t func, jit_type_t signature, void **args, void *return_area)
{
struct jit_backtrace call_trace;
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);
/* Clear the exception context */
jit_exception_clear_last();
/* Bail out if the function is NULL */
if(!func)
{
jit_exception_builtin(JIT_RESULT_NULL_FUNCTION);
}
/* Make sure that the function is compiled */
if(func->is_compiled)
{
entry = (jit_function_interp_t)(func->entry_point);
}
else
{
entry = (jit_function_interp_t)(*func->context->on_demand_driver)(func);
}
/* Populate the low-level argument buffer */
if(!signature)
{
signature = func->signature;
arg_buffer = (jit_item *)alloca(entry->args_size);
}
else if(signature == func->signature)
{
arg_buffer = (jit_item *)alloca(entry->args_size);
}
else
{
arg_buffer = (jit_item *)alloca
(_jit_interp_calculate_arg_size(func, signature));
}
temp_arg = arg_buffer;
if(func->nested_parent)
{
jit_exception_builtin(JIT_RESULT_CALLED_NESTED);
}
type = jit_type_get_return(signature);
if(jit_type_return_via_pointer(type))
{
if(!return_area)
{
return_area = alloca(jit_type_get_size(type));
}
temp_arg->ptr_value = return_area;
++temp_arg;
}
( run in 0.446 second using v1.01-cache-2.11-cpan-119454b85a5 )