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 1466 2004-11-08 11:24:50Z 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"
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, codegendata *cd, t_inlining_globals *id)
120 cd->mcodebase = MNEW(u1, MCODEINITSIZE);
121 cd->mcodesize = MCODEINITSIZE;
123 cd->dsegtop = MNEW(u1, DSEGINITSIZE);
124 cd->dsegsize = DSEGINITSIZE;
125 cd->dsegtop += cd->dsegsize;
128 cd->jumpreferences = NULL;
129 cd->datareferences = NULL;
130 cd->xboundrefs = NULL;
131 cd->xcheckarefs = NULL;
132 cd->xnullrefs = NULL;
133 cd->xcastrefs = NULL;
135 cd->xexceptionrefs = NULL;
137 cd->linenumberreferences = NULL;
138 cd->linenumbertablesizepos = 0;
139 cd->linenumbertablestartpos = 0;
140 cd->linenumbertab = 0;
143 cd->exceptiontable = 0;
144 cd->exceptiontablelength = 0;
146 if (useinlining && id) {
147 if (id->cumextablelength > 0) {
148 cd->exceptiontablelength = id->cumextablelength;
149 cd->exceptiontable = DMNEW(exceptiontable, id->cumextablelength + 1);
152 } else if (id && (id->method->exceptiontablelength >0)) {
153 cd->exceptiontablelength = m->exceptiontablelength;
154 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
158 cd->maxstack = id->cummaxstack;
159 cd->maxlocals = id->cumlocals;
161 cd->maxstack = m->maxstack;
162 cd->maxlocals = m->maxlocals;
165 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
166 cd->threadcritcurrent.next = NULL;
167 cd->threadcritcount = 0;
172 /* codegen_free ****************************************************************
174 releases temporary code and data area
176 *******************************************************************************/
178 void codegen_free(methodinfo *m, codegendata *cd)
182 if (cd->exceptiontablelength) {
183 cd->exceptiontablelength = m->exceptiontablelength;
184 MFREE(cd->exceptiontable, exceptiontable, cd->exceptiontablelength + 1);
185 cd->exceptiontable = 0;
186 cd->exceptiontablelength = 0;
191 MFREE(cd->mcodebase, u1, cd->mcodesize);
192 cd->mcodebase = NULL;
196 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
203 /* codegen_close ***************************************************************
207 *******************************************************************************/
211 /* TODO: release avl tree on i386 and x86_64 */
215 /* codegen_increase doubles code area */
217 static s4 *codegen_increase(codegendata *cd, u1 *codeptr)
221 len = codeptr - cd->mcodebase;
222 cd->mcodebase = MREALLOC(cd->mcodebase,
227 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
229 return (s4 *) (cd->mcodebase + len);
233 /* desg_increase doubles data area */
235 static void dseg_increase(codegendata *cd)
239 newstorage = MNEW(u1, cd->dsegsize * 2);
241 memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
242 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
244 cd->dsegtop = newstorage;
246 cd->dsegtop += cd->dsegsize;
250 static s4 dseg_adds4_increase(codegendata *cd, s4 value)
254 *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
256 return -(cd->dseglen);
260 static s4 dseg_adds4(codegendata *cd, s4 value)
265 dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
267 if (cd->dseglen > cd->dsegsize)
268 return dseg_adds4_increase(cd, value);
272 return -(cd->dseglen);
276 #if !defined(__I386__)
277 static s4 dseg_adds8_increase(codegendata *cd, s8 value)
281 *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
283 return -(cd->dseglen);
287 static s4 dseg_adds8(codegendata *cd, s8 value)
291 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
292 dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
294 if (cd->dseglen > cd->dsegsize)
295 return dseg_adds8_increase(cd, value);
299 return -(cd->dseglen);
304 static s4 dseg_addfloat_increase(codegendata *cd, float value)
308 *((float *) (cd->dsegtop - cd->dseglen)) = value;
310 return -(cd->dseglen);
314 static s4 dseg_addfloat(codegendata *cd, float value)
319 dataptr = (float *) (cd->dsegtop - cd->dseglen);
321 if (cd->dseglen > cd->dsegsize)
322 return dseg_addfloat_increase(cd, value);
326 return -(cd->dseglen);
330 static s4 dseg_adddouble_increase(codegendata *cd, double value)
334 *((double *) (cd->dsegtop - cd->dseglen)) = value;
336 return -(cd->dseglen);
340 static s4 dseg_adddouble(codegendata *cd, double value)
344 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
345 dataptr = (double *) (cd->dsegtop - cd->dseglen);
347 if (cd->dseglen > cd->dsegsize)
348 return dseg_adddouble_increase(cd, value);
352 return -(cd->dseglen);
356 static void dseg_addtarget(codegendata *cd, basicblock *target)
361 jr->tablepos = dseg_addaddress(cd, NULL);
363 jr->next = cd->jumpreferences;
364 cd->jumpreferences = jr;
368 static void dseg_adddata(codegendata *cd, u1 *ptr)
373 dr->pos = (u1 *) (ptr - cd->mcodebase);
374 dr->next = cd->datareferences;
375 cd->datareferences = dr;
379 static void dseg_addlinenumbertablesize(codegendata *cd)
382 dseg_adds4(cd, 0); /*PADDING*/
384 cd->linenumbertablesizepos = dseg_addaddress(cd, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
386 cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
388 dseg_adds4(cd, 0); /*PADDING*/
393 static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
397 lr = DNEW(linenumberref);
398 lr->linenumber = linenumber;
400 lr->targetmpc = (ptr - cd->mcodebase);
401 lr->next = cd->linenumberreferences;
402 cd->linenumberreferences = lr;
406 /* we need this function externally on i386 and x86_64, but keep the call fast
409 #if defined(__I386__) || defined(__X86_64__)
410 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
412 static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
417 branchpos = (u1 *) branchptr - cd->mcodebase;
419 if (target->mpc >= 0) {
420 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
425 branchref *br = DNEW(branchref);
427 br->branchpos = branchpos;
428 br->next = target->branchrefs;
429 target->branchrefs = br;
434 static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
439 branchpos = (u1 *) branchptr - cd->mcodebase;
441 br = DNEW(branchref);
442 br->branchpos = branchpos;
444 br->next = cd->xboundrefs;
449 static void codegen_addxcheckarefs(codegendata *cd, void *branchptr)
454 branchpos = (u1 *) branchptr - cd->mcodebase;
456 br = DNEW(branchref);
457 br->branchpos = branchpos;
458 br->next = cd->xcheckarefs;
459 cd->xcheckarefs = br;
463 static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
468 branchpos = (u1 *) branchptr - cd->mcodebase;
470 br = DNEW(branchref);
471 br->branchpos = branchpos;
472 br->next = cd->xnullrefs;
477 static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
482 branchpos = (u1 *) branchptr - cd->mcodebase;
484 br = DNEW(branchref);
485 br->branchpos = branchpos;
486 br->next = cd->xcastrefs;
491 static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
496 branchpos = (u1 *) branchptr - cd->mcodebase;
498 br = DNEW(branchref);
499 br->branchpos = branchpos;
500 br->next = cd->xexceptionrefs;
501 cd->xexceptionrefs = br;
505 #if defined(__I386__) || defined(__X86_64__)
506 static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
511 branchpos = (u1 *) branchptr - cd->mcodebase;
513 br = DNEW(branchref);
514 br->branchpos = branchpos;
515 br->next = cd->xdivrefs;
521 static void codegen_createlinenumbertable(codegendata *cd)
526 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
527 lr->tablepos = dseg_addaddress(cd, NULL);
529 if (cd->linenumbertab == 0)
530 cd->linenumbertab = lr->tablepos;
532 dseg_addaddress(cd, lr->linenumber);
538 #if defined(__I386__) || defined(__X86_64__)
539 static int methodtree_comparator(const void *pc, const void *element, void *param)
541 methodtree_element *mte;
542 methodtree_element *mtepc;
544 mte = (methodtree_element *) element;
545 mtepc = (methodtree_element *) pc;
547 /* compare both startpc and endpc of pc, even if they have the same value,
548 otherwise the avl_probe sometimes thinks the element is already in the
550 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
551 mte->startpc <= mtepc->endpc && mtepc->endpc <= mte->endpc) {
554 } else if (mtepc->startpc < mte->startpc) {
564 void *codegen_findmethod1(void *pc)
566 void * retVal=findmethod(pc);
567 methodinfo **ma=(methodinfo**)retVal;
568 methodinfo *m=ma[-1];
571 utf_display(m->name);
574 else log_text("No methodinfo");
580 void codegen_insertmethod(void *startpc, void *endpc)
582 methodtree_element *mte;
584 #if defined(USE_THREADS)
585 #if defined(NATIVE_THREADS)
590 mte = NEW(methodtree_element);
591 mte->startpc = startpc;
594 if (avl_insert(methodtree, mte)) {
595 #if defined(USE_THREADS)
596 #if defined(NATIVE_THREADS)
600 throw_cacao_exception_exit(string_java_lang_InternalError,
604 #if defined(USE_THREADS)
605 #if defined(NATIVE_THREADS)
612 void *codegen_findmethod(void *pc)
614 methodtree_element *mtepc;
615 methodtree_element *mte;
617 #if defined(USE_THREADS)
618 #if defined(NATIVE_THREADS)
623 mtepc = NEW(methodtree_element);
627 mte = avl_find(methodtree, mtepc);
629 FREE(mtepc, methodtree_element);
632 #if defined(USE_THREADS)
633 #if defined(NATIVE_THREADS)
637 throw_cacao_exception_exit(string_java_lang_InternalError,
638 "cannot find function");
641 #if defined(USE_THREADS)
642 #if defined(NATIVE_THREADS)
652 static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
659 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
660 extralen = sizeof(threadcritnode) * cd->threadcritcount;
665 #if defined(STATISTICS)
667 count_code_len += mcodelen;
668 count_data_len += cd->dseglen;
672 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
673 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
675 m->mcodelength = mcodelen + cd->dseglen;
676 m->mcode = CNEW(u1, alignedlen + extralen);
678 memcpy(m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
679 memcpy(m->mcode + cd->dseglen, cd->mcodebase, mcodelen);
681 m->entrypoint = epoint = (u1 *) (m->mcode + cd->dseglen);
683 /* jump table resolving */
684 jr = cd->jumpreferences;
686 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
691 /* line number table resolving */
700 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
702 *((void**) (epoint + lr->tablepos)) = epoint + lr->targetmpc;
705 *((void**) (epoint + cd->linenumbertablestartpos)) =
706 epoint + cd->linenumbertab;
708 *((s8*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
710 *((s4*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
715 #if defined(__I386__) || defined(__X86_64__)
719 /* add method into methodtree to find the entrypoint */
720 codegen_insertmethod(m->entrypoint, m->entrypoint + mcodelen);
722 /* data segment references resolving */
723 dr = cd->datareferences;
725 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
731 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
733 threadcritnode *n = (threadcritnode *) (m->mcode + alignedlen);
735 threadcritnodetemp *nt = cd->threadcrit;
737 for (i = 0; i < cd->threadcritcount; i++) {
738 n->mcodebegin = m->mcode + nt->mcodebegin;
739 n->mcodeend = m->mcode + nt->mcodeend;
740 n->mcoderestart = m->mcode + nt->mcoderestart;
741 thread_registercritical(n);
750 void dseg_display(methodinfo *m, codegendata *cd)
755 s4ptr = (s4 *) m->mcode;
757 printf(" --- dump of datasegment\n");
758 for (i = cd->dseglen; i > 0 ; i -= 4) {
759 printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
761 printf(" --- begin of data segment: %p\n", s4ptr);
765 #if !defined(__POWERPC__)
767 This function determines a register, to which the result of an operation
768 should go, when it is ultimatively intended to store the result in
770 If v is assigned to an actual register, this register will be returned.
771 Otherwise (when v is spilled) this function returns tempregnum.
772 If not already done, regoff and flags are set in the stack location.
775 static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
779 switch (v->varkind) {
781 if (!(v->flags & INMEMORY))
785 var = &(rd->interfaces[v->varnum][v->type]);
786 v->regoff = var->regoff;
787 if (!(var->flags & INMEMORY))
791 var = &(rd->locals[v->varnum][v->type]);
792 v->regoff = var->regoff;
793 if (!(var->flags & INMEMORY))
797 v->regoff = v->varnum;
798 if (IS_FLT_DBL_TYPE(v->type)) {
799 if (v->varnum < rd->fltreg_argnum) {
800 v->regoff = rd->argfltregs[v->varnum];
801 return(rd->argfltregs[v->varnum]);
805 if (v->varnum < rd->intreg_argnum) {
806 v->regoff = rd->argintregs[v->varnum];
807 return (rd->argintregs[v->varnum]);
809 v->regoff -= rd->intreg_argnum;
812 v->flags |= INMEMORY;
818 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
819 static void codegen_threadcritrestart(codegendata *cd, int offset)
821 cd->threadcritcurrent.mcoderestart = offset;
825 static void codegen_threadcritstart(codegendata *cd, int offset)
827 cd->threadcritcurrent.mcodebegin = offset;
831 static void codegen_threadcritstop(codegendata *cd, int offset)
833 cd->threadcritcurrent.next = cd->threadcrit;
834 cd->threadcritcurrent.mcodeend = offset;
835 cd->threadcrit = DNEW(threadcritnodetemp);
836 *(cd->threadcrit) = cd->threadcritcurrent;
837 cd->threadcritcount++;
842 #ifndef STATIC_CLASSPATH
843 static size_t codegen_overloadPartLen(utf *desc) {
844 char *utf_ptr=desc->text;
847 while ((c=utf_nextu2(&utf_ptr))!=')') {
864 while ( (c=utf_nextu2(&utf_ptr)) != ';')
870 default: panic ("invalid method descriptor");
877 static void codegen_fillInOverloadPart(char *target,utf *desc) {
878 char *utf_ptr=desc->text;
880 char* insertpos=&target[strlen(target)];
883 while ((c=utf_nextu2(&utf_ptr))!=')') {
901 while ( (c=utf_nextu2(&utf_ptr)) != ';')
902 if ( ((c>='a') && (c<='z')) ||
903 ((c>='A') && (c<='Z')) ||
904 ((c>='0') && (c<='9')) )
906 else *(insertpos++)='_';
912 default: panic ("invalid method descriptor");
919 static void codegen_resolve_native(methodinfo *m,void **insertionPoint,void *jmpTarget,void **jmpPatchTarget) {
920 char *nativeName, *nativeNameEscape;
924 builtin_monitorenter((java_objectheader*) m);
925 if ((*jmpPatchTarget)==jmpTarget) {
926 builtin_monitorexit((java_objectheader*) m);
929 log_text("trying to resolve a native method");
930 utf_display(m->class->name);
931 utf_display(m->name);
933 void *lib=dlopen(0,RTLD_NOW | RTLD_GLOBAL);
936 /*generate the name of the native function in the form Java_package1_package2...._classname_methodname*/
937 nativeLen=/*Java_*/5+strlen(m->class->name->text)+/*_*/1+strlen(m->name->text)+/*\0*/1;
938 nativeName=MNEW(char,nativeLen);
939 sprintf(nativeName,"Java_%s/%s",m->class->name->text,m->name->text);
941 while (i<nativeLen) {
942 if (nativeName[i]=='_') { // escape underscore
943 nativeNameEscape = MNEW(char,nativeLen+1);
944 memcpy(nativeNameEscape,nativeName,i+1);
945 nativeNameEscape[i+1] = '1'; // escape sequence for _ is _1
946 memcpy(&nativeNameEscape[i+2],&nativeName[i+1],nativeLen-i-1);
947 MFREE(nativeName,char,nativeLen);
950 nativeNameEscape[nativeLen]=0;
951 nativeName=nativeNameEscape;
953 if (nativeName[i]=='/') nativeName[i]='_';
957 /* printf("nativename: %s\n",nativeName); */
959 void *sym=dlsym(lib,nativeName);
962 log_text("resolved");
963 MFREE(nativeName,char,nativeLen);
965 size_t overloadedNativeLen=nativeLen+codegen_overloadPartLen(m->descriptor);
966 char *overloadedNative=MNEW(char,overloadedNativeLen);
967 sprintf(overloadedNative,"%s",nativeName);
968 MFREE(nativeName,char,nativeLen);
969 codegen_fillInOverloadPart(overloadedNative,m->descriptor);
970 log_text("symbol not found,trying harder (overloaded member ?)");
971 sym=dlsym(lib,overloadedNative);
973 MFREE(overloadedNative,char,overloadedNativeLen);
975 log_text("resolved");
977 MFREE(overloadedNative,char,overloadedNativeLen);
978 log_text("It was not possible to find the native function implementation. Not even in overloading case");
982 (*insertionPoint)=sym;
983 (*jmpPatchTarget)=jmpTarget;
984 builtin_monitorexit((java_objectheader *) m );
988 } else log_text("library not found");
994 slen=2+strlen(m->class->name->text)+strlen(m->name->text)+strlen(m->descriptor->text);
995 info=(char*)MNEW(char,slen);
996 sprintf(info,"%s.%s%s",m->class->name->text,m->name->text,m->descriptor->text);
998 builtin_monitorexit((java_objectheader *) m );
999 throw_cacao_exception_exit(string_java_lang_LinkageError,
1008 * These are local overrides for various environment variables in Emacs.
1009 * Please do not remove this and leave it at the end of the file, where
1010 * Emacs will automagically detect them.
1011 * ---------------------------------------------------------------------
1014 * indent-tabs-mode: t