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 1173 2004-06-16 14:56:18Z jowenn $
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=0;
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);
189 mte->startpc = asm_calljavafunction;
190 mte->endpc = asm_calljavafunction2-1;
192 avl_insert(methodtree, mte);
194 mte = NEW(methodtree_element);
196 mte->startpc = asm_calljavafunction2;
197 mte->endpc = asm_call_jit_compiler-1;
199 avl_insert(methodtree, mte);
203 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
204 threadcritcurrent.next = NULL;
211 /* codegen_close releases temporary code and data area */
216 MFREE(mcodebase, u1, mcodesize);
221 MFREE(dsegtop - dsegsize, u1, dsegsize);
228 /* codegen_increase doubles code area */
230 static s4 *codegen_increase(u1 *codeptr)
234 len = codeptr - mcodebase;
235 mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
237 mcodeend = (s4*) (mcodebase + mcodesize);
238 return (s4*) (mcodebase + len);
243 /* desg_increase doubles data area */
245 static void dseg_increase()
247 u1 *newstorage = MNEW(u1, dsegsize * 2);
248 memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
249 MFREE(dsegtop - dsegsize, u1, dsegsize);
250 dsegtop = newstorage;
257 static s4 dseg_adds4_increase(s4 value)
260 *((s4 *) (dsegtop - dseglen)) = value;
266 static s4 dseg_adds4(s4 value)
271 dataptr = (s4 *) (dsegtop - dseglen);
272 if (dseglen > dsegsize)
273 return dseg_adds4_increase(value);
280 #if !defined(__I386__)
281 static s4 dseg_adds8_increase(s8 value)
284 *((s8 *) (dsegtop - dseglen)) = value;
289 static s4 dseg_adds8(s8 value)
293 dseglen = ALIGN (dseglen + 8, 8);
294 dataptr = (s8 *) (dsegtop - dseglen);
295 if (dseglen > dsegsize)
296 return dseg_adds8_increase(value);
303 static s4 dseg_addfloat_increase(float value)
306 *((float *) (dsegtop - dseglen)) = value;
312 static s4 dseg_addfloat(float value)
317 dataptr = (float *) (dsegtop - dseglen);
318 if (dseglen > dsegsize)
319 return dseg_addfloat_increase(value);
326 static s4 dseg_adddouble_increase(double value)
329 *((double *) (dsegtop - dseglen)) = value;
335 static s4 dseg_adddouble(double value)
339 dseglen = ALIGN (dseglen + 8, 8);
340 dataptr = (double *) (dsegtop - dseglen);
341 if (dseglen > dsegsize)
342 return dseg_adddouble_increase(value);
349 static void dseg_addtarget(basicblock *target)
351 jumpref *jr = DNEW(jumpref);
353 jr->tablepos = dseg_addaddress(NULL);
355 jr->next = jumpreferences;
361 static void dseg_adddata(u1 *ptr)
363 dataref *dr = DNEW(dataref);
365 dr->pos = (u1 *) (ptr - mcodebase);
366 dr->next = datareferences;
370 static void dseg_addlinenumbertablesize() {
372 dseg_adds4(0); /*PADDING*/
374 linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
376 linenumbertablestartpos=dseg_addaddress(NULL);
378 dseg_adds4(0); /*PADDING*/
382 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
383 linenumberref *lr=DNEW(linenumberref);
384 lr->linenumber=linenumber;
386 lr->targetmpc=(ptr-mcodebase);
387 lr->next=linenumberreferences;
388 linenumberreferences=lr;
391 static void codegen_addreference(basicblock *target, void *branchptr)
393 s4 branchpos = (u1*) branchptr - mcodebase;
395 if (target->mpc >= 0) {
396 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
399 branchref *br = DNEW(branchref);
401 br->branchpos = branchpos;
402 br->next = target->branchrefs;
403 target->branchrefs= br;
409 static void codegen_addxboundrefs(void *branchptr, s4 reg)
411 s4 branchpos = (u1*) branchptr - mcodebase;
413 branchref *br = DNEW(branchref);
415 br->branchpos = branchpos;
417 br->next = xboundrefs;
423 static void codegen_addxcheckarefs(void *branchptr)
425 s4 branchpos = (u1*) branchptr - mcodebase;
427 branchref *br = DNEW(branchref);
429 br->branchpos = branchpos;
430 br->next = xcheckarefs;
436 static void codegen_addxnullrefs(void *branchptr)
438 s4 branchpos = (u1*) branchptr - mcodebase;
440 branchref *br = DNEW(branchref);
442 br->branchpos = branchpos;
443 br->next = xnullrefs;
449 static void codegen_addxcastrefs(void *branchptr)
451 s4 branchpos = (u1*) branchptr - mcodebase;
453 branchref *br = DNEW(branchref);
455 br->branchpos = branchpos;
456 br->next = xcastrefs;
461 static void codegen_addxexceptionrefs(void *branchptr)
463 s4 branchpos = (u1*) branchptr - mcodebase;
465 branchref *br = DNEW(branchref);
467 br->branchpos = branchpos;
468 br->next = xexceptionrefs;
473 static void codegen_addxdivrefs(void *branchptr)
475 s4 branchpos = (u1*) branchptr - mcodebase;
477 branchref *br = DNEW(branchref);
479 br->branchpos = branchpos;
485 static void codegen_createlinenumbertable() {
487 /*log_text("codegen_createlinnumbertable");*/
490 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
491 /*log_text("Adding line number entry");*/
492 lr->tablepos=dseg_addaddress(NULL);
493 if (linenumbertab==0) linenumbertab=lr->tablepos;
494 dseg_addaddress(lr->linenumber);
501 #if defined(__I386__) || defined(__X86_64__)
502 static int methodtree_comparator(const void *pc, const void *element,
505 methodtree_element *mte;
506 methodtree_element *mtepc;
508 mte = (methodtree_element *) element;
509 mtepc = (methodtree_element *) pc;
511 /* compare both startpc and endpc of pc, even if they have the same value,
512 otherwise the avl_probe sometime thinks the element is still in the
514 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
515 mte->startpc <= mtepc->endpc && mtepc->endpc <= mte->endpc) {
518 } else if (mtepc->startpc < mte->startpc) {
528 void *codegen_findmethod1(void *pc)
530 void * retVal=findmethod(pc);
531 methodinfo **ma=(methodinfo**)retVal;
532 methodinfo *m=ma[-1];
535 utf_display(m->name);
538 else log_text("No methodinfo");
543 void *codegen_findmethod(void *pc)
545 methodtree_element *mtepc;
546 methodtree_element *mte;
548 mtepc = NEW(methodtree_element);
552 mte = avl_find(methodtree, mtepc);
554 FREE(mtepc, methodtree_element);
557 throw_cacao_exception_exit(string_java_lang_InternalError, "cannot find function");
564 static void codegen_finish(int mcodelen)
572 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
573 extralen += sizeof(threadcritnode) * threadcritcount;
576 count_code_len += mcodelen;
577 count_data_len += dseglen;
579 dseglen = ALIGN(dseglen, MAX_ALIGN);
580 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + dseglen;
582 method->mcodelength = mcodelen + dseglen;
583 method->mcode = CNEW(u1, alignedlen + extralen);
585 memcpy(method->mcode, dsegtop - dseglen, dseglen);
586 memcpy(method->mcode + dseglen, mcodebase, mcodelen);
588 method->entrypoint = epoint = (u1 *) (method->mcode + dseglen);
590 /* jump table resolving */
593 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
598 /* line number table resolving */
607 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
609 *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
610 /*log_text("resolving line number information");*/
613 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
615 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
617 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
622 #if defined(__I386__) || defined(__X86_64__)
626 /* add method into methodtree to find the entrypoint */
627 methodtree_element *mte;
629 mte = NEW(methodtree_element);
630 mte->startpc = method->entrypoint;
631 mte->endpc = method->entrypoint + mcodelen;
633 if (avl_insert(methodtree, mte))
634 panic("duplicate entry");
636 /* data segment references resolving */
639 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
646 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
648 threadcritnode *n = (threadcritnode*) (method->mcode + alignedlen);
650 struct threadcritnodetemp *nt = threadcrit;
652 for (i=0; i<threadcritcount; i++)
654 n->mcodebegin = method->mcode + nt->mcodebegin;
655 n->mcodeend = method->mcode + nt->mcodeend;
656 n->mcoderestart = method->mcode + nt->mcoderestart;
657 thread_registercritical(n);
666 void codegen_insertNative(void *startpc,void *endpc) {
667 methodtree_element *mte;
670 methodtree_element *mte;
672 methodtree = avl_create(methodtree_comparator, NULL, NULL);
674 mte = NEW(methodtree_element);
675 mte->startpc = asm_calljavafunction;
676 mte->endpc = asm_calljavafunction2-1;
677 avl_insert(methodtree, mte);
679 mte = NEW(methodtree_element);
680 mte->startpc = asm_calljavafunction2;
681 mte->endpc = asm_call_jit_compiler-1;
682 avl_insert(methodtree, mte);
686 mte = NEW(methodtree_element);
687 mte->startpc = startpc;
690 if (avl_insert(methodtree, mte))
691 panic("duplicate entry");
694 void dseg_display(s4 *s4ptr)
698 printf(" --- dump of datasegment\n");
699 for (i = dseglen; i > 0 ; i -= 4) {
700 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
702 printf(" --- begin of data segment: %p\n", s4ptr);
705 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
706 void codegen_threadcritrestart(int offset)
708 threadcritcurrent.mcoderestart = offset;
711 void codegen_threadcritstart(int offset)
713 threadcritcurrent.mcodebegin = offset;
716 void codegen_threadcritstop(int offset)
718 threadcritcurrent.next = threadcrit;
719 threadcritcurrent.mcodeend = offset;
720 threadcrit = DNEW(struct threadcritnodetemp);
721 *threadcrit = threadcritcurrent;
727 * These are local overrides for various environment variables in Emacs.
728 * Please do not remove this and leave it at the end of the file, where
729 * Emacs will automagically detect them.
730 * ---------------------------------------------------------------------
733 * indent-tabs-mode: t