-/* vm/jit/codegen.inc - architecture independent code generator
+/* src/vm/jit/codegen.inc - architecture independent code generator
Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
memory. All functions writing values into the data area return the offset
relative the begin of the code area (start of procedure).
- $Id: codegen.inc 2424 2005-04-30 13:45:06Z jowenn $
+ $Id: codegen.inc 2734 2005-06-17 13:01:06Z twisti $
*/
-#ifndef _CODEGEN_INC_H_
-#define _CODEGEN_INC_H_
+#include <assert.h>
#include <string.h>
-#if !defined(STATIC_CLASSPATH)
-# include <dlfcn.h>
-#endif
+#include "config.h"
+#include "types.h"
+
+#include "disass.h"
#include "mm/memory.h"
#include "toolbox/avl.h"
#endif
#include "vm/exceptions.h"
+#include "vm/method.h"
#include "vm/options.h"
#include "vm/statistics.h"
#include "vm/jit/codegen.inc.h"
+#include "vm/jit/jit.h"
#undef JWDEBUG_X86
*******************************************************************************/
-void codegen_init()
+void codegen_init(void)
{
#if defined(__I386__) || defined(__X86_64__)
/* this tree is global, not method specific */
void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
{
- cd->mcodebase = MNEW(u1, MCODEINITSIZE);
+ cd->mcodebase = DMNEW(u1, MCODEINITSIZE);
cd->mcodesize = MCODEINITSIZE;
- cd->dsegtop = MNEW(u1, DSEGINITSIZE);
+ cd->dsegtop = DMNEW(u1, DSEGINITSIZE);
cd->dsegsize = DSEGINITSIZE;
cd->dsegtop += cd->dsegsize;
cd->dseglen = 0;
if (useinlining && id) {
if (id->cumextablelength > 0) {
cd->exceptiontablelength = id->cumextablelength;
- cd->exceptiontable = DMNEW(exceptiontable, id->cumextablelength + 1);
+ cd->exceptiontable =
+ DMNEW(exceptiontable, id->cumextablelength + 1);
}
- } else if (id && (id->method->exceptiontablelength >0)) {
+ } else if (id && (id->method->exceptiontablelength > 0)) {
cd->exceptiontablelength = m->exceptiontablelength;
- cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
+ cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
}
if (id) {
/* codegen_free ****************************************************************
- releases temporary code and data area
+ Releases temporary code and data area.
*******************************************************************************/
void codegen_free(methodinfo *m, codegendata *cd)
{
- if (cd) {
#if 0
- if (cd->exceptiontablelength) {
- cd->exceptiontablelength = m->exceptiontablelength;
- MFREE(cd->exceptiontable, exceptiontable, cd->exceptiontablelength + 1);
- cd->exceptiontable = 0;
- cd->exceptiontablelength = 0;
- }
-#endif
-
+ if (cd) {
if (cd->mcodebase) {
MFREE(cd->mcodebase, u1, cd->mcodesize);
cd->mcodebase = NULL;
cd->dsegtop = NULL;
}
}
+#endif
}
*******************************************************************************/
-void codegen_close()
+void codegen_close(void)
{
/* TODO: release avl tree on i386 and x86_64 */
}
long len;
len = codeptr - cd->mcodebase;
- cd->mcodebase = MREALLOC(cd->mcodebase,
- u1,
- cd->mcodesize,
- cd->mcodesize * 2);
+ cd->mcodebase = DMREALLOC(cd->mcodebase,
+ u1,
+ cd->mcodesize,
+ cd->mcodesize * 2);
cd->mcodesize *= 2;
cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
{
u1 *newstorage;
- newstorage = MNEW(u1, cd->dsegsize * 2);
+ newstorage = DMNEW(u1, cd->dsegsize * 2);
- memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
- MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
+ MCOPY(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, u1,
+ cd->dsegsize);
cd->dsegtop = newstorage;
cd->dsegsize *= 2;
}
-#if !defined(__I386__)
+#if !defined(__I386__) && !defined(__POWERPC__)
static s4 dseg_adds8_increase(codegendata *cd, s8 value)
{
dseg_increase(cd);
}
+#if defined(__I386__) || defined(__X86_64__)
static void dseg_adddata(codegendata *cd, u1 *ptr)
{
dataref *dr;
dr->next = cd->datareferences;
cd->datareferences = dr;
}
+#endif
static void dseg_addlinenumbertablesize(codegendata *cd)
branchpos = (u1 *) branchptr - cd->mcodebase;
+ /* Check if the target basicblock has already a start pc, so the jump is */
+ /* backward and we can resolve it immediately. */
+
if (target->mpc >= 0) {
gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
branchpos,
tables_unlock();
#endif
#endif
+ assert(0);
throw_cacao_exception_exit(string_java_lang_InternalError,
"duplicate entry");
}
tables_unlock();
#endif
#endif
- {
#ifdef JWDEBUG_X86
{
void *bt[5];
backtrace_symbols_fd(bt,5,2);
}
#endif
- char msg[63];
- sprintf(msg,"cannot find function (%p)",pc);
- throw_cacao_exception_exit(string_java_lang_InternalError,
- msg);
- }
+ assert(0);
+ throw_cacao_exception_exit(string_java_lang_InternalError,
+ "Cannot find Java function at %p", pc);
}
#if defined(USE_THREADS)
#endif
+/* codegen_finish **************************************************************
+
+ Finishes the code generation. A new memory, large enough for both
+ data and code, is allocated and data and code are copied together
+ to their final layout, unresolved jumps are resolved, ...
+
+*******************************************************************************/
+
static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
{
- jumpref *jr;
- functionptr epoint;
- s4 extralen;
- s4 alignedlen;
+ jumpref *jr;
+ functionptr epoint;
+ s4 extralen;
+ s4 alignedlen;
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
extralen = sizeof(threadcritnode) * cd->threadcritcount;
cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
+ /* allocate new memory */
+
m->mcodelength = mcodelen + cd->dseglen;
- m->mcode = (functionptr) (long) CNEW(u1, alignedlen + extralen);
+ m->mcode = (functionptr) (ptrint) CNEW(u1, alignedlen + extralen);
+
+ /* copy data and code to their new location */
- memcpy((void *) (long) m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
- memcpy((void *) ((long) m->mcode + cd->dseglen), cd->mcodebase, mcodelen);
+ MCOPY((void *) (ptrint) m->mcode, cd->dsegtop - cd->dseglen, u1,
+ cd->dseglen);
+ MCOPY((void *) ((ptrint) m->mcode + cd->dseglen), cd->mcodebase, u1,
+ mcodelen);
- m->entrypoint = epoint = (functionptr) ((long) m->mcode + cd->dseglen);
+ m->entrypoint = epoint = (functionptr) ((ptrint) m->mcode + cd->dseglen);
/* jump table resolving */
+
jr = cd->jumpreferences;
while (jr != NULL) {
- *((functionptr *) ((long) epoint + jr->tablepos)) =
- (functionptr) ((long) epoint + (long) jr->target->mpc);
+ *((functionptr *) ((ptrint) epoint + jr->tablepos)) =
+ (functionptr) ((ptrint) epoint + (ptrint) jr->target->mpc);
jr = jr->next;
}
/* line number table resolving */
{
linenumberref *lr;
-#if POINTERSIZE == 8
- s8 lrtlen = 0;
-#else
- s4 lrtlen = 0;
-#endif
+ ptrint lrtlen = 0;
+
for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
lrtlen++;
- *((functionptr *) ((long) epoint + (long) lr->tablepos)) =
- (functionptr) ((long) epoint + (long) lr->targetmpc);
+ *((functionptr *) ((ptrint) epoint + (ptrint) lr->tablepos)) =
+ (functionptr) ((ptrint) epoint + (ptrint) lr->targetmpc);
}
- *((functionptr *) ((long) epoint + cd->linenumbertablestartpos)) =
- (functionptr) ((long) epoint + cd->linenumbertab);
-#if POINTERSIZE == 8
- *((s8 *) ((s8) epoint + cd->linenumbertablesizepos)) = lrtlen;
-#else
- *((s4 *) ((s4) epoint + cd->linenumbertablesizepos)) = lrtlen;
-#endif
+ *((functionptr *) ((ptrint) epoint + cd->linenumbertablestartpos)) =
+ (functionptr) ((ptrint) epoint + cd->linenumbertab);
+
+ *((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
}
#endif
dr = cd->datareferences;
while (dr != NULL) {
- *((functionptr *) ((ptrint) epoint + (ptrint) dr->pos - POINTERSIZE)) = epoint;
+ *((functionptr *) ((ptrint) epoint + (ptrint) dr->pos -
+ SIZEOF_VOID_P)) = epoint;
dr = dr->next;
}
}
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
{
- threadcritnode *n = (threadcritnode *) ((long) m->mcode + alignedlen);
+ threadcritnode *n = (threadcritnode *) ((ptrint) m->mcode + alignedlen);
s4 i;
threadcritnodetemp *nt = cd->threadcrit;
for (i = 0; i < cd->threadcritcount; i++) {
- n->mcodebegin = (u1 *) (long) m->mcode + nt->mcodebegin;
- n->mcodeend = (u1 *) (long) m->mcode + nt->mcodeend;
- n->mcoderestart = (u1 *) (long) m->mcode + nt->mcoderestart;
+ n->mcodebegin = (u1 *) (ptrint) m->mcode + nt->mcodebegin;
+ n->mcodeend = (u1 *) (ptrint) m->mcode + nt->mcodeend;
+ n->mcoderestart = (u1 *) (ptrint) m->mcode + nt->mcoderestart;
thread_registercritical(n);
n++;
nt = nt->next;
printf(" --- dump of datasegment\n");
for (i = cd->dseglen; i > 0 ; i -= 4) {
-#if defined(__I386__) || defined(__POWERPC__)
- printf("0x%08x: -%6x (%6d): %8x\n",
+#if SIZEOF_VOID_P == 8
+ printf("0x%016lx: -%6x (%6d): %8x\n",
(ptrint) s4ptr, i, i, (s4) *s4ptr);
#else
- printf("0x%016lx: -%6x (%6d): %8x\n",
+ printf("0x%08x: -%6x (%6d): %8x\n",
(ptrint) s4ptr, i, i, (s4) *s4ptr);
#endif
s4ptr++;
}
+
+/* codegen_createnativestub ****************************************************
+
+ Wrapper for createnativestub.
+
+*******************************************************************************/
+
+functionptr codegen_createnativestub(functionptr f, methodinfo *m)
+{
+ codegendata *cd;
+ registerdata *rd;
+ t_inlining_globals *id;
+ s4 dumpsize;
+
+ /* mark dump memory */
+
+ dumpsize = dump_size();
+
+ cd = DNEW(codegendata);
+ rd = DNEW(registerdata);
+ id = DNEW(t_inlining_globals);
+
+ /* setup code generation stuff */
+
+ inlining_setup(m, id);
+ reg_setup(m, rd, id);
+ codegen_setup(m, cd, id);
+
+ m->stubroutine = createnativestub(f, m, cd, rd);
+
+ /* entrypoint was set in codegen_finish, clear it */
+
+ m->entrypoint = NULL;
+
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_nstub_len += m->mcodelength;
+#endif
+
+ /* release memory */
+
+ dump_release(dumpsize);
+
+
+ /* disassemble native stub */
+
+ if (showdisassemble)
+ codegen_disassemble_nativestub(m, (s4 *) (ptrint) m->stubroutine,
+ m->mcodelength - cd->dseglen);
+
+ /* show data segment */
+
+ if (showddatasegment)
+ dseg_display(m, cd);
+
+ /* return stubroutine entry point */
+
+ return m->stubroutine;
+}
+
+
+/* codegen_disassemble_nativestub **********************************************
+
+ Disassembles the generated native stub.
+
+*******************************************************************************/
+
+void codegen_disassemble_nativestub(methodinfo *m, s4 *code, s4 len)
+{
+ printf("Native stub: ");
+ utf_fprint_classname(stdout, m->class->name);
+ printf(".");
+ utf_fprint(stdout, m->name);
+ utf_fprint(stdout, m->descriptor);
+ printf("\n\nLength: %d\n\n", len);
+
+#if defined(__I386__) || defined(__X86_64__)
+ disassemble((u1 *) code, len);
+#else
+ disassemble(code, len);
+#endif
+}
+
+
+/* removecompilerstub **********************************************************
+
+ Deletes a compilerstub from memory (simply by freeing it).
+
+*******************************************************************************/
+
+void removecompilerstub(functionptr stub)
+{
+ CFREE(stub, 1);
+}
+
+
+/* removenativestub ************************************************************
+
+ Removes a previously created native-stub from memory.
+
+*******************************************************************************/
+
+void removenativestub(functionptr stub)
+{
+ CFREE(stub, 1);
+}
+
+
/* reg_of_var:
This function determines a register, to which the result of an operation
should go, when it is ultimatively intended to store the result in
#endif
-#ifndef STATIC_CLASSPATH
-static size_t codegen_overloadPartLen(utf *desc) {
- char *utf_ptr=desc->text;
- u2 c;
- size_t len=2;
- while ((c=utf_nextu2(&utf_ptr))!=')') {
- switch (c) {
- case 'I':
- case 'S':
- case 'B':
- case 'C':
- case 'Z':
- case 'J':
- case 'F':
- case 'D':
- len ++;
- break;
- case '[':
- len = len+2;
- break;
- case 'L':
- len++;
- while ( (c=utf_nextu2(&utf_ptr)) != ';')
- len++;
- len=len+2;
- break;
- case '(':
- break;
- default: panic ("invalid method descriptor");
- }
- }
- return len;
-
-}
-
-static void codegen_fillInOverloadPart(char *target,utf *desc) {
- char *utf_ptr=desc->text;
- u2 c;
- char* insertpos=&target[strlen(target)];
- *(insertpos++)='_';
- *(insertpos++)='_';
- while ((c=utf_nextu2(&utf_ptr))!=')') {
- switch (c) {
- case 'I':
- case 'S':
- case 'B':
- case 'C':
- case 'Z':
- case 'J':
- case 'F':
- case 'D':
- *(insertpos++)=c;
- break;
- case '[':
- *(insertpos++)='_';
- *(insertpos++)='3';
- break;
- case 'L':
- *(insertpos++)='L';
- while ( (c=utf_nextu2(&utf_ptr)) != ';')
- if ( ((c>='a') && (c<='z')) ||
- ((c>='A') && (c<='Z')) ||
- ((c>='0') && (c<='9')) )
- *(insertpos++)=c;
- else *(insertpos++)='_';
- *(insertpos++)='_';
- *(insertpos++)='2';
- break;
- case '(':
- break;
- default: panic ("invalid method descriptor");
- }
- }
- *insertpos='\0';
-
-}
-
-static void codegen_resolve_native(methodinfo *m,void **insertionPoint,void *jmpTarget,void **jmpPatchTarget) {
- char *nativeName, *nativeNameEscape;
- size_t nativeLen;
- size_t i;
- void *lib;
- void *sym;
-
-#if defined(USE_THREADS)
- builtin_monitorenter((java_objectheader*) m);
-#endif
-
-#if defined(__X86_64__)
- if ((*((s4*)jmpPatchTarget))==((s4)jmpTarget)) {
-#else
- if ((*jmpPatchTarget)==jmpTarget) {
-#endif
-
-#if defined(USE_THREADS)
- builtin_monitorexit((java_objectheader*) m);
-#endif
-
- return;
- }
- /*log_text("trying to resolve a native method");
- utf_display(m->class->name);
- utf_display(m->name);*/
-
- lib=dlopen(0,RTLD_NOW | RTLD_GLOBAL); /* open the application execution image */
- if (lib) { /* it did work -> good, otherwise fail with error*/
- int ok=0;
- /*generate the name of the native function in the form Java_package1_package2...._classname_methodname*/
- nativeLen=/*Java_*/5+strlen(m->class->name->text)+/*_*/1+strlen(m->name->text)+/*\0*/1;
- nativeName=MNEW(char,nativeLen);
- sprintf(nativeName,"Java_%s/%s",m->class->name->text,m->name->text);
- i=5;
- while (i<nativeLen) {
- if (nativeName[i]=='_') { /* escape underscore */
- nativeNameEscape = MNEW(char,nativeLen+1);
- memcpy(nativeNameEscape,nativeName,i+1);
- nativeNameEscape[i+1] = '1'; /* escape sequence for _ is _1 */
- memcpy(&nativeNameEscape[i+2],&nativeName[i+1],nativeLen-i-1);
- MFREE(nativeName,char,nativeLen);
- i++;
- nativeLen++;
- nativeNameEscape[nativeLen-1]=0;
- nativeName=nativeNameEscape;
- }
- if (nativeName[i]=='/') nativeName[i]='_';
- i++;
- }
-
- /*printf("\nnativename: %s\n",nativeName);*/
-
- /*try to find the symbal fo the function */
- sym=dlsym(lib,nativeName);
- if (sym) {
- ok=1; /* it worked, everything fine */
- /*log_text("resolved");*/
- /*printf("strlen %d, nativeLen %d\n",strlen(nativeName),nativeLen);*/
- MFREE(nativeName,char,nativeLen);
- } else { /* we didn't find the symbol yet, try to resolve an overlaoded function (having the types in it's name*/
- size_t overloadedNativeLen=nativeLen+codegen_overloadPartLen(m->descriptor);
- char *overloadedNative=MNEW(char,overloadedNativeLen);
- sprintf(overloadedNative,"%s",nativeName);
- MFREE(nativeName,char,nativeLen);
- codegen_fillInOverloadPart(overloadedNative,m->descriptor);
- /*log_text("symbol not found,trying harder (overloaded member ?)");*/
- sym=dlsym(lib,overloadedNative);
- if (sym) {
- MFREE(overloadedNative,char,overloadedNativeLen);
- ok=1; /* we eventually found the native function -> everything ok*/
- /*log_text("resolved");*/
- } else {
- /* we failed to find the native function within the execution image (app + loaded libraries) -> will cause an exit*/
- dolog("\nnative function not found: %s",overloadedNative);
- MFREE(overloadedNative,char,overloadedNativeLen);
- log_text("It was not possible to find the native function implementation. Not even in overloading case");
- }
- }
- /* patch the address of the native function into the stub and make the stub jump over this function call in the future */
- if (ok) {
- (*insertionPoint)=sym;
-#if defined(__X86_64__)
- (*((s4*)jmpPatchTarget))=(s4)jmpTarget;
-#else
- (*jmpPatchTarget)=jmpTarget;
-#endif
-
-#if defined(USE_THREADS)
- builtin_monitorexit((java_objectheader *) m );
-#endif
-
- return;
- }
-
- } else log_text("library not found");
-
- /* There was an error, either the app image could not be opened or the native does not exist in the application and the
- loaded libraries. Show an additional error and exit the vm*/
- {
- char *info;
- size_t slen;
- slen=2+strlen(m->class->name->text)+strlen(m->name->text)+strlen(m->descriptor->text);
- info=(char*)MNEW(char,slen);
- sprintf(info,"%s.%s%s",m->class->name->text,m->name->text,m->descriptor->text);
-
-#if defined(USE_THREADS)
- builtin_monitorexit((java_objectheader *) m );
-#endif
-
- throw_cacao_exception_exit(string_java_lang_LinkageError,
- info);
- }
-
-}
-#endif
-
-
-#endif
-
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where