* src/vm/jit/executionstate.c (executionstate_unwind_exception): Added generic
[cacao.git] / src / vm / jit / executionstate.c
index 722922ce4f839e62b46297b31c20e4bef2d2e666..953c832a215439a90dfa12e14a4bf17697d853f6 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/executionstate.c - execution-state handling
 
-   Copyright (C) 2007, 2008
+   Copyright (C) 2007, 2008, 2009
    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 #include <stdint.h>
 #include <stdio.h>
 
+#include "arch.h"
+#include "md.h"
 #include "md-abi.h"
 
-#include "vm/descriptor.h"
+#include "vm/descriptor.hpp"
 #include "vm/os.hpp"
 
 #include "vm/jit/abi.h"
 #include "vm/jit/executionstate.h"
 
 
+/**
+ * Restore callee-saved registers (including the RA register),
+ * set the stack pointer to the next stackframe,
+ * set the PC to the return address of the popped frame.
+ *
+ * *** This function imitates the effects of the method epilog ***
+ * *** and returning from the method call.                     ***
+ *
+ * @param es Execution state to be modified.
+ *        NOTE: es->code and es->pv are NOT updated.
+ */
+void executionstate_pop_stackframe(executionstate_t *es)
+{
+       int32_t reg;
+       int32_t i;
+
+       // Sanity checks.
+       assert(es->code != NULL);
+
+       // Calculate the size of the stackframe.
+       int32_t framesize = md_stacktrace_get_framesize(es->code);
+
+       // Read the return address.
+       uint8_t* ra;
+#if STACKFRAME_LEAFMETHODS_RA_REGISTER
+       if (code_is_leafmethod(es->code))
+               ra = es->ra;
+       else
+#endif
+               ra = (u1*) md_stacktrace_get_returnaddress(es->sp, framesize);
+
+       // Calculate the base of the stack frame.
+       uintptr_t sp     = (uintptr_t) es->sp;
+       uintptr_t basesp = sp + es->code->stackframesize * SIZE_OF_STACKSLOT;
+
+       // Restore return address, if part of frame.
+#if STACKFRAME_RA_TOP_OF_FRAME
+# if STACKFRAME_LEAFMETHODS_RA_REGISTER
+       if (!code_is_leafmethod(es->code)) {
+# endif
+               basesp -= 1 * SIZE_OF_STACKSLOT;
+               es->ra = *((uint8_t**) basesp);
+# if STACKFRAME_LEAFMETHODS_RA_REGISTER
+       }
+# endif
+#endif /* STACKFRAME_RA_TOP_OF_FRAME */
+
+       // Restore return address, if inside linkage area.
+#if STACKFRAME_RA_LINKAGE_AREA
+# if STACKFRAME_LEAFMETHODS_RA_REGISTER
+       if (!code_is_leafmethod(es->code))
+# endif
+               es->ra = *((uint8_t**) (basesp + LA_LR_OFFSET));
+#endif /* STACKFRAME_RA_LINKAGE_AREA */
+
+       // Restore saved int registers.
+       reg = INT_REG_CNT;
+       for (i=0; i<es->code->savedintcount; ++i) {
+               while (nregdescint[--reg] != REG_SAV)
+                       ;
+               basesp -= 1 * SIZE_OF_STACKSLOT;
+               es->intregs[reg] = *((uintptr_t*) basesp);
+       }
+
+       // Restore saved flt registers.
+       // XXX align?
+       reg = FLT_REG_CNT;
+       for (i=0; i<es->code->savedfltcount; ++i) {
+               while (nregdescfloat[--reg] != REG_SAV)
+                       ;
+               basesp -= STACK_SLOTS_PER_FLOAT * SIZE_OF_STACKSLOT;
+               es->fltregs[reg] = *((double*) basesp);
+       }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+       // Restore saved adr registers.
+       reg = ADR_REG_CNT;
+       for (i=0; i<es->code->savedadrcount; ++i) {
+               while (nregdescadr[--reg] != REG_SAV)
+                       ;
+               basesp -= 1 * SIZE_OF_STACKSLOT;
+               es->adrregs[reg] = *((uintptr_t*) basesp);
+       }
+#endif
+
+       // Adjust the stackpointer.
+       es->sp += framesize;
+#if STACKFRMAE_RA_BETWEEN_FRAMES
+       es->sp += SIZEOF_VOID_P; /* skip return address */
+#endif
+
+       // Set the program counter to the return address.
+       es->pc = ra;
+
+       // In debugging mode clobber non-saved registers.
+#if !defined(NDEBUG)
+       for (i=0; i<INT_REG_CNT; ++i)
+               if (nregdescint[i] != REG_SAV)
+                       es->intregs[i] = (ptrint) 0x33dead3333dead33ULL;
+       for (i=0; i<FLT_REG_CNT; ++i)
+               if (nregdescfloat[i] != REG_SAV)
+                       *(u8*)&(es->fltregs[i]) = 0x33dead3333dead33ULL;
+# if defined(HAS_ADDRESS_REGISTER_FILE)
+       for (i=0; i<ADR_REG_CNT; ++i)
+               if (nregdescadr[i] != REG_SAV)
+                       es->adrregs[i] = (ptrint) 0x33dead3333dead33ULL;
+# endif
+#endif /* !defined(NDEBUG) */
+}
+
+
+// XXX Move this prototype somewhere else!
+void *exceptions_handle_exception(java_object_t *xptro, void *xpc, void *pv, void *sp);
+
+
+/**
+ * Performs stack unwinding in case of an exception. This is done by
+ * popping frames off the given execution state until a frame is reached
+ * for which there is a handler. Execution will continue at the handler
+ * site once the execution state is written back to the machine.
+ *
+ * @param es Execution state to be modified.
+ * @param e The thrown exception object.
+ *
+ * This is specified in:
+ *    The Java(TM) Virtual Machine Specification, Second Edition
+ *    Section 3.6.5: Abrupt Method Invocation Completion
+ */
+void executionstate_unwind_exception(executionstate_t* es, java_handle_t* e)
+{
+       void* handler = NULL;
+
+       // Iterate until we find an exception handler.
+       while (handler == NULL) {
+
+               // Search an exception handler in the current frame.
+               handler = exceptions_handle_exception(e, es->pc, es->pv, es->sp);
+
+               // Jump directly into the handler in case we found one.
+               if (handler != NULL)
+                       break;
+
+               // Find the codeinfo structure for the current frame.
+               es->code = code_get_codeinfo_for_pv(es->pv);
+
+               // Pop one frame off the stack.
+               executionstate_pop_stackframe(es);
+
+               // Get the PV for the parent Java method.
+               es->pv = md_codegen_get_pv_from_pc(es->pc);
+
+               // After popping the frame the PC points to the instruction just after
+               // the invocation. To get the XPC we need to correct the PC to point
+               // just before the invocation. But we do not know how big the
+               // invocation site actually is, so we subtract one, which should be
+               // sufficient for our purposes.
+               es->pc -= 1;
+       }
+
+       // Update the execution state to continue at the handler site.
+       es->pc = (uint8_t*) handler;
+}
+
+
 /* executionstate_sanity_check *************************************************
 
    Perform some sanity checks for the md_executionstate_read and
@@ -221,11 +387,7 @@ void executionstate_println(executionstate_t *es)
                        if (i%4 == 0)
                                printf("\n\t\t");
                        printf("M%02d%c", i, (i >= slots) ? '(' : ' ');
-#ifdef HAS_4BYTE_STACKSLOT
-                       printf("%08lx",(unsigned long)*sp++);
-#else
                        printf("%016llx",(unsigned long long)*sp++);
-#endif
                        printf("%c", (i >= slots) ? ')' : ' ');
                }
                printf("\n");