e3448940fbcdf13543dc54d4b8b38685823eef03
[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 1037 2004-04-26 16:36:48Z twisti $
52
53 */
54
55
56 #include <string.h>
57 #include "toolbox/memory.h"
58 #include "toolbox/loging.h"
59 #include "threads/thread.h"
60
61
62 /************************* critical sections  *********************************/
63
64 struct threadcritnodetemp {
65         struct threadcritnodetemp *next;
66         int mcodebegin, mcodeend;
67 };
68
69 #define MCODEINITSIZE (1<<15)       /* 32 Kbyte code area initialization size */
70 #define DSEGINITSIZE  (1<<12)       /*  4 Kbyte data area initialization size */
71
72 static u1* mcodebase = NULL;        /* base pointer of code area              */
73 static s4* mcodeend  = NULL;        /* pointer to end of code area            */
74 static int mcodesize;               /* complete size of code area (bytes)     */
75
76 static u1* dsegtop = NULL;          /* pointer to top (end) of data area      */
77 static int dsegsize;                /* complete size of data area (bytes)     */
78 int dseglen;                        /* used size of data area (bytes)         */
79                                     /* data area grows from top to bottom     */
80
81 static jumpref *jumpreferences;     /* list of jumptable target addresses     */
82 static dataref *datareferences;     /* list of data segment references        */
83 static branchref *xboundrefs;       /* list of bound check branches           */
84 static branchref *xcheckarefs;      /* list of array size check branches      */
85 static branchref *xnullrefs;        /* list of null check branches            */
86 static branchref *xcastrefs;        /* list of cast check branches            */
87 static branchref *xdivrefs;         /* list of divide by zero branches        */
88 static branchref *xoomrefs;         /* list of out of memory branches         */
89 static linenumberref *linenumberreferences; /*list of line numbers and the program counters of their first instruction*/
90 static s4 linenumbertablesizepos;
91 static s4 linenumbertablestartpos;
92 static s4 linenumbertab;
93
94 static struct threadcritnodetemp *threadcrit;
95                                     /* List of critical code regions          */
96 static struct threadcritnodetemp threadcritcurrent;
97 static int threadcritcount;         /* Number of critical regions             */
98
99 int parentargs_base; /* offset in stackframe for the parameter from the caller*/
100
101 void codegen_init();                /* allocates code and data area           */
102 void codegen_close();               /* releases temporary storage             */
103 static void codegen_finish();       /* makes code and data area permanent and */
104                                     /* updates branch references to code/data */
105
106 static s4 dseg_adds4(s4 value);         /* adds an int to data area           */
107 static s4 dseg_adds8(s8 value);         /* adds an long to data area          */
108 static s4 dseg_addfloat (float value);  /* adds an float to data area         */
109 static s4 dseg_adddouble(double value); /* adds an double to data area        */
110
111 #if POINTERSIZE == 8
112 #define dseg_addaddress(value)      dseg_adds8((s8)(value))
113 #else
114 #define dseg_addaddress(value)      dseg_adds4((s4)(value))
115 #endif
116
117 static void dseg_addtarget(basicblock *target);
118 static void dseg_adddata(u1 *ptr);
119 static void codegen_addreference(basicblock *target, void *branchptr);
120 static void codegen_addxboundrefs(void *branchptr, s4 reg);
121 static void codegen_addxnullrefs(void *branchptr);
122 static void codegen_addxcastrefs(void *branchptr);
123 static void codegen_addxdivrefs(void *branchptr);
124 static void codegen_addxoomrefs(void *branchptr);
125 static void codegen_threadcritstart(int offset);
126 static void codegen_threadcritstop(int offset);
127
128 void dseg_display(s4 *s4ptr);
129
130
131
132 /* codegen_init allocates and initialises code area, data area and references   */
133
134 void codegen_init()
135 {
136         if (!mcodebase) {
137                 mcodebase = MNEW(u1, MCODEINITSIZE);
138                 mcodesize = MCODEINITSIZE;
139         }
140
141         if (!dsegtop) {
142                 dsegtop = MNEW(u1, DSEGINITSIZE);
143                 dsegsize = DSEGINITSIZE;
144                 dsegtop += dsegsize;
145         }
146
147         dseglen = 0;
148
149         linenumberreferences=NULL;
150         linenumbertablesizepos=0;
151         linenumbertablestartpos=0;
152         linenumbertab=0;
153         jumpreferences = NULL;
154         datareferences = NULL;
155         xboundrefs = NULL;
156         xnullrefs = NULL;
157         xcastrefs = NULL;
158         xdivrefs = NULL;
159         xoomrefs = NULL;
160
161 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
162         threadcritcurrent.next = NULL;
163         threadcritcount = 0;
164 #endif
165 }
166
167
168
169 /* codegen_close releases temporary code and data area                          */
170
171 void codegen_close()
172 {
173         if (mcodebase) {
174                 MFREE(mcodebase, u1, mcodesize);
175                 mcodebase = NULL;
176         }
177
178         if (dsegtop) {
179                 MFREE(dsegtop - dsegsize, u1, dsegsize);
180                 dsegtop = NULL;
181         }
182 }
183
184
185
186 /* codegen_increase doubles code area                                           */
187
188 static s4 *codegen_increase(u1 *codeptr)
189 {
190         long len;
191
192         len = codeptr - mcodebase;
193         mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
194         mcodesize *= 2;
195         mcodeend = (s4*) (mcodebase + mcodesize);
196         return (s4*) (mcodebase + len);
197 }
198
199
200
201 /* desg_increase doubles data area                                            */
202
203 static void dseg_increase()
204 {
205         u1 *newstorage = MNEW(u1, dsegsize * 2);
206         memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
207         MFREE(dsegtop - dsegsize, u1, dsegsize);
208         dsegtop = newstorage;
209         dsegsize *= 2;
210         dsegtop += dsegsize;
211 }
212
213
214
215 static s4 dseg_adds4_increase(s4 value)
216 {
217         dseg_increase();
218         *((s4 *) (dsegtop - dseglen)) = value;
219         return -dseglen;
220 }
221
222
223
224 static s4 dseg_adds4(s4 value)
225 {
226         s4 *dataptr;
227
228         dseglen += 4;
229         dataptr = (s4 *) (dsegtop - dseglen);
230         if (dseglen > dsegsize)
231                 return dseg_adds4_increase(value);
232         *dataptr = value;
233         return -dseglen;
234 }
235
236
237
238 static s4 dseg_adds8_increase(s8 value)
239 {
240         dseg_increase();
241         *((s8 *) (dsegtop - dseglen)) = value;
242         return -dseglen;
243 }
244
245
246
247 static s4 dseg_adds8(s8 value)
248 {
249         s8 *dataptr;
250
251         dseglen = ALIGN (dseglen + 8, 8);
252         dataptr = (s8 *) (dsegtop - dseglen);
253         if (dseglen > dsegsize)
254                 return dseg_adds8_increase(value);
255         *dataptr = value;
256         return -dseglen;
257 }
258
259
260
261 static s4 dseg_addfloat_increase(float value)
262 {
263         dseg_increase();
264         *((float *) (dsegtop - dseglen)) = value;
265         return -dseglen;
266 }
267
268
269
270 static s4 dseg_addfloat(float value)
271 {
272         float *dataptr;
273
274         dseglen += 4;
275         dataptr = (float *) (dsegtop - dseglen);
276         if (dseglen > dsegsize)
277                 return dseg_addfloat_increase(value);
278         *dataptr = value;
279         return -dseglen;
280 }
281
282
283
284 static s4 dseg_adddouble_increase(double value)
285 {
286         dseg_increase();
287         *((double *) (dsegtop - dseglen)) = value;
288         return -dseglen;
289 }
290
291
292
293 static s4 dseg_adddouble(double value)
294 {
295         double *dataptr;
296
297         dseglen = ALIGN (dseglen + 8, 8);
298         dataptr = (double *) (dsegtop - dseglen);
299         if (dseglen > dsegsize)
300                 return dseg_adddouble_increase(value);
301         *dataptr = value;
302         return -dseglen;
303 }
304
305
306
307 static void dseg_addtarget(basicblock *target)
308 {
309         jumpref *jr = DNEW(jumpref);
310         
311         jr->tablepos = dseg_addaddress(NULL);
312         jr->target = target;
313         jr->next = jumpreferences;
314         jumpreferences = jr;
315 }
316
317
318
319 static void dseg_adddata(u1 *ptr)
320 {
321         dataref *dr = DNEW(dataref);
322
323         dr->pos = (u1 *) (ptr - mcodebase);
324         dr->next = datareferences;
325         datareferences = dr;
326 }
327
328 static void dseg_addlinenumbertablesize() {
329 #ifdef __ALPHA__
330         dseg_adds4(0); /*PADDING*/
331 #endif
332         linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
333
334         linenumbertablestartpos=dseg_addaddress(NULL);
335 #ifdef __ALPHA__
336         dseg_adds4(0); /*PADDING*/
337 #endif
338 }
339
340 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
341         linenumberref *lr=DNEW(linenumberref);
342         lr->linenumber=linenumber;
343         lr->tablepos=0;
344         lr->targetmpc=(ptr-mcodebase);
345         lr->next=linenumberreferences;
346         linenumberreferences=lr;
347 }
348
349 static void codegen_addreference(basicblock *target, void *branchptr)
350 {
351         s4 branchpos = (u1*) branchptr - mcodebase;
352
353         if (target->mpc >= 0) {
354                 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
355         }
356         else {
357                 branchref *br = DNEW(branchref);
358
359                 br->branchpos = branchpos;
360                 br->next = target->branchrefs;
361                 target->branchrefs= br;
362         }
363 }
364
365
366
367 static void codegen_addxboundrefs(void *branchptr, s4 reg)
368 {
369         s4 branchpos = (u1*) branchptr - mcodebase;
370
371         branchref *br = DNEW(branchref);
372
373         br->branchpos = branchpos;
374         br->reg = reg;
375         br->next = xboundrefs;
376         xboundrefs = br;
377 }
378
379
380
381 static void codegen_addxcheckarefs(void *branchptr)
382 {
383         s4 branchpos = (u1*) branchptr - mcodebase;
384
385         branchref *br = DNEW(branchref);
386
387         br->branchpos = branchpos;
388         br->next = xcheckarefs;
389         xcheckarefs = br;
390 }
391
392
393
394 static void codegen_addxnullrefs(void *branchptr)
395 {
396         s4 branchpos = (u1*) branchptr - mcodebase;
397
398         branchref *br = DNEW(branchref);
399
400         br->branchpos = branchpos;
401         br->next = xnullrefs;
402         xnullrefs = br;
403 }
404
405
406
407 static void codegen_addxcastrefs(void *branchptr)
408 {
409         s4 branchpos = (u1*) branchptr - mcodebase;
410
411         branchref *br = DNEW(branchref);
412
413         br->branchpos = branchpos;
414         br->next = xcastrefs;
415         xcastrefs = br;
416 }
417
418
419
420 static void codegen_addxoomrefs(void *branchptr)
421 {
422         s4 branchpos = (u1*) branchptr - mcodebase;
423
424         branchref *br = DNEW(branchref);
425
426         br->branchpos = branchpos;
427         br->next = xoomrefs;
428         xoomrefs = br;
429 }
430
431
432 static void codegen_addxdivrefs(void *branchptr)
433 {
434         s4 branchpos = (u1*) branchptr - mcodebase;
435
436         branchref *br = DNEW(branchref);
437
438         br->branchpos = branchpos;
439         br->next = xdivrefs;
440         xdivrefs = br;
441 }
442
443
444 static void codegen_createlinenumbertable() {
445 #ifdef __I386__
446         /*log_text("codegen_createlinnumbertable");*/
447         {
448                 linenumberref *lr;
449                 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
450                         /*log_text("Adding line number entry");*/
451                         lr->tablepos=dseg_addaddress(NULL);
452                         if (linenumbertab==0) linenumbertab=lr->tablepos;
453                         dseg_addaddress(lr->linenumber);
454                 }
455         }
456 #endif
457 }
458
459
460 static void codegen_finish(int mcodelen)
461 {
462         jumpref *jr;
463         u1 *epoint;
464
465         int extralen = 0;
466
467 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
468         extralen += sizeof(threadcritnode) * threadcritcount;
469 #endif
470
471         count_code_len += mcodelen;
472         count_data_len += dseglen;
473
474         dseglen = ALIGN(dseglen, MAX_ALIGN);
475
476         method -> mcodelength = mcodelen + dseglen;
477         method -> mcode = CNEW(u1, mcodelen + dseglen + extralen);
478
479         memcpy ( method->mcode, dsegtop - dseglen, dseglen);
480         memcpy ( method->mcode + dseglen, mcodebase, mcodelen);
481
482         method -> entrypoint = epoint = (u1*) (method->mcode + dseglen);
483
484         /* jump table resolving */
485         jr = jumpreferences;
486         while (jr != NULL) {
487             *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
488             jr = jr->next;
489         }
490
491 #ifdef __I386__
492         /* line number table resolving */
493         {
494                 linenumberref *lr;
495                 #if POINTERSIZE == 8
496                         s8  lrtlen=0;
497                 #else
498                         s4  lrtlen=0;
499                 #endif
500
501                 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
502                         lrtlen++;
503                         *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
504                         /*log_text("resolving line number information");*/
505                 }
506                 
507                 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
508 #if POINTERSIZE == 8
509                 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
510 #else
511                 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
512 #endif
513
514         }
515 #endif
516 #if defined(__I386__) || defined(__X86_64__)
517         {
518                 dataref *dr;
519                 /* add method into datastructure to find the entrypoint */
520                 addmethod(method->entrypoint, method->entrypoint + mcodelen);
521         
522                 /* data segment references resolving */
523                 dr = datareferences;
524                 while (dr != NULL) {
525                         *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
526                         dr = dr->next;
527                 }
528         }
529 #endif
530
531
532 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
533         {
534                 threadcritnode *n = (threadcritnode*) (method->mcode + mcodelen + dseglen);
535                 int i;
536                 struct threadcritnodetemp *nt = threadcrit;
537
538                 for (i=0; i<threadcritcount; i++)
539                 {
540                         n->mcodebegin = method->mcode + nt->mcodebegin;
541                         n->mcodeend = method->mcode + nt->mcodeend;
542                         thread_registercritical(n);
543                         n++;
544                         nt = nt->next;
545                 }
546         }
547 #endif
548 }
549
550
551
552 void dseg_display(s4 *s4ptr)
553 {
554         int i;
555         
556         printf("  --- dump of datasegment\n");
557         for (i = dseglen; i > 0 ; i -= 4) {
558                 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
559         }
560         printf("  --- begin of data segment: %p\n", s4ptr);
561 }
562
563 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
564 void codegen_threadcritstart(int offset)
565 {
566         threadcritcurrent.mcodebegin = offset;
567 }
568
569 void codegen_threadcritstop(int offset)
570 {
571         threadcritcurrent.next = threadcrit;
572         threadcritcurrent.mcodeend = offset;
573         threadcrit = DNEW(struct threadcritnodetemp);
574         *threadcrit = threadcritcurrent;
575         threadcritcount++;
576 }
577 #endif
578
579 /*
580  * These are local overrides for various environment variables in Emacs.
581  * Please do not remove this and leave it at the end of the file, where
582  * Emacs will automagically detect them.
583  * ---------------------------------------------------------------------
584  * Local variables:
585  * mode: c
586  * indent-tabs-mode: t
587  * c-basic-offset: 4
588  * tab-width: 4
589  * End:
590  */