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 1265 2004-07-01 20:36:38Z twisti $
58 #include "statistics.h"
59 #include "toolbox/memory.h"
60 #include "toolbox/logging.h"
61 #include "toolbox/avl.h"
62 #include "threads/thread.h"
65 /************************* critical sections *********************************/
67 struct threadcritnodetemp {
68 struct threadcritnodetemp *next;
69 int mcodebegin, mcodeend, mcoderestart;
72 #define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */
73 #define DSEGINITSIZE (1<<12) /* 4 Kbyte data area initialization size */
75 static u1* mcodebase = NULL; /* base pointer of code area */
76 static s4* mcodeend = NULL; /* pointer to end of code area */
77 static int mcodesize; /* complete size of code area (bytes) */
79 static u1* dsegtop = NULL; /* pointer to top (end) of data area */
80 static int dsegsize; /* complete size of data area (bytes) */
81 int dseglen; /* used size of data area (bytes) */
82 /* data area grows from top to bottom */
84 static jumpref *jumpreferences; /* list of jumptable target addresses */
85 static dataref *datareferences; /* list of data segment references */
86 static branchref *xboundrefs; /* list of bound check branches */
87 static branchref *xcheckarefs; /* list of array size check branches */
88 static branchref *xnullrefs; /* list of null check branches */
89 static branchref *xcastrefs; /* list of cast check branches */
90 static branchref *xdivrefs; /* list of divide by zero branches */
91 static branchref *xexceptionrefs; /* list of exception branches */
92 static linenumberref *linenumberreferences; /*list of line numbers and the program counters of their first instruction*/
93 static s4 linenumbertablesizepos;
94 static s4 linenumbertablestartpos;
95 static s4 linenumbertab;
97 static struct threadcritnodetemp *threadcrit;
98 /* List of critical code regions */
99 static struct threadcritnodetemp threadcritcurrent;
100 static int threadcritcount; /* Number of critical regions */
102 int parentargs_base; /* offset in stackframe for the parameter from the caller*/
104 void codegen_init(); /* allocates code and data area */
105 void codegen_close(); /* releases temporary storage */
106 static void codegen_finish(); /* makes code and data area permanent and */
107 /* updates branch references to code/data */
109 static s4 dseg_adds4(s4 value); /* adds an int to data area */
111 #if !defined(__I386__)
112 static s4 dseg_adds8(s8 value); /* adds an long to data area */
115 static s4 dseg_addfloat (float value); /* adds an float to data area */
116 static s4 dseg_adddouble(double value); /* adds an double to data area */
119 #define dseg_addaddress(value) dseg_adds8((s8)(value))
121 #define dseg_addaddress(value) dseg_adds4((s4)(value))
124 static void dseg_addtarget(basicblock *target);
125 static void dseg_adddata(u1 *ptr);
126 static void codegen_addxboundrefs(void *branchptr, s4 reg);
127 static void codegen_addxnullrefs(void *branchptr);
128 static void codegen_addxcastrefs(void *branchptr);
129 static void codegen_addxdivrefs(void *branchptr);
130 static void codegen_addxexceptionrefs(void *branchptr);
131 static void codegen_threadcritrestart(int offset);
132 static void codegen_threadcritstart(int offset);
133 static void codegen_threadcritstop(int offset);
135 #if defined(__I386__) || defined(__X86_64__)
136 typedef struct _methodtree_element methodtree_element;
138 struct _methodtree_element {
143 static struct avl_table *methodtree=0;
144 static int methodtree_comparator(const void *pc, const void *element,
148 void dseg_display(s4 *s4ptr);
152 /* codegen_init allocates and initialises code area, data area and references */
157 mcodebase = MNEW(u1, MCODEINITSIZE);
158 mcodesize = MCODEINITSIZE;
162 dsegtop = MNEW(u1, DSEGINITSIZE);
163 dsegsize = DSEGINITSIZE;
169 linenumberreferences = NULL;
170 linenumbertablesizepos = 0;
171 linenumbertablestartpos = 0;
173 jumpreferences = NULL;
174 datareferences = NULL;
180 xexceptionrefs = NULL;
182 #if defined(__I386__) || defined(__X86_64__)
184 methodtree_element *mte;
186 methodtree = avl_create(methodtree_comparator, NULL, NULL);
188 mte = NEW(methodtree_element);
190 mte->startpc = asm_calljavafunction;
191 mte->endpc = asm_calljavafunction2 - 1;
193 avl_insert(methodtree, mte);
195 mte = NEW(methodtree_element);
197 mte->startpc = asm_calljavafunction2;
198 mte->endpc = asm_call_jit_compiler - 1;
200 avl_insert(methodtree, mte);
204 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
205 threadcritcurrent.next = NULL;
212 /* codegen_close releases temporary code and data area */
217 MFREE(mcodebase, u1, mcodesize);
222 MFREE(dsegtop - dsegsize, u1, dsegsize);
229 /* codegen_increase doubles code area */
231 static s4 *codegen_increase(u1 *codeptr)
235 len = codeptr - mcodebase;
236 mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
238 mcodeend = (s4*) (mcodebase + mcodesize);
239 return (s4*) (mcodebase + len);
244 /* desg_increase doubles data area */
246 static void dseg_increase()
248 u1 *newstorage = MNEW(u1, dsegsize * 2);
249 memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
250 MFREE(dsegtop - dsegsize, u1, dsegsize);
251 dsegtop = newstorage;
258 static s4 dseg_adds4_increase(s4 value)
261 *((s4 *) (dsegtop - dseglen)) = value;
267 static s4 dseg_adds4(s4 value)
272 dataptr = (s4 *) (dsegtop - dseglen);
273 if (dseglen > dsegsize)
274 return dseg_adds4_increase(value);
281 #if !defined(__I386__)
282 static s4 dseg_adds8_increase(s8 value)
285 *((s8 *) (dsegtop - dseglen)) = value;
290 static s4 dseg_adds8(s8 value)
294 dseglen = ALIGN (dseglen + 8, 8);
295 dataptr = (s8 *) (dsegtop - dseglen);
296 if (dseglen > dsegsize)
297 return dseg_adds8_increase(value);
304 static s4 dseg_addfloat_increase(float value)
307 *((float *) (dsegtop - dseglen)) = value;
313 static s4 dseg_addfloat(float value)
318 dataptr = (float *) (dsegtop - dseglen);
319 if (dseglen > dsegsize)
320 return dseg_addfloat_increase(value);
327 static s4 dseg_adddouble_increase(double value)
330 *((double *) (dsegtop - dseglen)) = value;
336 static s4 dseg_adddouble(double value)
340 dseglen = ALIGN (dseglen + 8, 8);
341 dataptr = (double *) (dsegtop - dseglen);
342 if (dseglen > dsegsize)
343 return dseg_adddouble_increase(value);
350 static void dseg_addtarget(basicblock *target)
352 jumpref *jr = DNEW(jumpref);
354 jr->tablepos = dseg_addaddress(NULL);
356 jr->next = jumpreferences;
362 static void dseg_adddata(u1 *ptr)
364 dataref *dr = DNEW(dataref);
366 dr->pos = (u1 *) (ptr - mcodebase);
367 dr->next = datareferences;
371 static void dseg_addlinenumbertablesize() {
373 dseg_adds4(0); /*PADDING*/
375 linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
377 linenumbertablestartpos=dseg_addaddress(NULL);
379 dseg_adds4(0); /*PADDING*/
383 static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
384 linenumberref *lr=DNEW(linenumberref);
385 lr->linenumber=linenumber;
387 lr->targetmpc=(ptr-mcodebase);
388 lr->next=linenumberreferences;
389 linenumberreferences=lr;
393 /* we need this function externally on i386 and x86_64, but keep the call fast
396 #if defined(__I386__) || defined(__X86_64__)
397 void codegen_addreference(basicblock *target, void *branchptr)
399 static void codegen_addreference(basicblock *target, void *branchptr)
402 s4 branchpos = (u1*) branchptr - mcodebase;
404 if (target->mpc >= 0) {
405 gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
408 branchref *br = DNEW(branchref);
410 br->branchpos = branchpos;
411 br->next = target->branchrefs;
412 target->branchrefs= br;
418 static void codegen_addxboundrefs(void *branchptr, s4 reg)
420 s4 branchpos = (u1*) branchptr - mcodebase;
422 branchref *br = DNEW(branchref);
424 br->branchpos = branchpos;
426 br->next = xboundrefs;
432 static void codegen_addxcheckarefs(void *branchptr)
434 s4 branchpos = (u1*) branchptr - mcodebase;
436 branchref *br = DNEW(branchref);
438 br->branchpos = branchpos;
439 br->next = xcheckarefs;
445 static void codegen_addxnullrefs(void *branchptr)
447 s4 branchpos = (u1*) branchptr - mcodebase;
449 branchref *br = DNEW(branchref);
451 br->branchpos = branchpos;
452 br->next = xnullrefs;
458 static void codegen_addxcastrefs(void *branchptr)
460 s4 branchpos = (u1*) branchptr - mcodebase;
462 branchref *br = DNEW(branchref);
464 br->branchpos = branchpos;
465 br->next = xcastrefs;
470 static void codegen_addxexceptionrefs(void *branchptr)
472 s4 branchpos = (u1*) branchptr - mcodebase;
474 branchref *br = DNEW(branchref);
476 br->branchpos = branchpos;
477 br->next = xexceptionrefs;
482 static void codegen_addxdivrefs(void *branchptr)
484 s4 branchpos = (u1*) branchptr - mcodebase;
486 branchref *br = DNEW(branchref);
488 br->branchpos = branchpos;
494 static void codegen_createlinenumbertable() {
496 /*log_text("codegen_createlinnumbertable");*/
499 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
500 /*log_text("Adding line number entry");*/
501 lr->tablepos=dseg_addaddress(NULL);
502 if (linenumbertab==0) linenumbertab=lr->tablepos;
503 dseg_addaddress(lr->linenumber);
510 #if defined(__I386__) || defined(__X86_64__)
511 static int methodtree_comparator(const void *pc, const void *element,
514 methodtree_element *mte;
515 methodtree_element *mtepc;
517 mte = (methodtree_element *) element;
518 mtepc = (methodtree_element *) pc;
520 /* compare both startpc and endpc of pc, even if they have the same value,
521 otherwise the avl_probe sometime thinks the element is still in the
523 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
524 mte->startpc <= mtepc->endpc && mtepc->endpc <= mte->endpc) {
527 } else if (mtepc->startpc < mte->startpc) {
537 void *codegen_findmethod1(void *pc)
539 void * retVal=findmethod(pc);
540 methodinfo **ma=(methodinfo**)retVal;
541 methodinfo *m=ma[-1];
544 utf_display(m->name);
547 else log_text("No methodinfo");
552 void *codegen_findmethod(void *pc)
554 methodtree_element *mtepc;
555 methodtree_element *mte;
557 mtepc = NEW(methodtree_element);
561 mte = avl_find(methodtree, mtepc);
563 FREE(mtepc, methodtree_element);
566 throw_cacao_exception_exit(string_java_lang_InternalError, "cannot find function");
573 static void codegen_finish(methodinfo *m, int mcodelen)
580 /* printf("codegen_finish\n"); */
581 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
582 extralen += sizeof(threadcritnode) * threadcritcount;
585 #if defined(STATISTICS)
587 count_code_len += mcodelen;
588 count_data_len += dseglen;
592 dseglen = ALIGN(dseglen, MAX_ALIGN);
593 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + dseglen;
595 m->mcodelength = mcodelen + dseglen;
596 m->mcode = CNEW(u1, alignedlen + extralen);
598 memcpy(m->mcode, dsegtop - dseglen, dseglen);
599 memcpy(m->mcode + dseglen, mcodebase, mcodelen);
601 m->entrypoint = epoint = (u1 *) (m->mcode + dseglen);
603 /* jump table resolving */
606 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
611 /* line number table resolving */
620 for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
622 *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
623 /*log_text("resolving line number information");*/
626 *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
628 *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
630 *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
635 #if defined(__I386__) || defined(__X86_64__)
639 /* add method into methodtree to find the entrypoint */
640 methodtree_element *mte;
642 mte = NEW(methodtree_element);
643 mte->startpc = m->entrypoint;
644 mte->endpc = m->entrypoint + mcodelen;
646 if (avl_insert(methodtree, mte))
647 panic("duplicate entry");
649 /* data segment references resolving */
652 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
659 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
661 threadcritnode *n = (threadcritnode*) (m->mcode + alignedlen);
663 struct threadcritnodetemp *nt = threadcrit;
665 for (i=0; i<threadcritcount; i++)
667 n->mcodebegin = m->mcode + nt->mcodebegin;
668 n->mcodeend = m->mcode + nt->mcodeend;
669 n->mcoderestart = m->mcode + nt->mcoderestart;
670 thread_registercritical(n);
679 #if defined(__I386__) || defined(__X86_64__)
680 void codegen_insertNative(void *startpc, void *endpc)
682 methodtree_element *mte;
685 methodtree_element *mte;
687 methodtree = avl_create(methodtree_comparator, NULL, NULL);
689 mte = NEW(methodtree_element);
690 mte->startpc = asm_calljavafunction;
691 mte->endpc = asm_calljavafunction2 - 1;
692 avl_insert(methodtree, mte);
694 mte = NEW(methodtree_element);
695 mte->startpc = asm_calljavafunction2;
696 mte->endpc = asm_call_jit_compiler - 1;
697 avl_insert(methodtree, mte);
700 mte = NEW(methodtree_element);
701 mte->startpc = startpc;
704 if (avl_insert(methodtree, mte))
705 panic("duplicate entry");
710 void dseg_display(s4 *s4ptr)
714 printf(" --- dump of datasegment\n");
715 for (i = dseglen; i > 0 ; i -= 4) {
716 printf("-%6x: %8x\n", i, (int)(*s4ptr++));
718 printf(" --- begin of data segment: %p\n", s4ptr);
723 This function determines a register, to which the result of an operation
724 should go, when it is ultimatively intended to store the result in
726 If v is assigned to an actual register, this register will be returned.
727 Otherwise (when v is spilled) this function returns tempregnum.
728 If not already done, regoff and flags are set in the stack location.
731 static int reg_of_var(methodinfo *m, stackptr v, int tempregnum)
735 switch (v->varkind) {
737 if (!(v->flags & INMEMORY))
741 var = &(m->registerdata->interfaces[v->varnum][v->type]);
742 v->regoff = var->regoff;
743 if (!(var->flags & INMEMORY))
747 var = &(m->registerdata->locals[v->varnum][v->type]);
748 v->regoff = var->regoff;
749 if (!(var->flags & INMEMORY))
753 v->regoff = v->varnum;
754 if (IS_FLT_DBL_TYPE(v->type)) {
755 if (v->varnum < m->registerdata->fltreg_argnum) {
756 v->regoff = m->registerdata->argfltregs[v->varnum];
757 return(m->registerdata->argfltregs[v->varnum]);
761 if (v->varnum < m->registerdata->intreg_argnum) {
762 v->regoff = m->registerdata->argintregs[v->varnum];
763 return(m->registerdata->argintregs[v->varnum]);
765 v->regoff -= m->registerdata->intreg_argnum;
768 v->flags |= INMEMORY;
773 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
774 void codegen_threadcritrestart(int offset)
776 threadcritcurrent.mcoderestart = offset;
779 void codegen_threadcritstart(int offset)
781 threadcritcurrent.mcodebegin = offset;
784 void codegen_threadcritstop(int offset)
786 threadcritcurrent.next = threadcrit;
787 threadcritcurrent.mcodeend = offset;
788 threadcrit = DNEW(struct threadcritnodetemp);
789 *threadcrit = threadcritcurrent;
795 * These are local overrides for various environment variables in Emacs.
796 * Please do not remove this and leave it at the end of the file, where
797 * Emacs will automagically detect them.
798 * ---------------------------------------------------------------------
801 * indent-tabs-mode: t