* src/vm/jit/trap.cpp (trap_handle): Adapted to support "reusable trap points".
authorMichael Starzinger <michi@complang.tuwien.ac.at>
Thu, 22 Oct 2009 11:30:44 +0000 (13:30 +0200)
committerMichael Starzinger <michi@complang.tuwien.ac.at>
Thu, 22 Oct 2009 11:30:44 +0000 (13:30 +0200)
* src/vm/jit/patcher-common.cpp (patcher_handler): Changed to return status
instead of the causing exception object itself.
* src/vm/jit/patcher-common.hpp: Likewise.

src/vm/jit/patcher-common.cpp
src/vm/jit/patcher-common.hpp
src/vm/jit/trap.cpp

index e7ec2086ef2566752fa5a093511e39d5b8e8a2b8..c364646be172ee8b249bb4c4fcc860c6b581c741 100644 (file)
@@ -356,7 +356,7 @@ static int patcher_depth = 0;
 #define TRACE_PATCHER_INDENT for (i=0; i<patcher_depth; i++) printf("\t")
 #endif /* !defined(NDEBUG) */
 
-java_handle_t *patcher_handler(u1 *pc)
+bool patcher_handler(u1 *pc)
 {
        codeinfo      *code;
        patchref_t    *pr;
@@ -392,7 +392,7 @@ java_handle_t *patcher_handler(u1 *pc)
                }
 #endif
                code->patchers->unlock();
-               return NULL;
+               return true;
        }
 
 #if !defined(NDEBUG)
@@ -446,24 +446,17 @@ java_handle_t *patcher_handler(u1 *pc)
        }
 #endif
 
-       // Check for return value and exit accordingly.
-       if (result == false) {
-               // Mangle the pending exception.
+       // Check return value and mangle the pending exception.
+       if (result == false)
                resolve_handle_pending_exception(true);
 
-               // Get the exception and return it.
-               java_handle_t* e = exceptions_get_and_clear_exception();
-
-               code->patchers->unlock();
-
-               return e;
-       }
-
-       pr->done = true; /* XXX this is only preliminary to prevent double-patching */
+       // XXX This is only preliminary to prevent double-patching.
+       else
+               pr->done = true;
 
        code->patchers->unlock();
 
-       return NULL;
+       return result;
 }
 
 
index d4a920339111437721b1703e801d809fc5f3d8ec..3f488809e74e7e37e5cf46d8b294dd526654ba80 100644 (file)
@@ -85,7 +85,7 @@ bool patcher_is_patched_at(void* pc);
 // MD function.
 bool patcher_is_valid_trap_instruction_at(void* pc);
 
-java_handle_t *patcher_handler(u1 *pc);
+bool patcher_handler(u1 *pc);
 
 
 /* empty patcher (just patches back original mcode) ***************************/
index 6d9340c18377cf6dbd5d891a1740b4a26366123d..8520214deaa35f7fa65e15270ae89858ffd78808 100644 (file)
@@ -103,10 +103,6 @@ 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)
@@ -172,7 +168,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. */
 
@@ -217,9 +224,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;
+       bool           was_patched;
+#if defined(ENABLE_REPLACEMENT)
+       bool           was_replaced;
+#endif
 
        switch (type) {
        case TRAP_NullPointerException:
@@ -231,7 +241,6 @@ void trap_handle(int sig, void *xpc, void *context)
                break;
 
        case TRAP_ArrayIndexOutOfBoundsException:
-               index = (int32_t) val;
                p = exceptions_new_arrayindexoutofboundsexception(index);
                break;
 
@@ -248,26 +257,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_me_wrapper((uint8_t*) xpc, context);
+               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_me_wrapper((uint8_t*) xpc - 13, context);
                break;
 #endif
 
@@ -323,12 +331,47 @@ void trap_handle(int sig, void *xpc, void *context)
                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;
                }