* src/threads/posix/thread-posix.cpp: Eliminated some easy-to-fix or pointless compil...
[cacao.git] / src / vm / jit / trap.cpp
index f43b1e7d09535ceaecefef1db029e283a9c769a5..e8bfb9beee61bad6a67be5bb287607ea40b44593 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/trap.cpp - hardware traps
 
-   Copyright (C) 2008
+   Copyright (C) 2008, 2009, 2010
    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
    Copyright (C) 2009 Theobroma Systems Ltd.
 
 #include "vm/jit/stacktrace.hpp"
 #include "vm/jit/trap.hpp"
 
+#if defined(__S390__)
+#include "vm/jit/s390/codegen.h"
+#else
+#define N_PV_OFFSET 0
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -66,21 +72,15 @@ extern "C" {
  */
 void trap_init(void)
 {
-#if !(defined(__ARM__) && defined(__LINUX__))
-       /* On arm-linux the first memory page can't be mmap'ed, as it
-          contains the exception vectors. */
-
-       int pagesize;
-
-       /* mmap a memory page at address 0x0, so our hardware-exceptions
-          work. */
+       TRACESUBSYSTEMINITIALIZATION("trap_init");
 
-       pagesize = os::getpagesize();
+       /* If requested we mmap a memory page at address 0x0,
+          so our hardware-exceptions work. */
 
-       (void) os::mmap_anonymous(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
-#endif
-
-       TRACESUBSYSTEMINITIALIZATION("trap_init");
+       if (opt_AlwaysMmapFirstPage) {
+               int pagesize = os::getpagesize();
+               (void) os::mmap_anonymous(NULL, pagesize, PROT_NONE, MAP_PRIVATE | MAP_FIXED);
+       }
 
 #if !defined(TRAP_INSTRUCTION_IS_LOAD)
 # error TRAP_INSTRUCTION_IS_LOAD is not defined in your md-trap.h
@@ -109,17 +109,13 @@ void trap_handle(int sig, void *xpc, void *context)
        stackframeinfo_t sfi;
        trapinfo_t       trp;
 
-       // Prevent compiler warnings.
-       java_handle_t* o = NULL;
-       methodinfo*    m = NULL;
-
 #if !defined(NDEBUG)
        // Sanity checking the XPC.
        if (xpc == NULL)
                vm_abort("trap_handle: The program counter is NULL!");
 #endif
 
-#if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
+#if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
 # if !defined(NDEBUG)
        /* Perform a sanity check on our execution state functions. */
 
@@ -178,7 +174,18 @@ void trap_handle(int sig, void *xpc, void *context)
        /* Do some preparations before we enter the nativeworld. */
        /* BEFORE: creating stackframeinfo */
 
+       // Prevent compiler warnings.
+       int32_t        index = 0;
+       java_handle_t* o     = NULL;
+       methodinfo*    m     = NULL;
+
        switch (type) {
+       case TRAP_ArrayIndexOutOfBoundsException:
+               /* Get the index into the array causing the exception. */
+
+               index = (int32_t) val;
+               break;
+
        case TRAP_ClassCastException:
                /* Wrap the value into a handle, as it is a reference. */
 
@@ -223,9 +230,12 @@ void trap_handle(int sig, void *xpc, void *context)
 
        /* Get resulting exception (or pointer to compiled method). */
 
-       int32_t        index;
        java_handle_t* p;
-       void*          entry;
+       void*          entry = 0;
+       bool           was_patched = false;
+#if defined(ENABLE_REPLACEMENT)
+       bool           was_replaced;
+#endif
 
        switch (type) {
        case TRAP_NullPointerException:
@@ -237,7 +247,6 @@ void trap_handle(int sig, void *xpc, void *context)
                break;
 
        case TRAP_ArrayIndexOutOfBoundsException:
-               index = (int32_t) val;
                p = exceptions_new_arrayindexoutofboundsexception(index);
                break;
 
@@ -254,26 +263,25 @@ void trap_handle(int sig, void *xpc, void *context)
                break;
 
        case TRAP_PATCHER:
+               p = NULL;
 #if defined(ENABLE_REPLACEMENT)
-               if (replace_me_wrapper((uint8_t*) xpc, context)) {
-                       p = NULL;
+               was_replaced = replace_handler((uint8_t*) xpc, &es);
+               if (was_replaced)
                        break;
-               }
 #endif
-               p = patcher_handler((uint8_t*) xpc);
+               was_patched = patcher_handler((uint8_t*) xpc);
                break;
 
        case TRAP_COMPILER:
-               entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
                p = NULL;
+               entry = jit_compile_handle(m, sfi.pv, ra, (void*) val);
                break;
 
-#if defined(ENABLE_REPLACEMENT)
+#if defined(__I386__) && defined(ENABLE_REPLACEMENT)
+# warning Port the below stuff to use the patching subsystem.
        case TRAP_COUNTDOWN:
-# if defined(__I386__)
-               replace_me_wrapper((uint8_t*) xpc - 13, context);
-# endif
                p = NULL;
+               (void) replace_handler((uint8_t*) xpc - 13, &es);
                break;
 #endif
 
@@ -295,7 +303,7 @@ void trap_handle(int sig, void *xpc, void *context)
 
        stacktrace_stackframeinfo_remove(&sfi);
 
-#if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__)
+#if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
        /* Update execution state and set registers. */
        /* AFTER: removing stackframeinfo */
 
@@ -306,7 +314,9 @@ void trap_handle(int sig, void *xpc, void *context)
 
                if (entry != NULL) {
                        es.pc = (uint8_t *) (uintptr_t) entry;
-                       es.pv = (uint8_t *) (uintptr_t) entry;
+                       // The s390 executionstate offsets pv, so we need to
+                       // compensate here.
+                       es.pv = (uint8_t *) (uintptr_t) entry - N_PV_OFFSET;
                        break;
                }
 
@@ -322,19 +332,54 @@ void trap_handle(int sig, void *xpc, void *context)
 
                // Get and set the PV from the parent Java method.
 
-               es.pv = (uint8_t*) md_codegen_get_pv_from_pc(ra);
+               es.pv = (uint8_t*) md_codegen_get_pv_from_pc(ra) - N_PV_OFFSET;
 
                // Now fall-through to default exception handling.
 
                goto trap_handle_exception;
 
        case TRAP_PATCHER:
+#if defined(ENABLE_REPLACEMENT)
+               // If on-stack-replacement suceeded, we are not allowed to touch
+               // the execution state. We assume that there was no exception.
+
+               if (was_replaced) {
+                       assert(exceptions_get_exception() == NULL);
+                       break;
+               }
+#endif
+
                // The normal case for a patcher trap is to continue execution at
                // the trap instruction. On some archs the PC may point after the
                // trap instruction, so we reset it here.
 
+               if (was_patched) {
+                       assert(exceptions_get_exception() == NULL);
+                       es.pc = (uint8_t *) (uintptr_t) xpc;
+                       break;
+               }
+
+               // In case patching was not successful, we try to fetch the pending
+               // exception here.
+
+               p = exceptions_get_and_clear_exception();
+
+               // If there is no pending exception, we continue execution behind
+               // the position still in need of patching. Normally this would
+               // indicate an error in the patching subsystem, but others might
+               // want to piggyback patchers and we want to be able to provide
+               // "reusable trap points" and avoid inifinite loops here. This is
+               // especially useful to implement breakpoints or profiling points
+               // of any kind. So before changing the trap logic, think about
+               // utilizing the patching subsystem on your quest. :)
+
                if (p == NULL) {
+#if !defined(NDEBUG)
+                       if (opt_PrintWarnings)
+                               log_println("trap_handle: Detected reusable trap at %p", xpc);
+#endif
                        es.pc = (uint8_t *) (uintptr_t) xpc;
+                       es.pc += REPLACEMENT_PATCH_SIZE;
                        break;
                }
 
@@ -343,9 +388,19 @@ void trap_handle(int sig, void *xpc, void *context)
        trap_handle_exception:
        default:
                if (p != NULL) {
+#if defined(__ALPHA__) || defined(__I386__) || defined(__X86_64__)
+                       // Perform stack unwinding for exceptions on execution state.
+                       es.pc = (uint8_t *) (uintptr_t) xpc;
+                       es.pv = (uint8_t *) (uintptr_t) sfi.pv;
+                       executionstate_unwind_exception(&es, p);
+
+                       // Pass the exception object to the exception handler.
+                       es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
+#else
                        es.intregs[REG_ITMP1_XPTR] = (uintptr_t) LLNI_DIRECT(p);
                        es.intregs[REG_ITMP2_XPC]  = (uintptr_t) xpc;
                        es.pc                      = (uint8_t *) (uintptr_t) asm_handle_exception;
+#endif
                }
        }