* Removed all Id tags.
[cacao.git] / src / vm / jit / dseg.c
index 6a109b26b24f6fa09bd485190934363b1c899f96..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 4598 2006-03-14 22:16:47Z edwin $
 
 */
 
 
 #include "config.h"
 
+#include <assert.h>
+
 #include "vm/types.h"
 
-#include <assert.h>
 #include "mm/memory.h"
 #include "vm/jit/codegen-common.h"
+#include "vm/jit/methodheader.h"
+#include "vmcore/options.h"
 
 
-/* desg_increase ***************************************************************
+/* dseg_finish *****************************************************************
 
-   Doubles data area.
+   Fills the data segment with the values stored.
 
 *******************************************************************************/
 
-void dseg_increase(codegendata *cd)
+void dseg_finish(jitdata *jd)
 {
-       u1 *newstorage;
+       codeinfo    *code;
+       codegendata *cd;
+       dsegentry   *de;
+
+       /* get required compiler data */
+
+       code = jd->code;
+       cd   = jd->cd;
+
+       /* process all data segment entries */
+
+       for (de = cd->dseg; de != NULL; de = de->next) {
+               switch (de->type) {
+               case TYPE_INT:
+                       *((s4 *)     (code->entrypoint + de->disp)) = de->val.i;
+                       break;
+
+               case TYPE_LNG:
+                       *((s8 *)     (code->entrypoint + de->disp)) = de->val.l;
+                       break;
 
-       newstorage = DMNEW(u1, cd->dsegsize * 2);
+               case TYPE_FLT:
+                       *((float *)  (code->entrypoint + de->disp)) = de->val.f;
+                       break;
 
-       MCOPY(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, u1,
-                 cd->dsegsize);
+               case TYPE_DBL:
+                       *((double *) (code->entrypoint + de->disp)) = de->val.d;
+                       break;
 
-       cd->dsegtop   = newstorage;
-       cd->dsegsize *= 2;
-       cd->dsegtop  += cd->dsegsize;
+               case TYPE_ADR:
+                       *((void **)  (code->entrypoint + de->disp)) = de->val.a;
+                       break;
+               }
+       }
 }
 
 
-s4 dseg_adds4_increase(codegendata *cd, s4 value)
+static s4 dseg_find_s4(codegendata *cd, s4 value)
 {
-       dseg_increase(cd);
+       dsegentry *de;
+
+       /* search all data segment entries for a matching entry */
 
-       *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
+       for (de = cd->dseg; de != NULL; de = de->next) {
+               if (IS_INT_TYPE(de->type))
+                       if (de->flags & DSEG_FLAG_READONLY)
+                               if (de->val.i == value)
+                                       return de->disp;
+       }
 
-       return -(cd->dseglen);
+       /* no matching entry was found */
+
+       return 0;
 }
 
 
-s4 dseg_adds4(codegendata *cd, s4 value)
+static s4 dseg_find_s8(codegendata *cd, s8 value)
 {
-       s4 *dataptr;
+       dsegentry *de;
+
+       /* search all data segment entries for a matching entry */
+
+       for (de = cd->dseg; de != NULL; de = de->next) {
+               if (IS_LNG_TYPE(de->type))
+                       if (de->flags & DSEG_FLAG_READONLY)
+                               if (de->val.l == value)
+                                       return de->disp;
+       }
+
+       /* no matching entry was found */
+
+       return 0;
+}
+
+
+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.i == val.i)
+                                       return de->disp;
+       }
+
+       /* no matching entry was found */
+
+       return 0;
+}
+
+
+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.l == val.l)
+                                       return de->disp;
+       }
+
+       /* no matching entry was found */
+
+       return 0;
+}
+
+
+static s4 dseg_find_address(codegendata *cd, void *value)
+{
+       dsegentry *de;
+
+       /* search all data segment entries for a matching entry */
+
+       for (de = cd->dseg; de != NULL; de = de->next) {
+               if (IS_ADR_TYPE(de->type))
+                       if (de->flags & DSEG_FLAG_READONLY)
+                               if (de->val.a == value)
+                                       return de->disp;
+       }
+
+       /* no matching entry was found */
+
+       return 0;
+}
+
+
+/* dseg_add_s4_intern **********************************************************
+
+   Internal function to add an s4 value to the data segment.
+
+*******************************************************************************/
+
+static s4 dseg_add_s4_intern(codegendata *cd, s4 value, u4 flags)
+{
+       dsegentry *de;
+
+       /* Increase data segment size, which is also the displacement into
+          the data segment. */
 
        cd->dseglen += 4;
-       dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
 
-       if (cd->dseglen > cd->dsegsize)
-               return dseg_adds4_increase(cd, value);
+       /* allocate new entry */
+
+       de = DNEW(dsegentry);
+
+       de->type  = TYPE_INT;
+       de->flags = flags;
+       de->disp  = -(cd->dseglen);
+       de->val.i = value;
+       de->next  = cd->dseg;
+
+       /* insert into the chain */
+
+       cd->dseg = de;
+
+       return de->disp;
+}
+
+
+/* dseg_add_unique_s4 **********************************************************
+
+   Adds uniquely an s4 value to the data segment.
+
+*******************************************************************************/
+
+s4 dseg_add_unique_s4(codegendata *cd, s4 value)
+{
+       s4 disp;
 
-       *dataptr = value;
+       disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_UNIQUE);
 
-       return -(cd->dseglen);
+       return disp;
 }
 
 
-s4 dseg_adds8_increase(codegendata *cd, s8 value)
+/* dseg_add_s4 *****************************************************************
+
+   Adds an s4 value to the data segment. It tries to reuse previously
+   added values.
+
+*******************************************************************************/
+
+s4 dseg_add_s4(codegendata *cd, s4 value)
 {
-       dseg_increase(cd);
+       s4 disp;
+
+       /* search the data segment if the value is already stored */
 
-       *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
+       disp = dseg_find_s4(cd, value);
 
-       return -(cd->dseglen);
+       if (disp != 0)
+               return disp;
+               
+       disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_READONLY);
+
+       return disp;
 }
 
 
-s4 dseg_adds8(codegendata *cd, s8 value)
+/* dseg_add_s8_intern **********************************************************
+
+   Internal function to add an s8 value to the data segment.
+
+*******************************************************************************/
+
+static s4 dseg_add_s8_intern(codegendata *cd, s8 value, u4 flags)
 {
-       s8 *dataptr;
+       dsegentry *de;
+
+       /* Increase data segment size, which is also the displacement into
+          the data segment. */
+
+       cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
 
-       cd->dseglen = ALIGN(cd->dseglen + 8, 8);
-       dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
+       /* allocate new entry */
 
-       if (cd->dseglen > cd->dsegsize)
-               return dseg_adds8_increase(cd, value);
+       de = DNEW(dsegentry);
 
-       *dataptr = value;
+       de->type  = TYPE_LNG;
+       de->flags = flags;
+       de->disp  = -(cd->dseglen);
+       de->val.l = value;
+       de->next  = cd->dseg;
 
-       return -(cd->dseglen);
+       /* insert into the chain */
+
+       cd->dseg = de;
+
+       return de->disp;
 }
 
 
-s4 dseg_addfloat_increase(codegendata *cd, float value)
+/* dseg_add_unique_s8 **********************************************************
+
+   Adds uniquely an s8 value to the data segment.
+
+*******************************************************************************/
+
+s4 dseg_add_unique_s8(codegendata *cd, s8 value)
 {
-       dseg_increase(cd);
+       s4 disp;
 
-       *((float *) (cd->dsegtop - cd->dseglen)) = value;
+       disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_UNIQUE);
 
-       return -(cd->dseglen);
+       return disp;
 }
 
 
-s4 dseg_addfloat(codegendata *cd, float value)
+/* dseg_add_s8 *****************************************************************
+
+   Adds an s8 value to the data segment. It tries to reuse previously
+   added values.
+
+*******************************************************************************/
+
+s4 dseg_add_s8(codegendata *cd, s8 value)
 {
-       float *dataptr;
+       s4 disp;
+
+       /* search the data segment if the value is already stored */
+
+       disp = dseg_find_s8(cd, value);
+
+       if (disp != 0)
+               return disp;
+               
+       disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_READONLY);
+
+       return disp;
+}
+
+
+/* dseg_add_float_intern *******************************************************
+
+   Internal function to add a float value to the data segment.
+
+*******************************************************************************/
+
+static s4 dseg_add_float_intern(codegendata *cd, float value, u4 flags)
+{
+       dsegentry *de;
+               
+       /* Increase data segment size, which is also the displacement into
+          the data segment. */
 
        cd->dseglen += 4;
-       dataptr = (float *) (cd->dsegtop - cd->dseglen);
 
-       if (cd->dseglen > cd->dsegsize)
-               return dseg_addfloat_increase(cd, value);
+       /* allocate new entry */
+
+       de = DNEW(dsegentry);
+
+       de->type  = TYPE_FLT;
+       de->flags = flags;
+       de->disp  = -(cd->dseglen);
+       de->val.f = value;
+       de->next  = cd->dseg;
 
-       *dataptr = value;
+       /* insert into the chain */
 
-       return -(cd->dseglen);
+       cd->dseg = de;
+
+       return de->disp;
 }
 
 
-s4 dseg_adddouble_increase(codegendata *cd, double value)
+/* dseg_add_unique_float *******************************************************
+
+   Adds uniquely an float value to the data segment.
+
+*******************************************************************************/
+
+s4 dseg_add_unique_float(codegendata *cd, float value)
+{
+       s4 disp;
+
+       disp = dseg_add_float_intern(cd, value, DSEG_FLAG_UNIQUE);
+
+       return disp;
+}
+
+
+/* dseg_add_float **************************************************************
+
+   Adds an float value to the data segment. It tries to reuse
+   previously added values.
+
+*******************************************************************************/
+
+s4 dseg_add_float(codegendata *cd, float value)
 {
-       dseg_increase(cd);
+       s4 disp;
+
+       /* search the data segment if the value is already stored */
+
+       disp = dseg_find_float(cd, value);
 
-       *((double *) (cd->dsegtop - cd->dseglen)) = value;
+       if (disp != 0)
+               return disp;
+               
+       disp = dseg_add_float_intern(cd, value, DSEG_FLAG_READONLY);
 
-       return -(cd->dseglen);
+       return disp;
 }
 
 
-s4 dseg_adddouble(codegendata *cd, double value)
+/* dseg_add_double_intern ******************************************************
+
+   Internal function to add a double value to the data segment.
+
+*******************************************************************************/
+
+static s4 dseg_add_double_intern(codegendata *cd, double value, u4 flags)
 {
-       double *dataptr;
+       dsegentry *de;
+               
+       /* Increase data segment size, which is also the displacement into
+          the data segment. */
+
+       cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
+
+       /* allocate new entry */
 
-       cd->dseglen = ALIGN(cd->dseglen + 8, 8);
-       dataptr = (double *) (cd->dsegtop - cd->dseglen);
+       de = DNEW(dsegentry);
 
-       if (cd->dseglen > cd->dsegsize)
-               return dseg_adddouble_increase(cd, value);
+       de->type  = TYPE_DBL;
+       de->flags = flags;
+       de->disp  = -(cd->dseglen);
+       de->val.d = value;
+       de->next  = cd->dseg;
 
-       *dataptr = value;
+       /* insert into the chain */
 
-       return -(cd->dseglen);
+       cd->dseg = de;
+
+       return de->disp;
 }
 
 
-void dseg_addtarget(codegendata *cd, basicblock *target)
+/* dseg_add_unique_double ******************************************************
+
+   Adds uniquely a double value to the data segment.
+
+*******************************************************************************/
+
+s4 dseg_add_unique_double(codegendata *cd, double value)
+{
+       s4 disp;
+
+       disp = dseg_add_double_intern(cd, value, DSEG_FLAG_UNIQUE);
+
+       return disp;
+}
+
+
+/* dseg_add_double *************************************************************
+
+   Adds a double value to the data segment. It tries to reuse
+   previously added values.
+
+*******************************************************************************/
+
+s4 dseg_add_double(codegendata *cd, double value)
+{
+       s4 disp;
+
+       /* search the data segment if the value is already stored */
+
+       disp = dseg_find_double(cd, value);
+
+       if (disp != 0)
+               return disp;
+               
+       disp = dseg_add_double_intern(cd, value, DSEG_FLAG_READONLY);
+
+       return disp;
+}
+
+
+/* dseg_add_address_intern *****************************************************
+
+   Internal function to add an address pointer to the data segment.
+
+*******************************************************************************/
+
+static s4 dseg_add_address_intern(codegendata *cd, void *value, u4 flags)
+{
+       dsegentry *de;
+
+       /* Increase data segment size, which is also the displacement into
+          the data segment. */
+
+#if SIZEOF_VOID_P == 8
+       cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
+#else
+       cd->dseglen += 4;
+#endif
+
+       /* allocate new entry */
+
+       de = DNEW(dsegentry);
+
+       de->type  = TYPE_ADR;
+       de->flags = flags;
+       de->disp  = -(cd->dseglen);
+       de->val.a = value;
+       de->next  = cd->dseg;
+
+       /* insert into the chain */
+
+       cd->dseg = de;
+
+       return de->disp;
+}
+
+
+/* dseg_add_unique_address *****************************************************
+
+   Adds uniquely an address value to the data segment.
+
+*******************************************************************************/
+
+s4 dseg_add_unique_address(codegendata *cd, void *value)
+{
+       s4 disp;
+
+       disp = dseg_add_address_intern(cd, value, DSEG_FLAG_UNIQUE);
+
+       return disp;
+}
+
+
+/* dseg_add_address ************************************************************
+
+   Adds an address value to the data segment. It tries to reuse
+   previously added values.
+
+*******************************************************************************/
+
+s4 dseg_add_address(codegendata *cd, void *value)
+{
+       s4 disp;
+
+       /* search the data segment if the value is already stored */
+
+       disp = dseg_find_address(cd, value);
+
+       if (disp != 0)
+               return disp;
+               
+       disp = dseg_add_address_intern(cd, value, DSEG_FLAG_READONLY);
+
+       return disp;
+}
+
+
+/* dseg_add_target *************************************************************
+
+   XXX
+
+*******************************************************************************/
+
+void dseg_add_target(codegendata *cd, basicblock *target)
 {
        jumpref *jr;
 
        jr = DNEW(jumpref);
 
-       jr->tablepos = dseg_addaddress(cd, NULL);
+       jr->tablepos = dseg_add_unique_address(cd, NULL);
        jr->target   = target;
        jr->next     = cd->jumpreferences;
 
@@ -195,16 +596,16 @@ void dseg_addlinenumbertablesize(codegendata *cd)
 #if SIZEOF_VOID_P == 8
        /* 4-byte ALIGNMENT PADDING */
 
-       dseg_adds4(cd, 0);
+       dseg_add_unique_s4(cd, 0);
 #endif
 
-       cd->linenumbertablesizepos  = dseg_addaddress(cd, NULL);
-       cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
+       cd->linenumbertablesizepos  = dseg_add_unique_address(cd, NULL);
+       cd->linenumbertablestartpos = dseg_add_unique_address(cd, NULL);
 
 #if SIZEOF_VOID_P == 8
        /* 4-byte ALIGNMENT PADDING */
 
-       dseg_adds4(cd, 0);
+       dseg_add_unique_s4(cd, 0);
 #endif
 }
 
@@ -220,7 +621,7 @@ void dseg_addlinenumbertablesize(codegendata *cd)
 
 *******************************************************************************/
 
-void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *mcodeptr)
+void dseg_addlinenumber(codegendata *cd, u2 linenumber)
 {
        linenumberref *lr;
 
@@ -228,7 +629,7 @@ void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *mcodeptr)
 
        lr->linenumber = linenumber;
        lr->tablepos   = 0;
-       lr->targetmpc  = mcodeptr - cd->mcodebase;
+       lr->targetmpc  = cd->mcodeptr - cd->mcodebase;
        lr->next       = cd->linenumberreferences;
 
        cd->linenumberreferences = lr;
@@ -242,27 +643,29 @@ void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *mcodeptr)
 
    IN:
       cd.............current codegen data
-      iptr...........the ICMD_INLINE_START instruction
+      iptr...........the ICMD_INLINE_BODY instruction
       mcodeptr.......start mcodeptr of inlined body
 
 *******************************************************************************/
 
-void dseg_addlinenumber_inline_start(codegendata *cd, 
-                                                                        instruction *iptr, 
-                                                                        u1 *mcodeptr)
+void dseg_addlinenumber_inline_start(codegendata *cd, instruction *iptr)
 {
        linenumberref *lr;
+       insinfo_inline *insinfo;
+       ptrint mpc;
 
        lr = DNEW(linenumberref);
 
        lr->linenumber = (-2); /* marks start of inlined method */
        lr->tablepos   = 0;
-       lr->targetmpc  = mcodeptr - cd->mcodebase;
+       lr->targetmpc  = (mpc = (u1 *) cd->mcodeptr - cd->mcodebase);
        lr->next       = cd->linenumberreferences;
 
        cd->linenumberreferences = lr;
 
-       iptr->target = mcodeptr; /* store for corresponding INLINE_END */
+       insinfo = iptr->sx.s23.s3.inlineinfo;
+
+       insinfo->startmpc = mpc; /* store for corresponding INLINE_END */
 }
 
 
@@ -284,20 +687,18 @@ void dseg_addlinenumber_inline_end(codegendata *cd, instruction *iptr)
 {
        linenumberref *lr;
        linenumberref *prev;
-       instruction *inlinestart;
+       insinfo_inline *insinfo;
 
-       /* get the pointer to the corresponding ICMD_INLINE_START */
-       inlinestart = (instruction *)iptr->target;
+       insinfo = iptr->sx.s23.s3.inlineinfo;
 
-       assert(inlinestart);
-       assert(iptr->method);
+       assert(insinfo);
 
        lr = DNEW(linenumberref);
 
        /* special entry containing the methodinfo * */
        lr->linenumber = (-3) - iptr->line;
        lr->tablepos   = 0;
-       lr->targetmpc  = (ptrint) iptr->method;
+       lr->targetmpc  = (ptrint) insinfo->method;
        lr->next       = cd->linenumberreferences;
 
        prev = lr;
@@ -306,7 +707,7 @@ void dseg_addlinenumber_inline_end(codegendata *cd, instruction *iptr)
        /* end marker with PC of start of body */
        lr->linenumber = (-1);
        lr->tablepos   = 0;
-       lr->targetmpc  = (u1*)inlinestart->target - cd->mcodebase;
+       lr->targetmpc  = insinfo->startmpc;
        lr->next       = prev;
 
        cd->linenumberreferences = lr;
@@ -325,30 +726,145 @@ void dseg_createlinenumbertable(codegendata *cd)
        linenumberref *lr;
 
        for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
-               lr->tablepos = dseg_addaddress(cd, NULL);
+               lr->tablepos = dseg_add_unique_address(cd, NULL);
 
                if (cd->linenumbertab == 0)
                        cd->linenumbertab = lr->tablepos;
 
-               dseg_addaddress(cd, lr->linenumber);
+#if SIZEOF_VOID_P == 8
+               /* This is for alignment and easier usage. */
+               (void) dseg_add_unique_s8(cd, lr->linenumber);
+#else
+               (void) dseg_add_unique_s4(cd, lr->linenumber);
+#endif
        }
 }
 
 
+/* 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)
-void dseg_adddata(codegendata *cd, u1 *mcodeptr)
+#if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
+void dseg_adddata(codegendata *cd)
 {
        dataref *dr;
 
        dr = DNEW(dataref);
 
-       dr->datapos = mcodeptr - cd->mcodebase;
+       dr->datapos = cd->mcodeptr - cd->mcodebase;
        dr->next    = cd->datareferences;
 
        cd->datareferences = dr;
@@ -362,15 +878,22 @@ void dseg_adddata(codegendata *cd, u1 *mcodeptr)
 
 *******************************************************************************/
 
-#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
-void dseg_resolve_datareferences(codegendata *cd, methodinfo *m)
+#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
+void dseg_resolve_datareferences(jitdata *jd)
 {
-       dataref *dr;
+       codeinfo    *code;
+       codegendata *cd;
+       dataref     *dr;
+
+       /* get required compiler data */
+
+       code = jd->code;
+       cd   = jd->cd;
 
        /* data segment references resolving */
 
        for (dr = cd->datareferences; dr != NULL; dr = dr->next)
-               *((u1 **) (cd->code->entrypoint + dr->datapos - SIZEOF_VOID_P)) = cd->code->entrypoint;
+               *((u1 **) (code->entrypoint + dr->datapos - SIZEOF_VOID_P)) = code->entrypoint;
 }
 #endif
 
@@ -382,27 +905,89 @@ void dseg_resolve_datareferences(codegendata *cd, methodinfo *m)
 *******************************************************************************/
 
 #if !defined(NDEBUG)
-void dseg_display(methodinfo *m, codegendata *cd)
+void dseg_display(jitdata *jd)
 {
-       s4 *s4ptr;
-       s4 i;
-       
-       s4ptr = (s4 *) (ptrint) cd->code->mcode;
+       codeinfo    *code;
+       codegendata *cd;
+       dsegentry   *de;
+       imm_union   val;
+
+       /* get required compiler data */
+
+       code = jd->code;
+       cd   = jd->cd;
+
+       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);
+       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) */