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