* src/vm/jit/codegen-common.h (codegen_start_native_call): Changed signature.
[cacao.git] / src / vm / jit / codegen-common.c
index f7b44053e6f0b1006fb812325780a9ca82be9736..1044f1285162f9e5db9d7726720ffafb969351fe 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 7864 2007-05-03 21:17:26Z 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 "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 *********************************/
 
@@ -137,7 +143,9 @@ void codegen_init(void)
 
                avl_insert(methodtree, mte);
 #endif /* defined(ENABLE_JIT) */
+
        }
+
 }
 
 
@@ -261,6 +269,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;
@@ -372,7 +385,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)
@@ -542,12 +556,15 @@ 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
@@ -819,6 +836,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)
@@ -930,6 +948,7 @@ void codegen_finish(jitdata *jd)
 #endif
        s4           alignedmcodelen;
        jumpref     *jr;
+       patchref_t  *pr;
        u1          *epoint;
        s4           alignedlen;
 
@@ -1049,14 +1068,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);
@@ -1162,6 +1188,74 @@ u1 *codegen_generate_stub_compiler(methodinfo *m)
 }
 
 
+/* codegen_generate_stub_builtin ***********************************************
+
+   Wrapper for codegen_emit_stub_builtin.
+
+   Returns:
+       Pointer to the entrypoint of the stub.
+
+*******************************************************************************/
+
+void codegen_generate_stub_builtin(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     = NULL;
+       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(NULL);
+
+       /* 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
+               codegen_emit_stub_builtin(jd, bte);
+#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
+
+       /* release memory */
+
+       dump_release(dumpsize);
+#endif /* architecture list */
+}
+
+
 /* codegen_generate_stub_native ************************************************
 
    Wrapper for codegen_emit_stub_native.
@@ -1263,29 +1357,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(ENABLE_STATISTICS)
+       /* must be done after codegen_finish() */
+
+       if (opt_stat)
+               size_stub_native += code->mcodelength;
+#endif
+
 #if !defined(NDEBUG)
        /* disassemble native stub */
 
        if (opt_shownativestub) {
+#if defined(ENABLE_DEBUG_FILTER)
+               if (m->filtermatches & SHOW_FILTER_FLAG_SHOW_METHOD)
+#endif
+               {
 #if defined(ENABLE_DISASSEMBLER)
-               codegen_disassemble_nativestub(m,
-                                                                          (u1 *) (ptrint) code->entrypoint,
-                                                                          (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
+                       codegen_disassemble_nativestub(m,
+                                                                                  (u1 *) (ptrint) code->entrypoint,
+                                                                                  (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
 #endif
 
-               /* show data segment */
+                       /* show data segment */
 
-               if (opt_showddatasegment)
-                       dseg_display(jd);
+                       if (opt_showddatasegment)
+                               dseg_display(jd);
+               }
        }
 #endif /* !defined(NDEBUG) */
 
@@ -1320,14 +1421,13 @@ void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
 #endif
 
 
-/* codegen_start_native_call ***************************************************
+/* codegen_stub_builtin_enter **************************************************
 
-   Prepares the stuff required for a native (JNI) function call:
+   Prepares the stuff required for a builtin function call:
 
    - adds a stackframe info structure to the chain, for stacktraces
-   - prepares the local references table on the stack
 
-   The layout of the native stub stackframe should look like this:
+   The layout of the builtin stub stackframe should look like this:
 
    +---------------------------+ <- SP (of parent Java function)
    | return address            |
@@ -1337,112 +1437,206 @@ void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
    |                           |
    +---------------------------+
    |                           |
-   | local references table    |
-   |                           |
-   +---------------------------+
-   |                           |
    | arguments (if any)        |
    |                           |
    +---------------------------+ <- SP (native stub)
 
 *******************************************************************************/
 
-void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
+void codegen_stub_builtin_enter(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
 {
        stackframeinfo *sfi;
-       localref_table *lrt;
 
        /* get data structures from stack */
 
        sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
-       lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
-                                                         sizeof(localref_table));
 
        /* add a stackframeinfo to the chain */
 
        stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
+}
 
-#if defined(ENABLE_JNI)
-       /* add current JNI local references table to this thread */
 
-       lrt->capacity    = LOCALREFTABLE_CAPACITY;
-       lrt->used        = 0;
-       lrt->localframes = 1;
-       lrt->prev        = LOCALREFTABLE;
+/* codegen_stub_builtin_exit ***************************************************
 
-       /* clear the references array (memset is faster the a for-loop) */
+   Removes the stuff required for a builtin function call.
 
-       MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
+*******************************************************************************/
 
-       LOCALREFTABLE = lrt;
-#endif
+void codegen_stub_builtin_exit(u1 *datasp)
+{
+       stackframeinfo *sfi;
+
+       /* get data structures from stack */
+
+       sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
+
+       /* remove current stackframeinfo from chain */
+
+       stacktrace_remove_stackframeinfo(sfi);
 }
 
 
-/* codegen_finish_native_call **************************************************
+/* codegen_start_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.
+   Prepares the stuff required for a native (JNI) function call:
+
+   - adds a stackframe info structure to the chain, for stacktraces
+   - prepares the local references table on the stack
+
+   The layout of the native stub stackframe should look like this:
+
+   +---------------------------+ <- java SP (of parent Java function)
+   | return address            |
+   +---------------------------+ <- data SP
+   |                           |
+   | stackframe info structure |
+   |                           |
+   +---------------------------+
+   |                           |
+   | local references table    |
+   |                           |
+   +---------------------------+
+   |                           |
+   | saved registers (if any)  |
+   |                           |
+   +---------------------------+
+   |                           |
+   | arguments (if any)        |
+   |                           |
+   +---------------------------+ <- current SP (native stub)
 
 *******************************************************************************/
 
-java_objectheader *codegen_finish_native_call(u1 *datasp)
+void codegen_start_native_call(u1 *currentsp, u1 *pv)
 {
-       stackframeinfo     *sfi;
-       stackframeinfo    **psfi;
-#if defined(ENABLE_JNI)
-       localref_table     *lrt;
-       localref_table     *plrt;
-       s4                  localframes;
+       stackframeinfo *sfi;
+       localref_table *lrt;
+       codeinfo       *code;
+       methodinfo     *m;
+       int32_t         framesize;
+
+       uint8_t  *datasp;
+       uint8_t  *javasp;
+       uint8_t  *javara;
+#if !defined(NDEBUG)
+       uint64_t *args_regs;
+       uint64_t *args_stack;
 #endif
-       java_objectheader  *e;
 
-       /* get data structures from stack */
+       STATISTICS(count_calls_java_to_native++);
 
-       sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
+       /* get information from method header */
 
-       /* remove current stackframeinfo from chain */
+       code      = *((codeinfo **) (pv + CodeinfoPointer));
+       framesize = *((int32_t *)   (pv + FrameSize));
+
+       assert(code);
+       assert(framesize > sizeof(stackframeinfo) + sizeof(localref_table));
+
+       /* get the methodinfo */
 
-       psfi = &STACKFRAMEINFO;
+       m = code->m;
 
-       *psfi = sfi->prev;
+       assert(m);
+
+       /* calculate needed values */
+
+#if defined(__ALPHA__) || defined(__ARM__)
+       datasp = currentsp + framesize - SIZEOF_VOID_P;
+       javasp = currentsp + framesize;
+       javara = *((uint8_t **) datasp);
+#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);
+#elif defined(__POWERPC__) || defined(__POWERPC64__)
+       datasp = currentsp + framesize;
+       javasp = currentsp + framesize;
+       javara = *((uint8_t **) (datasp + LA_LR_OFFSET));
+#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 0
+       printf("NATIVE (framesize=%d): ", framesize);
+       method_print(m);
+       printf("\n");
+       fflush(stdout);
+#endif
+
+#if 0 && !defined(NDEBUG)
+       if (opt_TraceJavaCalls) {
+               args_regs  = currentsp;
+               args_stack = javasp;
+               trace_java_call_enter(m, args_regs, args_stack);
+       }
+#endif
+
+       /* get data structures from stack */
+
+       sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
+       lrt = (localref_table *) (datasp - sizeof(stackframeinfo) - 
+                                                         sizeof(localref_table));
 
 #if defined(ENABLE_JNI)
-       /* release JNI local references tables for this thread */
+       /* add current JNI local references table to this thread */
 
-       lrt = LOCALREFTABLE;
+       localref_table_add(lrt);
+#endif
 
-       /* release all current local frames */
+       /* XXX add references to lrt here!!! */
 
-       for (localframes = lrt->localframes; localframes >= 1; localframes--) {
-               /* get previous frame */
+       /* add a stackframeinfo to the chain */
 
-               plrt = lrt->prev;
+       stacktrace_create_native_stackframeinfo(sfi, pv, javasp, javara);
+}
 
-               /* Clear all reference entries (only for tables allocated on
-                  the Java heap). */
 
-               if (localframes > 1)
-                       MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
+/* codegen_finish_native_call **************************************************
 
-               lrt->prev = NULL;
+   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.
 
-               /* set new local references table */
+*******************************************************************************/
 
-               lrt = plrt;
-       }
+java_object_t *codegen_finish_native_call(u1 *datasp)
+{
+       stackframeinfo *sfi;
+       java_handle_t  *e;
+       java_object_t  *o;
 
-       /* now store the previous local frames in the thread structure */
+       /* get data structures from stack */
 
-       LOCALREFTABLE = lrt;
-#endif
+       sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
+
+       /* remove current stackframeinfo from chain */
+
+       stacktrace_remove_stackframeinfo(sfi);
 
-       /* get the exception and return it */
+       /* get and unwrap the exception */
+       /* ATTENTION: do the this _after_ the stackframeinfo was
+       removed but _before_ the localref_table gets removed! */
 
        e = exceptions_get_and_clear_exception();
+       o = LLNI_UNWRAP(e);
 
-       return e;
+#if defined(ENABLE_JNI)
+       /* release JNI local references table for this thread */
+
+       localref_frame_pop_all();
+       localref_table_remove();
+#endif
+
+       return o;
 }
 
 
@@ -1483,11 +1677,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)
@@ -1502,28 +1691,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
@@ -1533,11 +1707,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)
@@ -1546,6 +1715,97 @@ s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)
 }
 
 
+/* codegen_emit_phi_moves ****************************************************
+
+   Emits phi moves at the end of the basicblock.
+
+*******************************************************************************/
+
+#if defined(ENABLE_SSA)
+void codegen_emit_phi_moves(jitdata *jd, basicblock *bptr)
+{
+       int lt_d,lt_s,i;
+       lsradata *ls;
+       codegendata *cd;
+       varinfo *s, *d;
+       instruction tmp_i;
+
+       cd = jd->cd;
+       ls = jd->ls;
+
+       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) */
+
+
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where