Changed xoomrefs to xexceptionrefs.
[cacao.git] / src / vm / jit / codegen.inc
1 /* jit/codegen.inc - architecture independent code generator
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    Institut f. Computersprachen, TU Wien
5    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Probst,
6    S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich,
7    J. Wenninger
8
9    This file is part of CACAO.
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2, or (at
14    your option) any later version.
15
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24    02111-1307, USA.
25
26    Contact: cacao@complang.tuwien.ac.at
27
28    Authors: Reinhard Grafl
29             Andreas  Krall
30
31    Changes: Michael Gschwind
32             Christian Thalinger
33
34    All functions assume the following code area / data area layout:
35
36    +-----------+
37    |           |
38    | code area | code area grows to higher addresses
39    |           |
40    +-----------+ <-- start of procedure
41    |           |
42    | data area | data area grows to lower addresses
43    |           |
44    +-----------+
45
46    The functions first write into a temporary code/data area allocated by
47    "codegen_init". "codegen_finish" copies the code and data area into permanent
48    memory. All functions writing values into the data area return the offset
49    relative the begin of the code area (start of procedure).    
50
51    $Id: codegen.inc 1099 2004-05-27 16:06:14Z twisti $
52
53 */
54
55
56 #include <string.h>
57 #include "toolbox/memory.h"
58 #include "toolbox/logging.h"
59 #include "toolbox/avl.h"
60 #include "threads/thread.h"
61
62
63 /************************* critical sections  *********************************/
64
65 struct threadcritnodetemp {
66         struct threadcritnodetemp *next;
67         int mcodebegin, mcodeend, mcoderestart;
68 };
69
70 #define MCODEINITSIZE (1<<15)       /* 32 Kbyte code area initialization size */
71 #define DSEGINITSIZE  (1<<12)       /*  4 Kbyte data area initialization size */
72
73 static u1* mcodebase = NULL;        /* base pointer of code area              */
74 static s4* mcodeend  = NULL;        /* pointer to end of code area            */
75 static int mcodesize;               /* complete size of code area (bytes)     */
76
77 static u1* dsegtop = NULL;          /* pointer to top (end) of data area      */
78 static int dsegsize;                /* complete size of data area (bytes)     */
79 int dseglen;                        /* used size of data area (bytes)         */
80                                     /* data area grows from top to bottom     */
81
82 static jumpref *jumpreferences;     /* list of jumptable target addresses     */
83 static dataref *datareferences;     /* list of data segment references        */
84 static branchref *xboundrefs;       /* list of bound check branches           */
85 static branchref *xcheckarefs;      /* list of array size check branches      */
86 static branchref *xnullrefs;        /* list of null check branches            */
87 static branchref *xcastrefs;        /* list of cast check branches            */
88 static branchref *xdivrefs;         /* list of divide by zero branches        */
89 static branchref *xexceptionrefs;   /* list of exception branches             */
90 static linenumberref *linenumberreferences; /*list of line numbers and the program counters of their first instruction*/
91 static s4 linenumbertablesizepos;
92 static s4 linenumbertablestartpos;
93 static s4 linenumbertab;
94
95 static struct threadcritnodetemp *threadcrit;
96                                     /* List of critical code regions          */
97 static struct threadcritnodetemp threadcritcurrent;
98 static int threadcritcount;         /* Number of critical regions             */
99
100 int parentargs_base; /* offset in stackframe for the parameter from the caller*/
101
102 void codegen_init();                /* allocates code and data area           */
103 void codegen_close();               /* releases temporary storage             */
104 static void codegen_finish();       /* makes code and data area permanent and */
105                                     /* updates branch references to code/data */
106
107 static s4 dseg_adds4(s4 value);         /* adds an int to data area           */
108
109 #if !defined(__I386__)
110 static s4 dseg_adds8(s8 value);         /* adds an long to data area          */
111 #endif
112
113 static s4 dseg_addfloat (float value);  /* adds an float to data area         */
114 static s4 dseg_adddouble(double value); /* adds an double to data area        */
115
116 #if POINTERSIZE == 8
117 #define dseg_addaddress(value)      dseg_adds8((s8)(value))
118 #else
119 #define dseg_addaddress(value)      dseg_adds4((s4)(value))
120 #endif
121
122 static void dseg_addtarget(basicblock *target);
123 static void dseg_adddata(u1 *ptr);
124 static void codegen_addreference(basicblock *target, void *branchptr);
125 static void codegen_addxboundrefs(void *branchptr, s4 reg);
126 static void codegen_addxnullrefs(void *branchptr);
127 static void codegen_addxcastrefs(void *branchptr);
128 static void codegen_addxdivrefs(void *branchptr);
129 static void codegen_addxexceptionrefs(void *branchptr);
130 static void codegen_threadcritrestart(int offset);
131 static void codegen_threadcritstart(int offset);
132 static void codegen_threadcritstop(int offset);
133
134 #if defined(__I386__) || defined(__X86_64__)
135 typedef struct _methodtree_element methodtree_element;
136
137 struct _methodtree_element {
138         void *startpc;
139         void *endpc;
140 };
141
142 static struct avl_table *methodtree;
143 static int methodtree_comparator(const void *pc, const void *element,
144                                                                  void *param);
145 #endif
146
147 void dseg_display(s4 *s4ptr);
148
149
150
151 /* codegen_init allocates and initialises code area, data area and references */
152
153 void codegen_init()
154 {
155         if (!mcodebase) {
156                 mcodebase = MNEW(u1, MCODEINITSIZE);
157                 mcodesize = MCODEINITSIZE;
158         }
159
160         if (!dsegtop) {
161                 dsegtop = MNEW(u1, DSEGINITSIZE);
162                 dsegsize = DSEGINITSIZE;
163                 dsegtop += dsegsize;
164         }
165
166         dseglen = 0;
167
168         linenumberreferences = NULL;
169         linenumbertablesizepos = 0;
170         linenumbertablestartpos = 0;
171         linenumbertab = 0;
172         jumpreferences = NULL;
173         datareferences = NULL;
174         xboundrefs = NULL;
175         xnullrefs = NULL;
176         xcastrefs = NULL;
177         xdivrefs = NULL;
178         xexceptionrefs = NULL;
179
180 #if defined(__I386__) || defined(__X86_64__)
181         methodtree = avl_create(methodtree_comparator, NULL, NULL);
182 #endif
183
184 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
185         threadcritcurrent.next = NULL;
186         threadcritcount = 0;
187 #endif
188 }
189
190
191
192 /* codegen_close releases temporary code and data area                        */
193
194 void codegen_close()
195 {
196         if (mcodebase) {
197                 MFREE(mcodebase, u1, mcodesize);
198                 mcodebase = NULL;
199         }
200
201         if (dsegtop) {
202                 MFREE(dsegtop - dsegsize, u1, dsegsize);
203                 dsegtop = NULL;
204         }
205 }
206
207
208
209 /* codegen_increase doubles code area                                         */
210
211 static s4 *codegen_increase(u1 *codeptr)
212 {
213         long len;
214
215         len = codeptr - mcodebase;
216         mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
217         mcodesize *= 2;
218         mcodeend = (s4*) (mcodebase + mcodesize);
219         return (s4*) (mcodebase + len);
220 }
221
222
223
224 /* desg_increase doubles data area                                            */
225
226 static void dseg_increase()
227 {
228         u1 *newstorage = MNEW(u1, dsegsize * 2);
229         memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
230         MFREE(dsegtop - dsegsize, u1, dsegsize);
231         dsegtop = newstorage;
232         dsegsize *= 2;
233         dsegtop += dsegsize;
234 }
235
236
237
238 static s4 dseg_adds4_increase(s4 value)
239 {
240         dseg_increase();
241         *((s4 *) (dsegtop - dseglen)) = value;
242         return -dseglen;
243 }
244
245
246
247 static s4 dseg_adds4(s4 value)
248 {
249         s4 *dataptr;
250
251         dseglen += 4;
252         dataptr = (s4 *) (dsegtop - dseglen);
253         if (dseglen > dsegsize)
254                 return dseg_adds4_increase(value);
255         *dataptr = value;
256         return -dseglen;
257 }
258
259
260
261 #if !defined(__I386__)
262 static s4 dseg_adds8_increase(s8 value)
263 {
264         dseg_increase();
265         *((s8 *) (dsegtop - dseglen)) = value;
266         return -dseglen;
267 }
268
269
270 static s4 dseg_adds8(s8 value)
271 {
272         s8 *dataptr;
273
274         dseglen = ALIGN (dseglen + 8, 8);
275         dataptr = (s8 *) (dsegtop - dseglen);
276         if (dseglen > dsegsize)
277                 return dseg_adds8_increase(value);
278         *dataptr = value;
279         return -dseglen;
280 }
281 #endif
282
283
284 static s4 dseg_addfloat_increase(float value)
285 {
286         dseg_increase();
287         *((float *) (dsegtop - dseglen)) = value;
288         return -dseglen;
289 }
290
291
292
293 static s4 dseg_addfloat(float value)
294 {
295         float *dataptr;
296
297         dseglen += 4;
298         dataptr = (float *) (dsegtop - dseglen);
299         if (dseglen > dsegsize)
300                 return dseg_addfloat_increase(value);
301         *dataptr = value;
302         return -dseglen;
303 }
304
305
306
307 static s4 dseg_adddouble_increase(double value)
308 {
309         dseg_increase();
310         *((double *) (dsegtop - dseglen)) = value;
311         return -dseglen;
312 }
313
314
315
316 static s4 dseg_adddouble(double value)
317 {
318         double *dataptr;
319
320         dseglen = ALIGN (dseglen + 8, 8);
321         dataptr = (double *) (dsegtop - dseglen);
322         if (dseglen > dsegsize)
323                 return dseg_adddouble_increase(value);
324         *dataptr = value;
325         return -dseglen;
326 }
327
328
329
330 static void dseg_addtarget(basicblock *target)
331 {
332         jumpref *jr = DNEW(jumpref);
333         
334         jr->tablepos = dseg_addaddress(NULL);
335         jr->target = target;
336         jr->next = jumpreferences;
337         jumpreferences = jr;
338 }
339
340
341
342 static void dseg_adddata(u1 *ptr)
343 {
344         dataref *dr = DNEW(dataref);
345
346         dr->pos = (u1 *) (ptr - mcodebase);
347         dr->next = datareferences;
348         datareferences = dr;
349 }
350
351 static void dseg_addlinenumbertablesize() {
352 #ifdef __ALPHA__
353         dseg_adds4(0); /*PADDING*/
354 #endif
355         linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
356
357         linenumbertablestartpos=dseg_addaddress(NULL);
358 #ifdef __ALPHA__
359         dseg_adds4(0); /*PADDING*/
360 #endif
361 }
362
363 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
364         linenumberref *lr=DNEW(linenumberref);
365         lr->linenumber=linenumber;
366         lr->tablepos=0;
367         lr->targetmpc=(ptr-mcodebase);
368         lr->next=linenumberreferences;
369         linenumberreferences=lr;
370 }
371
372 static void codegen_addreference(basicblock *target, void *branchptr)
373 {
374         s4 branchpos = (u1*) branchptr - mcodebase;
375
376         if (target->mpc >= 0) {
377                 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
378         }
379         else {
380                 branchref *br = DNEW(branchref);
381
382                 br->branchpos = branchpos;
383                 br->next = target->branchrefs;
384                 target->branchrefs= br;
385         }
386 }
387
388
389
390 static void codegen_addxboundrefs(void *branchptr, s4 reg)
391 {
392         s4 branchpos = (u1*) branchptr - mcodebase;
393
394         branchref *br = DNEW(branchref);
395
396         br->branchpos = branchpos;
397         br->reg = reg;
398         br->next = xboundrefs;
399         xboundrefs = br;
400 }
401
402
403
404 static void codegen_addxcheckarefs(void *branchptr)
405 {
406         s4 branchpos = (u1*) branchptr - mcodebase;
407
408         branchref *br = DNEW(branchref);
409
410         br->branchpos = branchpos;
411         br->next = xcheckarefs;
412         xcheckarefs = br;
413 }
414
415
416
417 static void codegen_addxnullrefs(void *branchptr)
418 {
419         s4 branchpos = (u1*) branchptr - mcodebase;
420
421         branchref *br = DNEW(branchref);
422
423         br->branchpos = branchpos;
424         br->next = xnullrefs;
425         xnullrefs = br;
426 }
427
428
429
430 static void codegen_addxcastrefs(void *branchptr)
431 {
432         s4 branchpos = (u1*) branchptr - mcodebase;
433
434         branchref *br = DNEW(branchref);
435
436         br->branchpos = branchpos;
437         br->next = xcastrefs;
438         xcastrefs = br;
439 }
440
441
442 static void codegen_addxexceptionrefs(void *branchptr)
443 {
444         s4 branchpos = (u1*) branchptr - mcodebase;
445
446         branchref *br = DNEW(branchref);
447
448         br->branchpos = branchpos;
449         br->next = xexceptionrefs;
450         xexceptionrefs = br;
451 }
452
453
454 static void codegen_addxdivrefs(void *branchptr)
455 {
456         s4 branchpos = (u1*) branchptr - mcodebase;
457
458         branchref *br = DNEW(branchref);
459
460         br->branchpos = branchpos;
461         br->next = xdivrefs;
462         xdivrefs = br;
463 }
464
465
466 static void codegen_createlinenumbertable() {
467 #ifdef __I386__
468         /*log_text("codegen_createlinnumbertable");*/
469         {
470                 linenumberref *lr;
471                 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
472                         /*log_text("Adding line number entry");*/
473                         lr->tablepos=dseg_addaddress(NULL);
474                         if (linenumbertab==0) linenumbertab=lr->tablepos;
475                         dseg_addaddress(lr->linenumber);
476                 }
477         }
478 #endif
479 }
480
481
482 #if defined(__I386__) || defined(__X86_64__)
483 static int methodtree_comparator(const void *pc, const void *element,
484                                                                  void *param)
485 {
486         methodtree_element *mtepc;
487         methodtree_element *mte;
488
489         mtepc = (methodtree_element *) pc;
490         mte = (methodtree_element *) element;
491
492         if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc) {
493                 return 0;
494
495         } else if (mtepc->startpc < mte->startpc) {
496                 return -1;
497
498         } else {
499                 return 1;
500         }
501 }
502
503
504 void *codegen_findmethod(void *pc)
505 {
506 #if 1
507         return findmethod(pc);
508 #else
509         methodtree_element *mtepc;
510         methodtree_element *mte;
511
512         mtepc = NEW(methodtree_element);
513         mtepc->startpc = pc;
514
515         mte = avl_find(methodtree, mtepc);
516
517         FREE(mtepc, methodtree_element);
518
519 /*      if (!mte) */
520 /*              throw_cacao_exception_exit(string_java_lang_InternalError, "cannot find function"); */
521
522         fprintf(stderr, "mte=%p\n", mte);
523         fprintf(stderr, "startpc=%p, endpc=%p\n", mte->startpc, mte->endpc);
524
525         return mte->startpc;
526 #endif
527 }
528 #endif
529
530
531 static void codegen_finish(int mcodelen)
532 {
533         jumpref *jr;
534         u1 *epoint;
535
536         int extralen = 0;
537
538 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
539         extralen += sizeof(threadcritnode) * threadcritcount;
540 #endif
541
542         count_code_len += mcodelen;
543         count_data_len += dseglen;
544
545         dseglen = ALIGN(dseglen, MAX_ALIGN);
546
547         method->mcodelength = mcodelen + dseglen;
548         method->mcode = CNEW(u1, mcodelen + dseglen + extralen);
549
550         memcpy(method->mcode, dsegtop - dseglen, dseglen);
551         memcpy(method->mcode + dseglen, mcodebase, mcodelen);
552
553         method->entrypoint = epoint = (u1 *) (method->mcode + dseglen);
554
555         /* jump table resolving */
556         jr = jumpreferences;
557         while (jr != NULL) {
558             *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
559             jr = jr->next;
560         }
561
562 #ifdef __I386__
563         /* line number table resolving */
564         {
565                 linenumberref *lr;
566                 #if POINTERSIZE == 8
567                         s8  lrtlen=0;
568                 #else
569                         s4  lrtlen=0;
570                 #endif
571
572                 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
573                         lrtlen++;
574                         *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
575                         /*log_text("resolving line number information");*/
576                 }
577                 
578                 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
579 #if POINTERSIZE == 8
580                 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
581 #else
582                 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
583 #endif
584
585         }
586 #endif
587 #if defined(__I386__) || defined(__X86_64__)
588         {
589                 dataref *dr;
590 #if 1
591                 /* add method into methodtree to find the entrypoint */
592                 addmethod(method->entrypoint, method->entrypoint + mcodelen);
593 #else
594                 methodtree_element *mte;
595                 methodtree_element *p;
596
597                 mte = NEW(methodtree_element);
598                 mte->startpc = method->entrypoint;
599                 mte->endpc = method->entrypoint + mcodelen;
600
601                 p = avl_insert(methodtree, mte);
602         printf("p=%p\n", p);
603 #endif
604
605                 /* data segment references resolving */
606                 dr = datareferences;
607                 while (dr != NULL) {
608                         *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
609                         dr = dr->next;
610                 }
611         }
612 #endif
613
614
615 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
616         {
617                 threadcritnode *n = (threadcritnode*) (method->mcode + mcodelen + dseglen);
618                 int i;
619                 struct threadcritnodetemp *nt = threadcrit;
620
621                 for (i=0; i<threadcritcount; i++)
622                 {
623                         n->mcodebegin = method->mcode + nt->mcodebegin;
624                         n->mcodeend = method->mcode + nt->mcodeend;
625                         n->mcoderestart = method->mcode + nt->mcoderestart;
626                         thread_registercritical(n);
627                         n++;
628                         nt = nt->next;
629                 }
630         }
631 #endif
632 }
633
634
635
636 void dseg_display(s4 *s4ptr)
637 {
638         int i;
639         
640         printf("  --- dump of datasegment\n");
641         for (i = dseglen; i > 0 ; i -= 4) {
642                 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
643         }
644         printf("  --- begin of data segment: %p\n", s4ptr);
645 }
646
647 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
648 void codegen_threadcritrestart(int offset)
649 {
650         threadcritcurrent.mcoderestart = offset;
651 }
652
653 void codegen_threadcritstart(int offset)
654 {
655         threadcritcurrent.mcodebegin = offset;
656 }
657
658 void codegen_threadcritstop(int offset)
659 {
660         threadcritcurrent.next = threadcrit;
661         threadcritcurrent.mcodeend = offset;
662         threadcrit = DNEW(struct threadcritnodetemp);
663         *threadcrit = threadcritcurrent;
664         threadcritcount++;
665 }
666 #endif
667
668 /*
669  * These are local overrides for various environment variables in Emacs.
670  * Please do not remove this and leave it at the end of the file, where
671  * Emacs will automagically detect them.
672  * ---------------------------------------------------------------------
673  * Local variables:
674  * mode: c
675  * indent-tabs-mode: t
676  * c-basic-offset: 4
677  * tab-width: 4
678  * End:
679  */