* src/mm/memory.cpp,
[cacao.git] / src / vm / jit / dseg.c
1 /* src/vm/jit/dseg.c - data segment handling stuff
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29
30 #include "vm/types.h"
31
32 #include "mm/memory.hpp"
33
34 #include "vm/options.h"
35
36 #include "vm/jit/codegen-common.hpp"
37 #include "vm/jit/methodheader.h"
38
39
40 /* dseg_finish *****************************************************************
41
42    Fills the data segment with the values stored.
43
44 *******************************************************************************/
45
46 void dseg_finish(jitdata *jd)
47 {
48         codeinfo    *code;
49         codegendata *cd;
50         dsegentry   *de;
51
52         /* get required compiler data */
53
54         code = jd->code;
55         cd   = jd->cd;
56
57         /* process all data segment entries */
58
59         for (de = cd->dseg; de != NULL; de = de->next) {
60                 switch (de->type) {
61                 case TYPE_INT:
62                         *((s4 *)     (code->entrypoint + de->disp)) = de->val.i;
63                         break;
64
65                 case TYPE_LNG:
66                         *((s8 *)     (code->entrypoint + de->disp)) = de->val.l;
67                         break;
68
69                 case TYPE_FLT:
70                         *((float *)  (code->entrypoint + de->disp)) = de->val.f;
71                         break;
72
73                 case TYPE_DBL:
74                         *((double *) (code->entrypoint + de->disp)) = de->val.d;
75                         break;
76
77                 case TYPE_ADR:
78                         *((void **)  (code->entrypoint + de->disp)) = de->val.a;
79                         break;
80                 }
81         }
82 }
83
84
85 static s4 dseg_find_s4(codegendata *cd, s4 value)
86 {
87         dsegentry *de;
88
89         /* search all data segment entries for a matching entry */
90
91         for (de = cd->dseg; de != NULL; de = de->next) {
92                 if (IS_INT_TYPE(de->type))
93                         if (de->flags & DSEG_FLAG_READONLY)
94                                 if (de->val.i == value)
95                                         return de->disp;
96         }
97
98         /* no matching entry was found */
99
100         return 0;
101 }
102
103
104 static s4 dseg_find_s8(codegendata *cd, s8 value)
105 {
106         dsegentry *de;
107
108         /* search all data segment entries for a matching entry */
109
110         for (de = cd->dseg; de != NULL; de = de->next) {
111                 if (IS_LNG_TYPE(de->type))
112                         if (de->flags & DSEG_FLAG_READONLY)
113                                 if (de->val.l == value)
114                                         return de->disp;
115         }
116
117         /* no matching entry was found */
118
119         return 0;
120 }
121
122
123 static s4 dseg_find_float(codegendata *cd, float value)
124 {
125         dsegentry *de;
126         imm_union  val;
127
128         /* we compare the hex value of the float as 0.0 == -0.0 */
129
130         val.f = value;
131
132         /* search all data segment entries for a matching entry */
133
134         for (de = cd->dseg; de != NULL; de = de->next) {
135                 if (IS_FLT_TYPE(de->type))
136                         if (de->flags & DSEG_FLAG_READONLY)
137                                 if (de->val.i == val.i)
138                                         return de->disp;
139         }
140
141         /* no matching entry was found */
142
143         return 0;
144 }
145
146
147 static s4 dseg_find_double(codegendata *cd, double value)
148 {
149         dsegentry *de;
150         imm_union  val;
151
152         /* we compare the hex value of the double as 0.0 == -0.0 */
153
154         val.d = value;
155
156         /* search all data segment entries for a matching entry */
157
158         for (de = cd->dseg; de != NULL; de = de->next) {
159                 if (IS_DBL_TYPE(de->type))
160                         if (de->flags & DSEG_FLAG_READONLY)
161                                 if (de->val.l == val.l)
162                                         return de->disp;
163         }
164
165         /* no matching entry was found */
166
167         return 0;
168 }
169
170
171 static s4 dseg_find_address(codegendata *cd, void *value)
172 {
173         dsegentry *de;
174
175         /* search all data segment entries for a matching entry */
176
177         for (de = cd->dseg; de != NULL; de = de->next) {
178                 if (IS_ADR_TYPE(de->type))
179                         if (de->flags & DSEG_FLAG_READONLY)
180                                 if (de->val.a == value)
181                                         return de->disp;
182         }
183
184         /* no matching entry was found */
185
186         return 0;
187 }
188
189
190 /* dseg_add_s4_intern **********************************************************
191
192    Internal function to add an s4 value to the data segment.
193
194 *******************************************************************************/
195
196 static s4 dseg_add_s4_intern(codegendata *cd, s4 value, u4 flags)
197 {
198         dsegentry *de;
199
200         /* Increase data segment size, which is also the displacement into
201            the data segment. */
202
203         cd->dseglen += 4;
204
205         /* allocate new entry */
206
207         de = DNEW(dsegentry);
208
209         de->type  = TYPE_INT;
210         de->flags = flags;
211         de->disp  = -(cd->dseglen);
212         de->val.i = value;
213         de->next  = cd->dseg;
214
215         /* insert into the chain */
216
217         cd->dseg = de;
218
219         return de->disp;
220 }
221
222
223 /* dseg_add_unique_s4 **********************************************************
224
225    Adds uniquely an s4 value to the data segment.
226
227 *******************************************************************************/
228
229 s4 dseg_add_unique_s4(codegendata *cd, s4 value)
230 {
231         s4 disp;
232
233         disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_UNIQUE);
234
235         return disp;
236 }
237
238
239 /* dseg_add_s4 *****************************************************************
240
241    Adds an s4 value to the data segment. It tries to reuse previously
242    added values.
243
244 *******************************************************************************/
245
246 s4 dseg_add_s4(codegendata *cd, s4 value)
247 {
248         s4 disp;
249
250         /* search the data segment if the value is already stored */
251
252         disp = dseg_find_s4(cd, value);
253
254         if (disp != 0)
255                 return disp;
256                 
257         disp = dseg_add_s4_intern(cd, value, DSEG_FLAG_READONLY);
258
259         return disp;
260 }
261
262
263 /* dseg_add_s8_intern **********************************************************
264
265    Internal function to add an s8 value to the data segment.
266
267 *******************************************************************************/
268
269 static s4 dseg_add_s8_intern(codegendata *cd, s8 value, u4 flags)
270 {
271         dsegentry *de;
272
273         /* Increase data segment size, which is also the displacement into
274            the data segment. */
275
276         cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
277
278         /* allocate new entry */
279
280         de = DNEW(dsegentry);
281
282         de->type  = TYPE_LNG;
283         de->flags = flags;
284         de->disp  = -(cd->dseglen);
285         de->val.l = value;
286         de->next  = cd->dseg;
287
288         /* insert into the chain */
289
290         cd->dseg = de;
291
292         return de->disp;
293 }
294
295
296 /* dseg_add_unique_s8 **********************************************************
297
298    Adds uniquely an s8 value to the data segment.
299
300 *******************************************************************************/
301
302 s4 dseg_add_unique_s8(codegendata *cd, s8 value)
303 {
304         s4 disp;
305
306         disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_UNIQUE);
307
308         return disp;
309 }
310
311
312 /* dseg_add_s8 *****************************************************************
313
314    Adds an s8 value to the data segment. It tries to reuse previously
315    added values.
316
317 *******************************************************************************/
318
319 s4 dseg_add_s8(codegendata *cd, s8 value)
320 {
321         s4 disp;
322
323         /* search the data segment if the value is already stored */
324
325         disp = dseg_find_s8(cd, value);
326
327         if (disp != 0)
328                 return disp;
329                 
330         disp = dseg_add_s8_intern(cd, value, DSEG_FLAG_READONLY);
331
332         return disp;
333 }
334
335
336 /* dseg_add_float_intern *******************************************************
337
338    Internal function to add a float value to the data segment.
339
340 *******************************************************************************/
341
342 static s4 dseg_add_float_intern(codegendata *cd, float value, u4 flags)
343 {
344         dsegentry *de;
345                 
346         /* Increase data segment size, which is also the displacement into
347            the data segment. */
348
349         cd->dseglen += 4;
350
351         /* allocate new entry */
352
353         de = DNEW(dsegentry);
354
355         de->type  = TYPE_FLT;
356         de->flags = flags;
357         de->disp  = -(cd->dseglen);
358         de->val.f = value;
359         de->next  = cd->dseg;
360
361         /* insert into the chain */
362
363         cd->dseg = de;
364
365         return de->disp;
366 }
367
368
369 /* dseg_add_unique_float *******************************************************
370
371    Adds uniquely an float value to the data segment.
372
373 *******************************************************************************/
374
375 s4 dseg_add_unique_float(codegendata *cd, float value)
376 {
377         s4 disp;
378
379         disp = dseg_add_float_intern(cd, value, DSEG_FLAG_UNIQUE);
380
381         return disp;
382 }
383
384
385 /* dseg_add_float **************************************************************
386
387    Adds an float value to the data segment. It tries to reuse
388    previously added values.
389
390 *******************************************************************************/
391
392 s4 dseg_add_float(codegendata *cd, float value)
393 {
394         s4 disp;
395
396         /* search the data segment if the value is already stored */
397
398         disp = dseg_find_float(cd, value);
399
400         if (disp != 0)
401                 return disp;
402                 
403         disp = dseg_add_float_intern(cd, value, DSEG_FLAG_READONLY);
404
405         return disp;
406 }
407
408
409 /* dseg_add_double_intern ******************************************************
410
411    Internal function to add a double value to the data segment.
412
413 *******************************************************************************/
414
415 static s4 dseg_add_double_intern(codegendata *cd, double value, u4 flags)
416 {
417         dsegentry *de;
418                 
419         /* Increase data segment size, which is also the displacement into
420            the data segment. */
421
422         cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
423
424         /* allocate new entry */
425
426         de = DNEW(dsegentry);
427
428         de->type  = TYPE_DBL;
429         de->flags = flags;
430         de->disp  = -(cd->dseglen);
431         de->val.d = value;
432         de->next  = cd->dseg;
433
434         /* insert into the chain */
435
436         cd->dseg = de;
437
438         return de->disp;
439 }
440
441
442 /* dseg_add_unique_double ******************************************************
443
444    Adds uniquely a double value to the data segment.
445
446 *******************************************************************************/
447
448 s4 dseg_add_unique_double(codegendata *cd, double value)
449 {
450         s4 disp;
451
452         disp = dseg_add_double_intern(cd, value, DSEG_FLAG_UNIQUE);
453
454         return disp;
455 }
456
457
458 /* dseg_add_double *************************************************************
459
460    Adds a double value to the data segment. It tries to reuse
461    previously added values.
462
463 *******************************************************************************/
464
465 s4 dseg_add_double(codegendata *cd, double value)
466 {
467         s4 disp;
468
469         /* search the data segment if the value is already stored */
470
471         disp = dseg_find_double(cd, value);
472
473         if (disp != 0)
474                 return disp;
475                 
476         disp = dseg_add_double_intern(cd, value, DSEG_FLAG_READONLY);
477
478         return disp;
479 }
480
481
482 /* dseg_add_address_intern *****************************************************
483
484    Internal function to add an address pointer to the data segment.
485
486 *******************************************************************************/
487
488 static s4 dseg_add_address_intern(codegendata *cd, void *value, u4 flags)
489 {
490         dsegentry *de;
491
492         /* Increase data segment size, which is also the displacement into
493            the data segment. */
494
495 #if SIZEOF_VOID_P == 8
496         cd->dseglen = MEMORY_ALIGN(cd->dseglen + 8, 8);
497 #else
498         cd->dseglen += 4;
499 #endif
500
501         /* allocate new entry */
502
503         de = DNEW(dsegentry);
504
505         de->type  = TYPE_ADR;
506         de->flags = flags;
507         de->disp  = -(cd->dseglen);
508         de->val.a = value;
509         de->next  = cd->dseg;
510
511         /* insert into the chain */
512
513         cd->dseg = de;
514
515         return de->disp;
516 }
517
518
519 /* dseg_add_unique_address *****************************************************
520
521    Adds uniquely an address value to the data segment.
522
523 *******************************************************************************/
524
525 s4 dseg_add_unique_address(codegendata *cd, void *value)
526 {
527         s4 disp;
528
529         disp = dseg_add_address_intern(cd, value, DSEG_FLAG_UNIQUE);
530
531         return disp;
532 }
533
534
535 /* dseg_add_address ************************************************************
536
537    Adds an address value to the data segment. It tries to reuse
538    previously added values.
539
540 *******************************************************************************/
541
542 s4 dseg_add_address(codegendata *cd, void *value)
543 {
544         s4 disp;
545
546         /* search the data segment if the value is already stored */
547
548         disp = dseg_find_address(cd, value);
549
550         if (disp != 0)
551                 return disp;
552                 
553         disp = dseg_add_address_intern(cd, value, DSEG_FLAG_READONLY);
554
555         return disp;
556 }
557
558
559 /* dseg_add_target *************************************************************
560
561    XXX
562
563 *******************************************************************************/
564
565 void dseg_add_target(codegendata *cd, basicblock *target)
566 {
567         jumpref *jr;
568
569         jr = DNEW(jumpref);
570
571         jr->tablepos = dseg_add_unique_address(cd, NULL);
572         jr->target   = target;
573         jr->next     = cd->jumpreferences;
574
575         cd->jumpreferences = jr;
576 }
577
578
579 /* dseg_adddata ****************************************************************
580
581    Adds a data segment reference to the codegendata.
582
583 *******************************************************************************/
584
585 #if defined(__I386__) || defined(__X86_64__) || defined(__S390__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
586 void dseg_adddata(codegendata *cd)
587 {
588         dataref *dr;
589
590         dr = DNEW(dataref);
591
592         dr->datapos = cd->mcodeptr - cd->mcodebase;
593         dr->next    = cd->datareferences;
594
595         cd->datareferences = dr;
596 }
597 #endif
598
599
600 /* dseg_resolve_datareferences *************************************************
601
602    Resolve data segment references.
603
604 *******************************************************************************/
605
606 #if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
607 void dseg_resolve_datareferences(jitdata *jd)
608 {
609         codeinfo    *code;
610         codegendata *cd;
611         dataref     *dr;
612
613         /* get required compiler data */
614
615         code = jd->code;
616         cd   = jd->cd;
617
618         /* data segment references resolving */
619
620         for (dr = cd->datareferences; dr != NULL; dr = dr->next)
621                 *((u1 **) (code->entrypoint + dr->datapos - SIZEOF_VOID_P)) = code->entrypoint;
622 }
623 #endif
624
625
626 /* dseg_display ****************************************************************
627
628    Displays the content of the methods' data segment.
629
630 *******************************************************************************/
631
632 #if !defined(NDEBUG)
633 void dseg_display(jitdata *jd)
634 {
635         codeinfo    *code;
636         codegendata *cd;
637         dsegentry   *de;
638         imm_union   val;
639
640         /* get required compiler data */
641
642         code = jd->code;
643         cd   = jd->cd;
644
645         if (opt_debugcolor)
646                 printf("\033[34m");     /* blue */
647
648         printf("  --- dump of datasegment\n");
649
650         /* process all data segment entries */
651
652         for (de = cd->dseg; de != NULL; de = de->next) {
653 #if SIZEOF_VOID_P == 8
654                 printf("0x%016lx:", (ptrint) (code->entrypoint + de->disp));
655 #else
656                 printf("0x%08x:", (ptrint) (code->entrypoint + de->disp));
657 #endif
658
659                 printf("    %6x (%6d): ", de->disp, de->disp);
660
661                 /* We read the values from the data segment as some values,
662                    like the line number table, have been written directly to
663                    the data segment. */
664
665                 switch (de->type) {
666                 case TYPE_INT:
667                         val.i = *((s4 *) (code->entrypoint + de->disp));
668                         printf("(INT) %d (0x%08x)", val.i, val.i);
669                         break;
670
671                 case TYPE_LNG:
672                         val.l = *((s8 *) (code->entrypoint + de->disp));
673 #if SIZEOF_VOID_P == 8
674                         printf("(LNG) %ld (0x%016lx)", val.l, val.l);
675 #else
676                         printf("(LNG) %lld (0x%016llx)", val.l, val.l);
677 #endif
678                         break;
679
680                 case TYPE_FLT:
681                         val.f = *((float *) (code->entrypoint + de->disp));
682                         printf("(FLT) %g (0x%08x)", val.f, val.i);
683                         break;
684
685                 case TYPE_DBL:
686                         val.d = *((double *) (code->entrypoint + de->disp));
687 #if SIZEOF_VOID_P == 8
688                         printf("(DBL) %g (0x%016lx)", val.d, val.l);
689 #else
690                         printf("(DBL) %g (0x%016llx)", val.d, val.l);
691 #endif
692                         break;
693
694                 case TYPE_ADR:
695                         val.a = *((void **) (code->entrypoint + de->disp));
696 #if SIZEOF_VOID_P == 8
697                         printf("(ADR) %016lx", (ptrint) val.a);
698 #else
699                         printf("(ADR) %08x", (ptrint) val.a);
700 #endif
701                         break;
702                 }
703
704                 printf("\n");
705         }
706
707         printf("  --- begin of data segment: ");
708 #if SIZEOF_VOID_P == 8
709         printf("0x%016lx\n", (ptrint) code->entrypoint);
710 #else
711         printf("0x%08x\n", (ptrint) code->entrypoint);
712 #endif
713
714         if (opt_debugcolor)
715                 printf("\033[m");
716 }
717 #endif /* !defined(NDEBUG) */
718
719
720 /*
721  * These are local overrides for various environment variables in Emacs.
722  * Please do not remove this and leave it at the end of the file, where
723  * Emacs will automagically detect them.
724  * ---------------------------------------------------------------------
725  * Local variables:
726  * mode: c
727  * indent-tabs-mode: t
728  * c-basic-offset: 4
729  * tab-width: 4
730  * End:
731  * vim:noexpandtab:sw=4:ts=4:
732  */