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 1099 2004-05-27 16:06:14Z twisti $
57 #include "toolbox/memory.h"
58 #include "toolbox/logging.h"
59 #include "toolbox/avl.h"
60 #include "threads/thread.h"
63 /************************* critical sections *********************************/
65 struct threadcritnodetemp {
66 struct threadcritnodetemp *next;
67 int mcodebegin, mcodeend, mcoderestart;
70 #define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */
71 #define DSEGINITSIZE (1<<12) /* 4 Kbyte data area initialization size */
73 static u1* mcodebase = NULL; /* base pointer of code area */
74 static s4* mcodeend = NULL; /* pointer to end of code area */
75 static int mcodesize; /* complete size of code area (bytes) */
77 static u1* dsegtop = NULL; /* pointer to top (end) of data area */
78 static int dsegsize; /* complete size of data area (bytes) */
79 int dseglen; /* used size of data area (bytes) */
80 /* data area grows from top to bottom */
82 static jumpref *jumpreferences; /* list of jumptable target addresses */
83 static dataref *datareferences; /* list of data segment references */
84 static branchref *xboundrefs; /* list of bound check branches */
85 static branchref *xcheckarefs; /* list of array size check branches */
86 static branchref *xnullrefs; /* list of null check branches */
87 static branchref *xcastrefs; /* list of cast check branches */
88 static branchref *xdivrefs; /* list of divide by zero branches */
89 static branchref *xexceptionrefs; /* list of exception branches */
90 static linenumberref *linenumberreferences; /*list of line numbers and the program counters of their first instruction*/
91 static s4 linenumbertablesizepos;
92 static s4 linenumbertablestartpos;
93 static s4 linenumbertab;
95 static struct threadcritnodetemp *threadcrit;
96 /* List of critical code regions */
97 static struct threadcritnodetemp threadcritcurrent;
98 static int threadcritcount; /* Number of critical regions */
100 int parentargs_base; /* offset in stackframe for the parameter from the caller*/
102 void codegen_init(); /* allocates code and data area */
103 void codegen_close(); /* releases temporary storage */
104 static void codegen_finish(); /* makes code and data area permanent and */
105 /* updates branch references to code/data */
107 static s4 dseg_adds4(s4 value); /* adds an int to data area */
109 #if !defined(__I386__)
110 static s4 dseg_adds8(s8 value); /* adds an long to data area */
113 static s4 dseg_addfloat (float value); /* adds an float to data area */
114 static s4 dseg_adddouble(double value); /* adds an double to data area */
117 #define dseg_addaddress(value) dseg_adds8((s8)(value))
119 #define dseg_addaddress(value) dseg_adds4((s4)(value))
122 static void dseg_addtarget(basicblock *target);
123 static void dseg_adddata(u1 *ptr);
124 static void codegen_addreference(basicblock *target, void *branchptr);
125 static void codegen_addxboundrefs(void *branchptr, s4 reg);
126 static void codegen_addxnullrefs(void *branchptr);
127 static void codegen_addxcastrefs(void *branchptr);
128 static void codegen_addxdivrefs(void *branchptr);
129 static void codegen_addxexceptionrefs(void *branchptr);
130 static void codegen_threadcritrestart(int offset);
131 static void codegen_threadcritstart(int offset);
132 static void codegen_threadcritstop(int offset);
134 #if defined(__I386__) || defined(__X86_64__)
135 typedef struct _methodtree_element methodtree_element;
137 struct _methodtree_element {
142 static struct avl_table *methodtree;
143 static int methodtree_comparator(const void *pc, const void *element,
147 void dseg_display(s4 *s4ptr);
151 /* codegen_init allocates and initialises code area, data area and references */
156 mcodebase = MNEW(u1, MCODEINITSIZE);
157 mcodesize = MCODEINITSIZE;
161 dsegtop = MNEW(u1, DSEGINITSIZE);
162 dsegsize = DSEGINITSIZE;
168 linenumberreferences = NULL;
169 linenumbertablesizepos = 0;
170 linenumbertablestartpos = 0;
172 jumpreferences = NULL;
173 datareferences = NULL;
178 xexceptionrefs = NULL;
180 #if defined(__I386__) || defined(__X86_64__)
181 methodtree = avl_create(methodtree_comparator, NULL, NULL);
184 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
185 threadcritcurrent.next = NULL;
192 /* codegen_close releases temporary code and data area */
197 MFREE(mcodebase, u1, mcodesize);
202 MFREE(dsegtop - dsegsize, u1, dsegsize);
209 /* codegen_increase doubles code area */
211 static s4 *codegen_increase(u1 *codeptr)
215 len = codeptr - mcodebase;
216 mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
218 mcodeend = (s4*) (mcodebase + mcodesize);
219 return (s4*) (mcodebase + len);
224 /* desg_increase doubles data area */
226 static void dseg_increase()
228 u1 *newstorage = MNEW(u1, dsegsize * 2);
229 memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
230 MFREE(dsegtop - dsegsize, u1, dsegsize);
231 dsegtop = newstorage;
238 static s4 dseg_adds4_increase(s4 value)
241 *((s4 *) (dsegtop - dseglen)) = value;
247 static s4 dseg_adds4(s4 value)
252 dataptr = (s4 *) (dsegtop - dseglen);
253 if (dseglen > dsegsize)
254 return dseg_adds4_increase(value);
261 #if !defined(__I386__)
262 static s4 dseg_adds8_increase(s8 value)
265 *((s8 *) (dsegtop - dseglen)) = value;
270 static s4 dseg_adds8(s8 value)
274 dseglen = ALIGN (dseglen + 8, 8);
275 dataptr = (s8 *) (dsegtop - dseglen);
276 if (dseglen > dsegsize)
277 return dseg_adds8_increase(value);
284 static s4 dseg_addfloat_increase(float value)
287 *((float *) (dsegtop - dseglen)) = value;
293 static s4 dseg_addfloat(float value)
298 dataptr = (float *) (dsegtop - dseglen);
299 if (dseglen > dsegsize)
300 return dseg_addfloat_increase(value);
307 static s4 dseg_adddouble_increase(double value)
310 *((double *) (dsegtop - dseglen)) = value;
316 static s4 dseg_adddouble(double value)
320 dseglen = ALIGN (dseglen + 8, 8);
321 dataptr = (double *) (dsegtop - dseglen);
322 if (dseglen > dsegsize)
323 return dseg_adddouble_increase(value);
330 static void dseg_addtarget(basicblock *target)
332 jumpref *jr = DNEW(jumpref);
334 jr->tablepos = dseg_addaddress(NULL);
336 jr->next = jumpreferences;
342 static void dseg_adddata(u1 *ptr)
344 dataref *dr = DNEW(dataref);
346 dr->pos = (u1 *) (ptr - mcodebase);
347 dr->next = datareferences;
351 static void dseg_addlinenumbertablesize() {
353 dseg_adds4(0); /*PADDING*/
355 linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
357 linenumbertablestartpos=dseg_addaddress(NULL);
359 dseg_adds4(0); /*PADDING*/
363 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
364 linenumberref *lr=DNEW(linenumberref);
365 lr->linenumber=linenumber;
367 lr->targetmpc=(ptr-mcodebase);
368 lr->next=linenumberreferences;
369 linenumberreferences=lr;
372 static void codegen_addreference(basicblock *target, void *branchptr)
374 s4 branchpos = (u1*) branchptr - mcodebase;
376 if (target->mpc >= 0) {
377 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
380 branchref *br = DNEW(branchref);
382 br->branchpos = branchpos;
383 br->next = target->branchrefs;
384 target->branchrefs= br;
390 static void codegen_addxboundrefs(void *branchptr, s4 reg)
392 s4 branchpos = (u1*) branchptr - mcodebase;
394 branchref *br = DNEW(branchref);
396 br->branchpos = branchpos;
398 br->next = xboundrefs;
404 static void codegen_addxcheckarefs(void *branchptr)
406 s4 branchpos = (u1*) branchptr - mcodebase;
408 branchref *br = DNEW(branchref);
410 br->branchpos = branchpos;
411 br->next = xcheckarefs;
417 static void codegen_addxnullrefs(void *branchptr)
419 s4 branchpos = (u1*) branchptr - mcodebase;
421 branchref *br = DNEW(branchref);
423 br->branchpos = branchpos;
424 br->next = xnullrefs;
430 static void codegen_addxcastrefs(void *branchptr)
432 s4 branchpos = (u1*) branchptr - mcodebase;
434 branchref *br = DNEW(branchref);
436 br->branchpos = branchpos;
437 br->next = xcastrefs;
442 static void codegen_addxexceptionrefs(void *branchptr)
444 s4 branchpos = (u1*) branchptr - mcodebase;
446 branchref *br = DNEW(branchref);
448 br->branchpos = branchpos;
449 br->next = xexceptionrefs;
454 static void codegen_addxdivrefs(void *branchptr)
456 s4 branchpos = (u1*) branchptr - mcodebase;
458 branchref *br = DNEW(branchref);
460 br->branchpos = branchpos;
466 static void codegen_createlinenumbertable() {
468 /*log_text("codegen_createlinnumbertable");*/
471 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
472 /*log_text("Adding line number entry");*/
473 lr->tablepos=dseg_addaddress(NULL);
474 if (linenumbertab==0) linenumbertab=lr->tablepos;
475 dseg_addaddress(lr->linenumber);
482 #if defined(__I386__) || defined(__X86_64__)
483 static int methodtree_comparator(const void *pc, const void *element,
486 methodtree_element *mtepc;
487 methodtree_element *mte;
489 mtepc = (methodtree_element *) pc;
490 mte = (methodtree_element *) element;
492 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc) {
495 } else if (mtepc->startpc < mte->startpc) {
504 void *codegen_findmethod(void *pc)
507 return findmethod(pc);
509 methodtree_element *mtepc;
510 methodtree_element *mte;
512 mtepc = NEW(methodtree_element);
515 mte = avl_find(methodtree, mtepc);
517 FREE(mtepc, methodtree_element);
520 /* throw_cacao_exception_exit(string_java_lang_InternalError, "cannot find function"); */
522 fprintf(stderr, "mte=%p\n", mte);
523 fprintf(stderr, "startpc=%p, endpc=%p\n", mte->startpc, mte->endpc);
531 static void codegen_finish(int mcodelen)
538 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
539 extralen += sizeof(threadcritnode) * threadcritcount;
542 count_code_len += mcodelen;
543 count_data_len += dseglen;
545 dseglen = ALIGN(dseglen, MAX_ALIGN);
547 method->mcodelength = mcodelen + dseglen;
548 method->mcode = CNEW(u1, mcodelen + dseglen + extralen);
550 memcpy(method->mcode, dsegtop - dseglen, dseglen);
551 memcpy(method->mcode + dseglen, mcodebase, mcodelen);
553 method->entrypoint = epoint = (u1 *) (method->mcode + dseglen);
555 /* jump table resolving */
558 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
563 /* line number table resolving */
572 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
574 *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
575 /*log_text("resolving line number information");*/
578 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
580 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
582 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
587 #if defined(__I386__) || defined(__X86_64__)
591 /* add method into methodtree to find the entrypoint */
592 addmethod(method->entrypoint, method->entrypoint + mcodelen);
594 methodtree_element *mte;
595 methodtree_element *p;
597 mte = NEW(methodtree_element);
598 mte->startpc = method->entrypoint;
599 mte->endpc = method->entrypoint + mcodelen;
601 p = avl_insert(methodtree, mte);
605 /* data segment references resolving */
608 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
615 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
617 threadcritnode *n = (threadcritnode*) (method->mcode + mcodelen + dseglen);
619 struct threadcritnodetemp *nt = threadcrit;
621 for (i=0; i<threadcritcount; i++)
623 n->mcodebegin = method->mcode + nt->mcodebegin;
624 n->mcodeend = method->mcode + nt->mcodeend;
625 n->mcoderestart = method->mcode + nt->mcoderestart;
626 thread_registercritical(n);
636 void dseg_display(s4 *s4ptr)
640 printf(" --- dump of datasegment\n");
641 for (i = dseglen; i > 0 ; i -= 4) {
642 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
644 printf(" --- begin of data segment: %p\n", s4ptr);
647 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
648 void codegen_threadcritrestart(int offset)
650 threadcritcurrent.mcoderestart = offset;
653 void codegen_threadcritstart(int offset)
655 threadcritcurrent.mcodebegin = offset;
658 void codegen_threadcritstop(int offset)
660 threadcritcurrent.next = threadcrit;
661 threadcritcurrent.mcodeend = offset;
662 threadcrit = DNEW(struct threadcritnodetemp);
663 *threadcrit = threadcritcurrent;
669 * These are local overrides for various environment variables in Emacs.
670 * Please do not remove this and leave it at the end of the file, where
671 * Emacs will automagically detect them.
672 * ---------------------------------------------------------------------
675 * indent-tabs-mode: t