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