#include "jit-internal.h"
#include "jit-rules.h"
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#if defined(JIT_BACKEND_INTERP)
# include "jit-interp.h"
#endif
#include <stdio.h>
#include "jit-setjmp.h"
void *jit_exception_get_last(void)
{
jit_thread_control_t control = _jit_thread_get_control();
if(control)
{
return control->last_exception;
}
else
{
return 0;
}
}
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;
}
}
void jit_exception_set_last(void *object)
{
jit_thread_control_t control = _jit_thread_get_control();
if(control)
{
control->last_exception = object;
}
}
void jit_exception_clear_last(void)
{
jit_exception_set_last(0);
}
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);
}
}
}
void jit_exception_builtin(int exception_type)
{
jit_exception_func handler;
void *object;
static const char * const messages[11] = {
"Success",
"Overflow during checked arithmetic operation",
"Arithmetic exception (dividing the minimum integer by -1)",
"Division by zero",
"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 *))
handler = jit_exception_get_handler();
if(handler)
{
object = (*handler)(exception_type);
if(object)
{
jit_exception_throw(object);
}
}
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);
}
else
{
fprintf(stderr, "Unknown builtin exception %d",
(-exception_type) + 1);
}
putc('\n', stderr);
exit(1);
}
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;
}
}
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;
}
}
struct jit_stack_trace
{
unsigned int size;
void *items[1];
};
jit_stack_trace_t jit_exception_get_stack_trace(void)
{
jit_stack_trace_t trace;
unsigned int size;
jit_unwind_context_t unwind;
size = 0;
if(jit_unwind_init(&unwind, NULL))
{
do
{
size++;
}
while(jit_unwind_next_pc(&unwind));
jit_unwind_free(&unwind);
}
if(size == 0)
{
return 0;
}
trace = (jit_stack_trace_t) jit_malloc(sizeof(struct jit_stack_trace)
+ size * sizeof(void *)
- sizeof(void *));
if(!trace)
{
return 0;
}
trace->size = size;
size = 0;
if(jit_unwind_init(&unwind, NULL))
{
do
{
trace->items[size] = jit_unwind_get_pc(&unwind);
size++;
}
while(jit_unwind_next_pc(&unwind));
jit_unwind_free(&unwind);
}
else
{
jit_free(trace);
return 0;
}
return trace;
}
unsigned int jit_stack_trace_get_size(jit_stack_trace_t trace)
{
if(trace)
{
return trace->size;
}
else
{
return 0;
}
}
jit_function_t
jit_stack_trace_get_function(jit_context_t context, jit_stack_trace_t trace, unsigned int posn)
{
if(trace && posn < trace->size)
{
void *func_info = _jit_memory_find_function_info(context, trace->items[posn]);
if(func_info)
{
return _jit_memory_get_function(context, func_info);
}
}
return 0;
}
void *jit_stack_trace_get_pc
(jit_stack_trace_t trace, unsigned int posn)
{
if(trace && posn < trace->size)
{
return trace->items[posn];
}
else
{
return 0;
}
}
unsigned int
jit_stack_trace_get_offset(jit_context_t context, jit_stack_trace_t trace, unsigned int posn)
{
void *func_info;
jit_function_t func;
if(!trace || posn >= trace->size)
{
return JIT_NO_OFFSET;
}
func_info = _jit_memory_find_function_info(context, trace->items[posn]);
if(!func_info)
{
return JIT_NO_OFFSET;
}
func = _jit_memory_get_function(context, func_info);
if(!func)
{
return JIT_NO_OFFSET;
}
return _jit_function_get_bytecode(func, func_info, trace->items[posn], 0);
}
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();
jit_exception_throw(jit_exception_get_last());
}