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