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