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 1429 2004-11-02 08:58:26Z jowenn $
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"
66 #ifndef STATIC_CLASSPATH
70 /* in this tree we store all method addresses */
72 #if defined(__I386__) || defined(__X86_64__)
73 static struct avl_table *methodtree = NULL;
74 static int methodtree_comparator(const void *pc, const void *element,
79 /* codegen_init ****************************************************************
83 *******************************************************************************/
87 #if defined(__I386__) || defined(__X86_64__)
88 /* this tree is global, not method specific */
90 methodtree_element *mte;
92 methodtree = avl_create(methodtree_comparator, NULL, NULL);
94 mte = NEW(methodtree_element);
96 mte->startpc = asm_calljavafunction;
97 mte->endpc = asm_calljavafunction2 - 1;
99 avl_insert(methodtree, mte);
101 mte = NEW(methodtree_element);
103 mte->startpc = asm_calljavafunction2;
104 mte->endpc = asm_call_jit_compiler - 1;
106 avl_insert(methodtree, mte);
112 /* codegen_setup **************************************************************
114 allocates and initialises code area, data area and references
116 *******************************************************************************/
118 void codegen_setup(methodinfo *m, t_inlining_globals * e)
122 m->codegendata = NEW(codegendata);
124 /* keep code size smaller */
127 cd->mcodebase = MNEW(u1, MCODEINITSIZE);
128 cd->mcodesize = MCODEINITSIZE;
130 cd->dsegtop = MNEW(u1, DSEGINITSIZE);
131 cd->dsegsize = DSEGINITSIZE;
132 cd->dsegtop += cd->dsegsize;
135 cd->jumpreferences = NULL;
136 cd->datareferences = NULL;
137 cd->xboundrefs = NULL;
138 cd->xcheckarefs = NULL;
139 cd->xnullrefs = NULL;
140 cd->xcastrefs = NULL;
142 cd->xexceptionrefs = NULL;
144 cd->linenumberreferences = NULL;
145 cd->linenumbertablesizepos = 0;
146 cd->linenumbertablestartpos = 0;
147 cd->linenumbertab = 0;
150 cd->exceptiontable=0;
151 cd->exceptiontablelength=0;
152 if (useinlining && e) {
153 if (e->cumextablelength>0) {
154 cd->exceptiontablelength=e->cumextablelength;
155 cd->exceptiontable = MNEW(exceptiontable, e->cumextablelength + 1);
157 } else if (e && (e->method->exceptiontablelength >0)) {
158 cd->exceptiontablelength=m->exceptiontablelength;
159 cd->exceptiontable = MNEW(exceptiontable, m->exceptiontablelength + 1);
162 cd->maxstack=e->cummaxstack;
163 cd->maxlocals=e->cumlocals;
165 cd->maxstack=m->maxstack;
166 cd->maxlocals=m->maxlocals;
168 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
169 cd->threadcritcurrent.next = NULL;
170 cd->threadcritcount = 0;
175 /* codegen_close releases temporary code and data area */
177 void codegen_close(methodinfo *m)
184 if (cd->exceptiontablelength) {
185 cd->exceptiontablelength=m->exceptiontablelength;
186 MFREE(cd->exceptiontable, exceptiontable, cd->exceptiontablelength + 1);
187 cd->exceptiontable=0;
188 cd->exceptiontablelength=0;
191 MFREE(cd->mcodebase, u1, cd->mcodesize);
192 cd->mcodebase = NULL;
196 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
200 FREE(m->codegendata, codegendata);
201 m->codegendata = NULL;
206 /* codegen_increase doubles code area */
208 static s4 *codegen_increase(methodinfo *m, u1 *codeptr)
215 len = codeptr - cd->mcodebase;
216 cd->mcodebase = MREALLOC(cd->mcodebase,
221 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
223 return (s4 *) (cd->mcodebase + len);
227 /* desg_increase doubles data area */
229 static void dseg_increase(methodinfo *m)
236 newstorage = MNEW(u1, cd->dsegsize * 2);
238 memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
239 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
241 cd->dsegtop = newstorage;
243 cd->dsegtop += cd->dsegsize;
247 static s4 dseg_adds4_increase(methodinfo *m, s4 value)
255 *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
257 return -(cd->dseglen);
261 static s4 dseg_adds4(methodinfo *m, s4 value)
269 dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
271 if (cd->dseglen > cd->dsegsize)
272 return dseg_adds4_increase(m, value);
276 return -(cd->dseglen);
280 #if !defined(__I386__)
281 static s4 dseg_adds8_increase(methodinfo *m, s8 value)
289 *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
291 return -(cd->dseglen);
295 static s4 dseg_adds8(methodinfo *m, s8 value)
302 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
303 dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
305 if (cd->dseglen > cd->dsegsize)
306 return dseg_adds8_increase(m, value);
310 return -(cd->dseglen);
315 static s4 dseg_addfloat_increase(methodinfo *m, float value)
323 *((float *) (cd->dsegtop - cd->dseglen)) = value;
325 return -(cd->dseglen);
329 static s4 dseg_addfloat(methodinfo *m, float value)
337 dataptr = (float *) (cd->dsegtop - cd->dseglen);
339 if (cd->dseglen > cd->dsegsize)
340 return dseg_addfloat_increase(m, value);
344 return -(cd->dseglen);
348 static s4 dseg_adddouble_increase(methodinfo *m, double value)
356 *((double *) (cd->dsegtop - cd->dseglen)) = value;
358 return -(cd->dseglen);
362 static s4 dseg_adddouble(methodinfo *m, double value)
369 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
370 dataptr = (double *) (cd->dsegtop - cd->dseglen);
372 if (cd->dseglen > cd->dsegsize)
373 return dseg_adddouble_increase(m, value);
377 return -(cd->dseglen);
381 static void dseg_addtarget(methodinfo *m, basicblock *target)
389 jr->tablepos = dseg_addaddress(m, NULL);
391 jr->next = cd->jumpreferences;
392 cd->jumpreferences = jr;
396 static void dseg_adddata(methodinfo *m, u1 *ptr)
404 dr->pos = (u1 *) (ptr - cd->mcodebase);
405 dr->next = cd->datareferences;
406 cd->datareferences = dr;
410 static void dseg_addlinenumbertablesize(methodinfo *m)
417 dseg_adds4(m, 0); /*PADDING*/
419 cd->linenumbertablesizepos = dseg_addaddress(m, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
421 cd->linenumbertablestartpos = dseg_addaddress(m, NULL);
423 dseg_adds4(m, 0); /*PADDING*/
428 static void dseg_addlinenumber(methodinfo *m, u2 linenumber, u1 *ptr)
435 lr = DNEW(linenumberref);
436 lr->linenumber = linenumber;
438 lr->targetmpc = (ptr - cd->mcodebase);
439 lr->next = cd->linenumberreferences;
440 cd->linenumberreferences = lr;
444 /* we need this function externally on i386 and x86_64, but keep the call fast
447 #if defined(__I386__) || defined(__X86_64__)
448 void codegen_addreference(methodinfo *m, basicblock *target, void *branchptr)
450 static void codegen_addreference(methodinfo *m, basicblock *target, void *branchptr)
458 branchpos = (u1 *) branchptr - cd->mcodebase;
460 if (target->mpc >= 0) {
461 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
466 branchref *br = DNEW(branchref);
468 br->branchpos = branchpos;
469 br->next = target->branchrefs;
470 target->branchrefs = br;
475 static void codegen_addxboundrefs(methodinfo *m, void *branchptr, s4 reg)
483 branchpos = (u1 *) branchptr - cd->mcodebase;
485 br = DNEW(branchref);
486 br->branchpos = branchpos;
488 br->next = cd->xboundrefs;
493 static void codegen_addxcheckarefs(methodinfo *m, void *branchptr)
501 branchpos = (u1 *) branchptr - cd->mcodebase;
503 br = DNEW(branchref);
504 br->branchpos = branchpos;
505 br->next = cd->xcheckarefs;
506 cd->xcheckarefs = br;
510 static void codegen_addxnullrefs(methodinfo *m, void *branchptr)
518 branchpos = (u1 *) branchptr - cd->mcodebase;
520 br = DNEW(branchref);
521 br->branchpos = branchpos;
522 br->next = cd->xnullrefs;
528 static void codegen_addxcastrefs(methodinfo *m, void *branchptr)
536 branchpos = (u1 *) branchptr - cd->mcodebase;
538 br = DNEW(branchref);
539 br->branchpos = branchpos;
540 br->next = cd->xcastrefs;
545 static void codegen_addxexceptionrefs(methodinfo *m, void *branchptr)
553 branchpos = (u1 *) branchptr - cd->mcodebase;
555 br = DNEW(branchref);
556 br->branchpos = branchpos;
557 br->next = cd->xexceptionrefs;
558 cd->xexceptionrefs = br;
562 #if defined(__I386__) || defined(__X86_64__)
563 static void codegen_addxdivrefs(methodinfo *m, void *branchptr)
571 branchpos = (u1 *) branchptr - cd->mcodebase;
573 br = DNEW(branchref);
574 br->branchpos = branchpos;
575 br->next = cd->xdivrefs;
581 static void codegen_createlinenumbertable(methodinfo *m)
589 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
590 lr->tablepos = dseg_addaddress(m, NULL);
592 if (cd->linenumbertab == 0)
593 cd->linenumbertab = lr->tablepos;
595 dseg_addaddress(m, lr->linenumber);
601 #if defined(__I386__) || defined(__X86_64__)
602 static int methodtree_comparator(const void *pc, const void *element, void *param)
604 methodtree_element *mte;
605 methodtree_element *mtepc;
607 mte = (methodtree_element *) element;
608 mtepc = (methodtree_element *) pc;
610 /* compare both startpc and endpc of pc, even if they have the same value,
611 otherwise the avl_probe sometimes thinks the element is already in the
613 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
614 mte->startpc <= mtepc->endpc && mtepc->endpc <= mte->endpc) {
617 } else if (mtepc->startpc < mte->startpc) {
627 void *codegen_findmethod1(void *pc)
629 void * retVal=findmethod(pc);
630 methodinfo **ma=(methodinfo**)retVal;
631 methodinfo *m=ma[-1];
634 utf_display(m->name);
637 else log_text("No methodinfo");
643 void codegen_insertmethod(void *startpc, void *endpc)
645 methodtree_element *mte;
647 #if defined(USE_THREADS)
648 #if defined(NATIVE_THREADS)
653 mte = NEW(methodtree_element);
654 mte->startpc = startpc;
657 if (avl_insert(methodtree, mte)) {
658 #if defined(USE_THREADS)
659 #if defined(NATIVE_THREADS)
663 throw_cacao_exception_exit(string_java_lang_InternalError,
667 #if defined(USE_THREADS)
668 #if defined(NATIVE_THREADS)
675 void *codegen_findmethod(void *pc)
677 methodtree_element *mtepc;
678 methodtree_element *mte;
680 mtepc = NEW(methodtree_element);
684 mte = avl_find(methodtree, mtepc);
686 FREE(mtepc, methodtree_element);
689 throw_cacao_exception_exit(string_java_lang_InternalError,
690 "cannot find function");
697 static void codegen_finish(methodinfo *m, s4 mcodelen)
707 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
708 extralen += sizeof(threadcritnode) * cd->threadcritcount;
711 #if defined(STATISTICS)
713 count_code_len += mcodelen;
714 count_data_len += cd->dseglen;
718 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
719 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
721 m->mcodelength = mcodelen + cd->dseglen;
722 m->mcode = CNEW(u1, alignedlen + extralen);
724 memcpy(m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
725 memcpy(m->mcode + cd->dseglen, cd->mcodebase, mcodelen);
727 m->entrypoint = epoint = (u1 *) (m->mcode + cd->dseglen);
729 /* jump table resolving */
730 jr = cd->jumpreferences;
732 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
737 /* line number table resolving */
746 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
748 *((void**) (epoint + lr->tablepos)) = epoint + lr->targetmpc;
751 *((void**) (epoint + cd->linenumbertablestartpos)) =
752 epoint + cd->linenumbertab;
754 *((s8*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
756 *((s4*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
761 #if defined(__I386__) || defined(__X86_64__)
765 /* add method into methodtree to find the entrypoint */
766 codegen_insertmethod(m->entrypoint, m->entrypoint + mcodelen);
768 /* data segment references resolving */
769 dr = cd->datareferences;
771 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
777 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
779 threadcritnode *n = (threadcritnode *) (m->mcode + alignedlen);
781 threadcritnodetemp *nt = cd->threadcrit;
783 for (i = 0; i < cd->threadcritcount; i++) {
784 n->mcodebegin = m->mcode + nt->mcodebegin;
785 n->mcodeend = m->mcode + nt->mcodeend;
786 n->mcoderestart = m->mcode + nt->mcoderestart;
787 thread_registercritical(n);
796 void dseg_display(methodinfo *m)
801 s4ptr = (s4 *) m->mcode;
803 printf(" --- dump of datasegment\n");
804 for (i = m->codegendata->dseglen; i > 0 ; i -= 4) {
805 printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
807 printf(" --- begin of data segment: %p\n", s4ptr);
811 #if !defined(__POWERPC__)
813 This function determines a register, to which the result of an operation
814 should go, when it is ultimatively intended to store the result in
816 If v is assigned to an actual register, this register will be returned.
817 Otherwise (when v is spilled) this function returns tempregnum.
818 If not already done, regoff and flags are set in the stack location.
821 static int reg_of_var(methodinfo *m, stackptr v, int tempregnum)
825 switch (v->varkind) {
827 if (!(v->flags & INMEMORY))
831 var = &(m->registerdata->interfaces[v->varnum][v->type]);
832 v->regoff = var->regoff;
833 if (!(var->flags & INMEMORY))
837 var = &(m->registerdata->locals[v->varnum][v->type]);
838 v->regoff = var->regoff;
839 if (!(var->flags & INMEMORY))
843 v->regoff = v->varnum;
844 if (IS_FLT_DBL_TYPE(v->type)) {
845 if (v->varnum < m->registerdata->fltreg_argnum) {
846 v->regoff = m->registerdata->argfltregs[v->varnum];
847 return(m->registerdata->argfltregs[v->varnum]);
851 if (v->varnum < m->registerdata->intreg_argnum) {
852 v->regoff = m->registerdata->argintregs[v->varnum];
853 return(m->registerdata->argintregs[v->varnum]);
855 v->regoff -= m->registerdata->intreg_argnum;
858 v->flags |= INMEMORY;
864 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
865 static void codegen_threadcritrestart(methodinfo *m, int offset)
867 m->codegendata->threadcritcurrent.mcoderestart = offset;
870 static void codegen_threadcritstart(methodinfo *m, int offset)
872 m->codegendata->threadcritcurrent.mcodebegin = offset;
875 static void codegen_threadcritstop(methodinfo *m, int offset)
881 cd->threadcritcurrent.next = cd->threadcrit;
882 cd->threadcritcurrent.mcodeend = offset;
883 cd->threadcrit = DNEW(threadcritnodetemp);
884 *(cd->threadcrit) = cd->threadcritcurrent;
885 cd->threadcritcount++;
889 #ifndef STATIC_CLASSPATH
890 static size_t codegen_overloadPartLen(utf *desc) {
891 char *utf_ptr=desc->text;
894 while ((c=utf_nextu2(&utf_ptr))!=')') {
911 while ( (c=utf_nextu2(&utf_ptr)) != ';')
917 default: panic ("invalid method descriptor");
924 static void codegen_fillInOverloadPart(char *target,utf *desc) {
925 char *utf_ptr=desc->text;
927 char* insertpos=&target[strlen(target)];
930 while ((c=utf_nextu2(&utf_ptr))!=')') {
948 while ( (c=utf_nextu2(&utf_ptr)) != ';')
949 if ( ((c>='a') && (c<='z')) ||
950 ((c>='A') && (c<='Z')) ||
951 ((c>='0') && (c<='9')) )
953 else *(insertpos++)='_';
959 default: panic ("invalid method descriptor");
966 static void codegen_resolve_native(methodinfo *m,void **insertionPoint,void *jmpTarget,void **jmpPatchTarget) {
971 builtin_monitorenter((java_objectheader*) m);
972 if ((*jmpPatchTarget)==jmpTarget) {
973 builtin_monitorexit((java_objectheader*) m);
976 log_text("trying to resolve a native method");
977 utf_display(m->class->name);
978 utf_display(m->name);
980 void *lib=dlopen(0,RTLD_NOW | RTLD_GLOBAL);
983 /*generate the name of the native function in the form Java_package1_package2...._classname_methodname*/
984 nativeLen=/*Java_*/5+strlen(m->class->name->text)+/*_*/1+strlen(m->name->text)+/*\0*/1;
985 nativeName=MNEW(char,nativeLen);
986 sprintf(nativeName,"Java_%s_%s",m->class->name->text,m->name->text);
987 for (i=0;i<nativeLen;i++) {
988 if (nativeName[i]=='/') nativeName[i]='_';
992 void *sym=dlsym(lib,nativeName);
995 log_text("resolved");
996 MFREE(nativeName,char,nativeLen);
998 size_t overloadedNativeLen=nativeLen+codegen_overloadPartLen(m->descriptor);
999 char *overloadedNative=MNEW(char,overloadedNativeLen);
1000 sprintf(overloadedNative,"%s",nativeName);
1001 MFREE(nativeName,char,nativeLen);
1002 codegen_fillInOverloadPart(overloadedNative,m->descriptor);
1003 log_text("symbol not found,trying harder (overloaded member ?)");
1004 sym=dlsym(lib,overloadedNative);
1006 MFREE(overloadedNative,char,overloadedNativeLen);
1008 log_text("resolved");
1010 MFREE(overloadedNative,char,overloadedNativeLen);
1011 log_text("It was not possible to find the native function implementation. Not even in overloading case");
1015 (*insertionPoint)=sym;
1016 (*jmpPatchTarget)=jmpTarget;
1017 builtin_monitorexit((java_objectheader *) m );
1021 } else log_text("library not found");
1027 slen=2+strlen(m->class->name->text)+strlen(m->name->text)+strlen(m->descriptor->text);
1028 info=(char*)MNEW(char,slen);
1029 sprintf(info,"%s.%s%s",m->class->name->text,m->name->text,m->descriptor->text);
1031 builtin_monitorexit((java_objectheader *) m );
1032 throw_cacao_exception_exit(string_java_lang_LinkageError,
1040 * These are local overrides for various environment variables in Emacs.
1041 * Please do not remove this and leave it at the end of the file, where
1042 * Emacs will automagically detect them.
1043 * ---------------------------------------------------------------------
1046 * indent-tabs-mode: t