* src/vm/jit/dseg.c (dseg_display): Rewritten.
[cacao.git] / src / vm / jit / dseg.c
1 /* src/vm/jit/dseg.c - data segment handling stuff
2
3    Copyright (C) 1996-2005, 2006 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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Reinhard Grafl
28             Andreas  Krall
29
30    Changes: Christian Thalinger
31             Joseph Wenninger
32                         Edwin Steiner
33
34    $Id: dseg.c 5820 2006-10-24 11:17:30Z twisti $
35
36 */
37
38
39 #include "config.h"
40
41 #include <assert.h>
42
43 #include "vm/options.h"
44 #include "vm/types.h"
45
46 #include "mm/memory.h"
47 #include "vm/jit/codegen-common.h"
48
49
50
51 /* dseg_finish *****************************************************************
52
53    Fills the data segment with the values stored.
54
55 *******************************************************************************/
56
57 void dseg_finish(jitdata *jd)
58 {
59         codeinfo    *code;
60         codegendata *cd;
61         dsegentry   *de;
62
63         /* get required compiler data */
64
65         code = jd->code;
66         cd   = jd->cd;
67
68         /* process all data segment entries */
69
70         for (de = cd->dseg; de != NULL; de = de->next) {
71                 switch (de->type) {
72                 case TYPE_INT:
73                         *((s4 *)     (code->entrypoint + de->disp)) = de->val.i;
74                         break;
75
76                 case TYPE_LNG:
77                         *((s8 *)     (code->entrypoint + de->disp)) = de->val.l;
78                         break;
79
80                 case TYPE_FLT:
81                         *((float *)  (code->entrypoint + de->disp)) = de->val.f;
82                         break;
83
84                 case TYPE_DBL:
85                         *((double *) (code->entrypoint + de->disp)) = de->val.d;
86                         break;
87
88                 case TYPE_ADR:
89                         *((void **)  (code->entrypoint + de->disp)) = de->val.a;
90                         break;
91                 }
92         }
93 }
94
95
96 static s4 dseg_find_s4(codegendata *cd, s4 value)
97 {
98         dsegentry *de;
99
100         /* search all data segment entries for a matching entry */
101
102         for (de = cd->dseg; de != NULL; de = de->next) {
103                 if (IS_INT_TYPE(de->type))
104                         if (de->flags & DSEG_FLAG_READONLY)
105                                 if (de->val.i == value)
106                                         return de->disp;
107         }
108
109         /* no matching entry was found */
110
111         return 0;
112 }
113
114
115 static s4 dseg_find_s8(codegendata *cd, s8 value)
116 {
117         dsegentry *de;
118
119         /* search all data segment entries for a matching entry */
120
121         for (de = cd->dseg; de != NULL; de = de->next) {
122                 if (IS_LNG_TYPE(de->type))
123                         if (de->flags & DSEG_FLAG_READONLY)
124                                 if (de->val.l == value)
125                                         return de->disp;
126         }
127
128         /* no matching entry was found */
129
130         return 0;
131 }
132
133
134 static s4 dseg_find_float(codegendata *cd, float value)
135 {
136         dsegentry *de;
137
138         /* search all data segment entries for a matching entry */
139
140         for (de = cd->dseg; de != NULL; de = de->next) {
141                 if (IS_FLT_TYPE(de->type))
142                         if (de->flags & DSEG_FLAG_READONLY)
143                                 if (de->val.f == value)
144                                         return de->disp;
145         }
146
147         /* no matching entry was found */
148
149         return 0;
150 }
151
152
153 static s4 dseg_find_double(codegendata *cd, double value)
154 {
155         dsegentry *de;
156
157         /* search all data segment entries for a matching entry */
158
159         for (de = cd->dseg; de != NULL; de = de->next) {
160                 if (IS_DBL_TYPE(de->type))
161                         if (de->flags & DSEG_FLAG_READONLY)
162                                 if (de->val.d == value)
163                                         return de->disp;
164         }
165
166         /* no matching entry was found */
167
168         return 0;
169 }
170
171
172 static s4 dseg_find_address(codegendata *cd, void *value)
173 {
174         dsegentry *de;
175
176         /* search all data segment entries for a matching entry */
177
178         for (de = cd->dseg; de != NULL; de = de->next) {
179                 if (IS_ADR_TYPE(de->type))
180                         if (de->flags & DSEG_FLAG_READONLY)
181                                 if (de->val.a == value)
182                                         return de->disp;
183         }
184
185         /* no matching entry was found */
186
187         return 0;
188 }
189
190
191 /* dseg_add_s4_intern **********************************************************
192
193    Internal function to add an s4 value to the data segment.
194
195 *******************************************************************************/
196
197 static s4 dseg_add_s4_intern(codegendata *cd, s4 value, u4 flags)
198 {
199         dsegentry *de;
200
201         /* Increase data segment size, which is also the displacement into
202            the data segment. */
203
204         cd->dseglen += 4;
205
206         /* allocate new entry */
207
208         de = DNEW(dsegentry);
209
210         de->type  = TYPE_INT;
211         de->flags = flags;
212         de->disp  = -(cd->dseglen);
213         de->val.i = value;
214         de->next  = cd->dseg;
215
216         /* insert into the chain */
217
218         cd->dseg = de;
219
220         return de->disp;
221 }
222
223
224 /* dseg_add_unique_s4 **********************************************************
225
226    Adds uniquely an s4 value to the data segment.
227
228 *******************************************************************************/
229
230 s4 dseg_add_unique_s4(codegendata *cd, s4 value)
231 {
232         s4 disp;
233
234         disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_UNIQUE);
235
236         return disp;
237 }
238
239
240 /* dseg_add_s4 *****************************************************************
241
242    Adds an s4 value to the data segment. It tries to reuse previously
243    added values.
244
245 *******************************************************************************/
246
247 s4 dseg_add_s4(codegendata *cd, s4 value)
248 {
249         s4 disp;
250
251         /* search the data segment if the value is already stored */
252
253         disp = dseg_find_s4(cd, value);
254
255         if (disp != 0)
256                 return disp;
257                 
258         disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_READONLY);
259
260         return disp;
261 }
262
263
264 /* dseg_add_s8_intern **********************************************************
265
266    Internal function to add an s8 value to the data segment.
267
268 *******************************************************************************/
269
270 static s4 dseg_add_s8_intern(codegendata *cd, s8 value, u4 flags)
271 {
272         dsegentry *de;
273
274         /* Increase data segment size, which is also the displacement into
275            the data segment. */
276
277         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
278
279         /* allocate new entry */
280
281         de = DNEW(dsegentry);
282
283         de->type  = TYPE_LNG;
284         de->flags = flags;
285         de->disp  = -(cd->dseglen);
286         de->val.l = value;
287         de->next  = cd->dseg;
288
289         /* insert into the chain */
290
291         cd->dseg = de;
292
293         return de->disp;
294 }
295
296
297 /* dseg_add_unique_s8 **********************************************************
298
299    Adds uniquely an s8 value to the data segment.
300
301 *******************************************************************************/
302
303 s4 dseg_add_unique_s8(codegendata *cd, s8 value)
304 {
305         s4 disp;
306
307         disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_UNIQUE);
308
309         return disp;
310 }
311
312
313 /* dseg_add_s8 *****************************************************************
314
315    Adds an s8 value to the data segment. It tries to reuse previously
316    added values.
317
318 *******************************************************************************/
319
320 s4 dseg_add_s8(codegendata *cd, s8 value)
321 {
322         s4 disp;
323
324         /* search the data segment if the value is already stored */
325
326         disp = dseg_find_s8(cd, value);
327
328         if (disp != 0)
329                 return disp;
330                 
331         disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_READONLY);
332
333         return disp;
334 }
335
336
337 /* dseg_add_float_intern *******************************************************
338
339    Internal function to add a float value to the data segment.
340
341 *******************************************************************************/
342
343 static s4 dseg_add_float_intern(codegendata *cd, float value, u4 flags)
344 {
345         dsegentry *de;
346                 
347         /* Increase data segment size, which is also the displacement into
348            the data segment. */
349
350         cd->dseglen += 4;
351
352         /* allocate new entry */
353
354         de = DNEW(dsegentry);
355
356         de->type  = TYPE_FLT;
357         de->flags = flags;
358         de->disp  = -(cd->dseglen);
359         de->val.f = value;
360         de->next  = cd->dseg;
361
362         /* insert into the chain */
363
364         cd->dseg = de;
365
366         return de->disp;
367 }
368
369
370 /* dseg_add_unique_float *******************************************************
371
372    Adds uniquely an float value to the data segment.
373
374 *******************************************************************************/
375
376 s4 dseg_add_unique_float(codegendata *cd, float value)
377 {
378         s4 disp;
379
380         disp = dseg_add_float_intern(cd, value, DSEG_FLAG_UNIQUE);
381
382         return disp;
383 }
384
385
386 /* dseg_add_float **************************************************************
387
388    Adds an float value to the data segment. It tries to reuse
389    previously added values.
390
391 *******************************************************************************/
392
393 s4 dseg_add_float(codegendata *cd, float value)
394 {
395         s4 disp;
396
397         /* search the data segment if the value is already stored */
398
399         disp = dseg_find_float(cd, value);
400
401         if (disp != 0)
402                 return disp;
403                 
404         disp = dseg_add_float_intern(cd, value, DSEG_FLAG_READONLY);
405
406         return disp;
407 }
408
409
410 /* dseg_add_double_intern ******************************************************
411
412    Internal function to add a double value to the data segment.
413
414 *******************************************************************************/
415
416 static s4 dseg_add_double_intern(codegendata *cd, double value, u4 flags)
417 {
418         dsegentry *de;
419                 
420         /* Increase data segment size, which is also the displacement into
421            the data segment. */
422
423         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
424
425         /* allocate new entry */
426
427         de = DNEW(dsegentry);
428
429         de->type  = TYPE_DBL;
430         de->flags = flags;
431         de->disp  = -(cd->dseglen);
432         de->val.d = value;
433         de->next  = cd->dseg;
434
435         /* insert into the chain */
436
437         cd->dseg = de;
438
439         return de->disp;
440 }
441
442
443 /* dseg_add_unique_double ******************************************************
444
445    Adds uniquely a double value to the data segment.
446
447 *******************************************************************************/
448
449 s4 dseg_add_unique_double(codegendata *cd, double value)
450 {
451         s4 disp;
452
453         disp = dseg_add_double_intern(cd, value, DSEG_FLAG_UNIQUE);
454
455         return disp;
456 }
457
458
459 /* dseg_add_double *************************************************************
460
461    Adds a double value to the data segment. It tries to reuse
462    previously added values.
463
464 *******************************************************************************/
465
466 s4 dseg_add_double(codegendata *cd, double value)
467 {
468         s4 disp;
469
470         /* search the data segment if the value is already stored */
471
472         disp = dseg_find_double(cd, value);
473
474         if (disp != 0)
475                 return disp;
476                 
477         disp = dseg_add_double_intern(cd, value, DSEG_FLAG_READONLY);
478
479         return disp;
480 }
481
482
483 /* dseg_add_address_intern *****************************************************
484
485    Internal function to add an address pointer to the data segment.
486
487 *******************************************************************************/
488
489 static s4 dseg_add_address_intern(codegendata *cd, void *value, u4 flags)
490 {
491         dsegentry *de;
492
493         /* Increase data segment size, which is also the displacement into
494            the data segment. */
495
496 #if SIZEOF_VOID_P == 8
497         cd->dseglen = ALIGN(cd->dseglen + 8, 8);
498 #else
499         cd->dseglen += 4;
500 #endif
501
502         /* allocate new entry */
503
504         de = DNEW(dsegentry);
505
506         de->type  = TYPE_ADR;
507         de->flags = flags;
508         de->disp  = -(cd->dseglen);
509         de->val.a = value;
510         de->next  = cd->dseg;
511
512         /* insert into the chain */
513
514         cd->dseg = de;
515
516         return de->disp;
517 }
518
519
520 /* dseg_add_unique_address *****************************************************
521
522    Adds uniquely an address value to the data segment.
523
524 *******************************************************************************/
525
526 s4 dseg_add_unique_address(codegendata *cd, void *value)
527 {
528         s4 disp;
529
530         disp = dseg_add_address_intern(cd, value, DSEG_FLAG_UNIQUE);
531
532         return disp;
533 }
534
535
536 /* dseg_add_address ************************************************************
537
538    Adds an address value to the data segment. It tries to reuse
539    previously added values.
540
541 *******************************************************************************/
542
543 s4 dseg_add_address(codegendata *cd, void *value)
544 {
545         s4 disp;
546
547         /* search the data segment if the value is already stored */
548
549         disp = dseg_find_address(cd, value);
550
551         if (disp != 0)
552                 return disp;
553                 
554         disp = dseg_add_address_intern(cd, value, DSEG_FLAG_READONLY);
555
556         return disp;
557 }
558
559
560 /* dseg_add_target *************************************************************
561
562    XXX
563
564 *******************************************************************************/
565
566 void dseg_add_target(codegendata *cd, basicblock *target)
567 {
568         jumpref *jr;
569
570         jr = DNEW(jumpref);
571
572         jr->tablepos = dseg_add_unique_address(cd, NULL);
573         jr->target   = target;
574         jr->next     = cd->jumpreferences;
575
576         cd->jumpreferences = jr;
577 }
578
579
580 /* dseg_addlinenumbertablesize *************************************************
581
582    XXX
583
584 *******************************************************************************/
585
586 void dseg_addlinenumbertablesize(codegendata *cd)
587 {
588 #if SIZEOF_VOID_P == 8
589         /* 4-byte ALIGNMENT PADDING */
590
591         dseg_add_unique_s4(cd, 0);
592 #endif
593
594         cd->linenumbertablesizepos  = dseg_add_unique_address(cd, NULL);
595         cd->linenumbertablestartpos = dseg_add_unique_address(cd, NULL);
596
597 #if SIZEOF_VOID_P == 8
598         /* 4-byte ALIGNMENT PADDING */
599
600         dseg_add_unique_s4(cd, 0);
601 #endif
602 }
603
604
605 /* dseg_addlinenumber **********************************************************
606
607    Add a line number reference.
608
609    IN:
610       cd.............current codegen data
611       linenumber.....number of line that starts with the given mcodeptr
612       mcodeptr.......start mcodeptr of line
613
614 *******************************************************************************/
615
616 void dseg_addlinenumber(codegendata *cd, u2 linenumber)
617 {
618         linenumberref *lr;
619
620         lr = DNEW(linenumberref);
621
622         lr->linenumber = linenumber;
623         lr->tablepos   = 0;
624         lr->targetmpc  = cd->mcodeptr - cd->mcodebase;
625         lr->next       = cd->linenumberreferences;
626
627         cd->linenumberreferences = lr;
628 }
629
630
631 /* dseg_addlinenumber_inline_start *********************************************
632
633    Add a marker to the line number table indicating the start of an inlined
634    method body. (see doc/inlining_stacktrace.txt)
635
636    IN:
637       cd.............current codegen data
638       iptr...........the ICMD_INLINE_START instruction
639       mcodeptr.......start mcodeptr of inlined body
640
641 *******************************************************************************/
642
643 void dseg_addlinenumber_inline_start(codegendata *cd, instruction *iptr)
644 {
645         linenumberref *lr;
646         insinfo_inline *insinfo;
647         ptrint mpc;
648
649         lr = DNEW(linenumberref);
650
651         lr->linenumber = (-2); /* marks start of inlined method */
652         lr->tablepos   = 0;
653         lr->targetmpc  = (mpc = (u1 *) cd->mcodeptr - cd->mcodebase);
654         lr->next       = cd->linenumberreferences;
655
656         cd->linenumberreferences = lr;
657
658 #if 0
659         insinfo = (insinfo_inline *) iptr->target;
660 #endif
661
662         insinfo->startmpc = mpc; /* store for corresponding INLINE_END */
663 }
664
665
666 /* dseg_addlinenumber_inline_end ***********************************************
667
668    Add a marker to the line number table indicating the end of an inlined
669    method body. (see doc/inlining_stacktrace.txt)
670
671    IN:
672       cd.............current codegen data
673       iptr...........the ICMD_INLINE_END instruction
674
675    Note:
676       iptr->method must point to the inlined callee.
677
678 *******************************************************************************/
679
680 void dseg_addlinenumber_inline_end(codegendata *cd, instruction *iptr)
681 {
682         linenumberref *lr;
683         linenumberref *prev;
684         insinfo_inline *insinfo;
685
686 #if 0
687         insinfo = (insinfo_inline *) iptr->target;
688 #endif
689
690         assert(insinfo);
691
692         lr = DNEW(linenumberref);
693
694         /* special entry containing the methodinfo * */
695         lr->linenumber = (-3) - iptr->line;
696         lr->tablepos   = 0;
697         lr->targetmpc  = (ptrint) insinfo->method;
698         lr->next       = cd->linenumberreferences;
699
700         prev = lr;
701         lr = DNEW(linenumberref);
702
703         /* end marker with PC of start of body */
704         lr->linenumber = (-1);
705         lr->tablepos   = 0;
706         lr->targetmpc  = insinfo->startmpc;
707         lr->next       = prev;
708
709         cd->linenumberreferences = lr;
710 }
711
712
713 /* dseg_createlinenumbertable **************************************************
714
715    Creates a line number table in the data segment from the created
716    entries in linenumberreferences.
717
718 *******************************************************************************/
719
720 void dseg_createlinenumbertable(codegendata *cd)
721 {
722         linenumberref *lr;
723
724         for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
725                 lr->tablepos = dseg_add_unique_address(cd, NULL);
726
727                 if (cd->linenumbertab == 0)
728                         cd->linenumbertab = lr->tablepos;
729
730 #if SIZEOF_VOID_P == 8
731                 /* This is for alignment and easier usage. */
732                 (void) dseg_add_unique_s8(cd, lr->linenumber);
733 #else
734                 (void) dseg_add_unique_s4(cd, lr->linenumber);
735 #endif
736         }
737 }
738
739
740 /* dseg_adddata ****************************************************************
741
742    Adds a data segment reference to the codegendata.
743
744 *******************************************************************************/
745
746 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
747 void dseg_adddata(codegendata *cd)
748 {
749         dataref *dr;
750
751         dr = DNEW(dataref);
752
753         dr->datapos = cd->mcodeptr - cd->mcodebase;
754         dr->next    = cd->datareferences;
755
756         cd->datareferences = dr;
757 }
758 #endif
759
760
761 /* dseg_resolve_datareferences *************************************************
762
763    Resolve data segment references.
764
765 *******************************************************************************/
766
767 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(ENABLE_INTRP)
768 void dseg_resolve_datareferences(jitdata *jd)
769 {
770         codeinfo    *code;
771         codegendata *cd;
772         dataref     *dr;
773
774         /* get required compiler data */
775
776         code = jd->code;
777         cd   = jd->cd;
778
779         /* data segment references resolving */
780
781         for (dr = cd->datareferences; dr != NULL; dr = dr->next)
782                 *((u1 **) (code->entrypoint + dr->datapos - SIZEOF_VOID_P)) = code->entrypoint;
783 }
784 #endif
785
786
787 /* dseg_display ****************************************************************
788
789    Displays the content of the methods' data segment.
790
791 *******************************************************************************/
792
793 #if !defined(NDEBUG)
794 void dseg_display(jitdata *jd)
795 {
796         codeinfo    *code;
797         codegendata *cd;
798         dsegentry   *de;
799         imm_union   val;
800
801         /* get required compiler data */
802
803         code = jd->code;
804         cd   = jd->cd;
805
806         if (opt_debugcolor)
807                 printf("\033[34m");     /* blue */
808
809         printf("  --- dump of datasegment\n");
810
811         /* process all data segment entries */
812
813         for (de = cd->dseg; de != NULL; de = de->next) {
814 #if SIZEOF_VOID_P == 8
815                 printf("0x%016lx:", (ptrint) (code->entrypoint + de->disp));
816 #else
817                 printf("0x%08x:", (ptrint) (code->entrypoint + de->disp));
818 #endif
819
820                 printf("    %6x (%6d): ", de->disp, de->disp);
821
822                 /* We read the values from the data segment as some values,
823                    like the line number table, have been written directly to
824                    the data segment. */
825
826                 switch (de->type) {
827                 case TYPE_INT:
828                         val.i = *((s4 *) (code->entrypoint + de->disp));
829                         printf("(INT) %d (0x%08x)", val.i, val.i);
830                         break;
831
832                 case TYPE_LNG:
833                         val.l = *((s8 *) (code->entrypoint + de->disp));
834 #if SIZEOF_VOID_P == 8
835                         printf("(LNG) %ld (0x%016lx)", val.l, val.l);
836 #else
837                         printf("(LNG) %lld (0x%016llx)", val.l, val.l);
838 #endif
839                         break;
840
841                 case TYPE_FLT:
842                         val.f = *((float *) (code->entrypoint + de->disp));
843                         printf("(FLT) %g (0x%08x)", val.f, val.i);
844                         break;
845
846                 case TYPE_DBL:
847                         val.d = *((double *) (code->entrypoint + de->disp));
848 #if SIZEOF_VOID_P == 8
849                         printf("(DBL) %g (0x%016lx)", val.d, val.l);
850 #else
851                         printf("(DBL) %g (0x%016llx)", val.d, val.l);
852 #endif
853                         break;
854
855                 case TYPE_ADR:
856                         val.a = *((void **) (code->entrypoint + de->disp));
857 #if SIZEOF_VOID_P == 8
858                         printf("(ADR) %016lx", (ptrint) val.a);
859 #else
860                         printf("(ADR) %08x", (ptrint) val.a);
861 #endif
862                         break;
863                 }
864
865                 printf("\n");
866         }
867
868         printf("  --- begin of data segment: ");
869 #if SIZEOF_VOID_P == 8
870         printf("0x%016lx\n", (ptrint) code->entrypoint);
871 #else
872         printf("0x%08x\n", (ptrint) code->entrypoint);
873 #endif
874
875         if (opt_debugcolor)
876                 printf("\033[m");
877 }
878 #endif /* !defined(NDEBUG) */
879
880
881 /*
882  * These are local overrides for various environment variables in Emacs.
883  * Please do not remove this and leave it at the end of the file, where
884  * Emacs will automagically detect them.
885  * ---------------------------------------------------------------------
886  * Local variables:
887  * mode: c
888  * indent-tabs-mode: t
889  * c-basic-offset: 4
890  * tab-width: 4
891  * End:
892  * vim:noexpandtab:sw=4:ts=4:
893  */