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 1037 2004-04-26 16:36:48Z twisti $
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 branchref *xoomrefs; /* list of out of memory branches */
89 static linenumberref *linenumberreferences; /*list of line numbers and the program counters of their first instruction*/
90 static s4 linenumbertablesizepos;
91 static s4 linenumbertablestartpos;
92 static s4 linenumbertab;
94 static struct threadcritnodetemp *threadcrit;
95 /* List of critical code regions */
96 static struct threadcritnodetemp threadcritcurrent;
97 static int threadcritcount; /* Number of critical regions */
99 int parentargs_base; /* offset in stackframe for the parameter from the caller*/
101 void codegen_init(); /* allocates code and data area */
102 void codegen_close(); /* releases temporary storage */
103 static void codegen_finish(); /* makes code and data area permanent and */
104 /* updates branch references to code/data */
106 static s4 dseg_adds4(s4 value); /* adds an int to data area */
107 static s4 dseg_adds8(s8 value); /* adds an long to data area */
108 static s4 dseg_addfloat (float value); /* adds an float to data area */
109 static s4 dseg_adddouble(double value); /* adds an double to data area */
112 #define dseg_addaddress(value) dseg_adds8((s8)(value))
114 #define dseg_addaddress(value) dseg_adds4((s4)(value))
117 static void dseg_addtarget(basicblock *target);
118 static void dseg_adddata(u1 *ptr);
119 static void codegen_addreference(basicblock *target, void *branchptr);
120 static void codegen_addxboundrefs(void *branchptr, s4 reg);
121 static void codegen_addxnullrefs(void *branchptr);
122 static void codegen_addxcastrefs(void *branchptr);
123 static void codegen_addxdivrefs(void *branchptr);
124 static void codegen_addxoomrefs(void *branchptr);
125 static void codegen_threadcritstart(int offset);
126 static void codegen_threadcritstop(int offset);
128 void dseg_display(s4 *s4ptr);
132 /* codegen_init allocates and initialises code area, data area and references */
137 mcodebase = MNEW(u1, MCODEINITSIZE);
138 mcodesize = MCODEINITSIZE;
142 dsegtop = MNEW(u1, DSEGINITSIZE);
143 dsegsize = DSEGINITSIZE;
149 linenumberreferences=NULL;
150 linenumbertablesizepos=0;
151 linenumbertablestartpos=0;
153 jumpreferences = NULL;
154 datareferences = NULL;
161 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
162 threadcritcurrent.next = NULL;
169 /* codegen_close releases temporary code and data area */
174 MFREE(mcodebase, u1, mcodesize);
179 MFREE(dsegtop - dsegsize, u1, dsegsize);
186 /* codegen_increase doubles code area */
188 static s4 *codegen_increase(u1 *codeptr)
192 len = codeptr - mcodebase;
193 mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
195 mcodeend = (s4*) (mcodebase + mcodesize);
196 return (s4*) (mcodebase + len);
201 /* desg_increase doubles data area */
203 static void dseg_increase()
205 u1 *newstorage = MNEW(u1, dsegsize * 2);
206 memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
207 MFREE(dsegtop - dsegsize, u1, dsegsize);
208 dsegtop = newstorage;
215 static s4 dseg_adds4_increase(s4 value)
218 *((s4 *) (dsegtop - dseglen)) = value;
224 static s4 dseg_adds4(s4 value)
229 dataptr = (s4 *) (dsegtop - dseglen);
230 if (dseglen > dsegsize)
231 return dseg_adds4_increase(value);
238 static s4 dseg_adds8_increase(s8 value)
241 *((s8 *) (dsegtop - dseglen)) = value;
247 static s4 dseg_adds8(s8 value)
251 dseglen = ALIGN (dseglen + 8, 8);
252 dataptr = (s8 *) (dsegtop - dseglen);
253 if (dseglen > dsegsize)
254 return dseg_adds8_increase(value);
261 static s4 dseg_addfloat_increase(float value)
264 *((float *) (dsegtop - dseglen)) = value;
270 static s4 dseg_addfloat(float value)
275 dataptr = (float *) (dsegtop - dseglen);
276 if (dseglen > dsegsize)
277 return dseg_addfloat_increase(value);
284 static s4 dseg_adddouble_increase(double value)
287 *((double *) (dsegtop - dseglen)) = value;
293 static s4 dseg_adddouble(double value)
297 dseglen = ALIGN (dseglen + 8, 8);
298 dataptr = (double *) (dsegtop - dseglen);
299 if (dseglen > dsegsize)
300 return dseg_adddouble_increase(value);
307 static void dseg_addtarget(basicblock *target)
309 jumpref *jr = DNEW(jumpref);
311 jr->tablepos = dseg_addaddress(NULL);
313 jr->next = jumpreferences;
319 static void dseg_adddata(u1 *ptr)
321 dataref *dr = DNEW(dataref);
323 dr->pos = (u1 *) (ptr - mcodebase);
324 dr->next = datareferences;
328 static void dseg_addlinenumbertablesize() {
330 dseg_adds4(0); /*PADDING*/
332 linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
334 linenumbertablestartpos=dseg_addaddress(NULL);
336 dseg_adds4(0); /*PADDING*/
340 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
341 linenumberref *lr=DNEW(linenumberref);
342 lr->linenumber=linenumber;
344 lr->targetmpc=(ptr-mcodebase);
345 lr->next=linenumberreferences;
346 linenumberreferences=lr;
349 static void codegen_addreference(basicblock *target, void *branchptr)
351 s4 branchpos = (u1*) branchptr - mcodebase;
353 if (target->mpc >= 0) {
354 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
357 branchref *br = DNEW(branchref);
359 br->branchpos = branchpos;
360 br->next = target->branchrefs;
361 target->branchrefs= br;
367 static void codegen_addxboundrefs(void *branchptr, s4 reg)
369 s4 branchpos = (u1*) branchptr - mcodebase;
371 branchref *br = DNEW(branchref);
373 br->branchpos = branchpos;
375 br->next = xboundrefs;
381 static void codegen_addxcheckarefs(void *branchptr)
383 s4 branchpos = (u1*) branchptr - mcodebase;
385 branchref *br = DNEW(branchref);
387 br->branchpos = branchpos;
388 br->next = xcheckarefs;
394 static void codegen_addxnullrefs(void *branchptr)
396 s4 branchpos = (u1*) branchptr - mcodebase;
398 branchref *br = DNEW(branchref);
400 br->branchpos = branchpos;
401 br->next = xnullrefs;
407 static void codegen_addxcastrefs(void *branchptr)
409 s4 branchpos = (u1*) branchptr - mcodebase;
411 branchref *br = DNEW(branchref);
413 br->branchpos = branchpos;
414 br->next = xcastrefs;
420 static void codegen_addxoomrefs(void *branchptr)
422 s4 branchpos = (u1*) branchptr - mcodebase;
424 branchref *br = DNEW(branchref);
426 br->branchpos = branchpos;
432 static void codegen_addxdivrefs(void *branchptr)
434 s4 branchpos = (u1*) branchptr - mcodebase;
436 branchref *br = DNEW(branchref);
438 br->branchpos = branchpos;
444 static void codegen_createlinenumbertable() {
446 /*log_text("codegen_createlinnumbertable");*/
449 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
450 /*log_text("Adding line number entry");*/
451 lr->tablepos=dseg_addaddress(NULL);
452 if (linenumbertab==0) linenumbertab=lr->tablepos;
453 dseg_addaddress(lr->linenumber);
460 static void codegen_finish(int mcodelen)
467 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
468 extralen += sizeof(threadcritnode) * threadcritcount;
471 count_code_len += mcodelen;
472 count_data_len += dseglen;
474 dseglen = ALIGN(dseglen, MAX_ALIGN);
476 method -> mcodelength = mcodelen + dseglen;
477 method -> mcode = CNEW(u1, mcodelen + dseglen + extralen);
479 memcpy ( method->mcode, dsegtop - dseglen, dseglen);
480 memcpy ( method->mcode + dseglen, mcodebase, mcodelen);
482 method -> entrypoint = epoint = (u1*) (method->mcode + dseglen);
484 /* jump table resolving */
487 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
492 /* line number table resolving */
501 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
503 *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
504 /*log_text("resolving line number information");*/
507 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
509 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
511 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
516 #if defined(__I386__) || defined(__X86_64__)
519 /* add method into datastructure to find the entrypoint */
520 addmethod(method->entrypoint, method->entrypoint + mcodelen);
522 /* data segment references resolving */
525 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
532 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
534 threadcritnode *n = (threadcritnode*) (method->mcode + mcodelen + dseglen);
536 struct threadcritnodetemp *nt = threadcrit;
538 for (i=0; i<threadcritcount; i++)
540 n->mcodebegin = method->mcode + nt->mcodebegin;
541 n->mcodeend = method->mcode + nt->mcodeend;
542 thread_registercritical(n);
552 void dseg_display(s4 *s4ptr)
556 printf(" --- dump of datasegment\n");
557 for (i = dseglen; i > 0 ; i -= 4) {
558 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
560 printf(" --- begin of data segment: %p\n", s4ptr);
563 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
564 void codegen_threadcritstart(int offset)
566 threadcritcurrent.mcodebegin = offset;
569 void codegen_threadcritstop(int offset)
571 threadcritcurrent.next = threadcrit;
572 threadcritcurrent.mcodeend = offset;
573 threadcrit = DNEW(struct threadcritnodetemp);
574 *threadcrit = threadcritcurrent;
580 * These are local overrides for various environment variables in Emacs.
581 * Please do not remove this and leave it at the end of the file, where
582 * Emacs will automagically detect them.
583 * ---------------------------------------------------------------------
586 * indent-tabs-mode: t