comments
[cacao.git] / 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 592 2003-11-09 19:46:15Z twisti $
52
53 */
54
55
56 #include <string.h>
57 #include "toolbox/memory.h"
58 #include "toolbox/loging.h"
59
60
61 #define MCODEINITSIZE (1<<15)       /* 32 Kbyte code area initialization size */
62 #define DSEGINITSIZE  (1<<12)       /*  4 Kbyte data area initialization size */
63
64 static u1* mcodebase = NULL;        /* base pointer of code area              */
65 static s4* mcodeend  = NULL;        /* pointer to end of code area            */
66 static int mcodesize;               /* complete size of code area (bytes)     */
67
68 static u1* dsegtop = NULL;          /* pointer to top (end) of data area      */
69 static int dsegsize;                /* complete size of data area (bytes)     */
70 int dseglen;                        /* used size of data area (bytes)         */
71                                     /* data area grows from top to bottom     */
72
73 static jumpref *jumpreferences;     /* list of jumptable target addresses     */
74 static dataref *datareferences;     /* list of data segment references        */
75 static branchref *xboundrefs;       /* list of bound check branches           */
76 static branchref *xcheckarefs;      /* list of array size check branches      */
77 static branchref *xnullrefs;        /* list of null check branches            */
78 static branchref *xcastrefs;        /* list of cast check branches            */
79 static branchref *xdivrefs;         /* list of divide by zero branches        */
80
81 int parentargs_base; /* offset in stackframe for the parameter from the caller*/
82
83 void codegen_init();                /* allocates code and data area           */
84 void codegen_close();               /* releases temporary storage             */
85 static void codegen_finish();       /* makes code and data area permanent and */
86                                     /* updates branch references to code/data */
87
88 static s4 dseg_adds4(s4 value);         /* adds an int to data area           */
89 static s4 dseg_adds8(s8 value);         /* adds an long to data area          */
90 static s4 dseg_addfloat (float value);  /* adds an float to data area         */
91 static s4 dseg_adddouble(double value); /* adds an double to data area        */
92
93 #if POINTERSIZE == 8
94 #define dseg_addaddress(value)      dseg_adds8((s8)(value))
95 #else
96 #define dseg_addaddress(value)      dseg_adds4((s4)(value))
97 #endif
98
99 static void dseg_addtarget(basicblock *target);
100 static void dseg_adddata(u1 *ptr);
101 static void codegen_addreference(basicblock *target, void *branchptr);
102 static void codegen_addxboundrefs(void *branchptr);
103 static void codegen_addxnullrefs(void *branchptr);
104 static void codegen_addxcastrefs(void *branchptr);
105 static void codegen_addxdivrefs(void *branchptr);
106
107 void dseg_display(s4 *s4ptr);
108
109
110
111 /* codegen_init allocates and initialises code area, data area and references   */
112
113 void codegen_init()
114 {
115         if (!mcodebase) {
116                 mcodebase = MNEW(u1, MCODEINITSIZE);
117                 mcodesize = MCODEINITSIZE;
118         }
119
120         if (!dsegtop) {
121                 dsegtop = MNEW(u1, DSEGINITSIZE);
122                 dsegsize = DSEGINITSIZE;
123                 dsegtop += dsegsize;
124         }
125
126         dseglen = 0;
127
128         jumpreferences = NULL;
129         datareferences = NULL;
130         xboundrefs = NULL;
131         xnullrefs = NULL;
132         xcastrefs = NULL;
133         xdivrefs = NULL;
134 }
135
136
137
138 /* codegen_close releases temporary code and data area                          */
139
140 void codegen_close()
141 {
142         if (mcodebase) {
143                 MFREE(mcodebase, u1, mcodesize);
144                 mcodebase = NULL;
145         }
146
147         if (dsegtop) {
148                 MFREE(dsegtop - dsegsize, u1, dsegsize);
149                 dsegtop = NULL;
150         }
151 }
152
153
154
155 /* codegen_increase doubles code area                                           */
156
157 static s4 *codegen_increase(u1 *codeptr)
158 {
159         long len;
160
161         len = codeptr - mcodebase;
162         mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
163         mcodesize *= 2;
164         mcodeend = (s4*) (mcodebase + mcodesize);
165         return (s4*) (mcodebase + len);
166 }
167
168
169
170 /* desg_increase doubles data area                                            */
171
172 static void dseg_increase()
173 {
174         u1 *newstorage = MNEW(u1, dsegsize * 2);
175         memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
176         MFREE(dsegtop - dsegsize, u1, dsegsize);
177         dsegtop = newstorage;
178         dsegsize *= 2;
179         dsegtop += dsegsize;
180 }
181
182
183
184 static s4 dseg_adds4_increase(s4 value)
185 {
186         dseg_increase();
187         *((s4 *) (dsegtop - dseglen)) = value;
188         return -dseglen;
189 }
190
191
192
193 static s4 dseg_adds4(s4 value)
194 {
195         s4 *dataptr;
196
197         dseglen += 4;
198         dataptr = (s4 *) (dsegtop - dseglen);
199         if (dseglen > dsegsize)
200                 return dseg_adds4_increase(value);
201         *dataptr = value;
202         return -dseglen;
203 }
204
205
206
207 static s4 dseg_adds8_increase(s8 value)
208 {
209         dseg_increase();
210         *((s8 *) (dsegtop - dseglen)) = value;
211         return -dseglen;
212 }
213
214
215
216 static s4 dseg_adds8(s8 value)
217 {
218         s8 *dataptr;
219
220         dseglen = ALIGN (dseglen + 8, 8);
221         dataptr = (s8 *) (dsegtop - dseglen);
222         if (dseglen > dsegsize)
223                 return dseg_adds8_increase(value);
224         *dataptr = value;
225         return -dseglen;
226 }
227
228
229
230 static s4 dseg_addfloat_increase(float value)
231 {
232         dseg_increase();
233         *((float *) (dsegtop - dseglen)) = value;
234         return -dseglen;
235 }
236
237
238
239 static s4 dseg_addfloat(float value)
240 {
241         float *dataptr;
242
243         dseglen += 4;
244         dataptr = (float *) (dsegtop - dseglen);
245         if (dseglen > dsegsize)
246                 return dseg_addfloat_increase(value);
247         *dataptr = value;
248         return -dseglen;
249 }
250
251
252
253 static s4 dseg_adddouble_increase(double value)
254 {
255         dseg_increase();
256         *((double *) (dsegtop - dseglen)) = value;
257         return -dseglen;
258 }
259
260
261
262 static s4 dseg_adddouble(double value)
263 {
264         double *dataptr;
265
266         dseglen = ALIGN (dseglen + 8, 8);
267         dataptr = (double *) (dsegtop - dseglen);
268         if (dseglen > dsegsize)
269                 return dseg_adddouble_increase(value);
270         *dataptr = value;
271         return -dseglen;
272 }
273
274
275
276 static void dseg_addtarget(basicblock *target)
277 {
278         jumpref *jr = DNEW(jumpref);
279
280         jr->tablepos = dseg_addaddress(NULL);
281         jr->target = target;
282         jr->next = jumpreferences;
283         jumpreferences = jr;
284 }
285
286
287
288 static void dseg_adddata(u1 *ptr)
289 {
290         dataref *dr = DNEW(dataref);
291
292         dr->pos = (u1 *) (ptr - mcodebase);
293         dr->next = datareferences;
294         datareferences = dr;
295 }
296
297
298
299 static void codegen_addreference(basicblock *target, void *branchptr)
300 {
301         s4 branchpos = (u1*) branchptr - mcodebase;
302
303         if (target->mpc >= 0) {
304                 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
305         }
306         else {
307                 branchref *br = DNEW(branchref);
308
309                 br->branchpos = branchpos;
310                 br->next = target->branchrefs;
311                 target->branchrefs= br;
312         }
313 }
314
315
316
317 static void codegen_addxboundrefs(void *branchptr)
318 {
319         s4 branchpos = (u1*) branchptr - mcodebase;
320
321         branchref *br = DNEW(branchref);
322
323         br->branchpos = branchpos;
324         br->next = xboundrefs;
325         xboundrefs = br;
326 }
327
328
329
330 static void codegen_addxcheckarefs(void *branchptr)
331 {
332         s4 branchpos = (u1*) branchptr - mcodebase;
333
334         branchref *br = DNEW(branchref);
335
336         br->branchpos = branchpos;
337         br->next = xcheckarefs;
338         xcheckarefs = br;
339 }
340
341
342
343 static void codegen_addxnullrefs(void *branchptr)
344 {
345         s4 branchpos = (u1*) branchptr - mcodebase;
346
347         branchref *br = DNEW(branchref);
348
349         br->branchpos = branchpos;
350         br->next = xnullrefs;
351         xnullrefs = br;
352 }
353
354
355
356 static void codegen_addxcastrefs(void *branchptr)
357 {
358         s4 branchpos = (u1*) branchptr - mcodebase;
359
360         branchref *br = DNEW(branchref);
361
362         br->branchpos = branchpos;
363         br->next = xcastrefs;
364         xcastrefs = br;
365 }
366
367
368
369 static void codegen_addxdivrefs(void *branchptr)
370 {
371         s4 branchpos = (u1*) branchptr - mcodebase;
372
373         branchref *br = DNEW(branchref);
374
375         br->branchpos = branchpos;
376         br->next = xdivrefs;
377         xdivrefs = br;
378 }
379
380
381
382 static void codegen_finish(int mcodelen)
383 {
384         jumpref *jr;
385         u1 *epoint;
386
387         count_code_len += mcodelen;
388         count_data_len += dseglen;
389
390         dseglen = ALIGN(dseglen, MAX_ALIGN);
391
392         method -> mcodelength = mcodelen + dseglen;
393         method -> mcode = CNEW(u1, mcodelen + dseglen);
394
395         memcpy ( method->mcode, dsegtop - dseglen, dseglen);
396         memcpy ( method->mcode + dseglen, mcodebase, mcodelen);
397
398         method -> entrypoint = epoint = (u1*) (method->mcode + dseglen);
399
400         /* jump table resolving */
401         jr = jumpreferences;
402         while (jr != NULL) {
403             *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
404             jr = jr->next;
405         }
406
407 #if defined(__I386__) || defined(__X86_64__)
408         {
409                 dataref *dr;
410                 /* add method into datastructure to find the entrypoint */
411                 addmethod(method->entrypoint, method->entrypoint + mcodelen);
412         
413                 /* data segment references resolving */
414                 dr = datareferences;
415                 while (dr != NULL) {
416                         *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
417                         dr = dr->next;
418                 }
419         }
420 #endif
421 }
422
423
424
425 void dseg_display(s4 *s4ptr)
426 {
427         int i;
428         
429         printf("  --- dump of datasegment\n");
430         for (i = dseglen; i > 0 ; i -= 4) {
431                 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
432         }
433         printf("  --- begin of data segment: %p\n", s4ptr);
434 }
435
436
437 /*
438  * These are local overrides for various environment variables in Emacs.
439  * Please do not remove this and leave it at the end of the file, where
440  * Emacs will automagically detect them.
441  * ---------------------------------------------------------------------
442  * Local variables:
443  * mode: c
444  * indent-tabs-mode: t
445  * c-basic-offset: 4
446  * tab-width: 4
447  * End:
448  */