* src/vm/jit/codegen-common.c (codegen_disassemble_stub): Renamed and works with
[cacao.git] / src / vm / jit / codegen-common.c
index 669ffec53363181b42e422934005d126bd111eee..8a04bea20ebb5691c4520b1dea3534b9a95a5feb 100644 (file)
@@ -39,8 +39,6 @@
    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 7859 2007-05-03 08:29:16Z twisti $
-
 */
 
 
 # include "codegen.h"
 #endif
 
-#if defined(__ARM__)
-/* this is required for REG_SPLIT */
-# include "md-abi.h"
-#endif
+#include "md-abi.h"
 
 #include "mm/memory.h"
 
 #include "toolbox/logging.h"
 
 #include "native/jni.h"
+#include "native/llni.h"
+#include "native/localref.h"
 #include "native/native.h"
 
+#include "native/include/java_lang_Class.h"
+
 #include "threads/threads-common.h"
 
+#include "vm/builtin.h"
 #include "vm/exceptions.h"
 #include "vm/stringlocal.h"
 
 #include "vm/jit/emit-common.h"
 #include "vm/jit/jit.h"
 #include "vm/jit/md.h"
+#include "vm/jit/methodheader.h"
+#include "vm/jit/patcher-common.h"
 #include "vm/jit/replace.h"
+#if defined(ENABLE_SSA)
+# include "vm/jit/optimizing/lsra.h"
+# include "vm/jit/optimizing/ssa.h"
+#endif
 #include "vm/jit/stacktrace.h"
+#include "vm/jit/trace.h"
 
 #if defined(ENABLE_INTRP)
 #include "vm/jit/intrp/intrp.h"
 #include <vmlog_cacao.h>
 #endif
 
+#include "show.h"
 
 /* in this tree we store all method addresses *********************************/
 
 static avl_tree_t *methodtree = NULL;
-static s4 methodtree_comparator(const void *pc, const void *element);
+static s4 methodtree_comparator(const void *treenode, const void *node);
 
 
 /* codegen_init ****************************************************************
@@ -137,7 +145,9 @@ void codegen_init(void)
 
                avl_insert(methodtree, mte);
 #endif /* defined(ENABLE_JIT) */
+
        }
+
 }
 
 
@@ -198,16 +208,12 @@ void codegen_setup(jitdata *jd)
 /*     cd->patchrefs      = list_create_dump(OFFSET(patchref, linkage)); */
        cd->patchrefs      = NULL;
        cd->brancheslabel  = list_create_dump(OFFSET(branch_label_ref_t, linkage));
+       cd->listcritical   = list_create_dump(OFFSET(critical_section_ref_t, linkage));
 
        cd->linenumberreferences = NULL;
        cd->linenumbertablesizepos = 0;
        cd->linenumbertablestartpos = 0;
        cd->linenumbertab = 0;
-       
-#if defined(ENABLE_THREADS)
-       cd->threadcritcurrent.next = NULL;
-       cd->threadcritcount = 0;
-#endif
 }
 
 
@@ -250,17 +256,13 @@ static void codegen_reset(jitdata *jd)
 /*     cd->patchrefs       = list_create_dump(OFFSET(patchref, linkage)); */
        cd->patchrefs       = NULL;
        cd->brancheslabel   = list_create_dump(OFFSET(branch_label_ref_t, linkage));
+       cd->listcritical    = list_create_dump(OFFSET(critical_section_ref_t, linkage));
 
        cd->linenumberreferences    = NULL;
        cd->linenumbertablesizepos  = 0;
        cd->linenumbertablestartpos = 0;
        cd->linenumbertab           = 0;
        
-#if defined(ENABLE_THREADS)
-       cd->threadcritcurrent.next = NULL;
-       cd->threadcritcount        = 0;
-#endif
-
        /* We need to clear the mpc and the branch references from all
           basic blocks as they will definitely change. */
 
@@ -269,6 +271,11 @@ static void codegen_reset(jitdata *jd)
                bptr->branchrefs = NULL;
        }
 
+       /* We need to clear all the patcher references from the codeinfo
+          since they all will be regenerated */
+
+       patcher_list_reset(code);
+
 #if defined(ENABLE_REPLACEMENT)
        code->rplpoints     = NULL;
        code->rplpointcount = 0;
@@ -380,7 +387,8 @@ void codegen_increase(codegendata *cd)
 
        cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
 
-#if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(ENABLE_INTRP)
+#if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(__M68K__) || defined(ENABLE_INTRP) \
+ || defined(__SPARC_64__)
        /* adjust the pointer to the last patcher position */
 
        if (cd->lastmcodeptr != NULL)
@@ -550,31 +558,197 @@ void codegen_add_patch_ref(codegendata *cd, functionptr patcher, voidptr ref,
        if (opt_shownops)
                PATCHER_NOPS;
 
-#if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__))
+#if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__MIPS__) \
+ || defined(__SPARC_64__) || 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. */
+       /* The nops are generated in codegen_emit in each codegen */
 
        cd->lastmcodeptr = cd->mcodeptr + PATCHER_CALL_SIZE;
 #endif
 }
 
 
+/* codegen_critical_section_new ************************************************
+
+   Allocates a new critical-section reference and adds it to the
+   critical-section list.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void codegen_critical_section_new(codegendata *cd)
+{
+       list_t                 *list;
+       critical_section_ref_t *csr;
+       s4                      mpc;
+
+       /* get the critical section list */
+
+       list = cd->listcritical;
+       
+       /* calculate the current mpc */
+
+       mpc = cd->mcodeptr - cd->mcodebase;
+
+       csr = DNEW(critical_section_ref_t);
+
+       /* We only can set restart right now, as start and end are set by
+          the following, corresponding functions. */
+
+       csr->start   = -1;
+       csr->end     = -1;
+       csr->restart = mpc;
+
+       /* add the branch to the list */
+
+       list_add_last_unsynced(list, csr);
+}
+#endif
+
+
+/* codegen_critical_section_start **********************************************
+
+   Set the start-point of the current critical section (which is the
+   last element of the list).
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void codegen_critical_section_start(codegendata *cd)
+{
+       list_t                 *list;
+       critical_section_ref_t *csr;
+       s4                      mpc;
+
+       /* get the critical section list */
+
+       list = cd->listcritical;
+       
+       /* calculate the current mpc */
+
+       mpc = cd->mcodeptr - cd->mcodebase;
+
+       /* get the current critical section */
+
+       csr = list_last_unsynced(list);
+
+       /* set the start point */
+
+       assert(csr->start == -1);
+
+       csr->start = mpc;
+}
+#endif
+
+
+/* codegen_critical_section_end ************************************************
+
+   Set the end-point of the current critical section (which is the
+   last element of the list).
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void codegen_critical_section_end(codegendata *cd)
+{
+       list_t                 *list;
+       critical_section_ref_t *csr;
+       s4                      mpc;
+
+       /* get the critical section list */
+
+       list = cd->listcritical;
+       
+       /* calculate the current mpc */
+
+       mpc = cd->mcodeptr - cd->mcodebase;
+
+       /* get the current critical section */
+
+       csr = list_last_unsynced(list);
+
+       /* set the end point */
+
+       assert(csr->end == -1);
+
+       csr->end = mpc;
+}
+#endif
+
+
+/* codegen_critical_section_finish *********************************************
+
+   Finish the critical sections, create the critical section nodes for
+   the AVL tree and insert them into the tree.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+static void codegen_critical_section_finish(jitdata *jd)
+{
+       codeinfo    *code;
+       codegendata *cd;
+       list_t                  *list;
+       critical_section_ref_t  *csr;
+       critical_section_node_t *csn;
+
+       /* get required compiler data */
+
+       code = jd->code;
+       cd   = jd->cd;
+
+       /* get the critical section list */
+
+       list = cd->listcritical;
+
+       /* iterate over all critical sections */
+
+       for (csr = list_first_unsynced(list); csr != NULL;
+                csr = list_next_unsynced(list, csr)) {
+               /* check if all points are set */
+
+               assert(csr->start   != -1);
+               assert(csr->end     != -1);
+               assert(csr->restart != -1);
+
+               /* allocate tree node */
+
+               csn = NEW(critical_section_node_t);
+
+               csn->start   = code->entrypoint + csr->start;
+               csn->end     = code->entrypoint + csr->end;
+               csn->restart = code->entrypoint + csr->restart;
+
+               /* insert into the tree */
+
+               critical_section_register(csn);
+       }
+}
+#endif
+
+
 /* methodtree_comparator *******************************************************
 
    Comparator function used for the AVL tree of methods.
 
+   ARGUMENTS:
+      treenode....the node from the tree
+      node........the node to compare to the tree-node
+
 *******************************************************************************/
 
-static s4 methodtree_comparator(const void *pc, const void *element)
+static s4 methodtree_comparator(const void *treenode, const void *node)
 {
        methodtree_element *mte;
        methodtree_element *mtepc;
 
-       mte = (methodtree_element *) element;
-       mtepc = (methodtree_element *) pc;
+       mte   = (methodtree_element *) treenode;
+       mtepc = (methodtree_element *) node;
 
        /* compare both startpc and endpc of pc, even if they have the same value,
           otherwise the avl_probe sometimes thinks the element is already in the
@@ -664,6 +838,7 @@ u1 *codegen_get_pv_from_pc(u1 *pc)
                log_println("PC=0x%08x", pc);
 #endif
                log_println("");
+               assert(0);
                log_println("Dumping the current stacktrace:");
 
 #if defined(ENABLE_THREADS)
@@ -775,8 +950,8 @@ void codegen_finish(jitdata *jd)
 #endif
        s4           alignedmcodelen;
        jumpref     *jr;
+       patchref_t  *pr;
        u1          *epoint;
-       s4           extralen;
        s4           alignedlen;
 
        /* get required compiler data */
@@ -794,12 +969,6 @@ void codegen_finish(jitdata *jd)
 
        mcodelen = (s4) (cd->mcodeptr - cd->mcodebase);
 
-#if defined(ENABLE_THREADS)
-       extralen = sizeof(critical_section_node_t) * cd->threadcritcount;
-#else
-       extralen = 0;
-#endif
-
 #if defined(ENABLE_STATISTICS)
        if (opt_stat) {
                count_code_len += mcodelen;
@@ -829,7 +998,7 @@ void codegen_finish(jitdata *jd)
        /* allocate new memory */
 
        code->mcodelength = mcodelen + cd->dseglen;
-       code->mcode       = CNEW(u1, alignedlen + extralen);
+       code->mcode       = CNEW(u1, alignedlen);
 
        /* set the entrypoint of the method */
        
@@ -901,14 +1070,21 @@ void codegen_finish(jitdata *jd)
                *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
        }
 
+       /* patcher resolving */
+
+       pr = list_first_unsynced(code->patchers);
+       while (pr) {
+               pr->mpc += (ptrint) epoint;
+               pr->datap = (ptrint) (pr->disp + epoint);
+               pr = list_next_unsynced(code->patchers, pr);
+       }
+
 #if defined(ENABLE_REPLACEMENT)
        /* replacement point resolving */
        {
                int i;
                rplpoint *rp;
 
-               code->replacementstubs += (ptrint) epoint;
-
                rp = code->rplpoints;
                for (i=0; i<code->rplpointcount; ++i, ++rp) {
                        rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
@@ -927,20 +1103,9 @@ void codegen_finish(jitdata *jd)
 #endif
 
 #if defined(ENABLE_THREADS)
-       {
-               critical_section_node_t *n = (critical_section_node_t *) ((ptrint) code->mcode + alignedlen);
-               s4 i;
-               codegen_critical_section_t *nt = cd->threadcrit;
-
-               for (i = 0; i < cd->threadcritcount; i++) {
-                       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;
-               }
-       }
+       /* create cirtical sections */
+
+       codegen_critical_section_finish(jd);
 #endif
 
        /* flush the instruction and data caches */
@@ -1025,6 +1190,90 @@ u1 *codegen_generate_stub_compiler(methodinfo *m)
 }
 
 
+/* codegen_generate_stub_builtin ***********************************************
+
+   Wrapper for codegen_emit_stub_builtin.
+
+*******************************************************************************/
+
+void codegen_generate_stub_builtin(methodinfo *m, builtintable_entry *bte)
+{
+#if defined(__ARM__) || defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__POWERPC__) || defined(__SPARC64__) || defined(__X86_64__)
+       jitdata  *jd;
+       codeinfo *code;
+       s4        dumpsize;
+
+       /* mark dump memory */
+
+       dumpsize = dump_size();
+
+       jd = DNEW(jitdata);
+
+       jd->m     = m;
+       jd->cd    = DNEW(codegendata);
+       jd->rd    = NULL;
+       jd->flags = 0;
+
+       /* 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;
+
+       /* setup code generation stuff */
+
+       codegen_setup(jd);
+
+       /* generate the code */
+
+#if defined(ENABLE_JIT)
+# if defined(ENABLE_INTRP)
+       if (!opt_intrp) {
+# endif
+               assert(bte->fp != NULL);
+               codegen_emit_stub_native(jd, bte->md, bte->fp);
+# if defined(ENABLE_INTRP)
+       }
+# endif
+#endif
+
+       /* reallocate the memory and finish the code generation */
+
+       codegen_finish(jd);
+
+       /* set the stub entry point in the builtin table */
+
+       bte->stub = code->entrypoint;
+
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               size_stub_native += code->mcodelength;
+#endif
+
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
+       /* disassemble native stub */
+
+       if (opt_DisassembleStubs) {
+               codegen_disassemble_stub(m,
+                                                                (u1 *) (ptrint) code->entrypoint,
+                                                                (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
+
+               /* show data segment */
+
+               if (opt_showddatasegment)
+                       dseg_display(jd);
+       }
+#endif /* !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) */
+
+       /* release memory */
+
+       dump_release(dumpsize);
+#endif /* architecture list */
+}
+
+
 /* codegen_generate_stub_native ************************************************
 
    Wrapper for codegen_emit_stub_native.
@@ -1126,31 +1375,36 @@ codeinfo *codegen_generate_stub_native(methodinfo *m, functionptr f)
        intrp_createnativestub(f, jd, nmd);
 #endif
 
-#if defined(ENABLE_STATISTICS)
-       if (opt_stat)
-               count_nstub_len += code->mcodelength;
-#endif
-
        /* reallocate the memory and finish the code generation */
 
        codegen_finish(jd);
 
-#if !defined(NDEBUG)
-       /* disassemble native stub */
+#if defined(ENABLE_STATISTICS)
+       /* must be done after codegen_finish() */
 
-       if (opt_shownativestub) {
-#if defined(ENABLE_DISASSEMBLER)
-               codegen_disassemble_nativestub(m,
-                                                                          (u1 *) (ptrint) code->entrypoint,
-                                                                          (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
+       if (opt_stat)
+               size_stub_native += code->mcodelength;
 #endif
 
-               /* show data segment */
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
+       /* disassemble native stub */
 
-               if (opt_showddatasegment)
-                       dseg_display(jd);
+       if (opt_DisassembleStubs) {
+# if defined(ENABLE_DEBUG_FILTER)
+               if (m->filtermatches & SHOW_FILTER_FLAG_SHOW_METHOD)
+# endif
+               {
+                       codegen_disassemble_stub(m,
+                                                                        (u1 *) (ptrint) code->entrypoint,
+                                                                        (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
+
+                       /* show data segment */
+
+                       if (opt_showddatasegment)
+                               dseg_display(jd);
+               }
        }
-#endif /* !defined(NDEBUG) */
+#endif /* !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) */
 
        /* release memory */
 
@@ -1164,19 +1418,22 @@ codeinfo *codegen_generate_stub_native(methodinfo *m, functionptr f)
 
 /* codegen_disassemble_nativestub **********************************************
 
-   Disassembles the generated native stub.
+   Disassembles the generated builtin or native stub.
 
 *******************************************************************************/
 
 #if defined(ENABLE_DISASSEMBLER)
-void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
+void codegen_disassemble_stub(methodinfo *m, u1 *start, u1 *end)
 {
-       printf("Native stub: ");
-       utf_fprint_printable_ascii_classname(stdout, m->class->name);
+       printf("Stub code: ");
+       if (m->class != NULL)
+               utf_fprint_printable_ascii_classname(stdout, m->class->name);
+       else
+               printf("NULL");
        printf(".");
        utf_fprint_printable_ascii(stdout, m->name);
        utf_fprint_printable_ascii(stdout, m->descriptor);
-       printf("\n\nLength: %d\n\n", (s4) (end - start));
+       printf("\nLength: %d\n\n", (s4) (end - start));
 
        DISASSEMBLE(start, end);
 }
@@ -1192,9 +1449,9 @@ void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
 
    The layout of the native stub stackframe should look like this:
 
-   +---------------------------+ <- SP (of parent Java function)
+   +---------------------------+ <- java SP (of parent Java function)
    | return address            |
-   +---------------------------+
+   +---------------------------+ <- data SP
    |                           |
    | stackframe info structure |
    |                           |
@@ -1204,16 +1461,83 @@ void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
    |                           |
    +---------------------------+
    |                           |
+   | saved registers (if any)  |
+   |                           |
+   +---------------------------+
+   |                           |
    | arguments (if any)        |
    |                           |
-   +---------------------------+ <- SP (native stub)
+   +---------------------------+ <- current SP (native stub)
 
 *******************************************************************************/
 
-void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
+java_handle_t *codegen_start_native_call(u1 *currentsp, u1 *pv)
 {
        stackframeinfo *sfi;
        localref_table *lrt;
+       codeinfo       *code;
+       methodinfo     *m;
+       int32_t         framesize;
+
+       uint8_t  *datasp;
+       uint8_t  *javasp;
+       uint8_t  *javara;
+       uint64_t *arg_regs;
+       uint64_t *arg_stack;
+
+       STATISTICS(count_calls_java_to_native++);
+
+       /* get information from method header */
+
+       code      = *((codeinfo **) (pv + CodeinfoPointer));
+       framesize = *((int32_t *)   (pv + FrameSize));
+       assert(code);
+       assert(framesize > sizeof(stackframeinfo) + sizeof(localref_table));
+
+       /* get the methodinfo */
+
+       m = code->m;
+       assert(m);
+
+       /* calculate needed values */
+
+#if defined(__ALPHA__) || defined(__ARM__)
+       datasp    = currentsp + framesize - SIZEOF_VOID_P;
+       javasp    = currentsp + framesize;
+       javara    = *((uint8_t **) datasp);
+       arg_regs  = (uint64_t *) currentsp;
+       arg_stack = (uint64_t *) javasp;
+#elif defined(__MIPS__) || defined(__S390__)
+       /* MIPS and S390 always uses 8 bytes to store the RA */
+       datasp    = currentsp + framesize - 8;
+       javasp    = currentsp + framesize;
+       javara    = *((uint8_t **) datasp);
+#elif defined(__I386__) || defined (__M68K__) || defined (__X86_64__)
+       datasp    = currentsp + framesize;
+       javasp    = currentsp + framesize + SIZEOF_VOID_P;
+       javara    = *((uint8_t **) datasp);
+       arg_regs  = (uint64_t *) currentsp;
+       arg_stack = (uint64_t *) javasp;
+#elif defined(__POWERPC__) || defined(__POWERPC64__)
+       datasp    = currentsp + framesize;
+       javasp    = currentsp + framesize;
+       javara    = *((uint8_t **) (datasp + LA_LR_OFFSET));
+       arg_regs  = (uint64_t *) (currentsp + LA_SIZE + 4 * SIZEOF_VOID_P);
+       arg_stack = (uint64_t *) javasp;
+#else
+       /* XXX is was unable to do this port for SPARC64, sorry. (-michi) */
+       /* XXX maybe we need to pass the RA as argument there */
+       vm_abort("codegen_start_native_call: unsupported architecture");
+#endif
+
+#if !defined(NDEBUG)
+# if defined(__POWERPC__) || defined (__X86_64__)
+       /* print the call-trace if necesarry */
+
+       if (opt_TraceJavaCalls)
+               trace_java_call_enter(m, arg_regs, arg_stack);
+# endif
+#endif
 
        /* get data structures from stack */
 
@@ -1221,24 +1545,28 @@ void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
        lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
                                                          sizeof(localref_table));
 
-       /* add a stackframeinfo to the chain */
+#if defined(ENABLE_JNI)
+       /* add current JNI local references table to this thread */
 
-       stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
+       localref_table_add(lrt);
+#endif
 
-#if defined(ENABLE_JAVASE)
-       /* add current JNI local references table to this thread */
+#if defined(ENABLE_HANDLES)
+       /* place all references into the local reference table */
 
-       lrt->capacity    = LOCALREFTABLE_CAPACITY;
-       lrt->used        = 0;
-       lrt->localframes = 1;
-       lrt->prev        = LOCALREFTABLE;
+       localref_fill(m, arg_regs, arg_stack);
+#endif
 
-       /* clear the references array (memset is faster the a for-loop) */
+       /* add a stackframeinfo to the chain */
 
-       MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
+       stacktrace_create_native_stackframeinfo(sfi, pv, javasp, javara);
 
-       LOCALREFTABLE = lrt;
-#endif
+       /* return a wrapped classinfo for static native methods */
+
+       if (m->flags & ACC_STATIC)
+               return LLNI_classinfo_wrap(m->class);
+       else
+               return NULL;
 }
 
 
@@ -1250,62 +1578,85 @@ void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
 
 *******************************************************************************/
 
-java_objectheader *codegen_finish_native_call(u1 *datasp)
+java_object_t *codegen_finish_native_call(u1 *currentsp, u1 *pv)
 {
-       stackframeinfo     *sfi;
-       stackframeinfo    **psfi;
-#if defined(ENABLE_JAVASE)
-       localref_table     *lrt;
-       localref_table     *plrt;
-       s4                  localframes;
+       stackframeinfo *sfi;
+       java_handle_t  *e;
+       java_object_t  *o;
+       codeinfo       *code;
+       methodinfo     *m;
+       int32_t         framesize;
+
+       uint8_t  *datasp;
+       uint64_t *ret_regs;
+
+       /* get information from method header */
+
+       code      = *((codeinfo **) (pv + CodeinfoPointer));
+       framesize = *((int32_t *)   (pv + FrameSize));
+       assert(code);
+
+       /* get the methodinfo */
+
+       m = code->m;
+       assert(m);
+
+       /* calculate needed values */
+
+#if defined(__ALPHA__) || defined(__ARM__)
+       datasp   = currentsp + framesize - SIZEOF_VOID_P;
+       ret_regs = (uint64_t *) currentsp;
+#elif defined(__MIPS__) || defined(__S390__)
+       /* MIPS and S390 always uses 8 bytes to store the RA */
+       datasp   = currentsp + framesize - 8;
+#elif defined(__I386__)
+       datasp   = currentsp + framesize;
+       ret_regs = (uint64_t *) (currentsp + 2 * SIZEOF_VOID_P);
+#elif defined (__M68K__) || defined (__X86_64__)
+       datasp   = currentsp + framesize;
+       ret_regs = (uint64_t *) currentsp;
+#elif defined(__POWERPC__) || defined(__POWERPC64__)
+       datasp   = currentsp + framesize;
+       ret_regs = (uint64_t *) (currentsp + LA_SIZE + 2 * SIZEOF_VOID_P);
+#else
+       vm_abort("codegen_finish_native_call: unsupported architecture");
 #endif
-       java_objectheader  *e;
-
-       /* get data structures from stack */
-
-       sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
-
-       /* remove current stackframeinfo from chain */
-
-       psfi = &STACKFRAMEINFO;
 
-       *psfi = sfi->prev;
 
-#if defined(ENABLE_JAVASE)
-       /* release JNI local references tables for this thread */
-
-       lrt = LOCALREFTABLE;
+#if !defined(NDEBUG)
+# if defined(__POWERPC__) || defined (__X86_64__)
+       /* print the call-trace if necesarry */
 
-       /* release all current local frames */
+       if (opt_TraceJavaCalls)
+               trace_java_call_exit(m, ret_regs);
+# endif
+#endif
 
-       for (localframes = lrt->localframes; localframes >= 1; localframes--) {
-               /* get previous frame */
+       /* get data structures from stack */
 
-               plrt = lrt->prev;
+       sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
 
-               /* Clear all reference entries (only for tables allocated on
-                  the Java heap). */
+       /* remove current stackframeinfo from chain */
 
-               if (localframes > 1)
-                       MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
+       stacktrace_remove_stackframeinfo(sfi);
 
-               lrt->prev = NULL;
+       /* XXX unfill lrt here!!! */
 
-               /* set new local references table */
+       /* get and unwrap the exception */
+       /* ATTENTION: do the this _after_ the stackframeinfo was
+       removed but _before_ the localref_table gets removed! */
 
-               lrt = plrt;
-       }
+       e = exceptions_get_and_clear_exception();
+       o = LLNI_UNWRAP(e);
 
-       /* now store the previous local frames in the thread structure */
+#if defined(ENABLE_JNI)
+       /* release JNI local references table for this thread */
 
-       LOCALREFTABLE = lrt;
+       localref_frame_pop_all();
+       localref_table_remove();
 #endif
 
-       /* get the exception and return it */
-
-       e = exceptions_get_and_clear_exception();
-
-       return e;
+       return o;
 }
 
 
@@ -1346,11 +1697,6 @@ void removenativestub(u1 *stub)
    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 v for LOW_REG and the tempregnum for HIGH_REG in such
-   cases.  (michi 2005/07/24)
-
 *******************************************************************************/
 
 s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
@@ -1365,28 +1711,13 @@ s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
                return tempregnum;
 #endif
 
-       if (!(v->flags & INMEMORY)) {
-#if defined(__ARM__) && defined(__ARMEL__)
-               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->vv.regoff) == REG_SPLIT))
-                       return PACK_REGS(GET_LOW_REG(tempregnum),
-                                                        GET_HIGH_REG(v->vv.regoff));
-#endif
+       if (!(v->flags & INMEMORY))
                return v->vv.regoff;
-       }
-
-#if defined(ENABLE_STATISTICS)
-       if (opt_stat)
-               count_spills_read++;
-#endif
 
        return tempregnum;
 }
 
+
 /* codegen_reg_of_dst **********************************************************
 
    This function determines a register, to which the result of an
@@ -1396,11 +1727,6 @@ s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
    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)
@@ -1409,28 +1735,95 @@ s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
 }
 
 
-#if defined(ENABLE_THREADS)
-void codegen_threadcritrestart(codegendata *cd, int offset)
-{
-       cd->threadcritcurrent.mcoderestart = offset;
-}
+/* codegen_emit_phi_moves ****************************************************
 
+   Emits phi moves at the end of the basicblock.
+
+*******************************************************************************/
 
-void codegen_threadcritstart(codegendata *cd, int offset)
+#if defined(ENABLE_SSA)
+void codegen_emit_phi_moves(jitdata *jd, basicblock *bptr)
 {
-       cd->threadcritcurrent.mcodebegin = offset;
-}
+       int lt_d,lt_s,i;
+       lsradata *ls;
+       codegendata *cd;
+       varinfo *s, *d;
+       instruction tmp_i;
 
+       cd = jd->cd;
+       ls = jd->ls;
 
-void codegen_threadcritstop(codegendata *cd, int offset)
-{
-       cd->threadcritcurrent.next = cd->threadcrit;
-       cd->threadcritcurrent.mcodeend = offset;
-       cd->threadcrit = DNEW(codegen_critical_section_t);
-       *(cd->threadcrit) = cd->threadcritcurrent;
-       cd->threadcritcount++;
-}
+       MCODECHECK(512);
+
+       /* Moves from phi functions with highest indices have to be */
+       /* inserted first, since this is the order as is used for   */
+       /* conflict resolution */
+
+       for(i = ls->num_phi_moves[bptr->nr] - 1; i >= 0 ; i--) {
+               lt_d = ls->phi_moves[bptr->nr][i][0];
+               lt_s = ls->phi_moves[bptr->nr][i][1];
+#if defined(SSA_DEBUG_VERBOSE)
+               if (compileverbose)
+                       printf("BB %3i Move %3i <- %3i ", bptr->nr, lt_d, lt_s);
 #endif
+               if (lt_s == UNUSED) {
+#if defined(SSA_DEBUG_VERBOSE)
+               if (compileverbose)
+                       printf(" ... not processed \n");
+#endif
+                       continue;
+               }
+                       
+               d = VAR(ls->lifetime[lt_d].v_index);
+               s = VAR(ls->lifetime[lt_s].v_index);
+               
+
+               if (d->type == -1) {
+#if defined(SSA_DEBUG_VERBOSE)
+                       if (compileverbose)
+                               printf("...returning - phi lifetimes where joined\n");
+#endif
+                       return;
+               }
+
+               if (s->type == -1) {
+#if defined(SSA_DEBUG_VERBOSE)
+                       if (compileverbose)
+                               printf("...returning - phi lifetimes where joined\n");
+#endif
+                       return;
+               }
+
+               tmp_i.opc = 0;
+               tmp_i.s1.varindex = ls->lifetime[lt_s].v_index;
+               tmp_i.dst.varindex = ls->lifetime[lt_d].v_index;
+               emit_copy(jd, &tmp_i);
+
+#if defined(SSA_DEBUG_VERBOSE)
+               if (compileverbose) {
+                       if (IS_INMEMORY(d->flags) && IS_INMEMORY(s->flags)) {
+                               /* mem -> mem */
+                               printf("M%3i <- M%3i",d->vv.regoff,s->vv.regoff);
+                       }
+                       else if (IS_INMEMORY(s->flags)) {
+                               /* mem -> reg */
+                               printf("R%3i <- M%3i",d->vv.regoff,s->vv.regoff);
+                       }
+                       else if (IS_INMEMORY(d->flags)) {
+                               /* reg -> mem */
+                               printf("M%3i <- R%3i",d->vv.regoff,s->vv.regoff);
+                       }
+                       else {
+                               /* reg -> reg */
+                               printf("R%3i <- R%3i",d->vv.regoff,s->vv.regoff);
+                       }
+                       printf("\n");
+               }
+#endif /* defined(SSA_DEBUG_VERBOSE) */
+       }
+}
+#endif /* defined(ENABLE_SSA) */
+
 
 
 /*