Merged revisions 7501-7598 via svnmerge from
[cacao.git] / src / vm / jit / dseg.c
index 2c08e8b66d621ad215dfccb3b5fbaece7860d10d..02400e62c636194ee1b5d370b6d5a809a34f73d8 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 5834 2006-10-26 11:23:00Z edwin $
+   $Id: dseg.c 7596 2007-03-28 21:05:53Z 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 +133,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 +157,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 +283,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 +429,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 +503,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 +644,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
 
 *******************************************************************************/
@@ -733,13 +742,119 @@ 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;
+
+       /* 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;
@@ -760,7 +875,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;