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 1420 2004-10-27 16:05:14Z twisti $
57 #include "exceptions.h"
60 #include "statistics.h"
61 #include "jit/codegen.inc.h"
62 #include "toolbox/memory.h"
63 #include "toolbox/logging.h"
64 #include "toolbox/avl.h"
65 #include "threads/thread.h"
68 /* in this tree we store all method addresses */
70 #if defined(__I386__) || defined(__X86_64__)
71 static struct avl_table *methodtree = NULL;
72 static int methodtree_comparator(const void *pc, const void *element,
77 /* codegen_init ****************************************************************
81 *******************************************************************************/
85 #if defined(__I386__) || defined(__X86_64__)
86 /* this tree is global, not method specific */
88 methodtree_element *mte;
90 methodtree = avl_create(methodtree_comparator, NULL, NULL);
92 mte = NEW(methodtree_element);
94 mte->startpc = asm_calljavafunction;
95 mte->endpc = asm_calljavafunction2 - 1;
97 avl_insert(methodtree, mte);
99 mte = NEW(methodtree_element);
101 mte->startpc = asm_calljavafunction2;
102 mte->endpc = asm_call_jit_compiler - 1;
104 avl_insert(methodtree, mte);
110 /* codegen_setup **************************************************************
112 allocates and initialises code area, data area and references
114 *******************************************************************************/
116 void codegen_setup(methodinfo *m, t_inlining_globals * e)
120 m->codegendata = NEW(codegendata);
122 /* keep code size smaller */
125 cd->mcodebase = MNEW(u1, MCODEINITSIZE);
126 cd->mcodesize = MCODEINITSIZE;
128 cd->dsegtop = MNEW(u1, DSEGINITSIZE);
129 cd->dsegsize = DSEGINITSIZE;
130 cd->dsegtop += cd->dsegsize;
133 cd->jumpreferences = NULL;
134 cd->datareferences = NULL;
135 cd->xboundrefs = NULL;
136 cd->xcheckarefs = NULL;
137 cd->xnullrefs = NULL;
138 cd->xcastrefs = NULL;
140 cd->xexceptionrefs = NULL;
142 cd->linenumberreferences = NULL;
143 cd->linenumbertablesizepos = 0;
144 cd->linenumbertablestartpos = 0;
145 cd->linenumbertab = 0;
148 cd->exceptiontable=0;
149 cd->exceptiontablelength=0;
150 if (useinlining && e) {
151 if (e->cumextablelength>0) {
152 cd->exceptiontablelength=e->cumextablelength;
153 cd->exceptiontable = MNEW(exceptiontable, e->cumextablelength + 1);
155 } else if (e && (e->method->exceptiontablelength >0)) {
156 cd->exceptiontablelength=m->exceptiontablelength;
157 cd->exceptiontable = MNEW(exceptiontable, m->exceptiontablelength + 1);
160 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
161 cd->threadcritcurrent.next = NULL;
162 cd->threadcritcount = 0;
167 /* codegen_close releases temporary code and data area */
169 void codegen_close(methodinfo *m)
176 if (cd->exceptiontablelength) {
177 cd->exceptiontablelength=m->exceptiontablelength;
178 MFREE(cd->exceptiontable, exceptiontable, cd->exceptiontablelength + 1);
179 cd->exceptiontable=0;
180 cd->exceptiontablelength=0;
183 MFREE(cd->mcodebase, u1, cd->mcodesize);
184 cd->mcodebase = NULL;
188 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
192 FREE(m->codegendata, codegendata);
193 m->codegendata = NULL;
198 /* codegen_increase doubles code area */
200 static s4 *codegen_increase(methodinfo *m, u1 *codeptr)
207 len = codeptr - cd->mcodebase;
208 cd->mcodebase = MREALLOC(cd->mcodebase,
213 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
215 return (s4 *) (cd->mcodebase + len);
219 /* desg_increase doubles data area */
221 static void dseg_increase(methodinfo *m)
228 newstorage = MNEW(u1, cd->dsegsize * 2);
230 memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
231 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
233 cd->dsegtop = newstorage;
235 cd->dsegtop += cd->dsegsize;
239 static s4 dseg_adds4_increase(methodinfo *m, s4 value)
247 *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
249 return -(cd->dseglen);
253 static s4 dseg_adds4(methodinfo *m, s4 value)
261 dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
263 if (cd->dseglen > cd->dsegsize)
264 return dseg_adds4_increase(m, value);
268 return -(cd->dseglen);
272 #if !defined(__I386__)
273 static s4 dseg_adds8_increase(methodinfo *m, s8 value)
281 *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
283 return -(cd->dseglen);
287 static s4 dseg_adds8(methodinfo *m, s8 value)
294 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
295 dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
297 if (cd->dseglen > cd->dsegsize)
298 return dseg_adds8_increase(m, value);
302 return -(cd->dseglen);
307 static s4 dseg_addfloat_increase(methodinfo *m, float value)
315 *((float *) (cd->dsegtop - cd->dseglen)) = value;
317 return -(cd->dseglen);
321 static s4 dseg_addfloat(methodinfo *m, float value)
329 dataptr = (float *) (cd->dsegtop - cd->dseglen);
331 if (cd->dseglen > cd->dsegsize)
332 return dseg_addfloat_increase(m, value);
336 return -(cd->dseglen);
340 static s4 dseg_adddouble_increase(methodinfo *m, double value)
348 *((double *) (cd->dsegtop - cd->dseglen)) = value;
350 return -(cd->dseglen);
354 static s4 dseg_adddouble(methodinfo *m, double value)
361 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
362 dataptr = (double *) (cd->dsegtop - cd->dseglen);
364 if (cd->dseglen > cd->dsegsize)
365 return dseg_adddouble_increase(m, value);
369 return -(cd->dseglen);
373 static void dseg_addtarget(methodinfo *m, basicblock *target)
381 jr->tablepos = dseg_addaddress(m, NULL);
383 jr->next = cd->jumpreferences;
384 cd->jumpreferences = jr;
388 static void dseg_adddata(methodinfo *m, u1 *ptr)
396 dr->pos = (u1 *) (ptr - cd->mcodebase);
397 dr->next = cd->datareferences;
398 cd->datareferences = dr;
402 static void dseg_addlinenumbertablesize(methodinfo *m)
409 dseg_adds4(m, 0); /*PADDING*/
411 cd->linenumbertablesizepos = dseg_addaddress(m, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
413 cd->linenumbertablestartpos = dseg_addaddress(m, NULL);
415 dseg_adds4(m, 0); /*PADDING*/
420 static void dseg_addlinenumber(methodinfo *m, u2 linenumber, u1 *ptr)
427 lr = DNEW(linenumberref);
428 lr->linenumber = linenumber;
430 lr->targetmpc = (ptr - cd->mcodebase);
431 lr->next = cd->linenumberreferences;
432 cd->linenumberreferences = lr;
436 /* we need this function externally on i386 and x86_64, but keep the call fast
439 #if defined(__I386__) || defined(__X86_64__)
440 void codegen_addreference(methodinfo *m, basicblock *target, void *branchptr)
442 static void codegen_addreference(methodinfo *m, basicblock *target, void *branchptr)
450 branchpos = (u1 *) branchptr - cd->mcodebase;
452 if (target->mpc >= 0) {
453 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
458 branchref *br = DNEW(branchref);
460 br->branchpos = branchpos;
461 br->next = target->branchrefs;
462 target->branchrefs = br;
467 static void codegen_addxboundrefs(methodinfo *m, void *branchptr, s4 reg)
475 branchpos = (u1 *) branchptr - cd->mcodebase;
477 br = DNEW(branchref);
478 br->branchpos = branchpos;
480 br->next = cd->xboundrefs;
485 static void codegen_addxcheckarefs(methodinfo *m, void *branchptr)
493 branchpos = (u1 *) branchptr - cd->mcodebase;
495 br = DNEW(branchref);
496 br->branchpos = branchpos;
497 br->next = cd->xcheckarefs;
498 cd->xcheckarefs = br;
502 static void codegen_addxnullrefs(methodinfo *m, void *branchptr)
510 branchpos = (u1 *) branchptr - cd->mcodebase;
512 br = DNEW(branchref);
513 br->branchpos = branchpos;
514 br->next = cd->xnullrefs;
520 static void codegen_addxcastrefs(methodinfo *m, void *branchptr)
528 branchpos = (u1 *) branchptr - cd->mcodebase;
530 br = DNEW(branchref);
531 br->branchpos = branchpos;
532 br->next = cd->xcastrefs;
537 static void codegen_addxexceptionrefs(methodinfo *m, void *branchptr)
545 branchpos = (u1 *) branchptr - cd->mcodebase;
547 br = DNEW(branchref);
548 br->branchpos = branchpos;
549 br->next = cd->xexceptionrefs;
550 cd->xexceptionrefs = br;
554 #if defined(__I386__) || defined(__X86_64__)
555 static void codegen_addxdivrefs(methodinfo *m, void *branchptr)
563 branchpos = (u1 *) branchptr - cd->mcodebase;
565 br = DNEW(branchref);
566 br->branchpos = branchpos;
567 br->next = cd->xdivrefs;
573 static void codegen_createlinenumbertable(methodinfo *m)
581 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
582 lr->tablepos = dseg_addaddress(m, NULL);
584 if (cd->linenumbertab == 0)
585 cd->linenumbertab = lr->tablepos;
587 dseg_addaddress(m, lr->linenumber);
593 #if defined(__I386__) || defined(__X86_64__)
594 static int methodtree_comparator(const void *pc, const void *element, void *param)
596 methodtree_element *mte;
597 methodtree_element *mtepc;
599 mte = (methodtree_element *) element;
600 mtepc = (methodtree_element *) pc;
602 /* compare both startpc and endpc of pc, even if they have the same value,
603 otherwise the avl_probe sometimes thinks the element is already in the
605 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
606 mte->startpc <= mtepc->endpc && mtepc->endpc <= mte->endpc) {
609 } else if (mtepc->startpc < mte->startpc) {
619 void *codegen_findmethod1(void *pc)
621 void * retVal=findmethod(pc);
622 methodinfo **ma=(methodinfo**)retVal;
623 methodinfo *m=ma[-1];
626 utf_display(m->name);
629 else log_text("No methodinfo");
635 void codegen_insertmethod(void *startpc, void *endpc)
637 methodtree_element *mte;
639 #if defined(USE_THREADS)
640 #if defined(NATIVE_THREADS)
645 mte = NEW(methodtree_element);
646 mte->startpc = startpc;
649 if (avl_insert(methodtree, mte)) {
650 #if defined(USE_THREADS)
651 #if defined(NATIVE_THREADS)
655 throw_cacao_exception_exit(string_java_lang_InternalError,
659 #if defined(USE_THREADS)
660 #if defined(NATIVE_THREADS)
667 void *codegen_findmethod(void *pc)
669 methodtree_element *mtepc;
670 methodtree_element *mte;
672 mtepc = NEW(methodtree_element);
676 mte = avl_find(methodtree, mtepc);
678 FREE(mtepc, methodtree_element);
681 throw_cacao_exception_exit(string_java_lang_InternalError,
682 "cannot find function");
689 static void codegen_finish(methodinfo *m, s4 mcodelen)
699 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
700 extralen += sizeof(threadcritnode) * cd->threadcritcount;
703 #if defined(STATISTICS)
705 count_code_len += mcodelen;
706 count_data_len += cd->dseglen;
710 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
711 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
713 m->mcodelength = mcodelen + cd->dseglen;
714 m->mcode = CNEW(u1, alignedlen + extralen);
716 memcpy(m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
717 memcpy(m->mcode + cd->dseglen, cd->mcodebase, mcodelen);
719 m->entrypoint = epoint = (u1 *) (m->mcode + cd->dseglen);
721 /* jump table resolving */
722 jr = cd->jumpreferences;
724 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
729 /* line number table resolving */
738 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
740 *((void**) (epoint + lr->tablepos)) = epoint + lr->targetmpc;
743 *((void**) (epoint + cd->linenumbertablestartpos)) =
744 epoint + cd->linenumbertab;
746 *((s8*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
748 *((s4*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
753 #if defined(__I386__) || defined(__X86_64__)
757 /* add method into methodtree to find the entrypoint */
758 codegen_insertmethod(m->entrypoint, m->entrypoint + mcodelen);
760 /* data segment references resolving */
761 dr = cd->datareferences;
763 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
769 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
771 threadcritnode *n = (threadcritnode *) (m->mcode + alignedlen);
773 threadcritnodetemp *nt = cd->threadcrit;
775 for (i = 0; i < cd->threadcritcount; i++) {
776 n->mcodebegin = m->mcode + nt->mcodebegin;
777 n->mcodeend = m->mcode + nt->mcodeend;
778 n->mcoderestart = m->mcode + nt->mcoderestart;
779 thread_registercritical(n);
788 void dseg_display(methodinfo *m)
793 s4ptr = (s4 *) m->mcode;
795 printf(" --- dump of datasegment\n");
796 for (i = m->codegendata->dseglen; i > 0 ; i -= 4) {
797 printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
799 printf(" --- begin of data segment: %p\n", s4ptr);
803 #if !defined(__POWERPC__)
805 This function determines a register, to which the result of an operation
806 should go, when it is ultimatively intended to store the result in
808 If v is assigned to an actual register, this register will be returned.
809 Otherwise (when v is spilled) this function returns tempregnum.
810 If not already done, regoff and flags are set in the stack location.
813 static int reg_of_var(methodinfo *m, stackptr v, int tempregnum)
817 switch (v->varkind) {
819 if (!(v->flags & INMEMORY))
823 var = &(m->registerdata->interfaces[v->varnum][v->type]);
824 v->regoff = var->regoff;
825 if (!(var->flags & INMEMORY))
829 var = &(m->registerdata->locals[v->varnum][v->type]);
830 v->regoff = var->regoff;
831 if (!(var->flags & INMEMORY))
835 v->regoff = v->varnum;
836 if (IS_FLT_DBL_TYPE(v->type)) {
837 if (v->varnum < m->registerdata->fltreg_argnum) {
838 v->regoff = m->registerdata->argfltregs[v->varnum];
839 return(m->registerdata->argfltregs[v->varnum]);
843 if (v->varnum < m->registerdata->intreg_argnum) {
844 v->regoff = m->registerdata->argintregs[v->varnum];
845 return(m->registerdata->argintregs[v->varnum]);
847 v->regoff -= m->registerdata->intreg_argnum;
850 v->flags |= INMEMORY;
856 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
857 static void codegen_threadcritrestart(methodinfo *m, int offset)
859 m->codegendata->threadcritcurrent.mcoderestart = offset;
862 static void codegen_threadcritstart(methodinfo *m, int offset)
864 m->codegendata->threadcritcurrent.mcodebegin = offset;
867 static void codegen_threadcritstop(methodinfo *m, int offset)
873 cd->threadcritcurrent.next = cd->threadcrit;
874 cd->threadcritcurrent.mcodeend = offset;
875 cd->threadcrit = DNEW(threadcritnodetemp);
876 *(cd->threadcrit) = cd->threadcritcurrent;
877 cd->threadcritcount++;
882 * These are local overrides for various environment variables in Emacs.
883 * Please do not remove this and leave it at the end of the file, where
884 * Emacs will automagically detect them.
885 * ---------------------------------------------------------------------
888 * indent-tabs-mode: t