-/* vm/jit/codegen.inc - architecture independent code generator
+/* src/vm/jit/codegen.inc - architecture independent code generator
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- Institut f. Computersprachen, TU Wien
- R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Probst,
- S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich,
- J. Wenninger
+ Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
+ R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
+ C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
+ Institut f. Computersprachen - TU Wien
This file is part of CACAO.
Andreas Krall
Changes: Christian Thalinger
+ Joseph Wenninger
All functions assume the following code area / data area layout:
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 1680 2004-12-04 12:02:08Z jowenn $
+ $Id: codegen.inc 3416 2005-10-12 13:20:53Z 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 "vm/types.h"
#include "mm/memory.h"
#include "toolbox/avl.h"
#include "toolbox/logging.h"
+#include "native/jni.h"
#include "native/native.h"
#if defined(USE_THREADS)
#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/disass.h"
+#include "vm/jit/jit.h"
+#include "vm/jit/stacktrace.h"
/* in this tree we store all method addresses *********************************/
-#if defined(__I386__) || defined(__X86_64__)
+#if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
static struct avl_table *methodtree = NULL;
static int methodtree_comparator(const void *pc, const void *element,
void *param);
*******************************************************************************/
-void codegen_init()
+void codegen_init(void)
{
-#if defined(__I386__) || defined(__X86_64__)
+#if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
/* this tree is global, not method specific */
+
if (!methodtree) {
+#if !defined(__INTRP__)
methodtree_element *mte;
+#endif
methodtree = avl_create(methodtree_comparator, NULL, NULL);
+#if !defined(__INTRP__)
+ /* insert asm_calljavafunction */
+
mte = NEW(methodtree_element);
mte->startpc = (functionptr) asm_calljavafunction;
- mte->endpc = (functionptr) ((long) asm_calljavafunction2 - 1);
+ mte->endpc = (functionptr) ((ptrint) asm_calljavafunction2 - 1);
avl_insert(methodtree, mte);
+ /* insert asm_calljavafunction2 */
+
mte = NEW(methodtree_element);
mte->startpc = (functionptr) asm_calljavafunction2;
- mte->endpc = (functionptr) ((long) asm_call_jit_compiler - 1);
+ mte->endpc = (functionptr) ((ptrint) asm_call_jit_compiler - 1);
avl_insert(methodtree, mte);
+#endif /* !defined(__INTRP__) */
}
#endif
}
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;
cd->jumpreferences = NULL;
cd->datareferences = NULL;
cd->xboundrefs = NULL;
- cd->xcheckarefs = NULL;
cd->xnullrefs = NULL;
cd->xcastrefs = NULL;
+ cd->xstorerefs = NULL;
cd->xdivrefs = NULL;
cd->xexceptionrefs = NULL;
- cd->clinitrefs = NULL;
+ cd->patchrefs = NULL;
cd->linenumberreferences = NULL;
cd->linenumbertablesizepos = 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);
#endif
+#if !defined(__XDSPCORE__)
static s4 dseg_addfloat_increase(codegendata *cd, float value)
{
dseg_increase(cd);
return -(cd->dseglen);
}
+#endif /* !defined(__XDSPCORE__) */
static void dseg_addtarget(codegendata *cd, basicblock *target)
}
+#if defined(__I386__) || defined(__X86_64__)
static void dseg_adddata(codegendata *cd, u1 *ptr)
{
dataref *dr;
dr->next = cd->datareferences;
cd->datareferences = dr;
}
+#endif
+
+/* dseg_addlinenumbertablesize *************************************************
+
+ XXX
+
+*******************************************************************************/
static void dseg_addlinenumbertablesize(codegendata *cd)
{
-#ifdef __ALPHA__
- dseg_adds4(cd, 0); /*PADDING*/
+#if defined (__ALPHA__) || defined(__MIPS__) || defined (__X86_64__)
+ /* 4-byte ALIGNMENT PADDING */
+
+ dseg_adds4(cd, 0);
#endif
- cd->linenumbertablesizepos = dseg_addaddress(cd, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
+ cd->linenumbertablesizepos = dseg_addaddress(cd, NULL);
cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
-#ifdef __ALPHA__
- dseg_adds4(cd, 0); /*PADDING*/
+
+#if defined(__ALPHA__) || defined(__MIPS__) || defined (__X86_64__)
+ /* 4-byte ALIGNMENT PADDING */
+
+ dseg_adds4(cd, 0);
#endif
}
branchpos = (u1 *) branchptr - cd->mcodebase;
+#if !defined(__INTRP__)
+ /* The interpreter uses absolute branches, so we do branch resolving */
+ /* after the code and data segment move. */
+
+ /* 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,
target->mpc);
- } else {
+ } else
+#endif
+ {
branchref *br = DNEW(branchref);
br->branchpos = branchpos;
}
-static void codegen_addxcheckarefs(codegendata *cd, void *branchptr)
+static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
{
s4 branchpos;
branchref *br;
br = DNEW(branchref);
br->branchpos = branchpos;
- br->next = cd->xcheckarefs;
- cd->xcheckarefs = br;
+ br->next = cd->xnullrefs;
+ cd->xnullrefs = br;
}
-static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
+static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
{
s4 branchpos;
branchref *br;
br = DNEW(branchref);
br->branchpos = branchpos;
- br->next = cd->xnullrefs;
- cd->xnullrefs = br;
+ br->next = cd->xcastrefs;
+ cd->xcastrefs = br;
}
-static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
+/* codegen_addxstorerefs *******************************************************
+
+ Adds an ArrayStoreException branch to the list.
+
+*******************************************************************************/
+
+static void codegen_addxstorerefs(codegendata *cd, void *branchptr)
{
- s4 branchpos;
+ s4 branchpos;
branchref *br;
branchpos = (u1 *) branchptr - cd->mcodebase;
br = DNEW(branchref);
br->branchpos = branchpos;
- br->next = cd->xcastrefs;
- cd->xcastrefs = br;
+ br->next = cd->xstorerefs;
+ cd->xstorerefs = br;
}
-static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
+/* codegen_addxdivrefs *********************************************************
+
+ Adds an ArithmeticException branch to the list.
+
+*******************************************************************************/
+
+static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
{
s4 branchpos;
branchref *br;
br = DNEW(branchref);
br->branchpos = branchpos;
- br->next = cd->xexceptionrefs;
- cd->xexceptionrefs = br;
+ br->next = cd->xdivrefs;
+ cd->xdivrefs = br;
}
-#if defined(__I386__) || defined(__X86_64__)
-static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
+static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
{
s4 branchpos;
branchref *br;
br = DNEW(branchref);
br->branchpos = branchpos;
- br->next = cd->xdivrefs;
- cd->xdivrefs = br;
+ br->next = cd->xexceptionrefs;
+ cd->xexceptionrefs = br;
}
-#endif
-static void codegen_addclinitref(codegendata *cd,
- void *branchptr,
- classinfo *class)
+/* codegen_addpatchref *********************************************************
+
+ Adds a new patcher reference to the list of patching positions.
+
+*******************************************************************************/
+
+static void codegen_addpatchref(codegendata *cd, voidptr branchptr,
+ functionptr patcher, voidptr ref, s4 disp)
{
- s4 branchpos;
- clinitref *cr;
+ patchref *pr;
+ s4 branchpos;
branchpos = (u1 *) branchptr - cd->mcodebase;
- cr = DNEW(clinitref);
- cr->branchpos = branchpos;
- cr->class = class;
- cr->next = cd->clinitrefs;
- cd->clinitrefs = cr;
+ pr = DNEW(patchref);
+
+ pr->branchpos = branchpos;
+ pr->patcher = patcher;
+ pr->ref = ref;
+ pr->disp = disp;
+
+ pr->next = cd->patchrefs;
+ cd->patchrefs = pr;
}
+/* codegen_createlinenumbertable ***********************************************
+
+ Creates a line number table in the data segment from the created
+ entries in linenumberreferences.
+
+*******************************************************************************/
+
static void codegen_createlinenumbertable(codegendata *cd)
{
-#ifdef __I386__
linenumberref *lr;
for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
dseg_addaddress(cd, lr->linenumber);
}
-#endif
}
-#if defined(__I386__) || defined(__X86_64__)
+#if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
+/* methodtree_comparator *******************************************************
+
+ XXX
+
+*******************************************************************************/
+
static int methodtree_comparator(const void *pc, const void *element, void *param)
{
methodtree_element *mte;
/* compare both startpc and endpc of pc, even if they have the same value,
otherwise the avl_probe sometimes thinks the element is already in the
tree */
+
if ((long) mte->startpc <= (long) mtepc->startpc &&
(long) mtepc->startpc <= (long) mte->endpc &&
(long) mte->startpc <= (long) mtepc->endpc &&
}
-#if 0
-void *codegen_findmethod1(void *pc)
-{
- void * retVal=findmethod(pc);
- methodinfo **ma=(methodinfo**)retVal;
- methodinfo *m=ma[-1];
- if (m)
- if (m->name)
- utf_display(m->name);
- else
- log_text("No Name");
- else log_text("No methodinfo");
- return retVal;
-}
-#endif
+/* codegen_insertmethod ********************************************************
+
+ XXX
+*******************************************************************************/
void codegen_insertmethod(functionptr startpc, functionptr endpc)
{
tables_unlock();
#endif
#endif
+ assert(0);
throw_cacao_exception_exit(string_java_lang_InternalError,
"duplicate entry");
}
}
+/* codegen_findmethod **********************************************************
+
+ XXX
+
+*******************************************************************************/
+
functionptr codegen_findmethod(functionptr pc)
{
methodtree_element *mtepc;
tables_unlock();
#endif
#endif
+ printf("Cannot find Java function at %p\n", (void *) (ptrint) pc);
+ assert(0);
throw_cacao_exception_exit(string_java_lang_InternalError,
- "cannot find function");
+ "Cannot find Java function at %p", pc);
}
#if defined(USE_THREADS)
return mte->startpc;
}
-#endif
+#endif /* defined(__I386__) || defined(__X86_64__) || defined(__INTRP__) */
+/* 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);
- memcpy((void *) (long) m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
- memcpy((void *) ((long) m->mcode + cd->dseglen), cd->mcodebase, mcodelen);
+ /* copy data and code to their new location */
- m->entrypoint = epoint = (functionptr) ((long) m->mcode + cd->dseglen);
+ 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) ((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;
}
-#ifdef __I386__
/* 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;
}
+
+#if defined(__I386__) || defined(__X86_64__) || defined(__INTRP__)
+ /* add method into methodtree to find the entrypoint */
+
+ codegen_insertmethod(m->entrypoint,
+ (functionptr) ((ptrint) m->entrypoint + mcodelen));
#endif
-#if defined(__I386__) || defined(__X86_64__)
+#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__)
{
dataref *dr;
- /* add method into methodtree to find the entrypoint */
- codegen_insertmethod(m->entrypoint,
- (functionptr) ((long) m->entrypoint + mcodelen));
-
/* data segment references resolving */
+
dr = cd->datareferences;
while (dr != NULL) {
- *((functionptr *) ((long) epoint + (long) 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;
s4 *s4ptr;
s4 i;
- s4ptr = (s4 *) (long) m->mcode;
+ s4ptr = (s4 *) (ptrint) m->mcode;
printf(" --- dump of datasegment\n");
for (i = cd->dseglen; i > 0 ; i -= 4) {
- printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
+#if SIZEOF_VOID_P == 8
+ printf("0x%016lx: -%6x (%6d): %8x\n",
+ (ptrint) s4ptr, i, i, (s4) *s4ptr);
+#else
+ printf("0x%08x: -%6x (%6d): %8x\n",
+ (ptrint) s4ptr, i, i, (s4) *s4ptr);
+#endif
+ s4ptr++;
}
+
printf(" --- begin of data segment: %p\n", (void *) s4ptr);
}
+
+/* codegen_createnativestub ****************************************************
+
+ Wrapper for createnativestub.
+
+*******************************************************************************/
+
+functionptr codegen_createnativestub(functionptr f, methodinfo *m)
+{
+ codegendata *cd;
+ registerdata *rd;
+ t_inlining_globals *id;
+ s4 dumpsize;
+ methoddesc *md;
+ methoddesc *nmd;
+ s4 nativeparams;
+
+ /* 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);
+#if !defined(__INTRP__)
+ reg_setup(m, rd, id);
+#endif
+ codegen_setup(m, cd, id);
+
+ /* create new method descriptor with additional native parameters */
+
+ md = m->parseddesc;
+ nativeparams = (m->flags & ACC_STATIC) ? 2 : 1;
+
+ nmd = (methoddesc *) DMNEW(u1, sizeof(methoddesc) - sizeof(typedesc) +
+ md->paramcount * sizeof(typedesc) +
+ nativeparams * sizeof(typedesc));
+
+ nmd->paramcount = md->paramcount + nativeparams;
+
+ nmd->params = DMNEW(paramdesc, nmd->paramcount);
+
+ nmd->paramtypes[0].type = TYPE_ADR; /* add environment pointer */
+
+ if (m->flags & ACC_STATIC)
+ nmd->paramtypes[1].type = TYPE_ADR; /* add class pointer */
+
+ MCOPY(nmd->paramtypes + nativeparams, md->paramtypes, typedesc,
+ md->paramcount);
+
+ md_param_alloc(nmd);
+
+ /* generate the code */
+
+ m->entrypoint = createnativestub(f, m, cd, rd, nmd);
+
+#if defined(STATISTICS)
+ if (opt_stat)
+ count_nstub_len += m->mcodelength;
+#endif
+
+ /* disassemble native stub */
+
+ if (opt_shownativestub) {
+ codegen_disassemble_nativestub(m,
+ (u1 *) (ptrint) m->entrypoint,
+ (u1 *) (ptrint) m->entrypoint + (m->mcodelength - cd->dseglen));
+
+ /* show data segment */
+
+ if (opt_showddatasegment)
+ dseg_display(m, cd);
+ }
+
+ /* release memory */
+
+ dump_release(dumpsize);
+
+ /* return native stub entry point */
+
+ return m->entrypoint;
+}
+
+
+/* codegen_disassemble_nativestub **********************************************
+
+ Disassembles the generated native stub.
+
+*******************************************************************************/
+
+void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
+{
+ 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", (s4) (end - start));
+
+ disassemble(start, end);
+}
+
+
+/* codegen_start_native_call ***************************************************
+
+ Prepares the stuff required for a native (JNI) function call:
+
+ - adds a stackframe info structure to the chain, for stacktraces
+ - prepares the local references table on the stack
+
+ The layout of the native stub stackframe should look like this:
+
+ +---------------------------+ <- SP (of parent Java function)
+ | return address |
+ +---------------------------+
+ | |
+ | stackframe info structure |
+ | |
+ +---------------------------+
+ | |
+ | local references table |
+ | |
+ +---------------------------+
+ | |
+ | arguments (if any) |
+ | |
+ +---------------------------+ <- SP (native stub)
+
+*******************************************************************************/
+
+void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, functionptr ra)
+{
+ stackframeinfo *sfi;
+ localref_table *lrt;
+ nativethread *info;
+
+ /* get data structures from stack */
+
+ sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
+ lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
+ sizeof(localref_table));
+
+ /* get thread info */
+
+ info = THREADINFO;
+
+ /* add a stackframeinfo to the chain */
+
+ stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
+
+ /* add current JNI local references table to this thread */
+
+ lrt->capacity = LOCALREFTABLE_CAPACITY;
+ lrt->used = 0;
+ lrt->localframes = 1;
+ lrt->prev = info->_localref_table;
+
+ /* clear the references array (memset is faster the a for-loop) */
+
+ MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
+
+ info->_localref_table = lrt;
+}
+
+
+/* codegen_finish_native_call **************************************************
+
+ Removes the stuff required for a native (JNI) function call.
+
+*******************************************************************************/
+
+void codegen_finish_native_call(u1 *datasp)
+{
+ stackframeinfo *sfi;
+ localref_table *lrt;
+ nativethread *info;
+ s4 localframes;
+
+ /* get data structures from stack */
+
+ sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
+ lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
+ sizeof(localref_table));
+
+ /* get thread info */
+
+ info = THREADINFO;
+
+ /* remove current stackframeinfo from chain */
+
+ info->_stackframeinfo = sfi->prev;
+
+ /* release JNI local references tables for this thread */
+
+ lrt = info->_localref_table;
+
+ /* got through all current local frames */
+
+ for (localframes = lrt->localframes; localframes >= 1; localframes--) {
+ lrt = lrt->prev;
+ }
+
+ /* now store the previous local frames in the thread structure */
+
+ info->_localref_table = lrt;
+}
+
+
+/* removecompilerstub **********************************************************
+
+ Deletes a compilerstub from memory (simply by freeing it).
+
+*******************************************************************************/
+
+void removecompilerstub(functionptr stub)
+{
+ /* pass size 1 to keep the intern function happy */
+
+ CFREE((void *) (ptrint) stub, 1);
+}
+
+
+/* removenativestub ************************************************************
+
+ Removes a previously created native-stub from memory.
+
+*******************************************************************************/
+
+void removenativestub(functionptr stub)
+{
+ /* pass size 1 to keep the intern function happy */
+
+ CFREE((void *) (ptrint) 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
Otherwise (when v is spilled) this function returns tempregnum.
If not already done, regoff and flags are set in the stack location.
*/
+/* On ARM we have to check if a long/double variable is splitted
+ across reg/stack (HIGH_REG == REG_SPLIT). We return the actual register
+ of v for LOW_REG and the tempregnum for HIGH_REG in such cases.
+ (michi 2005/07/24)
+*/
static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
{
if (!(v->flags & INMEMORY))
return(v->regoff);
break;
+
case STACKVAR:
var = &(rd->interfaces[v->varnum][v->type]);
v->regoff = var->regoff;
if (!(var->flags & INMEMORY))
return(var->regoff);
break;
+
case LOCALVAR:
var = &(rd->locals[v->varnum][v->type]);
v->regoff = var->regoff;
- if (!(var->flags & INMEMORY))
+ if (!(var->flags & INMEMORY)) {
+#if defined(__ARM__) && defined(__ARMEL__)
+ if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(var->regoff) == REG_SPLIT))
+ return(PACK_REGS(GET_LOW_REG(var->regoff), GET_HIGH_REG(tempregnum)));
+#endif
+#if defined(__ARM__) && defined(__ARMEB__)
+ if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(var->regoff) == REG_SPLIT))
+ return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(var->regoff)));
+#endif
return(var->regoff);
+ }
break;
+
case ARGVAR:
- v->regoff = v->varnum;
- if (IS_FLT_DBL_TYPE(v->type)) {
- if (v->varnum < rd->fltreg_argnum) {
- v->regoff = rd->argfltregs[v->varnum];
- return(rd->argfltregs[v->varnum]);
- }
-
- } else {
-#if defined(__POWERPC__)
- if (v->varnum < rd->intreg_argnum - (IS_2_WORD_TYPE(v->type) != 0)) {
-#else
- if (v->varnum < rd->intreg_argnum) {
+ if (!(v->flags & INMEMORY)) {
+#if defined(__ARM__) && defined(__ARMEL__)
+ if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->regoff) == REG_SPLIT))
+ return(PACK_REGS(GET_LOW_REG(v->regoff), GET_HIGH_REG(tempregnum)));
#endif
- v->regoff = rd->argintregs[v->varnum];
- return (rd->argintregs[v->varnum]);
- }
- }
-#if defined(__POWERPC__)
- v->regoff += 6;
-#else
- v->regoff -= rd->intreg_argnum;
+#if defined(__ARM__) && defined(__ARMEB__)
+ if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->regoff) == REG_SPLIT))
+ return(PACK_REGS(GET_LOW_REG(tempregnum), GET_HIGH_REG(v->regoff)));
#endif
+ return(v->regoff);
+ }
break;
}
+#ifdef STATISTICS
+ if (opt_stat)
+ count_spills_read++;
+#endif
v->flags |= INMEMORY;
return tempregnum;
}
#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;
-
- builtin_monitorenter((java_objectheader*) m);
-#if defined(__X86_64__)
- if ((*((s4*)jmpPatchTarget))==((s4)jmpTarget)) {
-#else
- if ((*jmpPatchTarget)==jmpTarget) {
-#endif
- builtin_monitorexit((java_objectheader*) m);
- 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]=0;
- nativeName=nativeNameEscape;
- }
- if (nativeName[i]=='/') nativeName[i]='_';
- i++;
- }
-
-/* printf("nativename: %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");*/
- 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*/
- 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
- builtin_monitorexit((java_objectheader *) m );
- 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);
-
- builtin_monitorexit((java_objectheader *) m );
- 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