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 cd->linenumbertablesizepos = dseg_add_unique_address(cd, NULL);
597 cd->linenumbertablestartpos = dseg_add_unique_address(cd, NULL);
601 /* dseg_addlinenumber **********************************************************
603 Add a line number reference.
606 cd.............current codegen data
607 linenumber.....number of line that starts with the given mcodeptr
608 mcodeptr.......start mcodeptr of line
610 *******************************************************************************/
612 void dseg_addlinenumber(codegendata *cd, u2 linenumber)
616 lr = DNEW(linenumberref);
618 lr->linenumber = linenumber;
620 lr->targetmpc = cd->mcodeptr - cd->mcodebase;
621 lr->next = cd->linenumberreferences;
623 cd->linenumberreferences = lr;
627 /* dseg_addlinenumber_inline_start *********************************************
629 Add a marker to the line number table indicating the start of an inlined
630 method body. (see doc/inlining_stacktrace.txt)
633 cd.............current codegen data
634 iptr...........the ICMD_INLINE_BODY instruction
635 mcodeptr.......start mcodeptr of inlined body
637 *******************************************************************************/
639 void dseg_addlinenumber_inline_start(codegendata *cd, instruction *iptr)
642 insinfo_inline *insinfo;
645 lr = DNEW(linenumberref);
647 lr->linenumber = (-2); /* marks start of inlined method */
649 lr->targetmpc = (mpc = (u1 *) cd->mcodeptr - cd->mcodebase);
650 lr->next = cd->linenumberreferences;
652 cd->linenumberreferences = lr;
654 insinfo = iptr->sx.s23.s3.inlineinfo;
656 insinfo->startmpc = mpc; /* store for corresponding INLINE_END */
660 /* dseg_addlinenumber_inline_end ***********************************************
662 Add a marker to the line number table indicating the end of an inlined
663 method body. (see doc/inlining_stacktrace.txt)
666 cd.............current codegen data
667 iptr...........the ICMD_INLINE_END instruction
670 iptr->method must point to the inlined callee.
672 *******************************************************************************/
674 void dseg_addlinenumber_inline_end(codegendata *cd, instruction *iptr)
678 insinfo_inline *insinfo;
680 insinfo = iptr->sx.s23.s3.inlineinfo;
684 lr = DNEW(linenumberref);
686 /* special entry containing the methodinfo * */
687 lr->linenumber = (-3) - iptr->line;
689 lr->targetmpc = (ptrint) insinfo->method;
690 lr->next = cd->linenumberreferences;
693 lr = DNEW(linenumberref);
695 /* end marker with PC of start of body */
696 lr->linenumber = (-1);
698 lr->targetmpc = insinfo->startmpc;
701 cd->linenumberreferences = lr;
705 /* dseg_createlinenumbertable **************************************************
707 Creates a line number table in the data segment from the created
708 entries in linenumberreferences.
710 *******************************************************************************/
712 void dseg_createlinenumbertable(codegendata *cd)
716 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
717 lr->tablepos = dseg_add_unique_address(cd, NULL);
719 if (cd->linenumbertab == 0)
720 cd->linenumbertab = lr->tablepos;
722 #if SIZEOF_VOID_P == 8
723 /* This is for alignment and easier usage. */
724 (void) dseg_add_unique_s8(cd, lr->linenumber);
726 (void) dseg_add_unique_s4(cd, lr->linenumber);
732 /* dseg_get_linenumber_from_pc_intern ******************************************
734 This function search the line number table for the line
735 corresponding to a given pc. The function recurses for inlined
738 *******************************************************************************/
740 static s4 dseg_get_linenumber_from_pc_intern(methodinfo **pm, linenumbertable_entry *lntentry, s4 lntsize, u1 *pc)
742 linenumbertable_entry *lntinline; /* special entry for inlined method */
744 for (; lntsize > 0; lntsize--, lntentry--) {
745 /* Note: In case of inlining this may actually compare the pc
746 against a methodinfo *, yielding a non-sensical
747 result. This is no problem, however, as we ignore such
748 entries in the switch below. This way we optimize for the
749 common case (ie. a real pc in lntentry->pc). */
751 if (pc >= lntentry->pc) {
752 /* did we reach the current line? */
754 if ((s4) lntentry->line >= 0)
755 return (s4) lntentry->line;
757 /* we found a special inline entry (see
758 doc/inlining_stacktrace.txt for details */
760 switch (lntentry->line) {
762 /* begin of inlined method (ie. INLINE_END
765 lntinline = --lntentry;/* get entry with methodinfo * */
766 lntentry--; /* skip the special entry */
769 /* search inside the inlined method */
771 if (dseg_get_linenumber_from_pc_intern(pm, lntentry, lntsize,
774 /* the inlined method contained the pc */
776 *pm = (methodinfo *) lntinline->pc;
778 assert(lntinline->line <= -3);
780 return (-3) - lntinline->line;
783 /* pc was not in inlined method, continue search.
784 Entries inside the inlined method will be skipped
785 because their lntentry->pc is higher than pc. */
789 /* end of inlined method */
793 /* default: is only reached for an -3-line entry after
794 a skipped -2 entry. We can safely ignore it and
795 continue searching. */
800 /* not found, return 0 */
806 /* dseg_get_linenumber_from_pc *************************************************
808 A wrapper for dseg_get_linenumber_from_pc_intern, so we don't have
809 to evaluate the method header on every call.
811 *******************************************************************************/
813 s4 dseg_get_linenumber_from_pc(methodinfo **pm, u1 *pv, u1 *pc)
815 ptrint lntsize; /* size of line number table */
816 u1 *lntstart; /* start of line number table */
817 linenumbertable_entry *lntentry; /* points to last entry in the table */
820 #if defined(__S390__)
821 pc = (u1 *)((intptr_t)pc & 0x7FFFFFFF);
824 /* get size of line number table */
826 lntsize = *((ptrint *) (pv + LineNumberTableSize));
827 lntstart = *((u1 **) (pv + LineNumberTableStart));
829 /* Subtract the size of the line number entry of the structure,
830 since the line number table start points to the pc. */
832 lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
834 /* get the line number */
836 linenumber = dseg_get_linenumber_from_pc_intern(pm, lntentry, lntsize, pc);
842 /* dseg_adddata ****************************************************************
844 Adds a data segment reference to the codegendata.
846 *******************************************************************************/
848 #if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
849 void dseg_adddata(codegendata *cd)
855 dr->datapos = cd->mcodeptr - cd->mcodebase;
856 dr->next = cd->datareferences;
858 cd->datareferences = dr;
863 /* dseg_resolve_datareferences *************************************************
865 Resolve data segment references.
867 *******************************************************************************/
869 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
870 void dseg_resolve_datareferences(jitdata *jd)
876 /* get required compiler data */
881 /* data segment references resolving */
883 for (dr = cd->datareferences; dr != NULL; dr = dr->next)
884 *((u1 **) (code->entrypoint + dr->datapos - SIZEOF_VOID_P)) = code->entrypoint;
889 /* dseg_display ****************************************************************
891 Displays the content of the methods' data segment.
893 *******************************************************************************/
896 void dseg_display(jitdata *jd)
903 /* get required compiler data */
909 printf("\033[34m"); /* blue */
911 printf(" --- dump of datasegment\n");
913 /* process all data segment entries */
915 for (de = cd->dseg; de != NULL; de = de->next) {
916 #if SIZEOF_VOID_P == 8
917 printf("0x%016lx:", (ptrint) (code->entrypoint + de->disp));
919 printf("0x%08x:", (ptrint) (code->entrypoint + de->disp));
922 printf(" %6x (%6d): ", de->disp, de->disp);
924 /* We read the values from the data segment as some values,
925 like the line number table, have been written directly to
930 val.i = *((s4 *) (code->entrypoint + de->disp));
931 printf("(INT) %d (0x%08x)", val.i, val.i);
935 val.l = *((s8 *) (code->entrypoint + de->disp));
936 #if SIZEOF_VOID_P == 8
937 printf("(LNG) %ld (0x%016lx)", val.l, val.l);
939 printf("(LNG) %lld (0x%016llx)", val.l, val.l);
944 val.f = *((float *) (code->entrypoint + de->disp));
945 printf("(FLT) %g (0x%08x)", val.f, val.i);
949 val.d = *((double *) (code->entrypoint + de->disp));
950 #if SIZEOF_VOID_P == 8
951 printf("(DBL) %g (0x%016lx)", val.d, val.l);
953 printf("(DBL) %g (0x%016llx)", val.d, val.l);
958 val.a = *((void **) (code->entrypoint + de->disp));
959 #if SIZEOF_VOID_P == 8
960 printf("(ADR) %016lx", (ptrint) val.a);
962 printf("(ADR) %08x", (ptrint) val.a);
970 printf(" --- begin of data segment: ");
971 #if SIZEOF_VOID_P == 8
972 printf("0x%016lx\n", (ptrint) code->entrypoint);
974 printf("0x%08x\n", (ptrint) code->entrypoint);
980 #endif /* !defined(NDEBUG) */
984 * These are local overrides for various environment variables in Emacs.
985 * Please do not remove this and leave it at the end of the file, where
986 * Emacs will automagically detect them.
987 * ---------------------------------------------------------------------
990 * indent-tabs-mode: t
994 * vim:noexpandtab:sw=4:ts=4: