Unified variables changes for common/i386.
[cacao.git] / src / vm / jit / codegen-common.c
index 682180680e88904d8e0c4cb82d764370cec1dc93..e21f4a2c503b04e10af975367c20f90ab30c4114 100644 (file)
@@ -1,9 +1,9 @@
 /* src/vm/jit/codegen-common.c - architecture independent code generator stuff
 
-   Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
-   R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
-   C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
-   Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+   J. Wenninger, Institut f. Computersprachen - TU Wien
 
    This file is part of CACAO.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+   Contact: cacao@cacaojvm.org
 
    Authors: Reinhard Grafl
             Andreas  Krall
 
    Changes: Christian Thalinger
             Joseph Wenninger
+                       Edwin Steiner
 
    All functions assume the following code area / data area layout:
 
@@ -47,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 4012 2005-12-30 14:17:30Z twisti $
+   $Id: codegen-common.c 5404 2006-09-07 13:29:05Z christian $
 
 */
 
 
 #include "vm/types.h"
 
-#include "codegen.h"
+#if defined(ENABLE_JIT)
+/* this is required for gen_resolvebranch and PATCHER_CALL_SIZE */
+# include "codegen.h"
+#endif
+
+#if defined(__ARM__)
+/* this is required for REG_SPLIT */
+# include "md-abi.h"
+#endif
 
 #include "mm/memory.h"
 #include "toolbox/avl.h"
 #include "native/jni.h"
 #include "native/native.h"
 
-#if defined(USE_THREADS)
-# if defined(NATIVE_THREADS)
-#  include "threads/native/threads.h"
-# else
-#  include "threads/green/threads.h"
-# endif
+#if defined(ENABLE_THREADS)
+# include "threads/native/threads.h"
 #endif
 
 #include "vm/exceptions.h"
 #include "vm/stringlocal.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/codegen-common.h"
-#include "vm/jit/disass.h"
+
+#if defined(ENABLE_DISASSEMBLER)
+# include "vm/jit/disass.h"
+#endif
+
 #include "vm/jit/dseg.h"
 #include "vm/jit/jit.h"
 #include "vm/jit/stacktrace.h"
+#include "vm/jit/replace.h"
 
 
 /* in this tree we store all method addresses *********************************/
 
-#if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
-static struct avl_table *methodtree = NULL;
-static int methodtree_comparator(const void *pc, const void *element,
-                                                                void *param);
-#endif
+static avl_tree *methodtree = NULL;
+static s4 methodtree_comparator(const void *pc, const void *element);
 
 
 /* codegen_init ****************************************************************
@@ -105,55 +112,53 @@ static int methodtree_comparator(const void *pc, const void *element,
 
 void codegen_init(void)
 {
-#if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
        /* this tree is global, not method specific */
 
        if (!methodtree) {
-#if !defined(ENABLE_INTRP)
+#if defined(ENABLE_JIT)
                methodtree_element *mte;
 #endif
 
-               methodtree = avl_create(methodtree_comparator, NULL, NULL);
+               methodtree = avl_create(&methodtree_comparator);
 
-#if !defined(ENABLE_INTRP)
-               /* insert asm_calljavafunction */
+#if defined(ENABLE_JIT)
+               /* insert asm_vm_call_method */
 
                mte = NEW(methodtree_element);
 
-               mte->startpc = (u1 *) (ptrint) asm_calljavafunction;
-               mte->endpc   = (u1 *) ((ptrint) asm_calljavafunction2 - 1);
-
-               avl_insert(methodtree, mte);
-
-               /* insert asm_calljavafunction2 */
-
-               mte = NEW(methodtree_element);
-
-               mte->startpc = (u1 *) (ptrint) asm_calljavafunction2;
+               mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
                mte->endpc   = (u1 *) ((ptrint) asm_call_jit_compiler - 1);
 
                avl_insert(methodtree, mte);
-#endif /* !defined(ENABLE_INTRP) */
+#endif /* defined(ENABLE_JIT) */
        }
-#endif
 }
 
 
-/* codegen_setup **************************************************************
+/* codegen_setup ***************************************************************
 
-   allocates and initialises code area, data area and references
+   Allocates and initialises code area, data area and references.
 
 *******************************************************************************/
 
-void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
+void codegen_setup(jitdata *jd)
 {
+       methodinfo  *m;
+       codegendata *cd;
+
+       /* get required compiler data */
+
+       m  = jd->m;
+       cd = jd->cd;
+
        cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
+       cd->mcodeend  = cd->mcodebase + MCODEINITSIZE;
        cd->mcodesize = MCODEINITSIZE;
 
        /* initialize mcode variables */
-       
-       cd->mcodeptr = cd->mcodebase;
-       cd->mcodeend = (s4 *) (cd->mcodebase + MCODEINITSIZE);
+
+       cd->mcodeptr     = cd->mcodebase;
+       cd->lastmcodeptr = cd->mcodebase;
 
 #if defined(ENABLE_INTRP)
        /* native dynamic superinstructions variables */
@@ -170,21 +175,18 @@ void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
                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;
+
+#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
        cd->datareferences = NULL;
-       cd->xboundrefs = NULL;
-       cd->xnullrefs = NULL;
-       cd->xcastrefs = NULL;
-       cd->xstorerefs = NULL;
-       cd->xdivrefs = NULL;
-       cd->xexceptionrefs = NULL;
-       cd->patchrefs = NULL;
+#endif
+
+       cd->exceptionrefs  = NULL;
+       cd->patchrefs      = NULL;
 
        cd->linenumberreferences = NULL;
        cd->linenumbertablesizepos = 0;
@@ -195,57 +197,21 @@ void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
        cd->exceptiontable = 0;
        cd->exceptiontablelength = 0;
 
-       if (useinlining && id) {
-               if (id->cumextablelength > 0) {
-                       cd->exceptiontablelength = id->cumextablelength;
-                       cd->exceptiontable =
-                               DMNEW(exceptiontable, id->cumextablelength + 1);
-               }
-
-       } else if (id && (id->method->exceptiontablelength > 0)) {
+       if (m->exceptiontablelength > 0) {
                cd->exceptiontablelength = m->exceptiontablelength;
                cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
        }
 
-       if (id) {
-               cd->maxstack = id->cummaxstack;
-               cd->maxlocals = id->cumlocals;
-       } else {
-               cd->maxstack = m->maxstack;
-               cd->maxlocals = m->maxlocals;
-       }
+       cd->maxstack = m->maxstack;
+       cd->maxlocals = m->maxlocals;
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+#if defined(ENABLE_THREADS)
        cd->threadcritcurrent.next = NULL;
        cd->threadcritcount = 0;
 #endif
 }
 
 
-/* codegen_free ****************************************************************
-
-   Releases temporary code and data area.
-
-*******************************************************************************/
-
-void codegen_free(methodinfo *m, codegendata *cd)
-{
-#if 0
-       if (cd) {
-               if (cd->mcodebase) {
-                       MFREE(cd->mcodebase, u1, cd->mcodesize);
-                       cd->mcodebase = NULL;
-               }
-
-               if (cd->dsegtop) {
-                       MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
-                       cd->dsegtop = NULL;
-               }
-       }
-#endif
-}
-
-
 /* codegen_close ***************************************************************
 
    TODO
@@ -264,7 +230,7 @@ void codegen_close(void)
 
 *******************************************************************************/
 
-s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
+void codegen_increase(codegendata *cd)
 {
        u1 *oldmcodebase;
 
@@ -279,7 +245,11 @@ s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
                                                          cd->mcodesize,
                                                          cd->mcodesize * 2);
        cd->mcodesize *= 2;
-       cd->mcodeend   = (s4 *) (cd->mcodebase + cd->mcodesize);
+       cd->mcodeend   = cd->mcodebase + cd->mcodesize;
+
+       /* set new mcodeptr */
+
+       cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
 
 #if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
        /* adjust the pointer to the last patcher position */
@@ -287,10 +257,6 @@ s4 *codegen_increase(codegendata *cd, u1 *mcodeptr)
        if (cd->lastmcodeptr != NULL)
                cd->lastmcodeptr = cd->mcodebase + (cd->lastmcodeptr - oldmcodebase);
 #endif
-
-       /* return the new mcodeptr */
-
-       return (s4 *) (cd->mcodebase + (mcodeptr - oldmcodebase));
 }
 
 
@@ -324,20 +290,25 @@ u1 *codegen_ncode_increase(codegendata *cd, u1 *ncodeptr)
 #endif
 
 
-void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
+void codegen_addreference(codegendata *cd, basicblock *target)
 {
        s4 branchpos;
 
-       branchpos = (u1 *) branchptr - cd->mcodebase;
+       branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
 
-#if !defined(ENABLE_INTRP)
-       /* The interpreter uses absolute branches, so we do branch resolving */
-       /* after the code and data segment move. */
+#if defined(ENABLE_JIT)
+       /* Check if the target basicblock has already a start pc, so the
+          jump is backward and we can resolve it immediately. */
 
-       /* Check if the target basicblock has already a start pc, so the jump is  */
-       /* backward and we can resolve it immediately.                            */
+       /* The interpreter uses absolute branches, so we do branch
+          resolving after the code and data segment move. */
 
-       if (target->mpc >= 0) {
+       if (target->mpc >= 0
+# if defined(ENABLE_INTRP)
+               && !opt_intrp
+# endif
+               )
+       {
                gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
                                                  branchpos,
                                                  target->mpc);
@@ -355,136 +326,101 @@ void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
 }
 
 
-/* codegen_addxboundrefs *******************************************************
+/* codegen_add_exception_ref ***************************************************
 
-   Adds an ArrayIndexOutOfBoundsException branch to the list.
+   Adds an exception branch to the list.
 
 *******************************************************************************/
 
-void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
+static void codegen_add_exception_ref(codegendata *cd, s4 reg,
+                                                                         functionptr function)
 {
-       s4 branchpos;
-       branchref *br;
+       s4            branchpos;
+       exceptionref *eref;
 
-       branchpos = (u1 *) branchptr - cd->mcodebase;
+       branchpos = (u1 *) cd->mcodeptr - cd->mcodebase;
 
-       br = DNEW(branchref);
+       eref = DNEW(exceptionref);
 
-       br->branchpos = branchpos;
-       br->reg       = reg;
-       br->next      = cd->xboundrefs;
+       eref->branchpos = branchpos;
+       eref->reg       = reg;
+       eref->function  = function;
+       eref->next      = cd->exceptionrefs;
 
-       cd->xboundrefs = br;
+       cd->exceptionrefs = eref;
 }
 
 
-/* codegen_addxcastrefs ********************************************************
+/* codegen_add_arithmeticexception_ref *****************************************
 
-   Adds an ClassCastException branch to the list.
+   Adds an ArithmeticException branch to the list.
 
 *******************************************************************************/
 
-void codegen_addxcastrefs(codegendata *cd, void *branchptr)
+void codegen_add_arithmeticexception_ref(codegendata *cd)
 {
-       s4         branchpos;
-       branchref *br;
-
-       branchpos = (u1 *) branchptr - cd->mcodebase;
-
-       br = DNEW(branchref);
-
-       br->branchpos = branchpos;
-       br->next      = cd->xcastrefs;
-
-       cd->xcastrefs = br;
+       codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arithmeticexception);
 }
 
 
-/* codegen_addxdivrefs *********************************************************
+/* codegen_add_arrayindexoutofboundsexception_ref ******************************
 
-   Adds an ArithmeticException branch to the list.
+   Adds an ArrayIndexOutOfBoundsException branch to the list.
 
 *******************************************************************************/
 
-void codegen_addxdivrefs(codegendata *cd, void *branchptr)
+void codegen_add_arrayindexoutofboundsexception_ref(codegendata *cd, s4 reg)
 {
-       s4         branchpos;
-       branchref *br;
-
-       branchpos = (u1 *) branchptr - cd->mcodebase;
-
-       br = DNEW(branchref);
-
-       br->branchpos = branchpos;
-       br->next      = cd->xdivrefs;
-
-       cd->xdivrefs = br;
+       codegen_add_exception_ref(cd, reg,
+                                                         STACKTRACE_inline_arrayindexoutofboundsexception);
 }
 
 
-/* codegen_addxstorerefs *******************************************************
+/* codegen_add_arraystoreexception_ref *****************************************
 
    Adds an ArrayStoreException branch to the list.
 
 *******************************************************************************/
 
-void codegen_addxstorerefs(codegendata *cd, void *branchptr)
+void codegen_add_arraystoreexception_ref(codegendata *cd)
 {
-       s4         branchpos;
-       branchref *br;
+       codegen_add_exception_ref(cd, -1, STACKTRACE_inline_arraystoreexception);
+}
 
-       branchpos = (u1 *) branchptr - cd->mcodebase;
 
-       br = DNEW(branchref);
+/* codegen_add_classcastexception_ref ******************************************
 
-       br->branchpos = branchpos;
-       br->next      = cd->xstorerefs;
+   Adds an ClassCastException branch to the list.
+
+*******************************************************************************/
 
-       cd->xstorerefs = br;
+void codegen_add_classcastexception_ref(codegendata *cd, s4 reg)
+{
+       codegen_add_exception_ref(cd, reg, STACKTRACE_inline_classcastexception);
 }
 
 
-/* codegen_addxnullrefs ********************************************************
+/* codegen_add_nullpointerexception_ref ****************************************
 
    Adds an NullPointerException branch to the list.
 
 *******************************************************************************/
 
-void codegen_addxnullrefs(codegendata *cd, void *branchptr)
+void codegen_add_nullpointerexception_ref(codegendata *cd)
 {
-       s4         branchpos;
-       branchref *br;
-
-       branchpos = (u1 *) branchptr - cd->mcodebase;
-
-       br = DNEW(branchref);
-
-       br->branchpos = branchpos;
-       br->next      = cd->xnullrefs;
-
-       cd->xnullrefs = br;
+       codegen_add_exception_ref(cd, -1, STACKTRACE_inline_nullpointerexception);
 }
 
 
-/* codegen_addxexceptionsrefs **************************************************
+/* codegen_add_fillinstacktrace_ref ********************************************
 
-   Adds an common exception branch to the list.
+   Adds a fillInStackTrace branch to the list.
 
 *******************************************************************************/
 
-void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
+void codegen_add_fillinstacktrace_ref(codegendata *cd)
 {
-       s4 branchpos;
-       branchref *br;
-
-       branchpos = (u1 *) branchptr - cd->mcodebase;
-
-       br = DNEW(branchref);
-
-       br->branchpos = branchpos;
-       br->next      = cd->xexceptionrefs;
-
-       cd->xexceptionrefs = br;
+       codegen_add_exception_ref(cd, -1, STACKTRACE_inline_fillInStackTrace);
 }
 
 
@@ -494,13 +430,13 @@ void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
 
 *******************************************************************************/
 
-void codegen_addpatchref(codegendata *cd, voidptr branchptr,
-                                                functionptr patcher, voidptr ref, s4 disp)
+void codegen_addpatchref(codegendata *cd, functionptr patcher, voidptr ref,
+                                                s4 disp)
 {
        patchref *pr;
        s4        branchpos;
 
-       branchpos = (u1 *) branchptr - cd->mcodebase;
+       branchpos = cd->mcodeptr - cd->mcodebase;
 
        pr = DNEW(patchref);
 
@@ -512,26 +448,25 @@ void codegen_addpatchref(codegendata *cd, voidptr branchptr,
        pr->next      = cd->patchrefs;
        cd->patchrefs = pr;
 
-#if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__)
+#if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
        /* On some architectures the patcher stub call instruction might
           be longer than the actual instruction generated.  On this
           architectures we store the last patcher call position and after
           the basic block code generation is completed, we check the
           range and maybe generate some nop's. */
 
-       cd->lastmcodeptr = ((u1 *) branchptr) + PATCHER_CALL_SIZE;
+       cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
 #endif
 }
 
 
-#if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
 /* methodtree_comparator *******************************************************
 
-   XXX
+   Comparator function used for the AVL tree of methods.
 
 *******************************************************************************/
 
-static int methodtree_comparator(const void *pc, const void *element, void *param)
+static s4 methodtree_comparator(const void *pc, const void *element)
 {
        methodtree_element *mte;
        methodtree_element *mtepc;
@@ -560,7 +495,7 @@ static int methodtree_comparator(const void *pc, const void *element, void *para
 
 /* codegen_insertmethod ********************************************************
 
-   XXX
+   Insert the machine code range of a method into the AVL tree of methods.
 
 *******************************************************************************/
 
@@ -568,78 +503,87 @@ void codegen_insertmethod(u1 *startpc, u1 *endpc)
 {
        methodtree_element *mte;
 
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
-       tables_lock();
-#endif
-#endif
+       /* allocate new method entry */
 
        mte = NEW(methodtree_element);
+
        mte->startpc = startpc;
        mte->endpc   = endpc;
 
-       if (avl_insert(methodtree, mte)) {
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
-               tables_unlock();
-#endif
-#endif
-               assert(0);
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                  "duplicate entry");
-       }
+       /* this function does not return an error, but asserts for
+          duplicate entries */
 
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
-       tables_unlock();
-#endif
-#endif
+       avl_insert(methodtree, mte);
 }
 
 
-/* codegen_findmethod **********************************************************
+/* codegen_get_pv_from_pc ******************************************************
 
-   XXX
+   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;
 
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
-       tables_lock();
-#endif
-#endif
+       /* allocation of the search structure on the stack is much faster */
 
        mtepc.startpc = pc;
-       mtepc.endpc = pc;
+       mtepc.endpc   = pc;
 
        mte = avl_find(methodtree, &mtepc);
 
-       if (!mte) {
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
-               tables_unlock();
-#endif
-#endif
-               printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
-               assert(0);
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                  "Cannot find Java function at %p", pc);
-       }
+       if (mte == NULL) {
+               /* No method was found.  Let's dump a stacktrace. */
 
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
-       tables_unlock();
-#endif
+               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;
 }
-#endif /* defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC) */
+
+
+/* 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 **************************************************************
@@ -650,22 +594,37 @@ u1 *codegen_findmethod(u1 *pc)
 
 *******************************************************************************/
 
-void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
+void codegen_finish(jitdata *jd)
 {
-#if 0
-       s4       mcodelen;
+       codeinfo    *code;
+       codegendata *cd;
+       s4           mcodelen;
+#if defined(ENABLE_INTRP)
+       s4           ncodelen;
 #endif
+       s4           alignedmcodelen;
+       jumpref     *jr;
+       u1          *epoint;
+       s4           extralen;
+       s4           alignedlen;
+
+       /* get required compiler data */
+
+       code = jd->code;
+       cd   = jd->cd;
+
+       /* prevent compiler warning */
+
 #if defined(ENABLE_INTRP)
-       s4       ncodelen;
+       ncodelen = 0;
 #endif
-       s4       alignedmcodelen;
-       jumpref *jr;
-       u1      *epoint;
-       s4       extralen;
-       s4       alignedlen;
-
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       extralen = sizeof(threadcritnode) * cd->threadcritcount;
+
+       /* calculate the code length */
+
+       mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
+
+#if defined(ENABLE_THREADS)
+       extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
 #else
        extralen = 0;
 #endif
@@ -677,14 +636,13 @@ void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
        }
 #endif
 
-#if 0
-       mcodelen = cd->mcodeptr - cd->mcodebase;
-#endif
        alignedmcodelen = ALIGN(mcodelen, MAX_ALIGN);
 
 #if defined(ENABLE_INTRP)
-       if (opt_intrp) {
+       if (opt_intrp)
                ncodelen = cd->ncodeptr - cd->ncodebase;
+       else {
+               ncodelen = 0; /* avoid compiler warning */
        }
 #endif
 
@@ -699,25 +657,36 @@ void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
 
        /* allocate new memory */
 
-       m->mcodelength = mcodelen + cd->dseglen;
-       m->mcode = CNEW(u1, alignedlen + extralen);
+       code->mcodelength = mcodelen + cd->dseglen;
+       code->mcode       = CNEW(u1, alignedlen + extralen);
 
-       /* copy data and code to their new location */
+       /* set the entrypoint of the method */
+       
+       assert(code->entrypoint == NULL);
+       code->entrypoint = epoint = (code->mcode + cd->dseglen);
 
-       MCOPY((void *) m->mcode, cd->dsegtop - cd->dseglen, u1, cd->dseglen);
-       MCOPY((void *) (m->mcode + cd->dseglen), cd->mcodebase, u1, mcodelen);
+       /* fill the data segment (code->entrypoint must already be set!) */
 
-       m->entrypoint = epoint = (m->mcode + cd->dseglen);
+       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) */
 
        if (opt_intrp) {
-               cd->mcodebase = m->entrypoint;
+               cd->mcodebase = code->entrypoint;
 
                if (ncodelen > 0) {
-                       u1 *ncodebase = m->mcode + cd->dseglen + alignedmcodelen;
-                       MCOPY((void *)ncodebase, cd->ncodebase, u1, ncodelen);
+                       u1 *ncodebase = code->mcode + cd->dseglen + alignedmcodelen;
+
+                       MCOPY((void *) ncodebase, cd->ncodebase, u1, ncodelen);
+
+                       /* flush the instruction and data caches */
+
+                       md_cacheflush(ncodebase, ncodelen);
 
                        /* set some cd variables for dynamic_super_rerwite */
 
@@ -741,11 +710,18 @@ void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
        {
                linenumberref *lr;
                ptrint lrtlen = 0;
+               ptrint target;
 
                for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
                        lrtlen++;
-                       *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
-                               (functionptr) ((ptrint) epoint + (ptrint) lr->targetmpc);
+                       target = lr->targetmpc;
+                       /* if the entry contains an mcode pointer (normal case), resolve it */
+                       /* (see doc/inlining_stacktrace.txt for details)                    */
+                       if (lr->linenumber >= -2) {
+                           target += (ptrint) epoint;
+                       }
+                       *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) = 
+                               (functionptr) target;
                }
                
                *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
@@ -754,39 +730,48 @@ void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
                *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
        }
 
-#if defined(__I386__) || defined(__X86_64__) || defined(ENABLE_INTRP) || defined(DISABLE_GC)
-       /* add method into methodtree to find the entrypoint */
+       /* replacement point resolving */
+       {
+               int i;
+               rplpoint *rp;
 
-       codegen_insertmethod(m->entrypoint, m->entrypoint + mcodelen);
-#endif
+               rp = code->rplpoints;
+               for (i=0; i<code->rplpointcount; ++i, ++rp) {
+                       rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
+                       rp->outcode = (u1*) ((ptrint) epoint + (ptrint) rp->outcode);
+               }
+       }
 
-#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__)
-       {
-               dataref *dr;
+       /* add method into methodtree to find the entrypoint */
 
-               /* data segment references resolving */
+       codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
 
-               for (dr = cd->datareferences; dr != NULL; dr = dr->next)
-                       *((u1 **) (epoint + dr->datapos - SIZEOF_VOID_P)) = epoint;
-       }
+#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
+       /* resolve data segment references */
+
+       dseg_resolve_datareferences(jd);
 #endif
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+#if defined(ENABLE_THREADS)
        {
-               threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
+               critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
                s4 i;
-               threadcritnodetemp *nt = cd->threadcrit;
+               codegen_critical_section_t *nt = cd->threadcrit;
 
                for (i = 0; i < cd->threadcritcount; i++) {
-                       n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
-                       n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
-                       n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
-                       thread_registercritical(n);
+                       n->mcodebegin = (u1 *) (ptrint) code->mcode + nt->mcodebegin;
+                       n->mcodeend = (u1 *) (ptrint) code->mcode + nt->mcodeend;
+                       n->mcoderestart = (u1 *) (ptrint) code->mcode + nt->mcoderestart;
+                       critical_register_critical_section(n);
                        n++;
                        nt = nt->next;
                }
        }
 #endif
+
+       /* flush the instruction and data caches */
+
+       md_cacheflush(code->mcode, code->mcodelength);
 }
 
 
@@ -794,34 +779,57 @@ void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
 
    Wrapper for createnativestub.
 
+   Returns:
+       the codeinfo representing the stub code.
+
 *******************************************************************************/
 
-u1 *codegen_createnativestub(functionptr f, methodinfo *m)
+codeinfo *codegen_createnativestub(functionptr f, methodinfo *m)
 {
-       codegendata        *cd;
-       registerdata       *rd;
-       t_inlining_globals *id;
-       s4                  dumpsize;
-       methoddesc         *md;
-       methoddesc         *nmd;        
-       s4                  nativeparams;
+       jitdata     *jd;
+       codeinfo    *code;
+       s4           dumpsize;
+       methoddesc  *md;
+       methoddesc  *nmd;       
+       s4           nativeparams;
 
        /* mark dump memory */
 
        dumpsize = dump_size();
 
-       cd = DNEW(codegendata);
-       rd = DNEW(registerdata);
-       id = DNEW(t_inlining_globals);
+       jd = DNEW(jitdata);
+
+       jd->m     = m;
+       jd->cd    = DNEW(codegendata);
+       jd->rd    = DNEW(registerdata);
+
+       /* Allocate codeinfo memory from the heap as we need to keep them. */
+
+       jd->code  = code_codeinfo_new(m); /* XXX check allocation */
+
+       /* get required compiler data */
+
+       code = jd->code;
+
+       /* set the flags for the current JIT run */
+
+       if (opt_prof)
+               jd->flags |= JITDATA_FLAG_INSTRUMENT;
+
+       if (opt_verbosecall)
+               jd->flags |= JITDATA_FLAG_VERBOSECALL;
 
        /* setup code generation stuff */
 
-       inlining_setup(m, id);
-#if !defined(ENABLE_INTRP)
-       reg_setup(m, rd, id);
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+       if (!opt_intrp)
+# endif
+               reg_setup(jd);
 #endif
-       codegen_setup(m, cd, id);
-                                               
+
+       codegen_setup(jd);
+
        /* create new method descriptor with additional native parameters */
 
        md = m->parseddesc;
@@ -843,37 +851,55 @@ u1 *codegen_createnativestub(functionptr f, methodinfo *m)
        MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
                  md->paramcount);
 
-       md_param_alloc(nmd);
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+       if (!opt_intrp)
+# endif
+               md_param_alloc(nmd);
+#endif
 
        /* generate the code */
 
-       m->entrypoint = createnativestub(f, m, cd, rd, nmd);
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+       if (opt_intrp)
+               code->entrypoint = intrp_createnativestub(f, jd, nmd);
+       else
+# endif
+               code->entrypoint = createnativestub(f, jd, nmd);
+#else
+       code->entrypoint = intrp_createnativestub(f, jd, nmd);
+#endif
 
 #if defined(ENABLE_STATISTICS)
        if (opt_stat)
-               count_nstub_len += m->mcodelength;
+               count_nstub_len += code->mcodelength;
 #endif
 
+#if !defined(NDEBUG)
        /* disassemble native stub */
 
        if (opt_shownativestub) {
+#if defined(ENABLE_DISASSEMBLER)
                codegen_disassemble_nativestub(m,
-                                                                          (u1 *) (ptrint) m->entrypoint,
-                                                                          (u1 *) (ptrint) m->entrypoint + (m->mcodelength - cd->dseglen));
+                                                                          (u1 *) (ptrint) code->entrypoint,
+                                                                          (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
+#endif
 
                /* show data segment */
 
                if (opt_showddatasegment)
-                       dseg_display(m, cd);
+                       dseg_display(jd);
        }
+#endif /* !defined(NDEBUG) */
 
        /* release memory */
 
        dump_release(dumpsize);
 
-       /* return native stub entry point */
+       /* return native stub code */
 
-       return m->entrypoint;
+       return code;
 }
 
 
@@ -883,17 +909,19 @@ u1 *codegen_createnativestub(functionptr f, methodinfo *m)
 
 *******************************************************************************/
 
+#if defined(ENABLE_DISASSEMBLER)
 void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
 {
        printf("Native stub: ");
-       utf_fprint_classname(stdout, m->class->name);
+       utf_fprint_printable_ascii_classname(stdout, m->class->name);
        printf(".");
-       utf_fprint(stdout, m->name);
-       utf_fprint(stdout, m->descriptor);
+       utf_fprint_printable_ascii(stdout, m->name);
+       utf_fprint_printable_ascii(stdout, m->descriptor);
        printf("\n\nLength: %d\n\n", (s4) (end - start));
 
-       disassemble(start, end);
+       DISASSEMBLE(start, end);
 }
+#endif
 
 
 /* codegen_start_native_call ***************************************************
@@ -956,15 +984,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;
-       s4               localframes;
+       stackframeinfo     *sfi;
+       stackframeinfo    **psfi;
+       localref_table     *lrt;
+       localref_table     *plrt;
+       s4                  localframes;
+       java_objectheader  *e;
 
        /* get data structures from stack */
 
@@ -982,15 +1014,35 @@ void codegen_finish_native_call(u1 *datasp)
 
        lrt = LOCALREFTABLE;
 
-       /* got through all current local frames */
+       /* release all current local frames */
 
        for (localframes = lrt->localframes; localframes >= 1; localframes--) {
-               lrt = lrt->prev;
+               /* get previous frame */
+
+               plrt = lrt->prev;
+
+               /* Clear all reference entries (only for tables allocated on
+                  the Java heap). */
+
+               if (localframes > 1)
+                       MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
+
+               lrt->prev = NULL;
+
+               /* set new local references table */
+
+               lrt = plrt;
        }
 
        /* 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;
 }
 
 
@@ -1022,7 +1074,7 @@ void removenativestub(u1 *stub)
 }
 
 
-/* reg_of_var ******************************************************************
+/* codegen_reg_of_var **********************************************************
 
    This function determines a register, to which the result of an
    operation should go, when it is ultimatively intended to store the
@@ -1038,10 +1090,54 @@ void removenativestub(u1 *stub)
 
 *******************************************************************************/
 
-s4 reg_of_var(registerdata *rd, stackptr v, s4 tempregnum)
+#if defined(NEW_VAR)
+s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
+{
+
+#if 0
+       /* Do we have to generate a conditional move?  Yes, then always
+          return the temporary register.  The real register is identified
+          during the store. */
+
+       if (opcode & ICMD_CONDITION_MASK)
+               return tempregnum;
+#endif
+
+       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(var->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(var->regoff)));
+#endif
+               return(v->regoff);
+       }
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               count_spills_read++;
+#endif
+
+       return tempregnum;
+}
+#else
+s4 codegen_reg_of_var(u2 opcode, stackptr v, s4 tempregnum)
 {
        varinfo *var;
 
+#if 0
+       /* Do we have to generate a conditional move?  Yes, then always
+          return the temporary register.  The real register is identified
+          during the store. */
+
+       if (opcode & ICMD_CONDITION_MASK)
+               return tempregnum;
+#endif
+
        switch (v->varkind) {
        case TEMPVAR:
                if (!(v->flags & INMEMORY))
@@ -1095,9 +1191,58 @@ s4 reg_of_var(registerdata *rd, stackptr v, s4 tempregnum)
 
        return tempregnum;
 }
+#endif
+
+
+/* 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)
+{
+       varinfo *v = &jd->var[iptr->dst.varindex];
+
+       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)));
+#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)));
+#endif
+               return (v->regoff);
+       }
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               count_spills_read++;
+#endif
+
+       /* Not necessary anymore - either v is inmemory or not. Setting again */
+       /* won't change anything */
+       v->flags |= INMEMORY;
+
+       return tempregnum;
+}
 
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+#if defined(ENABLE_THREADS)
 void codegen_threadcritrestart(codegendata *cd, int offset)
 {
        cd->threadcritcurrent.mcoderestart = offset;
@@ -1114,7 +1259,7 @@ void codegen_threadcritstop(codegendata *cd, int offset)
 {
        cd->threadcritcurrent.next = cd->threadcrit;
        cd->threadcritcurrent.mcodeend = offset;
-       cd->threadcrit = DNEW(threadcritnodetemp);
+       cd->threadcrit = DNEW(codegen_critical_section_t);
        *(cd->threadcrit) = cd->threadcritcurrent;
        cd->threadcritcount++;
 }
@@ -1132,4 +1277,5 @@ void codegen_threadcritstop(codegendata *cd, int offset)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */