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 1463 2004-11-06 21:20:53Z motse $
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 = MNEW(exceptiontable, id->cumextablelength + 1);
152 } else if (id && (id->method->exceptiontablelength >0)) {
153 cd->exceptiontablelength = m->exceptiontablelength;
154 cd->exceptiontable = MNEW(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)
181 if (cd->exceptiontablelength) {
182 cd->exceptiontablelength = m->exceptiontablelength;
183 MFREE(cd->exceptiontable, exceptiontable, cd->exceptiontablelength + 1);
184 cd->exceptiontable = 0;
185 cd->exceptiontablelength = 0;
189 MFREE(cd->mcodebase, u1, cd->mcodesize);
190 cd->mcodebase = NULL;
194 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
201 /* codegen_close ***************************************************************
205 *******************************************************************************/
209 /* TODO: release avl tree on i386 and x86_64 */
213 /* codegen_increase doubles code area */
215 static s4 *codegen_increase(codegendata *cd, u1 *codeptr)
219 len = codeptr - cd->mcodebase;
220 cd->mcodebase = MREALLOC(cd->mcodebase,
225 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
227 return (s4 *) (cd->mcodebase + len);
231 /* desg_increase doubles data area */
233 static void dseg_increase(codegendata *cd)
237 newstorage = MNEW(u1, cd->dsegsize * 2);
239 memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
240 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
242 cd->dsegtop = newstorage;
244 cd->dsegtop += cd->dsegsize;
248 static s4 dseg_adds4_increase(codegendata *cd, s4 value)
252 *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
254 return -(cd->dseglen);
258 static s4 dseg_adds4(codegendata *cd, s4 value)
263 dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
265 if (cd->dseglen > cd->dsegsize)
266 return dseg_adds4_increase(cd, value);
270 return -(cd->dseglen);
274 #if !defined(__I386__)
275 static s4 dseg_adds8_increase(codegendata *cd, s8 value)
279 *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
281 return -(cd->dseglen);
285 static s4 dseg_adds8(codegendata *cd, s8 value)
289 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
290 dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
292 if (cd->dseglen > cd->dsegsize)
293 return dseg_adds8_increase(cd, value);
297 return -(cd->dseglen);
302 static s4 dseg_addfloat_increase(codegendata *cd, float value)
306 *((float *) (cd->dsegtop - cd->dseglen)) = value;
308 return -(cd->dseglen);
312 static s4 dseg_addfloat(codegendata *cd, float value)
317 dataptr = (float *) (cd->dsegtop - cd->dseglen);
319 if (cd->dseglen > cd->dsegsize)
320 return dseg_addfloat_increase(cd, value);
324 return -(cd->dseglen);
328 static s4 dseg_adddouble_increase(codegendata *cd, double value)
332 *((double *) (cd->dsegtop - cd->dseglen)) = value;
334 return -(cd->dseglen);
338 static s4 dseg_adddouble(codegendata *cd, double value)
342 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
343 dataptr = (double *) (cd->dsegtop - cd->dseglen);
345 if (cd->dseglen > cd->dsegsize)
346 return dseg_adddouble_increase(cd, value);
350 return -(cd->dseglen);
354 static void dseg_addtarget(codegendata *cd, basicblock *target)
359 jr->tablepos = dseg_addaddress(cd, NULL);
361 jr->next = cd->jumpreferences;
362 cd->jumpreferences = jr;
366 static void dseg_adddata(codegendata *cd, u1 *ptr)
371 dr->pos = (u1 *) (ptr - cd->mcodebase);
372 dr->next = cd->datareferences;
373 cd->datareferences = dr;
377 static void dseg_addlinenumbertablesize(codegendata *cd)
380 dseg_adds4(cd, 0); /*PADDING*/
382 cd->linenumbertablesizepos = dseg_addaddress(cd, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
384 cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
386 dseg_adds4(cd, 0); /*PADDING*/
391 static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
395 lr = DNEW(linenumberref);
396 lr->linenumber = linenumber;
398 lr->targetmpc = (ptr - cd->mcodebase);
399 lr->next = cd->linenumberreferences;
400 cd->linenumberreferences = lr;
404 /* we need this function externally on i386 and x86_64, but keep the call fast
407 #if defined(__I386__) || defined(__X86_64__)
408 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
410 static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
415 branchpos = (u1 *) branchptr - cd->mcodebase;
417 if (target->mpc >= 0) {
418 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
423 branchref *br = DNEW(branchref);
425 br->branchpos = branchpos;
426 br->next = target->branchrefs;
427 target->branchrefs = br;
432 static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
437 branchpos = (u1 *) branchptr - cd->mcodebase;
439 br = DNEW(branchref);
440 br->branchpos = branchpos;
442 br->next = cd->xboundrefs;
447 static void codegen_addxcheckarefs(codegendata *cd, void *branchptr)
452 branchpos = (u1 *) branchptr - cd->mcodebase;
454 br = DNEW(branchref);
455 br->branchpos = branchpos;
456 br->next = cd->xcheckarefs;
457 cd->xcheckarefs = br;
461 static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
466 branchpos = (u1 *) branchptr - cd->mcodebase;
468 br = DNEW(branchref);
469 br->branchpos = branchpos;
470 br->next = cd->xnullrefs;
475 static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
480 branchpos = (u1 *) branchptr - cd->mcodebase;
482 br = DNEW(branchref);
483 br->branchpos = branchpos;
484 br->next = cd->xcastrefs;
489 static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
494 branchpos = (u1 *) branchptr - cd->mcodebase;
496 br = DNEW(branchref);
497 br->branchpos = branchpos;
498 br->next = cd->xexceptionrefs;
499 cd->xexceptionrefs = br;
503 #if defined(__I386__) || defined(__X86_64__)
504 static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
509 branchpos = (u1 *) branchptr - cd->mcodebase;
511 br = DNEW(branchref);
512 br->branchpos = branchpos;
513 br->next = cd->xdivrefs;
519 static void codegen_createlinenumbertable(codegendata *cd)
524 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
525 lr->tablepos = dseg_addaddress(cd, NULL);
527 if (cd->linenumbertab == 0)
528 cd->linenumbertab = lr->tablepos;
530 dseg_addaddress(cd, lr->linenumber);
536 #if defined(__I386__) || defined(__X86_64__)
537 static int methodtree_comparator(const void *pc, const void *element, void *param)
539 methodtree_element *mte;
540 methodtree_element *mtepc;
542 mte = (methodtree_element *) element;
543 mtepc = (methodtree_element *) pc;
545 /* compare both startpc and endpc of pc, even if they have the same value,
546 otherwise the avl_probe sometimes thinks the element is already in the
548 if (mte->startpc <= mtepc->startpc && mtepc->startpc <= mte->endpc &&
549 mte->startpc <= mtepc->endpc && mtepc->endpc <= mte->endpc) {
552 } else if (mtepc->startpc < mte->startpc) {
562 void *codegen_findmethod1(void *pc)
564 void * retVal=findmethod(pc);
565 methodinfo **ma=(methodinfo**)retVal;
566 methodinfo *m=ma[-1];
569 utf_display(m->name);
572 else log_text("No methodinfo");
578 void codegen_insertmethod(void *startpc, void *endpc)
580 methodtree_element *mte;
582 #if defined(USE_THREADS)
583 #if defined(NATIVE_THREADS)
588 mte = NEW(methodtree_element);
589 mte->startpc = startpc;
592 if (avl_insert(methodtree, mte)) {
593 #if defined(USE_THREADS)
594 #if defined(NATIVE_THREADS)
598 throw_cacao_exception_exit(string_java_lang_InternalError,
602 #if defined(USE_THREADS)
603 #if defined(NATIVE_THREADS)
610 void *codegen_findmethod(void *pc)
612 methodtree_element *mtepc;
613 methodtree_element *mte;
615 #if defined(USE_THREADS)
616 #if defined(NATIVE_THREADS)
621 mtepc = NEW(methodtree_element);
625 mte = avl_find(methodtree, mtepc);
627 FREE(mtepc, methodtree_element);
630 #if defined(USE_THREADS)
631 #if defined(NATIVE_THREADS)
635 throw_cacao_exception_exit(string_java_lang_InternalError,
636 "cannot find function");
639 #if defined(USE_THREADS)
640 #if defined(NATIVE_THREADS)
650 static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
657 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
658 extralen = sizeof(threadcritnode) * cd->threadcritcount;
663 #if defined(STATISTICS)
665 count_code_len += mcodelen;
666 count_data_len += cd->dseglen;
670 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
671 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
673 m->mcodelength = mcodelen + cd->dseglen;
674 m->mcode = CNEW(u1, alignedlen + extralen);
676 memcpy(m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
677 memcpy(m->mcode + cd->dseglen, cd->mcodebase, mcodelen);
679 m->entrypoint = epoint = (u1 *) (m->mcode + cd->dseglen);
681 /* jump table resolving */
682 jr = cd->jumpreferences;
684 *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
689 /* line number table resolving */
698 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
700 *((void**) (epoint + lr->tablepos)) = epoint + lr->targetmpc;
703 *((void**) (epoint + cd->linenumbertablestartpos)) =
704 epoint + cd->linenumbertab;
706 *((s8*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
708 *((s4*) (epoint + cd->linenumbertablesizepos)) = lrtlen;
713 #if defined(__I386__) || defined(__X86_64__)
717 /* add method into methodtree to find the entrypoint */
718 codegen_insertmethod(m->entrypoint, m->entrypoint + mcodelen);
720 /* data segment references resolving */
721 dr = cd->datareferences;
723 *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
729 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
731 threadcritnode *n = (threadcritnode *) (m->mcode + alignedlen);
733 threadcritnodetemp *nt = cd->threadcrit;
735 for (i = 0; i < cd->threadcritcount; i++) {
736 n->mcodebegin = m->mcode + nt->mcodebegin;
737 n->mcodeend = m->mcode + nt->mcodeend;
738 n->mcoderestart = m->mcode + nt->mcoderestart;
739 thread_registercritical(n);
748 void dseg_display(methodinfo *m, codegendata *cd)
753 s4ptr = (s4 *) m->mcode;
755 printf(" --- dump of datasegment\n");
756 for (i = cd->dseglen; i > 0 ; i -= 4) {
757 printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
759 printf(" --- begin of data segment: %p\n", s4ptr);
763 #if !defined(__POWERPC__)
765 This function determines a register, to which the result of an operation
766 should go, when it is ultimatively intended to store the result in
768 If v is assigned to an actual register, this register will be returned.
769 Otherwise (when v is spilled) this function returns tempregnum.
770 If not already done, regoff and flags are set in the stack location.
773 static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
777 switch (v->varkind) {
779 if (!(v->flags & INMEMORY))
783 var = &(rd->interfaces[v->varnum][v->type]);
784 v->regoff = var->regoff;
785 if (!(var->flags & INMEMORY))
789 var = &(rd->locals[v->varnum][v->type]);
790 v->regoff = var->regoff;
791 if (!(var->flags & INMEMORY))
795 v->regoff = v->varnum;
796 if (IS_FLT_DBL_TYPE(v->type)) {
797 if (v->varnum < rd->fltreg_argnum) {
798 v->regoff = rd->argfltregs[v->varnum];
799 return(rd->argfltregs[v->varnum]);
803 if (v->varnum < rd->intreg_argnum) {
804 v->regoff = rd->argintregs[v->varnum];
805 return (rd->argintregs[v->varnum]);
807 v->regoff -= rd->intreg_argnum;
810 v->flags |= INMEMORY;
816 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
817 static void codegen_threadcritrestart(codegendata *cd, int offset)
819 cd->threadcritcurrent.mcoderestart = offset;
823 static void codegen_threadcritstart(codegendata *cd, int offset)
825 cd->threadcritcurrent.mcodebegin = offset;
829 static void codegen_threadcritstop(codegendata *cd, int offset)
831 cd->threadcritcurrent.next = cd->threadcrit;
832 cd->threadcritcurrent.mcodeend = offset;
833 cd->threadcrit = DNEW(threadcritnodetemp);
834 *(cd->threadcrit) = cd->threadcritcurrent;
835 cd->threadcritcount++;
840 #ifndef STATIC_CLASSPATH
841 static size_t codegen_overloadPartLen(utf *desc) {
842 char *utf_ptr=desc->text;
845 while ((c=utf_nextu2(&utf_ptr))!=')') {
862 while ( (c=utf_nextu2(&utf_ptr)) != ';')
868 default: panic ("invalid method descriptor");
875 static void codegen_fillInOverloadPart(char *target,utf *desc) {
876 char *utf_ptr=desc->text;
878 char* insertpos=&target[strlen(target)];
881 while ((c=utf_nextu2(&utf_ptr))!=')') {
899 while ( (c=utf_nextu2(&utf_ptr)) != ';')
900 if ( ((c>='a') && (c<='z')) ||
901 ((c>='A') && (c<='Z')) ||
902 ((c>='0') && (c<='9')) )
904 else *(insertpos++)='_';
910 default: panic ("invalid method descriptor");
917 static void codegen_resolve_native(methodinfo *m,void **insertionPoint,void *jmpTarget,void **jmpPatchTarget) {
918 char *nativeName, *nativeNameEscape;
922 builtin_monitorenter((java_objectheader*) m);
923 if ((*jmpPatchTarget)==jmpTarget) {
924 builtin_monitorexit((java_objectheader*) m);
927 log_text("trying to resolve a native method");
928 utf_display(m->class->name);
929 utf_display(m->name);
931 void *lib=dlopen(0,RTLD_NOW | RTLD_GLOBAL);
934 /*generate the name of the native function in the form Java_package1_package2...._classname_methodname*/
935 nativeLen=/*Java_*/5+strlen(m->class->name->text)+/*_*/1+strlen(m->name->text)+/*\0*/1;
936 nativeName=MNEW(char,nativeLen);
937 sprintf(nativeName,"Java_%s/%s",m->class->name->text,m->name->text);
939 while (i<nativeLen) {
940 if (nativeName[i]=='_') { // escape underscore
941 nativeNameEscape = MNEW(char,nativeLen+1);
942 memcpy(nativeNameEscape,nativeName,i+1);
943 nativeNameEscape[i+1] = '1'; // escape sequence for _ is _1
944 memcpy(&nativeNameEscape[i+2],&nativeName[i+1],nativeLen-i-1);
945 MFREE(nativeName,char,nativeLen);
948 nativeNameEscape[nativeLen]=0;
949 nativeName=nativeNameEscape;
951 if (nativeName[i]=='/') nativeName[i]='_';
955 /* printf("nativename: %s\n",nativeName); */
957 void *sym=dlsym(lib,nativeName);
960 log_text("resolved");
961 MFREE(nativeName,char,nativeLen);
963 size_t overloadedNativeLen=nativeLen+codegen_overloadPartLen(m->descriptor);
964 char *overloadedNative=MNEW(char,overloadedNativeLen);
965 sprintf(overloadedNative,"%s",nativeName);
966 MFREE(nativeName,char,nativeLen);
967 codegen_fillInOverloadPart(overloadedNative,m->descriptor);
968 log_text("symbol not found,trying harder (overloaded member ?)");
969 sym=dlsym(lib,overloadedNative);
971 MFREE(overloadedNative,char,overloadedNativeLen);
973 log_text("resolved");
975 MFREE(overloadedNative,char,overloadedNativeLen);
976 log_text("It was not possible to find the native function implementation. Not even in overloading case");
980 (*insertionPoint)=sym;
981 (*jmpPatchTarget)=jmpTarget;
982 builtin_monitorexit((java_objectheader *) m );
986 } else log_text("library not found");
992 slen=2+strlen(m->class->name->text)+strlen(m->name->text)+strlen(m->descriptor->text);
993 info=(char*)MNEW(char,slen);
994 sprintf(info,"%s.%s%s",m->class->name->text,m->name->text,m->descriptor->text);
996 builtin_monitorexit((java_objectheader *) m );
997 throw_cacao_exception_exit(string_java_lang_LinkageError,
1006 * These are local overrides for various environment variables in Emacs.
1007 * Please do not remove this and leave it at the end of the file, where
1008 * Emacs will automagically detect them.
1009 * ---------------------------------------------------------------------
1012 * indent-tabs-mode: t