When method compilation fails some exception must be signalled and thrown. If exception is not created by code that fails it is created in the compile_error() function.
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/compiler.c | 9 +++++++++ jit/exception.c | 12 ++++++++++-- jit/trampoline.c | 13 ++++++++++--- vm/signal.c | 14 ++++++++++++-- 9 files changed, 109 insertions(+), 11 deletions(-) diff --git a/arch/x86/emit-code_32.c b/arch/x86/emit-code_32.c index 21853ef..27277c9 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> @@ -843,6 +844,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) { @@ -1138,6 +1145,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 b640778..e6d8c02 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> @@ -67,3 +68,30 @@ void throw_exception_from_signal(void *ctx, struct object *exception) uc->uc_mcontext.gregs[REG_IP] = (unsigned long)eh; } + +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 cbe952f..775108d 100644 --- a/include/jit/exception.h +++ b/include/jit/exception.h @@ -20,7 +20,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; /* * Holds a reference to exception that has been signalled. This @@ -47,6 +52,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/compiler.c b/jit/compiler.c index 3302748..41f37ec 100644 --- a/jit/compiler.c +++ b/jit/compiler.c @@ -24,6 +24,15 @@ static void compile_error(struct compilation_unit *cu, int err) printf("%s: Failed to compile method `%s' in class `%s', error: %i\n", __func__, cu->method->name, cb->name, err); + + if (!exception_occurred()) { + if (err == -ENOMEM) + /* TODO: throw OutOfMemoryError */ + die("%s: out of memory", __func__); + + signal_new_exception("java/lang/VirtualMachineError", + "method compilation failed"); + } } int compile(struct compilation_unit *cu) diff --git a/jit/exception.c b/jit/exception.c index e9e9c4b..d78fe83 100644 --- a/jit/exception.c +++ b/jit/exception.c @@ -41,13 +41,17 @@ __thread struct object *exception_holder = NULL; __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. */ @@ -59,7 +63,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; } /** @@ -77,6 +83,7 @@ void signal_exception(struct object *exception) if (exception == NULL) die("%s: exception is NULL.", __func__); + trampoline_exception_guard = trampoline_exceptions_guard_page; exception_guard = exceptions_guard_page; exception_holder = exception; } @@ -91,6 +98,7 @@ void signal_new_exception(char *class_name, char *msg) void clear_exception(void) { + trampoline_exception_guard = &trampoline_exception_guard; exception_guard = &exception_guard; exception_holder = NULL; } diff --git a/jit/trampoline.c b/jit/trampoline.c index 8812b0d..ff7e330 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> @@ -54,10 +55,15 @@ static void *jit_java_trampoline(struct compilation_unit *cu) if (cu->is_compiled) return buffer_ptr(cu->objcode); - compile(cu); + if (compile(cu)) { + assert(exception_occurred() != NULL); + + return NULL; + } if (add_cu_mapping(cu) != 0) - die("out of memory"); + /* TODO: throw OutOfMemoryError */ + die("%s: out of memory", __func__); return buffer_ptr(cu->objcode); } @@ -86,7 +92,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 (cu->is_compiled) + 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..747276a 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,11 @@ static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) goto exit; } - throw_exception_from_signal(ctx, 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 ------------------------------------------------------------------------------ Crystal Reports - New Free Runtime and 30 Day Trial Check out the new simplified licensing option that enables unlimited royalty-free distribution of the report engine for externally facing server and web deployment. http://p.sf.net/sfu/businessobjects _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel