1 /* src/vm/jit/dseg.c - data segment handling stuff
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Reinhard Grafl
43 #include "mm/memory.h"
44 #include "vm/jit/codegen-common.h"
45 #include "vm/jit/methodheader.h"
46 #include "vmcore/options.h"
49 /* dseg_finish *****************************************************************
51 Fills the data segment with the values stored.
53 *******************************************************************************/
55 void dseg_finish(jitdata *jd)
61 /* get required compiler data */
66 /* process all data segment entries */
68 for (de = cd->dseg; de != NULL; de = de->next) {
71 *((s4 *) (code->entrypoint + de->disp)) = de->val.i;
75 *((s8 *) (code->entrypoint + de->disp)) = de->val.l;
79 *((float *) (code->entrypoint + de->disp)) = de->val.f;
83 *((double *) (code->entrypoint + de->disp)) = de->val.d;
87 *((void **) (code->entrypoint + de->disp)) = de->val.a;
94 static s4 dseg_find_s4(codegendata *cd, s4 value)
98 /* search all data segment entries for a matching entry */
100 for (de = cd->dseg; de != NULL; de = de->next) {
101 if (IS_INT_TYPE(de->type))
102 if (de->flags & DSEG_FLAG_READONLY)
103 if (de->val.i == value)
107 /* no matching entry was found */
113 static s4 dseg_find_s8(codegendata *cd, s8 value)
117 /* search all data segment entries for a matching entry */
119 for (de = cd->dseg; de != NULL; de = de->next) {
120 if (IS_LNG_TYPE(de->type))
121 if (de->flags & DSEG_FLAG_READONLY)
122 if (de->val.l == value)
126 /* no matching entry was found */
132 static s4 dseg_find_float(codegendata *cd, float value)
137 /* we compare the hex value of the float as 0.0 == -0.0 */
141 /* search all data segment entries for a matching entry */
143 for (de = cd->dseg; de != NULL; de = de->next) {
144 if (IS_FLT_TYPE(de->type))
145 if (de->flags & DSEG_FLAG_READONLY)
146 if (de->val.i == val.i)
150 /* no matching entry was found */
156 static s4 dseg_find_double(codegendata *cd, double value)
161 /* we compare the hex value of the double as 0.0 == -0.0 */
165 /* search all data segment entries for a matching entry */
167 for (de = cd->dseg; de != NULL; de = de->next) {
168 if (IS_DBL_TYPE(de->type))
169 if (de->flags & DSEG_FLAG_READONLY)
170 if (de->val.l == val.l)
174 /* no matching entry was found */
180 static s4 dseg_find_address(codegendata *cd, void *value)
184 /* search all data segment entries for a matching entry */
186 for (de = cd->dseg; de != NULL; de = de->next) {
187 if (IS_ADR_TYPE(de->type))
188 if (de->flags & DSEG_FLAG_READONLY)
189 if (de->val.a == value)
193 /* no matching entry was found */
199 /* dseg_add_s4_intern **********************************************************
201 Internal function to add an s4 value to the data segment.
203 *******************************************************************************/
205 static s4 dseg_add_s4_intern(codegendata *cd, s4 value, u4 flags)
209 /* Increase data segment size, which is also the displacement into
214 /* allocate new entry */
216 de = DNEW(dsegentry);
220 de->disp = -(cd->dseglen);
224 /* insert into the chain */
232 /* dseg_add_unique_s4 **********************************************************
234 Adds uniquely an s4 value to the data segment.
236 *******************************************************************************/
238 s4 dseg_add_unique_s4(codegendata *cd, s4 value)
242 disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_UNIQUE);
248 /* dseg_add_s4 *****************************************************************
250 Adds an s4 value to the data segment. It tries to reuse previously
253 *******************************************************************************/
255 s4 dseg_add_s4(codegendata *cd, s4 value)
259 /* search the data segment if the value is already stored */
261 disp = dseg_find_s4(cd, value);
266 disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_READONLY);
272 /* dseg_add_s8_intern **********************************************************
274 Internal function to add an s8 value to the data segment.
276 *******************************************************************************/
278 static s4 dseg_add_s8_intern(codegendata *cd, s8 value, u4 flags)
282 /* Increase data segment size, which is also the displacement into
285 cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
287 /* allocate new entry */
289 de = DNEW(dsegentry);
293 de->disp = -(cd->dseglen);
297 /* insert into the chain */
305 /* dseg_add_unique_s8 **********************************************************
307 Adds uniquely an s8 value to the data segment.
309 *******************************************************************************/
311 s4 dseg_add_unique_s8(codegendata *cd, s8 value)
315 disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_UNIQUE);
321 /* dseg_add_s8 *****************************************************************
323 Adds an s8 value to the data segment. It tries to reuse previously
326 *******************************************************************************/
328 s4 dseg_add_s8(codegendata *cd, s8 value)
332 /* search the data segment if the value is already stored */
334 disp = dseg_find_s8(cd, value);
339 disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_READONLY);
345 /* dseg_add_float_intern *******************************************************
347 Internal function to add a float value to the data segment.
349 *******************************************************************************/
351 static s4 dseg_add_float_intern(codegendata *cd, float value, u4 flags)
355 /* Increase data segment size, which is also the displacement into
360 /* allocate new entry */
362 de = DNEW(dsegentry);
366 de->disp = -(cd->dseglen);
370 /* insert into the chain */
378 /* dseg_add_unique_float *******************************************************
380 Adds uniquely an float value to the data segment.
382 *******************************************************************************/
384 s4 dseg_add_unique_float(codegendata *cd, float value)
388 disp = dseg_add_float_intern(cd, value, DSEG_FLAG_UNIQUE);
394 /* dseg_add_float **************************************************************
396 Adds an float value to the data segment. It tries to reuse
397 previously added values.
399 *******************************************************************************/
401 s4 dseg_add_float(codegendata *cd, float value)
405 /* search the data segment if the value is already stored */
407 disp = dseg_find_float(cd, value);
412 disp = dseg_add_float_intern(cd, value, DSEG_FLAG_READONLY);
418 /* dseg_add_double_intern ******************************************************
420 Internal function to add a double value to the data segment.
422 *******************************************************************************/
424 static s4 dseg_add_double_intern(codegendata *cd, double value, u4 flags)
428 /* Increase data segment size, which is also the displacement into
431 cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
433 /* allocate new entry */
435 de = DNEW(dsegentry);
439 de->disp = -(cd->dseglen);
443 /* insert into the chain */
451 /* dseg_add_unique_double ******************************************************
453 Adds uniquely a double value to the data segment.
455 *******************************************************************************/
457 s4 dseg_add_unique_double(codegendata *cd, double value)
461 disp = dseg_add_double_intern(cd, value, DSEG_FLAG_UNIQUE);
467 /* dseg_add_double *************************************************************
469 Adds a double value to the data segment. It tries to reuse
470 previously added values.
472 *******************************************************************************/
474 s4 dseg_add_double(codegendata *cd, double value)
478 /* search the data segment if the value is already stored */
480 disp = dseg_find_double(cd, value);
485 disp = dseg_add_double_intern(cd, value, DSEG_FLAG_READONLY);
491 /* dseg_add_address_intern *****************************************************
493 Internal function to add an address pointer to the data segment.
495 *******************************************************************************/
497 static s4 dseg_add_address_intern(codegendata *cd, void *value, u4 flags)
501 /* Increase data segment size, which is also the displacement into
504 #if SIZEOF_VOID_P == 8
505 cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
510 /* allocate new entry */
512 de = DNEW(dsegentry);
516 de->disp = -(cd->dseglen);
520 /* insert into the chain */
528 /* dseg_add_unique_address *****************************************************
530 Adds uniquely an address value to the data segment.
532 *******************************************************************************/
534 s4 dseg_add_unique_address(codegendata *cd, void *value)
538 disp = dseg_add_address_intern(cd, value, DSEG_FLAG_UNIQUE);
544 /* dseg_add_address ************************************************************
546 Adds an address value to the data segment. It tries to reuse
547 previously added values.
549 *******************************************************************************/
551 s4 dseg_add_address(codegendata *cd, void *value)
555 /* search the data segment if the value is already stored */
557 disp = dseg_find_address(cd, value);
562 disp = dseg_add_address_intern(cd, value, DSEG_FLAG_READONLY);
568 /* dseg_add_target *************************************************************
572 *******************************************************************************/
574 void dseg_add_target(codegendata *cd, basicblock *target)
580 jr->tablepos = dseg_add_unique_address(cd, NULL);
582 jr->next = cd->jumpreferences;
584 cd->jumpreferences = jr;
588 /* dseg_addlinenumbertablesize *************************************************
592 *******************************************************************************/
594 void dseg_addlinenumbertablesize(codegendata *cd)
596 #if SIZEOF_VOID_P == 8
597 /* 4-byte ALIGNMENT PADDING */
599 dseg_add_unique_s4(cd, 0);
602 cd->linenumbertablesizepos = dseg_add_unique_address(cd, NULL);
603 cd->linenumbertablestartpos = dseg_add_unique_address(cd, NULL);
605 #if SIZEOF_VOID_P == 8
606 /* 4-byte ALIGNMENT PADDING */
608 dseg_add_unique_s4(cd, 0);
613 /* dseg_addlinenumber **********************************************************
615 Add a line number reference.
618 cd.............current codegen data
619 linenumber.....number of line that starts with the given mcodeptr
620 mcodeptr.......start mcodeptr of line
622 *******************************************************************************/
624 void dseg_addlinenumber(codegendata *cd, u2 linenumber)
628 lr = DNEW(linenumberref);
630 lr->linenumber = linenumber;
632 lr->targetmpc = cd->mcodeptr - cd->mcodebase;
633 lr->next = cd->linenumberreferences;
635 cd->linenumberreferences = lr;
639 /* dseg_addlinenumber_inline_start *********************************************
641 Add a marker to the line number table indicating the start of an inlined
642 method body. (see doc/inlining_stacktrace.txt)
645 cd.............current codegen data
646 iptr...........the ICMD_INLINE_BODY instruction
647 mcodeptr.......start mcodeptr of inlined body
649 *******************************************************************************/
651 void dseg_addlinenumber_inline_start(codegendata *cd, instruction *iptr)
654 insinfo_inline *insinfo;
657 lr = DNEW(linenumberref);
659 lr->linenumber = (-2); /* marks start of inlined method */
661 lr->targetmpc = (mpc = (u1 *) cd->mcodeptr - cd->mcodebase);
662 lr->next = cd->linenumberreferences;
664 cd->linenumberreferences = lr;
666 insinfo = iptr->sx.s23.s3.inlineinfo;
668 insinfo->startmpc = mpc; /* store for corresponding INLINE_END */
672 /* dseg_addlinenumber_inline_end ***********************************************
674 Add a marker to the line number table indicating the end of an inlined
675 method body. (see doc/inlining_stacktrace.txt)
678 cd.............current codegen data
679 iptr...........the ICMD_INLINE_END instruction
682 iptr->method must point to the inlined callee.
684 *******************************************************************************/
686 void dseg_addlinenumber_inline_end(codegendata *cd, instruction *iptr)
690 insinfo_inline *insinfo;
692 insinfo = iptr->sx.s23.s3.inlineinfo;
696 lr = DNEW(linenumberref);
698 /* special entry containing the methodinfo * */
699 lr->linenumber = (-3) - iptr->line;
701 lr->targetmpc = (ptrint) insinfo->method;
702 lr->next = cd->linenumberreferences;
705 lr = DNEW(linenumberref);
707 /* end marker with PC of start of body */
708 lr->linenumber = (-1);
710 lr->targetmpc = insinfo->startmpc;
713 cd->linenumberreferences = lr;
717 /* dseg_createlinenumbertable **************************************************
719 Creates a line number table in the data segment from the created
720 entries in linenumberreferences.
722 *******************************************************************************/
724 void dseg_createlinenumbertable(codegendata *cd)
728 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
729 lr->tablepos = dseg_add_unique_address(cd, NULL);
731 if (cd->linenumbertab == 0)
732 cd->linenumbertab = lr->tablepos;
734 #if SIZEOF_VOID_P == 8
735 /* This is for alignment and easier usage. */
736 (void) dseg_add_unique_s8(cd, lr->linenumber);
738 (void) dseg_add_unique_s4(cd, lr->linenumber);
744 /* dseg_get_linenumber_from_pc_intern ******************************************
746 This function search the line number table for the line
747 corresponding to a given pc. The function recurses for inlined
750 *******************************************************************************/
752 static s4 dseg_get_linenumber_from_pc_intern(methodinfo **pm, linenumbertable_entry *lntentry, s4 lntsize, u1 *pc)
754 linenumbertable_entry *lntinline; /* special entry for inlined method */
756 for (; lntsize > 0; lntsize--, lntentry--) {
757 /* Note: In case of inlining this may actually compare the pc
758 against a methodinfo *, yielding a non-sensical
759 result. This is no problem, however, as we ignore such
760 entries in the switch below. This way we optimize for the
761 common case (ie. a real pc in lntentry->pc). */
763 if (pc >= lntentry->pc) {
764 /* did we reach the current line? */
766 if ((s4) lntentry->line >= 0)
767 return (s4) lntentry->line;
769 /* we found a special inline entry (see
770 doc/inlining_stacktrace.txt for details */
772 switch (lntentry->line) {
774 /* begin of inlined method (ie. INLINE_END
777 lntinline = --lntentry;/* get entry with methodinfo * */
778 lntentry--; /* skip the special entry */
781 /* search inside the inlined method */
783 if (dseg_get_linenumber_from_pc_intern(pm, lntentry, lntsize,
786 /* the inlined method contained the pc */
788 *pm = (methodinfo *) lntinline->pc;
790 assert(lntinline->line <= -3);
792 return (-3) - lntinline->line;
795 /* pc was not in inlined method, continue search.
796 Entries inside the inlined method will be skipped
797 because their lntentry->pc is higher than pc. */
801 /* end of inlined method */
805 /* default: is only reached for an -3-line entry after
806 a skipped -2 entry. We can safely ignore it and
807 continue searching. */
812 /* not found, return 0 */
818 /* dseg_get_linenumber_from_pc *************************************************
820 A wrapper for dseg_get_linenumber_from_pc_intern, so we don't have
821 to evaluate the method header on every call.
823 *******************************************************************************/
825 s4 dseg_get_linenumber_from_pc(methodinfo **pm, u1 *pv, u1 *pc)
827 ptrint lntsize; /* size of line number table */
828 u1 *lntstart; /* start of line number table */
829 linenumbertable_entry *lntentry; /* points to last entry in the table */
832 #if defined(__S390__)
833 pc = (u1 *)((intptr_t)pc & 0x7FFFFFFF);
836 /* get size of line number table */
838 lntsize = *((ptrint *) (pv + LineNumberTableSize));
839 lntstart = *((u1 **) (pv + LineNumberTableStart));
841 /* Subtract the size of the line number entry of the structure,
842 since the line number table start points to the pc. */
844 lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
846 /* get the line number */
848 linenumber = dseg_get_linenumber_from_pc_intern(pm, lntentry, lntsize, pc);
854 /* dseg_adddata ****************************************************************
856 Adds a data segment reference to the codegendata.
858 *******************************************************************************/
860 #if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
861 void dseg_adddata(codegendata *cd)
867 dr->datapos = cd->mcodeptr - cd->mcodebase;
868 dr->next = cd->datareferences;
870 cd->datareferences = dr;
875 /* dseg_resolve_datareferences *************************************************
877 Resolve data segment references.
879 *******************************************************************************/
881 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
882 void dseg_resolve_datareferences(jitdata *jd)
888 /* get required compiler data */
893 /* data segment references resolving */
895 for (dr = cd->datareferences; dr != NULL; dr = dr->next)
896 *((u1 **) (code->entrypoint + dr->datapos - SIZEOF_VOID_P)) = code->entrypoint;
901 /* dseg_display ****************************************************************
903 Displays the content of the methods' data segment.
905 *******************************************************************************/
908 void dseg_display(jitdata *jd)
915 /* get required compiler data */
921 printf("\033[34m"); /* blue */
923 printf(" --- dump of datasegment\n");
925 /* process all data segment entries */
927 for (de = cd->dseg; de != NULL; de = de->next) {
928 #if SIZEOF_VOID_P == 8
929 printf("0x%016lx:", (ptrint) (code->entrypoint + de->disp));
931 printf("0x%08x:", (ptrint) (code->entrypoint + de->disp));
934 printf(" %6x (%6d): ", de->disp, de->disp);
936 /* We read the values from the data segment as some values,
937 like the line number table, have been written directly to
942 val.i = *((s4 *) (code->entrypoint + de->disp));
943 printf("(INT) %d (0x%08x)", val.i, val.i);
947 val.l = *((s8 *) (code->entrypoint + de->disp));
948 #if SIZEOF_VOID_P == 8
949 printf("(LNG) %ld (0x%016lx)", val.l, val.l);
951 printf("(LNG) %lld (0x%016llx)", val.l, val.l);
956 val.f = *((float *) (code->entrypoint + de->disp));
957 printf("(FLT) %g (0x%08x)", val.f, val.i);
961 val.d = *((double *) (code->entrypoint + de->disp));
962 #if SIZEOF_VOID_P == 8
963 printf("(DBL) %g (0x%016lx)", val.d, val.l);
965 printf("(DBL) %g (0x%016llx)", val.d, val.l);
970 val.a = *((void **) (code->entrypoint + de->disp));
971 #if SIZEOF_VOID_P == 8
972 printf("(ADR) %016lx", (ptrint) val.a);
974 printf("(ADR) %08x", (ptrint) val.a);
982 printf(" --- begin of data segment: ");
983 #if SIZEOF_VOID_P == 8
984 printf("0x%016lx\n", (ptrint) code->entrypoint);
986 printf("0x%08x\n", (ptrint) code->entrypoint);
992 #endif /* !defined(NDEBUG) */
996 * These are local overrides for various environment variables in Emacs.
997 * Please do not remove this and leave it at the end of the file, where
998 * Emacs will automagically detect them.
999 * ---------------------------------------------------------------------
1002 * indent-tabs-mode: t
1006 * vim:noexpandtab:sw=4:ts=4: