If method compilation failed but exception is signalled we should throw that exception rather than die.
Signed-off-by: Tomek Grabiec <tgrab...@gmail.com> --- arch/x86/emit-code_32.c | 21 +++++++++++++++++++++ arch/x86/exception.c | 28 ++++++++++++++++++++++++++++ arch/x86/include/arch/signal.h | 5 +++++ arch/x86/signal.c | 12 ++++++++---- include/jit/exception.h | 6 ++++++ jit/exception.c | 12 ++++++++++-- jit/trampoline.c | 30 +++++++++++++++++++++++++----- vm/signal.c | 16 ++++++++++++++-- 8 files changed, 117 insertions(+), 13 deletions(-) diff --git a/arch/x86/emit-code_32.c b/arch/x86/emit-code_32.c index 6006336..e50fc1b 100644 --- a/arch/x86/emit-code_32.c +++ b/arch/x86/emit-code_32.c @@ -22,6 +22,7 @@ #include <arch/instruction.h> #include <arch/memory.h> #include <arch/stack-frame.h> +#include <arch/thread.h> #include <assert.h> #include <errno.h> @@ -848,6 +849,12 @@ static void emit_xor_imm_reg(struct buffer *buf, struct operand * src, __emit_xor_imm_reg(buf, src->imm, mach_reg(&dest->reg)); } +static void __emit_test_membase_reg(struct buffer *buf, enum machine_reg src, + unsigned long disp, enum machine_reg dest) +{ + __emit_membase_reg(buf, 0x85, src, disp, dest); +} + static void emit_test_membase_reg(struct buffer *buf, struct operand *src, struct operand *dest) { @@ -1143,6 +1150,20 @@ void emit_trampoline(struct compilation_unit *cu, __emit_call(buf, call_target); __emit_add_imm_reg(buf, 0x04, REG_ESP); + /* + * Test for exeption occurance. + * We do this by polling a dedicated thread-specific pointer, + * which triggers SIGSEGV when exception is set. + * + * mov gs:(0xXXX), %ecx + * test (%ecx), %ecx + */ + emit(buf, 0x65); + __emit_memdisp_reg(buf, 0x8b, + get_thread_local_offset(&trampoline_exception_guard), + REG_ECX); + __emit_test_membase_reg(buf, REG_ECX, 0, REG_ECX); + __emit_push_reg(buf, REG_EAX); if (method_is_virtual(cu->method)) { diff --git a/arch/x86/exception.c b/arch/x86/exception.c index 2a8d6c3..c67d7dd 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -28,6 +28,7 @@ #include <jit/basic-block.h> #include <jit/cu-mapping.h> #include <jit/exception.h> +#include <jit/compiler.h> #include <arch/stack-frame.h> #include <arch/memory.h> @@ -70,3 +71,30 @@ void throw_exception_from_signal(void *ctx, struct object *exception) stack = (unsigned long*)uc->uc_mcontext.gregs[REG_SP]; *stack = (unsigned long)exception; } + +void throw_exception_from_trampoline(void *ctx, struct object *exception) +{ + unsigned long return_address; + unsigned long *stack; + ucontext_t *uc; + + uc = ctx; + + stack = (unsigned long*)uc->uc_mcontext.gregs[REG_SP]; + return_address = stack[1]; + + if (!is_jit_method(return_address)) { + /* Signal exception and return to caller. */ + signal_exception(exception); + uc->uc_mcontext.gregs[REG_IP] = return_address; + } else { + /* Unwind to previous jit method. */ + uc->uc_mcontext.gregs[REG_CX] = (unsigned long)exception; + uc->uc_mcontext.gregs[REG_IP] = (unsigned long)unwind; + } + + /* pop EBP from stack */ + stack = (unsigned long*)uc->uc_mcontext.gregs[REG_SP]; + uc->uc_mcontext.gregs[REG_BP] = *stack; + uc->uc_mcontext.gregs[REG_SP] += sizeof(unsigned long); +} diff --git a/arch/x86/include/arch/signal.h b/arch/x86/include/arch/signal.h index 49ce51f..313d9cb 100644 --- a/arch/x86/include/arch/signal.h +++ b/arch/x86/include/arch/signal.h @@ -9,14 +9,19 @@ #define REG_IP REG_EIP #define REG_SP REG_ESP #define REG_BP REG_EBP + #define REG_CX REG_ECX #elif defined(CONFIG_X86_64) #define REG_IP REG_RIP #define REG_SP REG_RSP #define REG_BP REG_RBP + #define REG_CX REG_RCX #else #error Unsupported architecture #endif +struct compilation_unit; + bool signal_from_jit_method(void *ctx); +struct compilation_unit *get_signal_source_cu(void *ctx); #endif diff --git a/arch/x86/signal.c b/arch/x86/signal.c index de79379..dccf4aa 100644 --- a/arch/x86/signal.c +++ b/arch/x86/signal.c @@ -41,9 +41,13 @@ bool signal_from_jit_method(void *ctx) if (!is_jit_method(ip)) return false; - /* We must be extra caucious here because IP might be iinvalid*/ - if (get_cu_from_native_addr(ip) == NULL) - return false; - return true; } + +struct compilation_unit *get_signal_source_cu(void *ctx) +{ + ucontext_t *uc; + + uc = ctx; + return get_cu_from_native_addr(uc->uc_mcontext.gregs[REG_IP]); +} diff --git a/include/jit/exception.h b/include/jit/exception.h index 5c0b0e0..469c5f2 100644 --- a/include/jit/exception.h +++ b/include/jit/exception.h @@ -16,7 +16,12 @@ struct jit_stack_frame; */ extern __thread void *exception_guard; +/* Same as exception_guard but destined to be used in trampolines + to distinguish between them and the general case. */ +extern __thread void *trampoline_exception_guard; + extern void *exceptions_guard_page; +extern void *trampoline_exceptions_guard_page; struct exception_table_entry *exception_find_entry(struct methodblock *, unsigned long); @@ -37,6 +42,7 @@ int insert_exception_spill_insns(struct compilation_unit *cu); unsigned char *throw_exception(struct compilation_unit *cu, struct object *exception); void throw_exception_from_signal(void *ctx, struct object *exception); +void throw_exception_from_trampoline(void *ctx, struct object *exception); void unwind(void); void signal_exception(struct object *obj); void signal_new_exception(char *class_name, char *msg); diff --git a/jit/exception.c b/jit/exception.c index 2237dbe..337aee3 100644 --- a/jit/exception.c +++ b/jit/exception.c @@ -40,12 +40,16 @@ #include <errno.h> __thread void *exception_guard = NULL; +__thread void *trampoline_exception_guard = NULL; void *exceptions_guard_page; +void *trampoline_exceptions_guard_page; void init_exceptions(void) { exceptions_guard_page = alloc_guard_page(); - if (!exceptions_guard_page) + trampoline_exceptions_guard_page = alloc_guard_page(); + + if (!exceptions_guard_page || !trampoline_exceptions_guard_page) die("%s: failed to allocate exceptions guard page.", __func__); /* TODO: Should be called from thread initialization code. */ @@ -57,7 +61,9 @@ void init_exceptions(void) */ void thread_init_exceptions(void) { - exception_guard = &exception_guard; /* assign a safe pointer */ + /* Assign safe pointers. */ + exception_guard = &exception_guard; + trampoline_exception_guard = &trampoline_exception_guard; } /** @@ -79,6 +85,7 @@ void signal_exception(struct object *exception) getExecEnv()->exception = exception; exception_guard = exceptions_guard_page; + trampoline_exception_guard = trampoline_exceptions_guard_page; } void signal_new_exception(char *class_name, char *msg) @@ -97,6 +104,7 @@ struct object *exception_occurred(void) void clear_exception(void) { exception_guard = &exception_guard; + trampoline_exception_guard = &trampoline_exception_guard; getExecEnv()->exception = NULL; } diff --git a/jit/trampoline.c b/jit/trampoline.c index 8812b0d..618691d 100644 --- a/jit/trampoline.c +++ b/jit/trampoline.c @@ -26,6 +26,7 @@ #include <jit/cu-mapping.h> #include <jit/emit-code.h> +#include <jit/exception.h> #include <jit/compiler.h> #include <vm/natives.h> @@ -51,15 +52,33 @@ static void *jit_native_trampoline(struct compilation_unit *cu) static void *jit_java_trampoline(struct compilation_unit *cu) { + struct object *e; + if (cu->is_compiled) return buffer_ptr(cu->objcode); - compile(cu); + if (compile(cu) == 0) { + if (add_cu_mapping(cu) != 0) + die("%s: out of memory", __func__); + + return buffer_ptr(cu->objcode); + } + + if (!exception_occurred()) + die("%s: unrecoverable error, aborting.", __func__); - if (add_cu_mapping(cu) != 0) - die("out of memory"); + /* + * If exception has been signalled we can recover. + * + * We must re-signal exception because when exception comes + * from JamVM then exception guards are not set up. When JamVM + * is finally removed this can be too. + */ + e = exception_occurred(); + clear_exception(); + signal_exception(e); - return buffer_ptr(cu->objcode); + return NULL; } void *jit_magic_trampoline(struct compilation_unit *cu) @@ -86,7 +105,8 @@ void *jit_magic_trampoline(struct compilation_unit *cu) * Therefore, do fixup for direct call sites unconditionally and fixup * vtables if method can be invoked via invokevirtual. */ - fixup_direct_calls(method->trampoline, (unsigned long) ret); + if (ret) + fixup_direct_calls(method->trampoline, (unsigned long) ret); pthread_mutex_unlock(&cu->mutex); diff --git a/vm/signal.c b/vm/signal.c index af89c6e..bf76cda 100644 --- a/vm/signal.c +++ b/vm/signal.c @@ -67,6 +67,11 @@ static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) if ((unsigned long)si->si_addr < (unsigned long)getpagesize()) { struct object *exception; + /* We must be extra caucious here because IP might be + invalid */ + if (get_signal_source_cu(ctx) == NULL) + goto exit; + /* TODO: exception's stack trace should be filled using ctx */ exception = new_exception("java/lang/NullPointerException", NULL); if (exception == NULL) { @@ -80,7 +85,8 @@ static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) } /* Check if exception was triggered by exception guard */ - if (si->si_addr == exceptions_guard_page) { + if (si->si_addr == exceptions_guard_page || + si->si_addr == trampoline_exceptions_guard_page) { struct object *exception; exception = exception_occurred(); @@ -90,7 +96,13 @@ static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) goto exit; } - throw_exception_from_signal(ctx, exception); + clear_exception(); + + if (si->si_addr == trampoline_exceptions_guard_page) + throw_exception_from_trampoline(ctx, exception); + else + throw_exception_from_signal(ctx, exception); + return; } -- 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