* src/vm/jit/codegen-common.c (codegen_disassemble_stub): Renamed and works with
[cacao.git] / src / vm / jit / codegen-common.c
index 344dcad6ceb7392d30e33666f349dac078fb2fae..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 7940 2007-05-23 09:42:08Z michi $
-
 */
 
 
 # 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/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 *********************************/
 
@@ -142,7 +145,9 @@ void codegen_init(void)
 
                avl_insert(methodtree, mte);
 #endif /* defined(ENABLE_JIT) */
+
        }
+
 }
 
 
@@ -266,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;
@@ -377,7 +387,8 @@ void codegen_increase(codegendata *cd)
 
        cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
 
-#if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(__M68K__) || 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)
@@ -547,7 +558,9 @@ 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__) || defined(__M68K__))
+#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
@@ -825,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)
@@ -936,6 +950,7 @@ void codegen_finish(jitdata *jd)
 #endif
        s4           alignedmcodelen;
        jumpref     *jr;
+       patchref_t  *pr;
        u1          *epoint;
        s4           alignedlen;
 
@@ -1055,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);
@@ -1172,13 +1194,11 @@ u1 *codegen_generate_stub_compiler(methodinfo *m)
 
    Wrapper for codegen_emit_stub_builtin.
 
-   Returns:
-       Pointer to the entrypoint of the stub.
-
 *******************************************************************************/
 
-void codegen_generate_stub_builtin(builtintable_entry *bte)
+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;
@@ -1189,14 +1209,14 @@ void codegen_generate_stub_builtin(builtintable_entry *bte)
 
        jd = DNEW(jitdata);
 
-       jd->m     = NULL;
+       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(NULL);
+       jd->code  = code_codeinfo_new(m); /* XXX check allocation */
 
        /* get required compiler data */
 
@@ -1210,9 +1230,13 @@ void codegen_generate_stub_builtin(builtintable_entry *bte)
 
 #if defined(ENABLE_JIT)
 # if defined(ENABLE_INTRP)
-       if (!opt_intrp)
+       if (!opt_intrp) {
+# endif
+               assert(bte->fp != NULL);
+               codegen_emit_stub_native(jd, bte->md, bte->fp);
+# if defined(ENABLE_INTRP)
+       }
 # endif
-               codegen_emit_stub_builtin(jd, bte);
 #endif
 
        /* reallocate the memory and finish the code generation */
@@ -1228,9 +1252,25 @@ void codegen_generate_stub_builtin(builtintable_entry *bte)
                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 */
 }
 
 
@@ -1346,22 +1386,25 @@ codeinfo *codegen_generate_stub_native(methodinfo *m, functionptr f)
                size_stub_native += code->mcodelength;
 #endif
 
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
        /* disassemble native stub */
 
-       if (opt_shownativestub) {
-#if defined(ENABLE_DISASSEMBLER)
-               codegen_disassemble_nativestub(m,
-                                                                          (u1 *) (ptrint) code->entrypoint,
-                                                                          (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
-#endif
+       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 */
+                       /* show data segment */
 
-               if (opt_showddatasegment)
-                       dseg_display(jd);
+                       if (opt_showddatasegment)
+                               dseg_display(jd);
+               }
        }
-#endif /* !defined(NDEBUG) */
+#endif /* !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) */
 
        /* release memory */
 
@@ -1375,96 +1418,28 @@ 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);
 }
 #endif
 
 
-/* codegen_stub_builtin_enter **************************************************
-
-   Prepares the stuff required for a builtin function call:
-
-   - adds a stackframe info structure to the chain, for stacktraces
-
-   The layout of the builtin stub stackframe should look like this:
-
-   +---------------------------+ <- SP (of parent Java function)
-   | return address            |
-   +---------------------------+
-   |                           |
-   | stackframe info structure |
-   |                           |
-   +---------------------------+
-   |                           |
-   | arguments (if any)        |
-   |                           |
-   +---------------------------+ <- SP (native stub)
-
-*******************************************************************************/
-
-void codegen_stub_builtin_enter(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
-{
-       stackframeinfo *sfi;
-
-       /* get data structures from stack */
-
-       sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
-
-       /* add a stackframeinfo to the chain */
-
-       stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-       /* set the native world flag */
-
-       THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
-#endif
-}
-
-
-/* codegen_stub_builtin_exit ***************************************************
-
-   Removes the stuff required for a builtin function call.
-
-*******************************************************************************/
-
-void codegen_stub_builtin_exit(u1 *datasp)
-{
-       stackframeinfo     *sfi;
-       stackframeinfo    **psfi;
-
-       /* get data structures from stack */
-
-       sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
-
-       /* remove current stackframeinfo from chain */
-
-       psfi = &STACKFRAMEINFO;
-
-       *psfi = sfi->prev;
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-       /* clear the native world flag */
-
-       THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
-#endif
-}
-
-
 /* codegen_start_native_call ***************************************************
 
    Prepares the stuff required for a native (JNI) function call:
@@ -1474,9 +1449,9 @@ void codegen_stub_builtin_exit(u1 *datasp)
 
    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 |
    |                           |
@@ -1486,16 +1461,83 @@ void codegen_stub_builtin_exit(u1 *datasp)
    |                           |
    +---------------------------+
    |                           |
+   | 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 */
 
@@ -1503,30 +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 */
-
-       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;
-
-       /* clear the references array (memset is faster the a for-loop) */
+       localref_table_add(lrt);
+#endif
 
-       MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
+#if defined(ENABLE_HANDLES)
+       /* place all references into the local reference table */
 
-       LOCALREFTABLE = lrt;
+       localref_fill(m, arg_regs, arg_stack);
 #endif
 
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-       /* set the native world flag */
+       /* add a stackframeinfo to the chain */
 
-       THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
-#endif
+       stacktrace_create_native_stackframeinfo(sfi, pv, javasp, javara);
+
+       /* return a wrapped classinfo for static native methods */
+
+       if (m->flags & ACC_STATIC)
+               return LLNI_classinfo_wrap(m->class);
+       else
+               return NULL;
 }
 
 
@@ -1538,68 +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_JNI)
-       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));
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-       /* clear the native world flag */
+#if !defined(NDEBUG)
+# if defined(__POWERPC__) || defined (__X86_64__)
+       /* print the call-trace if necesarry */
 
-       THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
+       if (opt_TraceJavaCalls)
+               trace_java_call_exit(m, ret_regs);
+# endif
 #endif
 
-       /* remove current stackframeinfo from chain */
-
-       psfi = &STACKFRAMEINFO;
-
-       *psfi = sfi->prev;
-
-#if defined(ENABLE_JNI)
-       /* release JNI local references tables for this thread */
-
-       lrt = LOCALREFTABLE;
-
-       /* release all current local frames */
-
-       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;
 }
 
 
@@ -1640,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)
@@ -1659,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
@@ -1690,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)