* src/vm/resolve.c (resolve_method_lazy): Removed dependence on
[cacao.git] / src / vm / jit / codegen-common.c
index b71a96b1c0c1ad72023c17dbcd161199fe88f865..205367c848af5b2301d0da3914624bf53a50a768 100644 (file)
@@ -48,7 +48,7 @@
    memory. All functions writing values into the data area return the offset
    relative the begin of the code area (start of procedure).   
 
-   $Id: codegen-common.c 5052 2006-06-28 17:05:46Z twisti $
+   $Id: codegen-common.c 5703 2006-10-05 20:21:04Z edwin $
 
 */
 
 #include "vm/jit/stacktrace.h"
 #include "vm/jit/replace.h"
 
+#if defined(ENABLE_INTRP)
+#include "vm/jit/intrp/intrp.h"
+#endif
+
 
 /* in this tree we store all method addresses *********************************/
 
@@ -175,11 +179,9 @@ void codegen_setup(jitdata *jd)
                cd->superstarts = NULL;
        }
 #endif
-       
-       cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
-       cd->dsegsize = DSEGINITSIZE;
-       cd->dsegtop += cd->dsegsize;
-       cd->dseglen = 0;
+
+       cd->dseg           = NULL;
+       cd->dseglen        = 0;
 
        cd->jumpreferences = NULL;
 
@@ -396,9 +398,9 @@ void codegen_add_arraystoreexception_ref(codegendata *cd)
 
 *******************************************************************************/
 
-void codegen_add_classcastexception_ref(codegendata *cd)
+void codegen_add_classcastexception_ref(codegendata *cd, s4 reg)
 {
-       codegen_add_exception_ref(cd, -1, STACKTRACE_inline_classcastexception);
+       codegen_add_exception_ref(cd, reg, STACKTRACE_inline_classcastexception);
 }
 
 
@@ -438,7 +440,7 @@ void codegen_addpatchref(codegendata *cd, functionptr patcher, voidptr ref,
        patchref *pr;
        s4        branchpos;
 
-       branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
+       branchpos = cd->mcodeptr - cd->mcodebase;
 
        pr = DNEW(patchref);
 
@@ -457,7 +459,7 @@ void codegen_addpatchref(codegendata *cd, functionptr patcher, voidptr ref,
           the basic block code generation is completed, we check the
           range and maybe generate some nop's. */
 
-       cd->lastmcodeptr = ((u1 *) cd->mcodeptr) + PATCHER_CALL_SIZE;
+       cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
 #endif
 }
 
@@ -519,13 +521,14 @@ void codegen_insertmethod(u1 *startpc, u1 *endpc)
 }
 
 
-/* codegen_findmethod **********************************************************
+/* codegen_get_pv_from_pc ******************************************************
 
-   Find the PV for the given PC by searching in the AVL tree of methods.
+   Find the PV for the given PC by searching in the AVL tree of
+   methods.
 
 *******************************************************************************/
 
-u1 *codegen_findmethod(u1 *pc)
+u1 *codegen_get_pv_from_pc(u1 *pc)
 {
        methodtree_element  mtepc;
        methodtree_element *mte;
@@ -538,15 +541,55 @@ u1 *codegen_findmethod(u1 *pc)
        mte = avl_find(methodtree, &mtepc);
 
        if (mte == NULL) {
-/*             fprintf(stderr, "Cannot find Java function at %p\n", (void *) (ptrint) pc); */
+               /* No method was found.  Let's dump a stacktrace. */
 
-               return NULL;
+               log_println("We received a SIGSEGV and tried to handle it, but we were");
+               log_println("unable to find a Java method at:");
+               log_println("");
+#if SIZEOF_VOID_P == 8
+               log_println("PC=0x%016lx", pc);
+#else
+               log_println("PC=0x%08x", pc);
+#endif
+               log_println("");
+               log_println("Dumping the current stacktrace:");
+
+               stacktrace_dump_trace();
+
+               vm_abort("Exiting...");
        }
 
        return mte->startpc;
 }
 
 
+/* codegen_get_pv_from_pc_nocheck **********************************************
+
+   Find the PV for the given PC by searching in the AVL tree of
+   methods.  This method does not check the return value and is used
+   by the profiler.
+
+*******************************************************************************/
+
+u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
+{
+       methodtree_element  mtepc;
+       methodtree_element *mte;
+
+       /* allocation of the search structure on the stack is much faster */
+
+       mtepc.startpc = pc;
+       mtepc.endpc   = pc;
+
+       mte = avl_find(methodtree, &mtepc);
+
+       if (mte == NULL)
+               return NULL;
+       else
+               return mte->startpc;
+}
+
+
 /* codegen_finish **************************************************************
 
    Finishes the code generation. A new memory, large enough for both
@@ -582,7 +625,7 @@ void codegen_finish(jitdata *jd)
 
        /* calculate the code length */
 
-       mcodelen = (s4) ((u1 *) cd->mcodeptr - cd->mcodebase);
+       mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
 
 #if defined(ENABLE_THREADS)
        extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
@@ -619,18 +662,21 @@ void codegen_finish(jitdata *jd)
        /* allocate new memory */
 
        code->mcodelength = mcodelen + cd->dseglen;
-       code->mcode = CNEW(u1, alignedlen + extralen);
-
-       /* copy data and code to their new location */
-
-       MCOPY((void *) code->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
-       MCOPY((void *) (code->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
+       code->mcode       = CNEW(u1, alignedlen + extralen);
 
        /* set the entrypoint of the method */
        
        assert(code->entrypoint == NULL);
        code->entrypoint = epoint = (code->mcode + cd->dseglen);
 
+       /* fill the data segment (code->entrypoint must already be set!) */
+
+       dseg_finish(jd);
+
+       /* copy code to the new location */
+
+       MCOPY((void *) code->entrypoint, cd->mcodebase, u1, mcodelen);
+
 #if defined(ENABLE_INTRP)
        /* relocate native dynamic superinstruction code (if any) */
 
@@ -771,6 +817,9 @@ codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
 
        /* set the flags for the current JIT run */
 
+       if (opt_prof)
+               jd->flags |= JITDATA_FLAG_INSTRUMENT;
+
        if (opt_verbosecall)
                jd->flags |= JITDATA_FLAG_VERBOSECALL;
 
@@ -939,16 +988,19 @@ void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
 /* codegen_finish_native_call **************************************************
 
    Removes the stuff required for a native (JNI) function call.
+   Additionally it checks for an exceptions and in case, get the
+   exception object and clear the pointer.
 
 *******************************************************************************/
 
-void codegen_finish_native_call(u1 *datasp)
+java_objectheader *codegen_finish_native_call(u1 *datasp)
 {
-       stackframeinfo  *sfi;
-       stackframeinfo **psfi;
-       localref_table  *lrt;
-       localref_table  *plrt;
-       s4               localframes;
+       stackframeinfo     *sfi;
+       stackframeinfo    **psfi;
+       localref_table     *lrt;
+       localref_table     *plrt;
+       s4                  localframes;
+       java_objectheader  *e;
 
        /* get data structures from stack */
 
@@ -989,6 +1041,12 @@ void codegen_finish_native_call(u1 *datasp)
        /* now store the previous local frames in the thread structure */
 
        LOCALREFTABLE = lrt;
+
+       /* get the exception and return it */
+
+       e = exceptions_get_and_clear_exception();
+
+       return e;
 }
 
 
@@ -1036,9 +1094,8 @@ void removenativestub(u1 *stub)
 
 *******************************************************************************/
 
-s4 codegen_reg_of_var(registerdata *rd, u2 opcode, stackptr v, s4 tempregnum)
+inline s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
 {
-       varinfo *var;
 
 #if 0
        /* Do we have to generate a conditional move?  Yes, then always
@@ -1049,48 +1106,18 @@ s4 codegen_reg_of_var(registerdata *rd, u2 opcode, stackptr v, s4 tempregnum)
                return tempregnum;
 #endif
 
-       switch (v->varkind) {
-       case TEMPVAR:
-               if (!(v->flags & INMEMORY))
-                       return(v->regoff);
-               break;
-
-       case STACKVAR:
-               var = &(rd->interfaces[v->varnum][v->type]);
-               v->regoff = var->regoff;
-               if (!(var->flags & INMEMORY))
-                       return(var->regoff);
-               break;
-
-       case LOCALVAR:
-               var = &(rd->locals[v->varnum][v->type]);
-               v->regoff = var->regoff;
-               if (!(var->flags & INMEMORY)) {
-#if defined(__ARM__) && defined(__ARMEL__)
-                       if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
-                               return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
-#endif
-#if defined(__ARM__) && defined(__ARMEB__)
-                       if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
-                               return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
-#endif
-                       return(var->regoff);
-               }
-               break;
-
-       case ARGVAR:
-               if (!(v->flags & INMEMORY)) {
+       if (!(v->flags & INMEMORY)) {
 #if defined(__ARM__) && defined(__ARMEL__)
-                       if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
-                               return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
+               if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
+                       return PACK_REGS(GET_LOW_REG(v->vv.regoff),
+                                                        GET_HIGH_REG(tempregnum));
 #endif
 #if defined(__ARM__) && defined(__ARMEB__)
-                       if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
-                               return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
+               if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
+                       return PACK_REGS(GET_LOW_REG(tempregnum),
+                                                        GET_HIGH_REG(v->vv.regoff));
 #endif
-                       return(v->regoff);
-               }
-               break;
+               return v->vv.regoff;
        }
 
 #if defined(ENABLE_STATISTICS)
@@ -1098,11 +1125,30 @@ s4 codegen_reg_of_var(registerdata *rd, u2 opcode, stackptr v, s4 tempregnum)
                count_spills_read++;
 #endif
 
-       v->flags |= INMEMORY;
-
        return tempregnum;
 }
 
+/* codegen_reg_of_dst **********************************************************
+
+   This function determines a register, to which the result of an
+   operation should go, when it is ultimatively intended to store the
+   result in iptr->dst.var.  If dst.var is assigned to an actual
+   register, this register will be returned.  Otherwise (when it is
+   spilled) this function returns tempregnum.  If not already done,
+   regoff and flags are set in the stack location.
+       
+   On ARM we have to check if a long/double variable is splitted
+   across reg/stack (HIGH_REG == REG_SPLIT). We return the actual
+   register of dst.var for LOW_REG and the tempregnum for HIGH_REG in such
+   cases.  (michi 2005/07/24)
+
+*******************************************************************************/
+
+s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
+{
+       return codegen_reg_of_var(iptr->opc, VAROP(iptr->dst), tempregnum);
+}
+
 
 #if defined(ENABLE_THREADS)
 void codegen_threadcritrestart(codegendata *cd, int offset)