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

Reply via email to