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 1121 2004-06-03 20:40:39Z 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;
179 xexceptionrefs = NULL;
181 #if defined(__I386__) || defined(__X86_64__)
183 methodtree_element *mte;
185 methodtree = avl_create(methodtree_comparator, NULL, NULL);
187 mte = NEW(methodtree_element);
188 mte->startpc = asm_calljavafunction;
189 mte->endpc = asm_calljavafunction2;
190 avl_insert(methodtree, mte);
192 mte = NEW(methodtree_element);
193 mte->startpc = asm_calljavafunction2;
194 mte->endpc = asm_call_jit_compiler;
195 avl_insert(methodtree, mte);
199 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
200 threadcritcurrent.next = NULL;
207 /* codegen_close releases temporary code and data area */
212 MFREE(mcodebase, u1, mcodesize);
217 MFREE(dsegtop - dsegsize, u1, dsegsize);
224 /* codegen_increase doubles code area */
226 static s4 *codegen_increase(u1 *codeptr)
230 len = codeptr - mcodebase;
231 mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
233 mcodeend = (s4*) (mcodebase + mcodesize);
234 return (s4*) (mcodebase + len);
239 /* desg_increase doubles data area */
241 static void dseg_increase()
243 u1 *newstorage = MNEW(u1, dsegsize * 2);
244 memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
245 MFREE(dsegtop - dsegsize, u1, dsegsize);
246 dsegtop = newstorage;
253 static s4 dseg_adds4_increase(s4 value)
256 *((s4 *) (dsegtop - dseglen)) = value;
262 static s4 dseg_adds4(s4 value)
267 dataptr = (s4 *) (dsegtop - dseglen);
268 if (dseglen > dsegsize)
269 return dseg_adds4_increase(value);
276 #if !defined(__I386__)
277 static s4 dseg_adds8_increase(s8 value)
280 *((s8 *) (dsegtop - dseglen)) = value;
285 static s4 dseg_adds8(s8 value)
289 dseglen = ALIGN (dseglen + 8, 8);
290 dataptr = (s8 *) (dsegtop - dseglen);
291 if (dseglen > dsegsize)
292 return dseg_adds8_increase(value);
299 static s4 dseg_addfloat_increase(float value)
302 *((float *) (dsegtop - dseglen)) = value;
308 static s4 dseg_addfloat(float value)
313 dataptr = (float *) (dsegtop - dseglen);
314 if (dseglen > dsegsize)
315 return dseg_addfloat_increase(value);
322 static s4 dseg_adddouble_increase(double value)
325 *((double *) (dsegtop - dseglen)) = value;
331 static s4 dseg_adddouble(double value)
335 dseglen = ALIGN (dseglen + 8, 8);
336 dataptr = (double *) (dsegtop - dseglen);
337 if (dseglen > dsegsize)
338 return dseg_adddouble_increase(value);
345 static void dseg_addtarget(basicblock *target)
347 jumpref *jr = DNEW(jumpref);
349 jr->tablepos = dseg_addaddress(NULL);
351 jr->next = jumpreferences;
357 static void dseg_adddata(u1 *ptr)
359 dataref *dr = DNEW(dataref);
361 dr->pos = (u1 *) (ptr - mcodebase);
362 dr->next = datareferences;
366 static void dseg_addlinenumbertablesize() {
368 dseg_adds4(0); /*PADDING*/
370 linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
372 linenumbertablestartpos=dseg_addaddress(NULL);
374 dseg_adds4(0); /*PADDING*/
378 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
379 linenumberref *lr=DNEW(linenumberref);
380 lr->linenumber=linenumber;
382 lr->targetmpc=(ptr-mcodebase);
383 lr->next=linenumberreferences;
384 linenumberreferences=lr;
387 static void codegen_addreference(basicblock *target, void *branchptr)
389 s4 branchpos = (u1*) branchptr - mcodebase;
391 if (target->mpc >= 0) {
392 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
395 branchref *br = DNEW(branchref);
397 br->branchpos = branchpos;
398 br->next = target->branchrefs;
399 target->branchrefs= br;
405 static void codegen_addxboundrefs(void *branchptr, s4 reg)
407 s4 branchpos = (u1*) branchptr - mcodebase;
409 branchref *br = DNEW(branchref);
411 br->branchpos = branchpos;
413 br->next = xboundrefs;
419 static void codegen_addxcheckarefs(void *branchptr)
421 s4 branchpos = (u1*) branchptr - mcodebase;
423 branchref *br = DNEW(branchref);
425 br->branchpos = branchpos;
426 br->next = xcheckarefs;
432 static void codegen_addxnullrefs(void *branchptr)
434 s4 branchpos = (u1*) branchptr - mcodebase;
436 branchref *br = DNEW(branchref);
438 br->branchpos = branchpos;
439 br->next = xnullrefs;
445 static void codegen_addxcastrefs(void *branchptr)
447 s4 branchpos = (u1*) branchptr - mcodebase;
449 branchref *br = DNEW(branchref);
451 br->branchpos = branchpos;
452 br->next = xcastrefs;
457 static void codegen_addxexceptionrefs(void *branchptr)
459 s4 branchpos = (u1*) branchptr - mcodebase;
461 branchref *br = DNEW(branchref);
463 br->branchpos = branchpos;
464 br->next = xexceptionrefs;
469 static void codegen_addxdivrefs(void *branchptr)
471 s4 branchpos = (u1*) branchptr - mcodebase;
473 branchref *br = DNEW(branchref);
475 br->branchpos = branchpos;
481 static void codegen_createlinenumbertable() {
483 /*log_text("codegen_createlinnumbertable");*/
486 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
487 /*log_text("Adding line number entry");*/
488 lr->tablepos=dseg_addaddress(NULL);
489 if (linenumbertab==0) linenumbertab=lr->tablepos;
490 dseg_addaddress(lr->linenumber);
497 #if defined(__I386__) || defined(__X86_64__)
498 static int methodtree_comparator(const void *pc, const void *element,
501 methodtree_element *mtepc;
502 methodtree_element *mte;
504 mtepc = (methodtree_element *) pc;
505 mte = (methodtree_element *) element;
507 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc) {
510 } else if (mtepc->startpc < mte->startpc) {
520 void *codegen_findmethod1(void *pc)
522 void * retVal=findmethod(pc);
523 methodinfo **ma=(methodinfo**)retVal;
524 methodinfo *m=ma[-1];
527 utf_display(m->name);
530 else log_text("No methodinfo");
535 void *codegen_findmethod(void *pc)
537 methodtree_element *mtepc;
538 methodtree_element *mte;
540 mtepc = NEW(methodtree_element);
543 mte = avl_find(methodtree, mtepc);
545 FREE(mtepc, methodtree_element);
548 throw_cacao_exception_exit(string_java_lang_InternalError, "cannot find function");
555 static void codegen_finish(int mcodelen)
562 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
563 extralen += sizeof(threadcritnode) * threadcritcount;
566 count_code_len += mcodelen;
567 count_data_len += dseglen;
569 dseglen = ALIGN(dseglen, MAX_ALIGN);
571 method->mcodelength = mcodelen + dseglen;
572 method->mcode = CNEW(u1, mcodelen + dseglen + extralen);
574 memcpy(method->mcode, dsegtop - dseglen, dseglen);
575 memcpy(method->mcode + dseglen, mcodebase, mcodelen);
577 method->entrypoint = epoint = (u1 *) (method->mcode + dseglen);
579 /* jump table resolving */
582 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
587 /* line number table resolving */
596 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
598 *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
599 /*log_text("resolving line number information");*/
602 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
604 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
606 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
611 #if defined(__I386__) || defined(__X86_64__)
615 /* add method into methodtree to find the entrypoint */
616 methodtree_element *mte;
618 mte = NEW(methodtree_element);
619 mte->startpc = method->entrypoint;
620 mte->endpc = method->entrypoint + mcodelen;
622 if (avl_insert(methodtree, mte))
623 panic("duplicate entry");
625 /* data segment references resolving */
628 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
635 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
637 threadcritnode *n = (threadcritnode*) (method->mcode + mcodelen + dseglen);
639 struct threadcritnodetemp *nt = threadcrit;
641 for (i=0; i<threadcritcount; i++)
643 n->mcodebegin = method->mcode + nt->mcodebegin;
644 n->mcodeend = method->mcode + nt->mcodeend;
645 n->mcoderestart = method->mcode + nt->mcoderestart;
646 thread_registercritical(n);
656 void dseg_display(s4 *s4ptr)
660 printf(" --- dump of datasegment\n");
661 for (i = dseglen; i > 0 ; i -= 4) {
662 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
664 printf(" --- begin of data segment: %p\n", s4ptr);
667 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
668 void codegen_threadcritrestart(int offset)
670 threadcritcurrent.mcoderestart = offset;
673 void codegen_threadcritstart(int offset)
675 threadcritcurrent.mcodebegin = offset;
678 void codegen_threadcritstop(int offset)
680 threadcritcurrent.next = threadcrit;
681 threadcritcurrent.mcodeend = offset;
682 threadcrit = DNEW(struct threadcritnodetemp);
683 *threadcrit = threadcritcurrent;
689 * These are local overrides for various environment variables in Emacs.
690 * Please do not remove this and leave it at the end of the file, where
691 * Emacs will automagically detect them.
692 * ---------------------------------------------------------------------
695 * indent-tabs-mode: t