It is not possible to throw exceptions directly from jato functions because we cannot unwind C functions. Instead we store the exception pointer in current execution environment and set "exception_guard" pointer to a hidden guard page. When control will be returned to jit method the code will poll memory pointed by "exception_guard" and will trigger SIGSEGV. The signal handler takes care of throwing the exception.
Signed-off-by: Tomek Grabiec <tgrab...@gmail.com> --- include/jit/exception.h | 17 +++++++++++ jit/exception.c | 71 ++++++++++++++++++++++++++++++++++++++++------ test/arch-x86/Makefile | 1 + test/jit/Makefile | 1 + vm/jato.c | 5 ++- vm/signal.c | 21 ++++++++++++- 6 files changed, 103 insertions(+), 13 deletions(-) diff --git a/include/jit/exception.h b/include/jit/exception.h index 0c1ff5c..5bfce28 100644 --- a/include/jit/exception.h +++ b/include/jit/exception.h @@ -7,6 +7,17 @@ struct compilation_unit; struct jit_stack_frame; +/* + * This is a per-thread pointer to a memory location which should be + * polled by JIT code to check whether exception occurred. When + * exception is set this pointer will point to a hidden guard page + * which will trigger SIGSEGV on access. The signal handler will throw + * the exception then. + */ +extern __thread void *exception_guard; + +extern void *exceptions_guard_page; + struct exception_table_entry *exception_find_entry(struct methodblock *, unsigned long); @@ -27,5 +38,11 @@ unsigned char *throw_exception(struct compilation_unit *cu, struct object *exception); void throw_exception_from_signal(void *ctx, struct object *exception); void unwind(void); +void signal_exception(struct object *obj); +void clear_exception(); +struct object *exception_occurred(); +void init_exceptions(); +void thread_init_exceptions(); + #endif /* JATO_JIT_EXCEPTION_H */ diff --git a/jit/exception.c b/jit/exception.c index 3f05dd6..a01d06a 100644 --- a/jit/exception.c +++ b/jit/exception.c @@ -30,11 +30,59 @@ #include <jit/exception.h> #include <jit/compiler.h> +#include <vm/guard-page.h> #include <vm/buffer.h> +#include <vm/die.h> + #include <arch/stack-frame.h> #include <arch/instruction.h> #include <errno.h> +__thread void *exception_guard = NULL; +void *exceptions_guard_page; + +void init_exceptions() +{ + exceptions_guard_page = alloc_guard_page(); + if (!exceptions_guard_page) + die("%s: failed to allocate exceptions guard page.", __func__); + + /* TODO: Should be called from thread initialization code. */ + thread_init_exceptions(); +} + +/** + * thread_init_exceptions - initializes per-thread structures. + */ +void thread_init_exceptions() +{ + exception_guard = &exception_guard; /* assign a safe pointer */ +} + +/** + * signal_exception - used for signaling that exception has occurred in + * jato functions. Exception will be thrown as soon as + * controll is returned back to JIT method code. + * + * @exception: exception object to be thrown. + */ +void signal_exception(struct object *exception) +{ + getExecEnv()->exception = exception; + exception_guard = exceptions_guard_page; +} + +struct object *exception_occurred() +{ + return getExecEnv()->exception; +} + +void clear_exception() +{ + exception_guard = &exception_guard; + getExecEnv()->exception = NULL; +} + struct exception_table_entry *exception_find_entry(struct methodblock *method, unsigned long target) { @@ -116,14 +164,16 @@ unsigned char *throw_exception_from(struct compilation_unit *cu, unsigned char *native_ptr, struct object *exception) { - unsigned char *eh_ptr = NULL; + struct object *ee_exception; unsigned long bc_offset; + unsigned char *eh_ptr; + + eh_ptr = NULL; - if (getExecEnv()->exception != NULL) { - /* Looks like we've caught some asynchronous exception, - which must have precedence. */ - exception = getExecEnv()->exception; - getExecEnv()->exception = NULL; + ee_exception = exception_occurred(); + if (ee_exception) { + exception = ee_exception; + clear_exception(); } bc_offset = native_ptr_to_bytecode_offset(cu, native_ptr); @@ -134,10 +184,11 @@ unsigned char *throw_exception_from(struct compilation_unit *cu, } if (!is_jit_method(frame->return_address)) { - /* No handler found within jitted method call - chain. Set exception in execution environment and - return to previous (not jit) method. */ - getExecEnv()->exception = exception; + /* + * No handler found within jitted method call chain. + * Signal exception and return to previous (not jit) method. + */ + signal_exception(exception); return bb_native_ptr(cu->exit_bb); } diff --git a/test/arch-x86/Makefile b/test/arch-x86/Makefile index c12e0c9..91e27c2 100644 --- a/test/arch-x86/Makefile +++ b/test/arch-x86/Makefile @@ -36,6 +36,7 @@ OBJS = \ ../../vm/types.o \ ../../vm/zalloc.o \ ../../vm/radix-tree.o \ + ../../vm/guard-page.o \ ../../jit/alloc.o \ ../../jit/basic-block.o \ ../../jit/compilation-unit.o \ diff --git a/test/jit/Makefile b/test/jit/Makefile index 4d26480..ab708fc 100644 --- a/test/jit/Makefile +++ b/test/jit/Makefile @@ -14,6 +14,7 @@ OBJS = \ ../../vm/types.o \ ../../vm/zalloc.o \ ../../vm/radix-tree.o \ + ../../vm/guard-page.o \ ../../jit/alloc.o \ ../../jit/arithmetic-bc.o \ ../../jit/basic-block.o \ diff --git a/vm/jato.c b/vm/jato.c index 3960196..34125dc 100644 --- a/vm/jato.c +++ b/vm/jato.c @@ -28,8 +28,10 @@ #include <vm/natives.h> #include <vm/signal.h> #include <vm/vm.h> -#include <jit/compiler.h> + #include <jit/cu-mapping.h> +#include <jit/exception.h> +#include <jit/compiler.h> #ifdef USE_ZIP #define BCP_MESSAGE "<jar/zip files and directories separated by :>" @@ -300,6 +302,7 @@ int main(int argc, char *argv[]) { setup_signal_handlers(); init_cu_mapping(); + init_exceptions(); setDefaultInitArgs(&args); int class_arg = parseCommandLine(argc, argv, &args); diff --git a/vm/signal.c b/vm/signal.c index 0055ed1..af89c6e 100644 --- a/vm/signal.c +++ b/vm/signal.c @@ -59,10 +59,12 @@ static void sigfpe_handler(int sig, siginfo_t *si, void *ctx) static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) { + if (!signal_from_jit_method(ctx)) + goto exit; + /* Assume that zero-page access is caused by dereferencing a null pointer */ - if (signal_from_jit_method(ctx) && - ((unsigned long)si->si_addr < (unsigned long)getpagesize())) { + if ((unsigned long)si->si_addr < (unsigned long)getpagesize()) { struct object *exception; /* TODO: exception's stack trace should be filled using ctx */ @@ -77,6 +79,21 @@ static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) return; } + /* Check if exception was triggered by exception guard */ + if (si->si_addr == exceptions_guard_page) { + struct object *exception; + + exception = exception_occurred(); + if (exception == NULL) { + fprintf(stderr, "%s: spurious exception-test failure\n", + __func__); + goto exit; + } + + throw_exception_from_signal(ctx, exception); + return; + } + exit: print_backtrace_and_die(sig, si, ctx); } -- 1.6.0.6 ------------------------------------------------------------------------------ OpenSolaris 2009.06 is a cutting edge operating system for enterprises looking to deploy the next generation of Solaris that includes the latest innovations from Sun and the OpenSource community. Download a copy and enjoy capabilities such as Networking, Storage and Virtualization. Go to: http://p.sf.net/sfu/opensolaris-get _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel