1 /* vm/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: Christian Thalinger
33 All functions assume the following code area / data area layout:
37 | code area | code area grows to higher addresses
39 +-----------+ <-- start of procedure
41 | data area | data area grows to lower addresses
45 The functions first write into a temporary code/data area allocated by
46 "codegen_init". "codegen_finish" copies the code and data area into permanent
47 memory. All functions writing values into the data area return the offset
48 relative the begin of the code area (start of procedure).
50 $Id: codegen.inc 1662 2004-12-03 15:46:18Z twisti $
57 #if !defined(STATIC_CLASSPATH)
61 #include "mm/memory.h"
62 #include "toolbox/avl.h"
63 #include "toolbox/logging.h"
64 #include "native/native.h"
66 #if defined(USE_THREADS)
67 # if defined(NATIVE_THREADS)
68 # include "threads/native/threads.h"
70 # include "threads/green/threads.h"
74 #include "vm/exceptions.h"
75 #include "vm/options.h"
76 #include "vm/statistics.h"
77 #include "vm/jit/codegen.inc.h"
80 /* in this tree we store all method addresses *********************************/
82 #if defined(__I386__) || defined(__X86_64__)
83 static struct avl_table *methodtree = NULL;
84 static int methodtree_comparator(const void *pc, const void *element,
89 /* codegen_init ****************************************************************
93 *******************************************************************************/
97 #if defined(__I386__) || defined(__X86_64__)
98 /* this tree is global, not method specific */
100 methodtree_element *mte;
102 methodtree = avl_create(methodtree_comparator, NULL, NULL);
104 mte = NEW(methodtree_element);
106 mte->startpc = (functionptr) asm_calljavafunction;
107 mte->endpc = (functionptr) ((long) asm_calljavafunction2 - 1);
109 avl_insert(methodtree, mte);
111 mte = NEW(methodtree_element);
113 mte->startpc = (functionptr) asm_calljavafunction2;
114 mte->endpc = (functionptr) ((long) asm_call_jit_compiler - 1);
116 avl_insert(methodtree, mte);
122 /* codegen_setup **************************************************************
124 allocates and initialises code area, data area and references
126 *******************************************************************************/
128 void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
130 cd->mcodebase = MNEW(u1, MCODEINITSIZE);
131 cd->mcodesize = MCODEINITSIZE;
133 cd->dsegtop = MNEW(u1, DSEGINITSIZE);
134 cd->dsegsize = DSEGINITSIZE;
135 cd->dsegtop += cd->dsegsize;
138 cd->jumpreferences = NULL;
139 cd->datareferences = NULL;
140 cd->xboundrefs = NULL;
141 cd->xcheckarefs = NULL;
142 cd->xnullrefs = NULL;
143 cd->xcastrefs = NULL;
145 cd->xexceptionrefs = NULL;
146 cd->clinitrefs = NULL;
148 cd->linenumberreferences = NULL;
149 cd->linenumbertablesizepos = 0;
150 cd->linenumbertablestartpos = 0;
151 cd->linenumbertab = 0;
154 cd->exceptiontable = 0;
155 cd->exceptiontablelength = 0;
157 if (useinlining && id) {
158 if (id->cumextablelength > 0) {
159 cd->exceptiontablelength = id->cumextablelength;
160 cd->exceptiontable = DMNEW(exceptiontable, id->cumextablelength + 1);
163 } else if (id && (id->method->exceptiontablelength >0)) {
164 cd->exceptiontablelength = m->exceptiontablelength;
165 cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
169 cd->maxstack = id->cummaxstack;
170 cd->maxlocals = id->cumlocals;
172 cd->maxstack = m->maxstack;
173 cd->maxlocals = m->maxlocals;
176 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
177 cd->threadcritcurrent.next = NULL;
178 cd->threadcritcount = 0;
183 /* codegen_free ****************************************************************
185 releases temporary code and data area
187 *******************************************************************************/
189 void codegen_free(methodinfo *m, codegendata *cd)
193 if (cd->exceptiontablelength) {
194 cd->exceptiontablelength = m->exceptiontablelength;
195 MFREE(cd->exceptiontable, exceptiontable, cd->exceptiontablelength + 1);
196 cd->exceptiontable = 0;
197 cd->exceptiontablelength = 0;
202 MFREE(cd->mcodebase, u1, cd->mcodesize);
203 cd->mcodebase = NULL;
207 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
214 /* codegen_close ***************************************************************
218 *******************************************************************************/
222 /* TODO: release avl tree on i386 and x86_64 */
226 /* codegen_increase doubles code area */
228 static s4 *codegen_increase(codegendata *cd, u1 *codeptr)
232 len = codeptr - cd->mcodebase;
233 cd->mcodebase = MREALLOC(cd->mcodebase,
238 cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
240 return (s4 *) (cd->mcodebase + len);
244 /* desg_increase doubles data area */
246 static void dseg_increase(codegendata *cd)
250 newstorage = MNEW(u1, cd->dsegsize * 2);
252 memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
253 MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
255 cd->dsegtop = newstorage;
257 cd->dsegtop += cd->dsegsize;
261 static s4 dseg_adds4_increase(codegendata *cd, s4 value)
265 *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
267 return -(cd->dseglen);
271 static s4 dseg_adds4(codegendata *cd, s4 value)
276 dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
278 if (cd->dseglen > cd->dsegsize)
279 return dseg_adds4_increase(cd, value);
283 return -(cd->dseglen);
287 #if !defined(__I386__)
288 static s4 dseg_adds8_increase(codegendata *cd, s8 value)
292 *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
294 return -(cd->dseglen);
298 static s4 dseg_adds8(codegendata *cd, 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(cd, value);
310 return -(cd->dseglen);
315 static s4 dseg_addfloat_increase(codegendata *cd, float value)
319 *((float *) (cd->dsegtop - cd->dseglen)) = value;
321 return -(cd->dseglen);
325 static s4 dseg_addfloat(codegendata *cd, float value)
330 dataptr = (float *) (cd->dsegtop - cd->dseglen);
332 if (cd->dseglen > cd->dsegsize)
333 return dseg_addfloat_increase(cd, value);
337 return -(cd->dseglen);
341 static s4 dseg_adddouble_increase(codegendata *cd, double value)
345 *((double *) (cd->dsegtop - cd->dseglen)) = value;
347 return -(cd->dseglen);
351 static s4 dseg_adddouble(codegendata *cd, double value)
355 cd->dseglen = ALIGN(cd->dseglen + 8, 8);
356 dataptr = (double *) (cd->dsegtop - cd->dseglen);
358 if (cd->dseglen > cd->dsegsize)
359 return dseg_adddouble_increase(cd, value);
363 return -(cd->dseglen);
367 static void dseg_addtarget(codegendata *cd, basicblock *target)
372 jr->tablepos = dseg_addaddress(cd, NULL);
374 jr->next = cd->jumpreferences;
375 cd->jumpreferences = jr;
379 static void dseg_adddata(codegendata *cd, u1 *ptr)
384 dr->pos = (u1 *) (ptr - cd->mcodebase);
385 dr->next = cd->datareferences;
386 cd->datareferences = dr;
390 static void dseg_addlinenumbertablesize(codegendata *cd)
393 dseg_adds4(cd, 0); /*PADDING*/
395 cd->linenumbertablesizepos = dseg_addaddress(cd, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
397 cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
399 dseg_adds4(cd, 0); /*PADDING*/
404 static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
408 lr = DNEW(linenumberref);
409 lr->linenumber = linenumber;
411 lr->targetmpc = (ptr - cd->mcodebase);
412 lr->next = cd->linenumberreferences;
413 cd->linenumberreferences = lr;
417 /* we need this function externally on i386 and x86_64, but keep the call fast
420 #if defined(__I386__) || defined(__X86_64__)
421 void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
423 static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
428 branchpos = (u1 *) branchptr - cd->mcodebase;
430 if (target->mpc >= 0) {
431 gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
436 branchref *br = DNEW(branchref);
438 br->branchpos = branchpos;
439 br->next = target->branchrefs;
440 target->branchrefs = br;
445 static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
450 branchpos = (u1 *) branchptr - cd->mcodebase;
452 br = DNEW(branchref);
453 br->branchpos = branchpos;
455 br->next = cd->xboundrefs;
460 static void codegen_addxcheckarefs(codegendata *cd, void *branchptr)
465 branchpos = (u1 *) branchptr - cd->mcodebase;
467 br = DNEW(branchref);
468 br->branchpos = branchpos;
469 br->next = cd->xcheckarefs;
470 cd->xcheckarefs = br;
474 static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
479 branchpos = (u1 *) branchptr - cd->mcodebase;
481 br = DNEW(branchref);
482 br->branchpos = branchpos;
483 br->next = cd->xnullrefs;
488 static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
493 branchpos = (u1 *) branchptr - cd->mcodebase;
495 br = DNEW(branchref);
496 br->branchpos = branchpos;
497 br->next = cd->xcastrefs;
502 static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
507 branchpos = (u1 *) branchptr - cd->mcodebase;
509 br = DNEW(branchref);
510 br->branchpos = branchpos;
511 br->next = cd->xexceptionrefs;
512 cd->xexceptionrefs = br;
516 #if defined(__I386__) || defined(__X86_64__)
517 static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
522 branchpos = (u1 *) branchptr - cd->mcodebase;
524 br = DNEW(branchref);
525 br->branchpos = branchpos;
526 br->next = cd->xdivrefs;
532 static void codegen_addclinitref(codegendata *cd,
539 branchpos = (u1 *) branchptr - cd->mcodebase;
541 cr = DNEW(clinitref);
542 cr->branchpos = branchpos;
544 cr->next = cd->clinitrefs;
549 static void codegen_createlinenumbertable(codegendata *cd)
554 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
555 lr->tablepos = dseg_addaddress(cd, NULL);
557 if (cd->linenumbertab == 0)
558 cd->linenumbertab = lr->tablepos;
560 dseg_addaddress(cd, lr->linenumber);
566 #if defined(__I386__) || defined(__X86_64__)
567 static int methodtree_comparator(const void *pc, const void *element, void *param)
569 methodtree_element *mte;
570 methodtree_element *mtepc;
572 mte = (methodtree_element *) element;
573 mtepc = (methodtree_element *) pc;
575 /* compare both startpc and endpc of pc, even if they have the same value,
576 otherwise the avl_probe sometimes thinks the element is already in the
578 if ((long) mte->startpc <= (long) mtepc->startpc &&
579 (long) mtepc->startpc <= (long) mte->endpc &&
580 (long) mte->startpc <= (long) mtepc->endpc &&
581 (long) mtepc->endpc <= (long) mte->endpc) {
584 } else if ((long) mtepc->startpc < (long) mte->startpc) {
594 void *codegen_findmethod1(void *pc)
596 void * retVal=findmethod(pc);
597 methodinfo **ma=(methodinfo**)retVal;
598 methodinfo *m=ma[-1];
601 utf_display(m->name);
604 else log_text("No methodinfo");
610 void codegen_insertmethod(functionptr startpc, functionptr endpc)
612 methodtree_element *mte;
614 #if defined(USE_THREADS)
615 #if defined(NATIVE_THREADS)
620 mte = NEW(methodtree_element);
621 mte->startpc = startpc;
624 if (avl_insert(methodtree, mte)) {
625 #if defined(USE_THREADS)
626 #if defined(NATIVE_THREADS)
630 throw_cacao_exception_exit(string_java_lang_InternalError,
634 #if defined(USE_THREADS)
635 #if defined(NATIVE_THREADS)
642 functionptr codegen_findmethod(functionptr pc)
644 methodtree_element *mtepc;
645 methodtree_element *mte;
647 #if defined(USE_THREADS)
648 #if defined(NATIVE_THREADS)
653 mtepc = NEW(methodtree_element);
657 mte = avl_find(methodtree, mtepc);
659 FREE(mtepc, methodtree_element);
662 #if defined(USE_THREADS)
663 #if defined(NATIVE_THREADS)
667 throw_cacao_exception_exit(string_java_lang_InternalError,
668 "cannot find function");
671 #if defined(USE_THREADS)
672 #if defined(NATIVE_THREADS)
682 static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
689 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
690 extralen = sizeof(threadcritnode) * cd->threadcritcount;
695 #if defined(STATISTICS)
697 count_code_len += mcodelen;
698 count_data_len += cd->dseglen;
702 cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
703 alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
705 m->mcodelength = mcodelen + cd->dseglen;
706 m->mcode = (functionptr) (long) CNEW(u1, alignedlen + extralen);
708 memcpy((void *) (long) m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
709 memcpy((void *) ((long) m->mcode + cd->dseglen), cd->mcodebase, mcodelen);
711 m->entrypoint = epoint = (functionptr) ((long) m->mcode + cd->dseglen);
713 /* jump table resolving */
714 jr = cd->jumpreferences;
716 *((functionptr *) ((long) epoint + jr->tablepos)) =
717 (functionptr) ((long) epoint + (long) jr->target->mpc);
722 /* line number table resolving */
731 for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
733 *((functionptr *) ((long) epoint + (long) lr->tablepos)) =
734 (functionptr) ((long) epoint + (long) lr->targetmpc);
737 *((functionptr *) ((long) epoint + cd->linenumbertablestartpos)) =
738 (functionptr) ((long) epoint + cd->linenumbertab);
740 *((s8 *) ((s8) epoint + cd->linenumbertablesizepos)) = lrtlen;
742 *((s4 *) ((s4) epoint + cd->linenumbertablesizepos)) = lrtlen;
747 #if defined(__I386__) || defined(__X86_64__)
751 /* add method into methodtree to find the entrypoint */
752 codegen_insertmethod(m->entrypoint,
753 (functionptr) ((long) m->entrypoint + mcodelen));
755 /* data segment references resolving */
756 dr = cd->datareferences;
758 *((functionptr *) ((long) epoint + (long) dr->pos - POINTERSIZE)) =
765 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
767 threadcritnode *n = (threadcritnode *) ((long) m->mcode + alignedlen);
769 threadcritnodetemp *nt = cd->threadcrit;
771 for (i = 0; i < cd->threadcritcount; i++) {
772 n->mcodebegin = (u1 *) (long) m->mcode + nt->mcodebegin;
773 n->mcodeend = (u1 *) (long) m->mcode + nt->mcodeend;
774 n->mcoderestart = (u1 *) (long) m->mcode + nt->mcoderestart;
775 thread_registercritical(n);
784 void dseg_display(methodinfo *m, codegendata *cd)
789 s4ptr = (s4 *) (long) m->mcode;
791 printf(" --- dump of datasegment\n");
792 for (i = cd->dseglen; i > 0 ; i -= 4) {
793 printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
795 printf(" --- begin of data segment: %p\n", (void *) s4ptr);
800 This function determines a register, to which the result of an operation
801 should go, when it is ultimatively intended to store the result in
803 If v is assigned to an actual register, this register will be returned.
804 Otherwise (when v is spilled) this function returns tempregnum.
805 If not already done, regoff and flags are set in the stack location.
808 static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
812 switch (v->varkind) {
814 if (!(v->flags & INMEMORY))
818 var = &(rd->interfaces[v->varnum][v->type]);
819 v->regoff = var->regoff;
820 if (!(var->flags & INMEMORY))
824 var = &(rd->locals[v->varnum][v->type]);
825 v->regoff = var->regoff;
826 if (!(var->flags & INMEMORY))
830 v->regoff = v->varnum;
831 if (IS_FLT_DBL_TYPE(v->type)) {
832 if (v->varnum < rd->fltreg_argnum) {
833 v->regoff = rd->argfltregs[v->varnum];
834 return(rd->argfltregs[v->varnum]);
838 #if defined(__POWERPC__)
839 if (v->varnum < rd->intreg_argnum - (IS_2_WORD_TYPE(v->type) != 0)) {
841 if (v->varnum < rd->intreg_argnum) {
843 v->regoff = rd->argintregs[v->varnum];
844 return (rd->argintregs[v->varnum]);
847 #if defined(__POWERPC__)
850 v->regoff -= rd->intreg_argnum;
854 v->flags |= INMEMORY;
859 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
860 static void codegen_threadcritrestart(codegendata *cd, int offset)
862 cd->threadcritcurrent.mcoderestart = offset;
866 static void codegen_threadcritstart(codegendata *cd, int offset)
868 cd->threadcritcurrent.mcodebegin = offset;
872 static void codegen_threadcritstop(codegendata *cd, int offset)
874 cd->threadcritcurrent.next = cd->threadcrit;
875 cd->threadcritcurrent.mcodeend = offset;
876 cd->threadcrit = DNEW(threadcritnodetemp);
877 *(cd->threadcrit) = cd->threadcritcurrent;
878 cd->threadcritcount++;
883 #ifndef STATIC_CLASSPATH
884 static size_t codegen_overloadPartLen(utf *desc) {
885 char *utf_ptr=desc->text;
888 while ((c=utf_nextu2(&utf_ptr))!=')') {
905 while ( (c=utf_nextu2(&utf_ptr)) != ';')
911 default: panic ("invalid method descriptor");
918 static void codegen_fillInOverloadPart(char *target,utf *desc) {
919 char *utf_ptr=desc->text;
921 char* insertpos=&target[strlen(target)];
924 while ((c=utf_nextu2(&utf_ptr))!=')') {
942 while ( (c=utf_nextu2(&utf_ptr)) != ';')
943 if ( ((c>='a') && (c<='z')) ||
944 ((c>='A') && (c<='Z')) ||
945 ((c>='0') && (c<='9')) )
947 else *(insertpos++)='_';
953 default: panic ("invalid method descriptor");
960 static void codegen_resolve_native(methodinfo *m,void **insertionPoint,void *jmpTarget,void **jmpPatchTarget) {
961 char *nativeName, *nativeNameEscape;
967 builtin_monitorenter((java_objectheader*) m);
968 if ((*jmpPatchTarget)==jmpTarget) {
969 builtin_monitorexit((java_objectheader*) m);
972 log_text("trying to resolve a native method");
973 utf_display(m->class->name);
974 utf_display(m->name);
976 lib=dlopen(0,RTLD_NOW | RTLD_GLOBAL);
979 /*generate the name of the native function in the form Java_package1_package2...._classname_methodname*/
980 nativeLen=/*Java_*/5+strlen(m->class->name->text)+/*_*/1+strlen(m->name->text)+/*\0*/1;
981 nativeName=MNEW(char,nativeLen);
982 sprintf(nativeName,"Java_%s/%s",m->class->name->text,m->name->text);
984 while (i<nativeLen) {
985 if (nativeName[i]=='_') { /* escape underscore */
986 nativeNameEscape = MNEW(char,nativeLen+1);
987 memcpy(nativeNameEscape,nativeName,i+1);
988 nativeNameEscape[i+1] = '1'; /* escape sequence for _ is _1 */
989 memcpy(&nativeNameEscape[i+2],&nativeName[i+1],nativeLen-i-1);
990 MFREE(nativeName,char,nativeLen);
993 nativeNameEscape[nativeLen]=0;
994 nativeName=nativeNameEscape;
996 if (nativeName[i]=='/') nativeName[i]='_';
1000 /* printf("nativename: %s\n",nativeName); */
1002 sym=dlsym(lib,nativeName);
1005 log_text("resolved");
1006 MFREE(nativeName,char,nativeLen);
1008 size_t overloadedNativeLen=nativeLen+codegen_overloadPartLen(m->descriptor);
1009 char *overloadedNative=MNEW(char,overloadedNativeLen);
1010 sprintf(overloadedNative,"%s",nativeName);
1011 MFREE(nativeName,char,nativeLen);
1012 codegen_fillInOverloadPart(overloadedNative,m->descriptor);
1013 log_text("symbol not found,trying harder (overloaded member ?)");
1014 sym=dlsym(lib,overloadedNative);
1016 MFREE(overloadedNative,char,overloadedNativeLen);
1018 log_text("resolved");
1020 MFREE(overloadedNative,char,overloadedNativeLen);
1021 log_text("It was not possible to find the native function implementation. Not even in overloading case");
1025 (*insertionPoint)=sym;
1026 (*jmpPatchTarget)=jmpTarget;
1027 builtin_monitorexit((java_objectheader *) m );
1031 } else log_text("library not found");
1037 slen=2+strlen(m->class->name->text)+strlen(m->name->text)+strlen(m->descriptor->text);
1038 info=(char*)MNEW(char,slen);
1039 sprintf(info,"%s.%s%s",m->class->name->text,m->name->text,m->descriptor->text);
1041 builtin_monitorexit((java_objectheader *) m );
1042 throw_cacao_exception_exit(string_java_lang_LinkageError,
1051 * These are local overrides for various environment variables in Emacs.
1052 * Please do not remove this and leave it at the end of the file, where
1053 * Emacs will automagically detect them.
1054 * ---------------------------------------------------------------------
1057 * indent-tabs-mode: t