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
33 $Id: dseg.c 8298 2007-08-12 18:49:16Z pm $
44 #include "mm/memory.h"
45 #include "vm/jit/codegen-common.h"
46 #include "vm/jit/methodheader.h"
47 #include "vmcore/options.h"
50 /* dseg_finish *****************************************************************
52 Fills the data segment with the values stored.
54 *******************************************************************************/
56 void dseg_finish(jitdata *jd)
62 /* get required compiler data */
67 /* process all data segment entries */
69 for (de = cd->dseg; de != NULL; de = de->next) {
72 *((s4 *) (code->entrypoint + de->disp)) = de->val.i;
76 *((s8 *) (code->entrypoint + de->disp)) = de->val.l;
80 *((float *) (code->entrypoint + de->disp)) = de->val.f;
84 *((double *) (code->entrypoint + de->disp)) = de->val.d;
88 *((void **) (code->entrypoint + de->disp)) = de->val.a;
95 static s4 dseg_find_s4(codegendata *cd, s4 value)
99 /* search all data segment entries for a matching entry */
101 for (de = cd->dseg; de != NULL; de = de->next) {
102 if (IS_INT_TYPE(de->type))
103 if (de->flags & DSEG_FLAG_READONLY)
104 if (de->val.i == value)
108 /* no matching entry was found */
114 static s4 dseg_find_s8(codegendata *cd, s8 value)
118 /* search all data segment entries for a matching entry */
120 for (de = cd->dseg; de != NULL; de = de->next) {
121 if (IS_LNG_TYPE(de->type))
122 if (de->flags & DSEG_FLAG_READONLY)
123 if (de->val.l == value)
127 /* no matching entry was found */
133 static s4 dseg_find_float(codegendata *cd, float value)
138 /* we compare the hex value of the float as 0.0 == -0.0 */
142 /* search all data segment entries for a matching entry */
144 for (de = cd->dseg; de != NULL; de = de->next) {
145 if (IS_FLT_TYPE(de->type))
146 if (de->flags & DSEG_FLAG_READONLY)
147 if (de->val.i == val.i)
151 /* no matching entry was found */
157 static s4 dseg_find_double(codegendata *cd, double value)
162 /* we compare the hex value of the double as 0.0 == -0.0 */
166 /* search all data segment entries for a matching entry */
168 for (de = cd->dseg; de != NULL; de = de->next) {
169 if (IS_DBL_TYPE(de->type))
170 if (de->flags & DSEG_FLAG_READONLY)
171 if (de->val.l == val.l)
175 /* no matching entry was found */
181 static s4 dseg_find_address(codegendata *cd, void *value)
185 /* search all data segment entries for a matching entry */
187 for (de = cd->dseg; de != NULL; de = de->next) {
188 if (IS_ADR_TYPE(de->type))
189 if (de->flags & DSEG_FLAG_READONLY)
190 if (de->val.a == value)
194 /* no matching entry was found */
200 /* dseg_add_s4_intern **********************************************************
202 Internal function to add an s4 value to the data segment.
204 *******************************************************************************/
206 static s4 dseg_add_s4_intern(codegendata *cd, s4 value, u4 flags)
210 /* Increase data segment size, which is also the displacement into
215 /* allocate new entry */
217 de = DNEW(dsegentry);
221 de->disp = -(cd->dseglen);
225 /* insert into the chain */
233 /* dseg_add_unique_s4 **********************************************************
235 Adds uniquely an s4 value to the data segment.
237 *******************************************************************************/
239 s4 dseg_add_unique_s4(codegendata *cd, s4 value)
243 disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_UNIQUE);
249 /* dseg_add_s4 *****************************************************************
251 Adds an s4 value to the data segment. It tries to reuse previously
254 *******************************************************************************/
256 s4 dseg_add_s4(codegendata *cd, s4 value)
260 /* search the data segment if the value is already stored */
262 disp = dseg_find_s4(cd, value);
267 disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_READONLY);
273 /* dseg_add_s8_intern **********************************************************
275 Internal function to add an s8 value to the data segment.
277 *******************************************************************************/
279 static s4 dseg_add_s8_intern(codegendata *cd, s8 value, u4 flags)
283 /* Increase data segment size, which is also the displacement into
286 cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
288 /* allocate new entry */
290 de = DNEW(dsegentry);
294 de->disp = -(cd->dseglen);
298 /* insert into the chain */
306 /* dseg_add_unique_s8 **********************************************************
308 Adds uniquely an s8 value to the data segment.
310 *******************************************************************************/
312 s4 dseg_add_unique_s8(codegendata *cd, s8 value)
316 disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_UNIQUE);
322 /* dseg_add_s8 *****************************************************************
324 Adds an s8 value to the data segment. It tries to reuse previously
327 *******************************************************************************/
329 s4 dseg_add_s8(codegendata *cd, s8 value)
333 /* search the data segment if the value is already stored */
335 disp = dseg_find_s8(cd, value);
340 disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_READONLY);
346 /* dseg_add_float_intern *******************************************************
348 Internal function to add a float value to the data segment.
350 *******************************************************************************/
352 static s4 dseg_add_float_intern(codegendata *cd, float value, u4 flags)
356 /* Increase data segment size, which is also the displacement into
361 /* allocate new entry */
363 de = DNEW(dsegentry);
367 de->disp = -(cd->dseglen);
371 /* insert into the chain */
379 /* dseg_add_unique_float *******************************************************
381 Adds uniquely an float value to the data segment.
383 *******************************************************************************/
385 s4 dseg_add_unique_float(codegendata *cd, float value)
389 disp = dseg_add_float_intern(cd, value, DSEG_FLAG_UNIQUE);
395 /* dseg_add_float **************************************************************
397 Adds an float value to the data segment. It tries to reuse
398 previously added values.
400 *******************************************************************************/
402 s4 dseg_add_float(codegendata *cd, float value)
406 /* search the data segment if the value is already stored */
408 disp = dseg_find_float(cd, value);
413 disp = dseg_add_float_intern(cd, value, DSEG_FLAG_READONLY);
419 /* dseg_add_double_intern ******************************************************
421 Internal function to add a double value to the data segment.
423 *******************************************************************************/
425 static s4 dseg_add_double_intern(codegendata *cd, double value, u4 flags)
429 /* Increase data segment size, which is also the displacement into
432 cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
434 /* allocate new entry */
436 de = DNEW(dsegentry);
440 de->disp = -(cd->dseglen);
444 /* insert into the chain */
452 /* dseg_add_unique_double ******************************************************
454 Adds uniquely a double value to the data segment.
456 *******************************************************************************/
458 s4 dseg_add_unique_double(codegendata *cd, double value)
462 disp = dseg_add_double_intern(cd, value, DSEG_FLAG_UNIQUE);
468 /* dseg_add_double *************************************************************
470 Adds a double value to the data segment. It tries to reuse
471 previously added values.
473 *******************************************************************************/
475 s4 dseg_add_double(codegendata *cd, double value)
479 /* search the data segment if the value is already stored */
481 disp = dseg_find_double(cd, value);
486 disp = dseg_add_double_intern(cd, value, DSEG_FLAG_READONLY);
492 /* dseg_add_address_intern *****************************************************
494 Internal function to add an address pointer to the data segment.
496 *******************************************************************************/
498 static s4 dseg_add_address_intern(codegendata *cd, void *value, u4 flags)
502 /* Increase data segment size, which is also the displacement into
505 #if SIZEOF_VOID_P == 8
506 cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
511 /* allocate new entry */
513 de = DNEW(dsegentry);
517 de->disp = -(cd->dseglen);
521 /* insert into the chain */
529 /* dseg_add_unique_address *****************************************************
531 Adds uniquely an address value to the data segment.
533 *******************************************************************************/
535 s4 dseg_add_unique_address(codegendata *cd, void *value)
539 disp = dseg_add_address_intern(cd, value, DSEG_FLAG_UNIQUE);
545 /* dseg_add_address ************************************************************
547 Adds an address value to the data segment. It tries to reuse
548 previously added values.
550 *******************************************************************************/
552 s4 dseg_add_address(codegendata *cd, void *value)
556 /* search the data segment if the value is already stored */
558 disp = dseg_find_address(cd, value);
563 disp = dseg_add_address_intern(cd, value, DSEG_FLAG_READONLY);
569 /* dseg_add_target *************************************************************
573 *******************************************************************************/
575 void dseg_add_target(codegendata *cd, basicblock *target)
581 jr->tablepos = dseg_add_unique_address(cd, NULL);
583 jr->next = cd->jumpreferences;
585 cd->jumpreferences = jr;
589 /* dseg_addlinenumbertablesize *************************************************
593 *******************************************************************************/
595 void dseg_addlinenumbertablesize(codegendata *cd)
597 #if SIZEOF_VOID_P == 8
598 /* 4-byte ALIGNMENT PADDING */
600 dseg_add_unique_s4(cd, 0);
603 cd->linenumbertablesizepos = dseg_add_unique_address(cd, NULL);
604 cd->linenumbertablestartpos = dseg_add_unique_address(cd, NULL);
606 #if SIZEOF_VOID_P == 8
607 /* 4-byte ALIGNMENT PADDING */
609 dseg_add_unique_s4(cd, 0);
614 /* dseg_addlinenumber **********************************************************
616 Add a line number reference.
619 cd.............current codegen data
620 linenumber.....number of line that starts with the given mcodeptr
621 mcodeptr.......start mcodeptr of line
623 *******************************************************************************/
625 void dseg_addlinenumber(codegendata *cd, u2 linenumber)
629 lr = DNEW(linenumberref);
631 lr->linenumber = linenumber;
633 lr->targetmpc = cd->mcodeptr - cd->mcodebase;
634 lr->next = cd->linenumberreferences;
636 cd->linenumberreferences = lr;
640 /* dseg_addlinenumber_inline_start *********************************************
642 Add a marker to the line number table indicating the start of an inlined
643 method body. (see doc/inlining_stacktrace.txt)
646 cd.............current codegen data
647 iptr...........the ICMD_INLINE_BODY instruction
648 mcodeptr.......start mcodeptr of inlined body
650 *******************************************************************************/
652 void dseg_addlinenumber_inline_start(codegendata *cd, instruction *iptr)
655 insinfo_inline *insinfo;
658 lr = DNEW(linenumberref);
660 lr->linenumber = (-2); /* marks start of inlined method */
662 lr->targetmpc = (mpc = (u1 *) cd->mcodeptr - cd->mcodebase);
663 lr->next = cd->linenumberreferences;
665 cd->linenumberreferences = lr;
667 insinfo = iptr->sx.s23.s3.inlineinfo;
669 insinfo->startmpc = mpc; /* store for corresponding INLINE_END */
673 /* dseg_addlinenumber_inline_end ***********************************************
675 Add a marker to the line number table indicating the end of an inlined
676 method body. (see doc/inlining_stacktrace.txt)
679 cd.............current codegen data
680 iptr...........the ICMD_INLINE_END instruction
683 iptr->method must point to the inlined callee.
685 *******************************************************************************/
687 void dseg_addlinenumber_inline_end(codegendata *cd, instruction *iptr)
691 insinfo_inline *insinfo;
693 insinfo = iptr->sx.s23.s3.inlineinfo;
697 lr = DNEW(linenumberref);
699 /* special entry containing the methodinfo * */
700 lr->linenumber = (-3) - iptr->line;
702 lr->targetmpc = (ptrint) insinfo->method;
703 lr->next = cd->linenumberreferences;
706 lr = DNEW(linenumberref);
708 /* end marker with PC of start of body */
709 lr->linenumber = (-1);
711 lr->targetmpc = insinfo->startmpc;
714 cd->linenumberreferences = lr;
718 /* dseg_createlinenumbertable **************************************************
720 Creates a line number table in the data segment from the created
721 entries in linenumberreferences.
723 *******************************************************************************/
725 void dseg_createlinenumbertable(codegendata *cd)
729 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
730 lr->tablepos = dseg_add_unique_address(cd, NULL);
732 if (cd->linenumbertab == 0)
733 cd->linenumbertab = lr->tablepos;
735 #if SIZEOF_VOID_P == 8
736 /* This is for alignment and easier usage. */
737 (void) dseg_add_unique_s8(cd, lr->linenumber);
739 (void) dseg_add_unique_s4(cd, lr->linenumber);
745 /* dseg_get_linenumber_from_pc_intern ******************************************
747 This function search the line number table for the line
748 corresponding to a given pc. The function recurses for inlined
751 *******************************************************************************/
753 static s4 dseg_get_linenumber_from_pc_intern(methodinfo **pm, linenumbertable_entry *lntentry, s4 lntsize, u1 *pc)
755 linenumbertable_entry *lntinline; /* special entry for inlined method */
757 for (; lntsize > 0; lntsize--, lntentry--) {
758 /* Note: In case of inlining this may actually compare the pc
759 against a methodinfo *, yielding a non-sensical
760 result. This is no problem, however, as we ignore such
761 entries in the switch below. This way we optimize for the
762 common case (ie. a real pc in lntentry->pc). */
764 if (pc >= lntentry->pc) {
765 /* did we reach the current line? */
767 if ((s4) lntentry->line >= 0)
768 return (s4) lntentry->line;
770 /* we found a special inline entry (see
771 doc/inlining_stacktrace.txt for details */
773 switch (lntentry->line) {
775 /* begin of inlined method (ie. INLINE_END
778 lntinline = --lntentry;/* get entry with methodinfo * */
779 lntentry--; /* skip the special entry */
782 /* search inside the inlined method */
784 if (dseg_get_linenumber_from_pc_intern(pm, lntentry, lntsize,
787 /* the inlined method contained the pc */
789 *pm = (methodinfo *) lntinline->pc;
791 assert(lntinline->line <= -3);
793 return (-3) - lntinline->line;
796 /* pc was not in inlined method, continue search.
797 Entries inside the inlined method will be skipped
798 because their lntentry->pc is higher than pc. */
802 /* end of inlined method */
806 /* default: is only reached for an -3-line entry after
807 a skipped -2 entry. We can safely ignore it and
808 continue searching. */
813 /* not found, return 0 */
819 /* dseg_get_linenumber_from_pc *************************************************
821 A wrapper for dseg_get_linenumber_from_pc_intern, so we don't have
822 to evaluate the method header on every call.
824 *******************************************************************************/
826 s4 dseg_get_linenumber_from_pc(methodinfo **pm, u1 *pv, u1 *pc)
828 ptrint lntsize; /* size of line number table */
829 u1 *lntstart; /* start of line number table */
830 linenumbertable_entry *lntentry; /* points to last entry in the table */
833 #if defined(__S390__)
834 pc = (u1 *)((intptr_t)pc & 0x7FFFFFFF);
837 /* get size of line number table */
839 lntsize = *((ptrint *) (pv + LineNumberTableSize));
840 lntstart = *((u1 **) (pv + LineNumberTableStart));
842 /* Subtract the size of the line number entry of the structure,
843 since the line number table start points to the pc. */
845 lntentry = (linenumbertable_entry *) (lntstart - SIZEOF_VOID_P);
847 /* get the line number */
849 linenumber = dseg_get_linenumber_from_pc_intern(pm, lntentry, lntsize, pc);
855 /* dseg_adddata ****************************************************************
857 Adds a data segment reference to the codegendata.
859 *******************************************************************************/
861 #if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
862 void dseg_adddata(codegendata *cd)
868 dr->datapos = cd->mcodeptr - cd->mcodebase;
869 dr->next = cd->datareferences;
871 cd->datareferences = dr;
876 /* dseg_resolve_datareferences *************************************************
878 Resolve data segment references.
880 *******************************************************************************/
882 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
883 void dseg_resolve_datareferences(jitdata *jd)
889 /* get required compiler data */
894 /* data segment references resolving */
896 for (dr = cd->datareferences; dr != NULL; dr = dr->next)
897 *((u1 **) (code->entrypoint + dr->datapos - SIZEOF_VOID_P)) = code->entrypoint;
902 /* dseg_display ****************************************************************
904 Displays the content of the methods' data segment.
906 *******************************************************************************/
909 void dseg_display(jitdata *jd)
916 /* get required compiler data */
922 printf("\033[34m"); /* blue */
924 printf(" --- dump of datasegment\n");
926 /* process all data segment entries */
928 for (de = cd->dseg; de != NULL; de = de->next) {
929 #if SIZEOF_VOID_P == 8
930 printf("0x%016lx:", (ptrint) (code->entrypoint + de->disp));
932 printf("0x%08x:", (ptrint) (code->entrypoint + de->disp));
935 printf(" %6x (%6d): ", de->disp, de->disp);
937 /* We read the values from the data segment as some values,
938 like the line number table, have been written directly to
943 val.i = *((s4 *) (code->entrypoint + de->disp));
944 printf("(INT) %d (0x%08x)", val.i, val.i);
948 val.l = *((s8 *) (code->entrypoint + de->disp));
949 #if SIZEOF_VOID_P == 8
950 printf("(LNG) %ld (0x%016lx)", val.l, val.l);
952 printf("(LNG) %lld (0x%016llx)", val.l, val.l);
957 val.f = *((float *) (code->entrypoint + de->disp));
958 printf("(FLT) %g (0x%08x)", val.f, val.i);
962 val.d = *((double *) (code->entrypoint + de->disp));
963 #if SIZEOF_VOID_P == 8
964 printf("(DBL) %g (0x%016lx)", val.d, val.l);
966 printf("(DBL) %g (0x%016llx)", val.d, val.l);
971 val.a = *((void **) (code->entrypoint + de->disp));
972 #if SIZEOF_VOID_P == 8
973 printf("(ADR) %016lx", (ptrint) val.a);
975 printf("(ADR) %08x", (ptrint) val.a);
983 printf(" --- begin of data segment: ");
984 #if SIZEOF_VOID_P == 8
985 printf("0x%016lx\n", (ptrint) code->entrypoint);
987 printf("0x%08x\n", (ptrint) code->entrypoint);
993 #endif /* !defined(NDEBUG) */
997 * These are local overrides for various environment variables in Emacs.
998 * Please do not remove this and leave it at the end of the file, where
999 * Emacs will automagically detect them.
1000 * ---------------------------------------------------------------------
1003 * indent-tabs-mode: t
1007 * vim:noexpandtab:sw=4:ts=4: