a few finalizer testcases, old thread implementation uses now VMThread, no mor contex...
[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 1173 2004-06-16 14:56:18Z jowenn $
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=0;
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         xcheckarefs = NULL;
176         xnullrefs = NULL;
177         xcastrefs = NULL;
178         xdivrefs = NULL;
179         xexceptionrefs = NULL;
180
181 #if defined(__I386__) || defined(__X86_64__)
182         if (!methodtree) {
183                 methodtree_element *mte;
184
185                 methodtree = avl_create(methodtree_comparator, NULL, NULL);
186
187                 mte = NEW(methodtree_element);
188
189                 mte->startpc = asm_calljavafunction;
190                 mte->endpc = asm_calljavafunction2-1;
191
192                 avl_insert(methodtree, mte);
193
194                 mte = NEW(methodtree_element);
195
196                 mte->startpc = asm_calljavafunction2;
197                 mte->endpc = asm_call_jit_compiler-1;
198
199                 avl_insert(methodtree, mte);
200         }
201 #endif
202
203 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
204         threadcritcurrent.next = NULL;
205         threadcritcount = 0;
206 #endif
207 }
208
209
210
211 /* codegen_close releases temporary code and data area                        */
212
213 void codegen_close()
214 {
215         if (mcodebase) {
216                 MFREE(mcodebase, u1, mcodesize);
217                 mcodebase = NULL;
218         }
219
220         if (dsegtop) {
221                 MFREE(dsegtop - dsegsize, u1, dsegsize);
222                 dsegtop = NULL;
223         }
224 }
225
226
227
228 /* codegen_increase doubles code area                                         */
229
230 static s4 *codegen_increase(u1 *codeptr)
231 {
232         long len;
233
234         len = codeptr - mcodebase;
235         mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
236         mcodesize *= 2;
237         mcodeend = (s4*) (mcodebase + mcodesize);
238         return (s4*) (mcodebase + len);
239 }
240
241
242
243 /* desg_increase doubles data area                                            */
244
245 static void dseg_increase()
246 {
247         u1 *newstorage = MNEW(u1, dsegsize * 2);
248         memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
249         MFREE(dsegtop - dsegsize, u1, dsegsize);
250         dsegtop = newstorage;
251         dsegsize *= 2;
252         dsegtop += dsegsize;
253 }
254
255
256
257 static s4 dseg_adds4_increase(s4 value)
258 {
259         dseg_increase();
260         *((s4 *) (dsegtop - dseglen)) = value;
261         return -dseglen;
262 }
263
264
265
266 static s4 dseg_adds4(s4 value)
267 {
268         s4 *dataptr;
269
270         dseglen += 4;
271         dataptr = (s4 *) (dsegtop - dseglen);
272         if (dseglen > dsegsize)
273                 return dseg_adds4_increase(value);
274         *dataptr = value;
275         return -dseglen;
276 }
277
278
279
280 #if !defined(__I386__)
281 static s4 dseg_adds8_increase(s8 value)
282 {
283         dseg_increase();
284         *((s8 *) (dsegtop - dseglen)) = value;
285         return -dseglen;
286 }
287
288
289 static s4 dseg_adds8(s8 value)
290 {
291         s8 *dataptr;
292
293         dseglen = ALIGN (dseglen + 8, 8);
294         dataptr = (s8 *) (dsegtop - dseglen);
295         if (dseglen > dsegsize)
296                 return dseg_adds8_increase(value);
297         *dataptr = value;
298         return -dseglen;
299 }
300 #endif
301
302
303 static s4 dseg_addfloat_increase(float value)
304 {
305         dseg_increase();
306         *((float *) (dsegtop - dseglen)) = value;
307         return -dseglen;
308 }
309
310
311
312 static s4 dseg_addfloat(float value)
313 {
314         float *dataptr;
315
316         dseglen += 4;
317         dataptr = (float *) (dsegtop - dseglen);
318         if (dseglen > dsegsize)
319                 return dseg_addfloat_increase(value);
320         *dataptr = value;
321         return -dseglen;
322 }
323
324
325
326 static s4 dseg_adddouble_increase(double value)
327 {
328         dseg_increase();
329         *((double *) (dsegtop - dseglen)) = value;
330         return -dseglen;
331 }
332
333
334
335 static s4 dseg_adddouble(double value)
336 {
337         double *dataptr;
338
339         dseglen = ALIGN (dseglen + 8, 8);
340         dataptr = (double *) (dsegtop - dseglen);
341         if (dseglen > dsegsize)
342                 return dseg_adddouble_increase(value);
343         *dataptr = value;
344         return -dseglen;
345 }
346
347
348
349 static void dseg_addtarget(basicblock *target)
350 {
351         jumpref *jr = DNEW(jumpref);
352         
353         jr->tablepos = dseg_addaddress(NULL);
354         jr->target = target;
355         jr->next = jumpreferences;
356         jumpreferences = jr;
357 }
358
359
360
361 static void dseg_adddata(u1 *ptr)
362 {
363         dataref *dr = DNEW(dataref);
364
365         dr->pos = (u1 *) (ptr - mcodebase);
366         dr->next = datareferences;
367         datareferences = dr;
368 }
369
370 static void dseg_addlinenumbertablesize() {
371 #ifdef __ALPHA__
372         dseg_adds4(0); /*PADDING*/
373 #endif
374         linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
375
376         linenumbertablestartpos=dseg_addaddress(NULL);
377 #ifdef __ALPHA__
378         dseg_adds4(0); /*PADDING*/
379 #endif
380 }
381
382 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
383         linenumberref *lr=DNEW(linenumberref);
384         lr->linenumber=linenumber;
385         lr->tablepos=0;
386         lr->targetmpc=(ptr-mcodebase);
387         lr->next=linenumberreferences;
388         linenumberreferences=lr;
389 }
390
391 static void codegen_addreference(basicblock *target, void *branchptr)
392 {
393         s4 branchpos = (u1*) branchptr - mcodebase;
394
395         if (target->mpc >= 0) {
396                 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
397         }
398         else {
399                 branchref *br = DNEW(branchref);
400
401                 br->branchpos = branchpos;
402                 br->next = target->branchrefs;
403                 target->branchrefs= br;
404         }
405 }
406
407
408
409 static void codegen_addxboundrefs(void *branchptr, s4 reg)
410 {
411         s4 branchpos = (u1*) branchptr - mcodebase;
412
413         branchref *br = DNEW(branchref);
414
415         br->branchpos = branchpos;
416         br->reg = reg;
417         br->next = xboundrefs;
418         xboundrefs = br;
419 }
420
421
422
423 static void codegen_addxcheckarefs(void *branchptr)
424 {
425         s4 branchpos = (u1*) branchptr - mcodebase;
426
427         branchref *br = DNEW(branchref);
428
429         br->branchpos = branchpos;
430         br->next = xcheckarefs;
431         xcheckarefs = br;
432 }
433
434
435
436 static void codegen_addxnullrefs(void *branchptr)
437 {
438         s4 branchpos = (u1*) branchptr - mcodebase;
439
440         branchref *br = DNEW(branchref);
441
442         br->branchpos = branchpos;
443         br->next = xnullrefs;
444         xnullrefs = br;
445 }
446
447
448
449 static void codegen_addxcastrefs(void *branchptr)
450 {
451         s4 branchpos = (u1*) branchptr - mcodebase;
452
453         branchref *br = DNEW(branchref);
454
455         br->branchpos = branchpos;
456         br->next = xcastrefs;
457         xcastrefs = br;
458 }
459
460
461 static void codegen_addxexceptionrefs(void *branchptr)
462 {
463         s4 branchpos = (u1*) branchptr - mcodebase;
464
465         branchref *br = DNEW(branchref);
466
467         br->branchpos = branchpos;
468         br->next = xexceptionrefs;
469         xexceptionrefs = br;
470 }
471
472
473 static void codegen_addxdivrefs(void *branchptr)
474 {
475         s4 branchpos = (u1*) branchptr - mcodebase;
476
477         branchref *br = DNEW(branchref);
478
479         br->branchpos = branchpos;
480         br->next = xdivrefs;
481         xdivrefs = br;
482 }
483
484
485 static void codegen_createlinenumbertable() {
486 #ifdef __I386__
487         /*log_text("codegen_createlinnumbertable");*/
488         {
489                 linenumberref *lr;
490                 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
491                         /*log_text("Adding line number entry");*/
492                         lr->tablepos=dseg_addaddress(NULL);
493                         if (linenumbertab==0) linenumbertab=lr->tablepos;
494                         dseg_addaddress(lr->linenumber);
495                 }
496         }
497 #endif
498 }
499
500
501 #if defined(__I386__) || defined(__X86_64__)
502 static int methodtree_comparator(const void *pc, const void *element,
503                                                                  void *param)
504 {
505         methodtree_element *mte;
506         methodtree_element *mtepc;
507
508         mte = (methodtree_element *) element;
509         mtepc = (methodtree_element *) pc;
510
511         /* compare both startpc and endpc of pc, even if they have the same value,
512            otherwise the avl_probe sometime thinks the element is still in the
513            tree */
514         if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
515                 mte->startpc <= mtepc->endpc   && mtepc->endpc   <= mte->endpc) {
516                 return 0;
517
518         } else if (mtepc->startpc < mte->startpc) {
519                 return -1;
520
521         } else {
522                 return 1;
523         }
524 }
525
526
527 #if 0
528 void *codegen_findmethod1(void *pc)
529 {
530         void * retVal=findmethod(pc);
531         methodinfo **ma=(methodinfo**)retVal;
532         methodinfo *m=ma[-1];
533         if (m)
534                 if (m->name)
535                         utf_display(m->name);
536                 else 
537                         log_text("No Name");
538         else log_text("No methodinfo");
539         return retVal;
540 }
541 #endif
542
543 void *codegen_findmethod(void *pc)
544 {
545         methodtree_element *mtepc;
546         methodtree_element *mte;
547
548         mtepc = NEW(methodtree_element);
549         mtepc->startpc = pc;
550         mtepc->endpc = pc;
551
552         mte = avl_find(methodtree, mtepc);
553
554         FREE(mtepc, methodtree_element);
555
556         if (!mte)
557                 throw_cacao_exception_exit(string_java_lang_InternalError, "cannot find function");
558
559         return mte->startpc;
560 }
561 #endif
562
563
564 static void codegen_finish(int mcodelen)
565 {
566         jumpref *jr;
567         u1 *epoint;
568
569         int extralen = 0;
570         int alignedlen;
571
572 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
573         extralen += sizeof(threadcritnode) * threadcritcount;
574 #endif
575
576         count_code_len += mcodelen;
577         count_data_len += dseglen;
578
579         dseglen = ALIGN(dseglen, MAX_ALIGN);
580         alignedlen = ALIGN(mcodelen, MAX_ALIGN) + dseglen;
581
582         method->mcodelength = mcodelen + dseglen;
583         method->mcode = CNEW(u1, alignedlen + extralen);
584
585         memcpy(method->mcode, dsegtop - dseglen, dseglen);
586         memcpy(method->mcode + dseglen, mcodebase, mcodelen);
587
588         method->entrypoint = epoint = (u1 *) (method->mcode + dseglen);
589
590         /* jump table resolving */
591         jr = jumpreferences;
592         while (jr != NULL) {
593             *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
594             jr = jr->next;
595         }
596
597 #ifdef __I386__
598         /* line number table resolving */
599         {
600                 linenumberref *lr;
601                 #if POINTERSIZE == 8
602                         s8  lrtlen=0;
603                 #else
604                         s4  lrtlen=0;
605                 #endif
606
607                 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
608                         lrtlen++;
609                         *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
610                         /*log_text("resolving line number information");*/
611                 }
612                 
613                 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
614 #if POINTERSIZE == 8
615                 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
616 #else
617                 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
618 #endif
619
620         }
621 #endif
622 #if defined(__I386__) || defined(__X86_64__)
623         {
624                 dataref *dr;
625
626                 /* add method into methodtree to find the entrypoint */
627                 methodtree_element *mte;
628
629                 mte = NEW(methodtree_element);
630                 mte->startpc = method->entrypoint;
631                 mte->endpc = method->entrypoint + mcodelen;
632
633                 if (avl_insert(methodtree, mte))
634                         panic("duplicate entry");
635
636                 /* data segment references resolving */
637                 dr = datareferences;
638                 while (dr != NULL) {
639                         *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
640                         dr = dr->next;
641                 }
642         }
643 #endif
644
645
646 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
647         {
648                 threadcritnode *n = (threadcritnode*) (method->mcode + alignedlen);
649                 int i;
650                 struct threadcritnodetemp *nt = threadcrit;
651
652                 for (i=0; i<threadcritcount; i++)
653                 {
654                         n->mcodebegin = method->mcode + nt->mcodebegin;
655                         n->mcodeend = method->mcode + nt->mcodeend;
656                         n->mcoderestart = method->mcode + nt->mcoderestart;
657                         thread_registercritical(n);
658                         n++;
659                         nt = nt->next;
660                 }
661         }
662 #endif
663 }
664
665
666 void codegen_insertNative(void *startpc,void *endpc) {
667                 methodtree_element *mte;
668
669         if (!methodtree) {
670                 methodtree_element *mte;
671
672                 methodtree = avl_create(methodtree_comparator, NULL, NULL);
673
674                 mte = NEW(methodtree_element);
675                 mte->startpc = asm_calljavafunction;
676                 mte->endpc = asm_calljavafunction2-1;
677                 avl_insert(methodtree, mte);
678
679                 mte = NEW(methodtree_element);
680                 mte->startpc = asm_calljavafunction2;
681                 mte->endpc = asm_call_jit_compiler-1;
682                 avl_insert(methodtree, mte);
683         }
684
685
686                 mte = NEW(methodtree_element);
687                 mte->startpc = startpc;
688                 mte->endpc = endpc;
689
690                 if (avl_insert(methodtree, mte))
691                         panic("duplicate entry");
692 }
693
694 void dseg_display(s4 *s4ptr)
695 {
696         int i;
697         
698         printf("  --- dump of datasegment\n");
699         for (i = dseglen; i > 0 ; i -= 4) {
700                 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
701         }
702         printf("  --- begin of data segment: %p\n", s4ptr);
703 }
704
705 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
706 void codegen_threadcritrestart(int offset)
707 {
708         threadcritcurrent.mcoderestart = offset;
709 }
710
711 void codegen_threadcritstart(int offset)
712 {
713         threadcritcurrent.mcodebegin = offset;
714 }
715
716 void codegen_threadcritstop(int offset)
717 {
718         threadcritcurrent.next = threadcrit;
719         threadcritcurrent.mcodeend = offset;
720         threadcrit = DNEW(struct threadcritnodetemp);
721         *threadcrit = threadcritcurrent;
722         threadcritcount++;
723 }
724 #endif
725
726 /*
727  * These are local overrides for various environment variables in Emacs.
728  * Please do not remove this and leave it at the end of the file, where
729  * Emacs will automagically detect them.
730  * ---------------------------------------------------------------------
731  * Local variables:
732  * mode: c
733  * indent-tabs-mode: t
734  * c-basic-offset: 4
735  * tab-width: 4
736  * End:
737  */