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