* Removed all Id tags.
[cacao.git] / src / vm / jit / dseg.c
index 05fae7ca550cfc70c4b8034924993abcbc5bb750..f6079d09aded9b3d8174a99e16aaa321875054b4 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/dseg.c - data segment handling stuff
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 2006, 2007 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
 
    Authors: Reinhard Grafl
             Andreas  Krall
-
-   Changes: Christian Thalinger
+            Christian Thalinger
             Joseph Wenninger
-                       Edwin Steiner
+            Edwin Steiner
 
-   $Id: dseg.c 5332 2006-09-05 19:38:28Z twisti $
 
 */
 
 
 #include <assert.h>
 
-#include "vm/options.h"
 #include "vm/types.h"
 
 #include "mm/memory.h"
 #include "vm/jit/codegen-common.h"
-
+#include "vm/jit/methodheader.h"
+#include "vmcore/options.h"
 
 
 /* dseg_finish *****************************************************************
@@ -134,13 +132,18 @@ static s4 dseg_find_s8(codegendata *cd, s8 value)
 static s4 dseg_find_float(codegendata *cd, float value)
 {
        dsegentry *de;
+       imm_union  val;
+
+       /* we compare the hex value of the float as 0.0 == -0.0 */
+
+       val.f = value;
 
        /* search all data segment entries for a matching entry */
 
        for (de = cd->dseg; de != NULL; de = de->next) {
                if (IS_FLT_TYPE(de->type))
                        if (de->flags & DSEG_FLAG_READONLY)
-                               if (de->val.f == value)
+                               if (de->val.i == val.i)
                                        return de->disp;
        }
 
@@ -153,13 +156,18 @@ static s4 dseg_find_float(codegendata *cd, float value)
 static s4 dseg_find_double(codegendata *cd, double value)
 {
        dsegentry *de;
+       imm_union  val;
+
+       /* we compare the hex value of the double as 0.0 == -0.0 */
+
+       val.d = value;
 
        /* search all data segment entries for a matching entry */
 
        for (de = cd->dseg; de != NULL; de = de->next) {
                if (IS_DBL_TYPE(de->type))
                        if (de->flags & DSEG_FLAG_READONLY)
-                               if (de->val.d == value)
+                               if (de->val.l == val.l)
                                        return de->disp;
        }
 
@@ -274,7 +282,7 @@ static s4 dseg_add_s8_intern(codegendata *cd, s8 value, u4 flags)
        /* Increase data segment size, which is also the displacement into
           the data segment. */
 
-       cd->dseglen = ALIGN(cd->dseglen + 8, 8);
+       cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
 
        /* allocate new entry */
 
@@ -420,7 +428,7 @@ static s4 dseg_add_double_intern(codegendata *cd, double value, u4 flags)
        /* Increase data segment size, which is also the displacement into
           the data segment. */
 
-       cd->dseglen = ALIGN(cd->dseglen + 8, 8);
+       cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
 
        /* allocate new entry */
 
@@ -494,7 +502,7 @@ static s4 dseg_add_address_intern(codegendata *cd, void *value, u4 flags)
           the data segment. */
 
 #if SIZEOF_VOID_P == 8
-       cd->dseglen = ALIGN(cd->dseglen + 8, 8);
+       cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
 #else
        cd->dseglen += 4;
 #endif
@@ -635,7 +643,7 @@ void dseg_addlinenumber(codegendata *cd, u2 linenumber)
 
    IN:
       cd.............current codegen data
-      iptr...........the ICMD_INLINE_START instruction
+      iptr...........the ICMD_INLINE_BODY instruction
       mcodeptr.......start mcodeptr of inlined body
 
 *******************************************************************************/
@@ -655,9 +663,7 @@ void dseg_addlinenumber_inline_start(codegendata *cd, instruction *iptr)
 
        cd->linenumberreferences = lr;
 
-#if 0
-       insinfo = (insinfo_inline *) iptr->target;
-#endif
+       insinfo = iptr->sx.s23.s3.inlineinfo;
 
        insinfo->startmpc = mpc; /* store for corresponding INLINE_END */
 }
@@ -683,9 +689,7 @@ void dseg_addlinenumber_inline_end(codegendata *cd, instruction *iptr)
        linenumberref *prev;
        insinfo_inline *insinfo;
 
-#if 0
-       insinfo = (insinfo_inline *) iptr->target;
-#endif
+       insinfo = iptr->sx.s23.s3.inlineinfo;
 
        assert(insinfo);
 
@@ -737,13 +741,123 @@ void dseg_createlinenumbertable(codegendata *cd)
 }
 
 
+/* dseg_get_linenumber_from_pc_intern ******************************************
+
+   This function search the line number table for the line
+   corresponding to a given pc. The function recurses for inlined
+   methods.
+
+*******************************************************************************/
+
+static s4 dseg_get_linenumber_from_pc_intern(methodinfo **pm, linenumbertable_entry *lntentry, s4 lntsize, u1 *pc)
+{
+       linenumbertable_entry *lntinline;     /* special entry for inlined method */
+
+       for (; lntsize > 0; lntsize--, lntentry--) {
+               /* Note: In case of inlining this may actually compare the pc
+                  against a methodinfo *, yielding a non-sensical
+                  result. This is no problem, however, as we ignore such
+                  entries in the switch below. This way we optimize for the
+                  common case (ie. a real pc in lntentry->pc). */
+
+               if (pc >= lntentry->pc) {
+                       /* did we reach the current line? */
+
+                       if ((s4) lntentry->line >= 0)
+                               return (s4) lntentry->line;
+
+                       /* we found a special inline entry (see
+                          doc/inlining_stacktrace.txt for details */
+
+                       switch (lntentry->line) {
+                       case -1: 
+                               /* begin of inlined method (ie. INLINE_END
+                                  instruction) */
+
+                               lntinline = --lntentry;/* get entry with methodinfo * */
+                               lntentry--;            /* skip the special entry      */
+                               lntsize -= 2;
+
+                               /* search inside the inlined method */
+
+                               if (dseg_get_linenumber_from_pc_intern(pm, lntentry, lntsize,
+                                                                                                          pc))
+                               {
+                                       /* the inlined method contained the pc */
+
+                                       *pm = (methodinfo *) lntinline->pc;
+
+                                       assert(lntinline->line <= -3);
+
+                                       return (-3) - lntinline->line;
+                               }
+
+                               /* pc was not in inlined method, continue search.
+                                  Entries inside the inlined method will be skipped
+                                  because their lntentry->pc is higher than pc.  */
+                               break;
+
+                       case -2: 
+                               /* end of inlined method */
+
+                               return 0;
+
+                               /* default: is only reached for an -3-line entry after
+                                  a skipped -2 entry. We can safely ignore it and
+                                  continue searching.  */
+                       }
+               }
+       }
+
+       /* not found, return 0 */
+
+       return 0;
+}
+
+
+/* dseg_get_linenumber_from_pc *************************************************
+
+   A wrapper for dseg_get_linenumber_from_pc_intern, so we don't have
+   to evaluate the method header on every call.
+
+*******************************************************************************/
+
+s4 dseg_get_linenumber_from_pc(methodinfo **pm, u1 *pv, u1 *pc)
+{
+       ptrint                 lntsize;     /* size of line number table          */
+       u1                    *lntstart;    /* start of line number table         */
+       linenumbertable_entry *lntentry;    /* points to last entry in the table  */
+       s4                     linenumber;
+
+#if defined(__S390__)
+       pc = (u1 *)((intptr_t)pc & 0x7FFFFFFF);
+#endif
+
+       /* get size of line number table */
+
+       lntsize  = *((ptrint *) (pv + LineNumberTableSize));
+       lntstart = *((u1 **)    (pv + LineNumberTableStart));
+
+       /* Subtract the size of the line number entry of the structure,
+          since the line number table start points to the pc. */
+
+       lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
+
+       /* get the line number */
+
+       linenumber = dseg_get_linenumber_from_pc_intern(pm, lntentry, lntsize, pc);
+
+       return linenumber;
+}
+
+
 /* dseg_adddata ****************************************************************
 
    Adds a data segment reference to the codegendata.
 
 *******************************************************************************/
 
-#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
+#if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
 void dseg_adddata(codegendata *cd)
 {
        dataref *dr;
@@ -764,7 +878,7 @@ void dseg_adddata(codegendata *cd)
 
 *******************************************************************************/
 
-#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
+#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
 void dseg_resolve_datareferences(jitdata *jd)
 {
        codeinfo    *code;
@@ -795,32 +909,85 @@ void dseg_display(jitdata *jd)
 {
        codeinfo    *code;
        codegendata *cd;
-       s4          *s4ptr;
-       s4           i;
-       
+       dsegentry   *de;
+       imm_union   val;
+
        /* get required compiler data */
 
        code = jd->code;
        cd   = jd->cd;
 
-       s4ptr = (s4 *) (ptrint) code->mcode;
+       if (opt_debugcolor)
+               printf("\033[34m");     /* blue */
 
-       if (opt_debugcolor) printf("\033[34m"); /* blue */
        printf("  --- dump of datasegment\n");
 
-       for (i = cd->dseglen; i > 0 ; i -= 4) {
+       /* process all data segment entries */
+
+       for (de = cd->dseg; de != NULL; de = de->next) {
+#if SIZEOF_VOID_P == 8
+               printf("0x%016lx:", (ptrint) (code->entrypoint + de->disp));
+#else
+               printf("0x%08x:", (ptrint) (code->entrypoint + de->disp));
+#endif
+
+               printf("    %6x (%6d): ", de->disp, de->disp);
+
+               /* We read the values from the data segment as some values,
+                  like the line number table, have been written directly to
+                  the data segment. */
+
+               switch (de->type) {
+               case TYPE_INT:
+                       val.i = *((s4 *) (code->entrypoint + de->disp));
+                       printf("(INT) %d (0x%08x)", val.i, val.i);
+                       break;
+
+               case TYPE_LNG:
+                       val.l = *((s8 *) (code->entrypoint + de->disp));
 #if SIZEOF_VOID_P == 8
-               printf("0x%016lx:   -%6x (%6d): %8x\n",
-                          (ptrint) s4ptr, i, i, (s4) *s4ptr);
+                       printf("(LNG) %ld (0x%016lx)", val.l, val.l);
 #else
-               printf("0x%08x:   -%6x (%6d): %8x\n",
-                          (ptrint) s4ptr, i, i, (s4) *s4ptr);
+                       printf("(LNG) %lld (0x%016llx)", val.l, val.l);
 #endif
-               s4ptr++;
+                       break;
+
+               case TYPE_FLT:
+                       val.f = *((float *) (code->entrypoint + de->disp));
+                       printf("(FLT) %g (0x%08x)", val.f, val.i);
+                       break;
+
+               case TYPE_DBL:
+                       val.d = *((double *) (code->entrypoint + de->disp));
+#if SIZEOF_VOID_P == 8
+                       printf("(DBL) %g (0x%016lx)", val.d, val.l);
+#else
+                       printf("(DBL) %g (0x%016llx)", val.d, val.l);
+#endif
+                       break;
+
+               case TYPE_ADR:
+                       val.a = *((void **) (code->entrypoint + de->disp));
+#if SIZEOF_VOID_P == 8
+                       printf("(ADR) %016lx", (ptrint) val.a);
+#else
+                       printf("(ADR) %08x", (ptrint) val.a);
+#endif
+                       break;
+               }
+
+               printf("\n");
        }
 
-       printf("  --- begin of data segment: %p\n", (void *) s4ptr);
-       if (opt_debugcolor) printf("\033[m");
+       printf("  --- begin of data segment: ");
+#if SIZEOF_VOID_P == 8
+       printf("0x%016lx\n", (ptrint) code->entrypoint);
+#else
+       printf("0x%08x\n", (ptrint) code->entrypoint);
+#endif
+
+       if (opt_debugcolor)
+               printf("\033[m");
 }
 #endif /* !defined(NDEBUG) */