1 /* jit/codegen.inc - architecture independent code generator
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,
9 This file is part of CACAO.
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.
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.
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
26 Contact: cacao@complang.tuwien.ac.at
28 Authors: Reinhard Grafl
31 Changes: Michael Gschwind
34 All functions assume the following code area / data area layout:
38 | code area | code area grows to higher addresses
40 +-----------+ <-- start of procedure
42 | data area | data area grows to lower addresses
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).
51 $Id: codegen.inc 963 2004-03-15 07:37:49Z jowenn $
57 #include "toolbox/memory.h"
58 #include "toolbox/loging.h"
59 #include "threads/thread.h"
62 /************************* critical sections *********************************/
64 struct threadcritnodetemp {
65 struct threadcritnodetemp *next;
66 int mcodebegin, mcodeend;
69 #define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */
70 #define DSEGINITSIZE (1<<12) /* 4 Kbyte data area initialization size */
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) */
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 */
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;
93 static struct threadcritnodetemp *threadcrit;
94 /* List of critical code regions */
95 static struct threadcritnodetemp threadcritcurrent;
96 static int threadcritcount; /* Number of critical regions */
98 int parentargs_base; /* offset in stackframe for the parameter from the caller*/
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 */
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 */
111 #define dseg_addaddress(value) dseg_adds8((s8)(value))
113 #define dseg_addaddress(value) dseg_adds4((s4)(value))
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);
126 void dseg_display(s4 *s4ptr);
130 /* codegen_init allocates and initialises code area, data area and references */
135 mcodebase = MNEW(u1, MCODEINITSIZE);
136 mcodesize = MCODEINITSIZE;
140 dsegtop = MNEW(u1, DSEGINITSIZE);
141 dsegsize = DSEGINITSIZE;
147 linenumberreferences=NULL;
148 linenumbertablesizepos=0;
149 linenumbertablestartpos=0;
151 jumpreferences = NULL;
152 datareferences = NULL;
158 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
159 threadcritcurrent.next = NULL;
166 /* codegen_close releases temporary code and data area */
171 MFREE(mcodebase, u1, mcodesize);
176 MFREE(dsegtop - dsegsize, u1, dsegsize);
183 /* codegen_increase doubles code area */
185 static s4 *codegen_increase(u1 *codeptr)
189 len = codeptr - mcodebase;
190 mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
192 mcodeend = (s4*) (mcodebase + mcodesize);
193 return (s4*) (mcodebase + len);
198 /* desg_increase doubles data area */
200 static void dseg_increase()
202 u1 *newstorage = MNEW(u1, dsegsize * 2);
203 memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
204 MFREE(dsegtop - dsegsize, u1, dsegsize);
205 dsegtop = newstorage;
212 static s4 dseg_adds4_increase(s4 value)
215 *((s4 *) (dsegtop - dseglen)) = value;
221 static s4 dseg_adds4(s4 value)
226 dataptr = (s4 *) (dsegtop - dseglen);
227 if (dseglen > dsegsize)
228 return dseg_adds4_increase(value);
235 static s4 dseg_adds8_increase(s8 value)
238 *((s8 *) (dsegtop - dseglen)) = value;
244 static s4 dseg_adds8(s8 value)
248 dseglen = ALIGN (dseglen + 8, 8);
249 dataptr = (s8 *) (dsegtop - dseglen);
250 if (dseglen > dsegsize)
251 return dseg_adds8_increase(value);
258 static s4 dseg_addfloat_increase(float value)
261 *((float *) (dsegtop - dseglen)) = value;
267 static s4 dseg_addfloat(float value)
272 dataptr = (float *) (dsegtop - dseglen);
273 if (dseglen > dsegsize)
274 return dseg_addfloat_increase(value);
281 static s4 dseg_adddouble_increase(double value)
284 *((double *) (dsegtop - dseglen)) = value;
290 static s4 dseg_adddouble(double value)
294 dseglen = ALIGN (dseglen + 8, 8);
295 dataptr = (double *) (dsegtop - dseglen);
296 if (dseglen > dsegsize)
297 return dseg_adddouble_increase(value);
304 static void dseg_addtarget(basicblock *target)
306 jumpref *jr = DNEW(jumpref);
308 jr->tablepos = dseg_addaddress(NULL);
310 jr->next = jumpreferences;
316 static void dseg_adddata(u1 *ptr)
318 dataref *dr = DNEW(dataref);
320 dr->pos = (u1 *) (ptr - mcodebase);
321 dr->next = datareferences;
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*/
330 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
331 linenumberref *lr=DNEW(linenumberref);
332 lr->linenumber=linenumber;
334 lr->targetmpc=(ptr-mcodebase);
335 lr->next=linenumberreferences;
336 linenumberreferences=lr;
339 static void codegen_addreference(basicblock *target, void *branchptr)
341 s4 branchpos = (u1*) branchptr - mcodebase;
343 if (target->mpc >= 0) {
344 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
347 branchref *br = DNEW(branchref);
349 br->branchpos = branchpos;
350 br->next = target->branchrefs;
351 target->branchrefs= br;
357 static void codegen_addxboundrefs(void *branchptr, s4 reg)
359 s4 branchpos = (u1*) branchptr - mcodebase;
361 branchref *br = DNEW(branchref);
363 br->branchpos = branchpos;
365 br->next = xboundrefs;
371 static void codegen_addxcheckarefs(void *branchptr)
373 s4 branchpos = (u1*) branchptr - mcodebase;
375 branchref *br = DNEW(branchref);
377 br->branchpos = branchpos;
378 br->next = xcheckarefs;
384 static void codegen_addxnullrefs(void *branchptr)
386 s4 branchpos = (u1*) branchptr - mcodebase;
388 branchref *br = DNEW(branchref);
390 br->branchpos = branchpos;
391 br->next = xnullrefs;
397 static void codegen_addxcastrefs(void *branchptr)
399 s4 branchpos = (u1*) branchptr - mcodebase;
401 branchref *br = DNEW(branchref);
403 br->branchpos = branchpos;
404 br->next = xcastrefs;
410 static void codegen_addxdivrefs(void *branchptr)
412 s4 branchpos = (u1*) branchptr - mcodebase;
414 branchref *br = DNEW(branchref);
416 br->branchpos = branchpos;
423 static void codegen_createlinenumbertable() {
425 /*log_text("codegen_createlinnumbertable");*/
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);
439 static void codegen_finish(int mcodelen)
446 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
447 extralen += sizeof(threadcritnode) * threadcritcount;
450 count_code_len += mcodelen;
451 count_data_len += dseglen;
453 dseglen = ALIGN(dseglen, MAX_ALIGN);
455 method -> mcodelength = mcodelen + dseglen;
456 method -> mcode = CNEW(u1, mcodelen + dseglen + extralen);
458 memcpy ( method->mcode, dsegtop - dseglen, dseglen);
459 memcpy ( method->mcode + dseglen, mcodebase, mcodelen);
461 method -> entrypoint = epoint = (u1*) (method->mcode + dseglen);
463 /* jump table resolving */
466 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
471 /* line number table resolving */
480 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
482 *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
483 /*log_text("resolving line number information");*/
486 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
488 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
490 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
495 #if defined(__I386__) || defined(__X86_64__)
498 /* add method into datastructure to find the entrypoint */
499 addmethod(method->entrypoint, method->entrypoint + mcodelen);
501 /* data segment references resolving */
504 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
511 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
513 threadcritnode *n = (threadcritnode*) (method->mcode + mcodelen + dseglen);
515 struct threadcritnodetemp *nt = threadcrit;
517 for (i=0; i<threadcritcount; i++)
519 n->mcodebegin = method->mcode + nt->mcodebegin;
520 n->mcodeend = method->mcode + nt->mcodeend;
521 thread_registercritical(n);
531 void dseg_display(s4 *s4ptr)
535 printf(" --- dump of datasegment\n");
536 for (i = dseglen; i > 0 ; i -= 4) {
537 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
539 printf(" --- begin of data segment: %p\n", s4ptr);
542 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
543 void codegen_threadcritstart(int offset)
545 threadcritcurrent.mcodebegin = offset;
548 void codegen_threadcritstop(int offset)
550 threadcritcurrent.next = threadcrit;
551 threadcritcurrent.mcodeend = offset;
552 threadcrit = DNEW(struct threadcritnodetemp);
553 *threadcrit = threadcritcurrent;
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 * ---------------------------------------------------------------------
565 * indent-tabs-mode: t