-/* 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 1953 2005-02-17 13:42:23Z christian $
+ $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);
}
+#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)
{
-#if defined(__I386__) || defined(__ALPHA__)
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__) */
-#if defined(__ALPHA__)
-/*perhaps in the end I'll have to go for the tree version on alpha too, since this is insecure for eg segfault signals in native code,
-since it will still return an adress of a datasegment, but which will not be a valid one of a java method. This version is faster though (jowenn)*/
-void *codegen_findmethod(void *returnAdress)
- {
- void *result;
- s8 d;
- void *dataseg;
- d=*((s4*)returnAdress);
- d=d<<48;
- d=d>>48;
- dataseg=returnAdress+d;
- d=*(((s4*)returnAdress)+1);
- d=d>>16;
- d=d-0x177b;
- if (d==0) {
- d=*(((s4*)returnAdress)+1);
- d=d<<16;
- dataseg=dataseg+d;
- }
- return dataseg;
-#if 0
- ldl t0,0(ra) /* load instruction LDA PV,xxx(RA) */
- sll t0,48,t0
- sra t0,48,t0 /* isolate offset */
- addq t0,ra,pv /* compute update address */
- ldl t0,4(ra) /* load instruction LDAH PV,xxx(PV) */
- srl t0,16,t0 /* isolate instruction code */
- lda t0,-0x177b(t0) /* test for LDAH */
- bne t0,ex_stack_loop
- ldl t0,4(ra) /* load instruction LDAH PV,xxx(RA) */
- sll t0,16,t0 /* compute high offset */
- addl t0,0,t0 /* sign extend high offset */
- addq t0,pv,pv /* compute update address */
- br ex_stack_loop
-#endif
-}
-#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;
}
-#if defined(__I386__) || defined(__ALPHA__)
/* 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)
{
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 < FLT_ARG_CNT) {
- v->regoff = rd->argfltregs[v->varnum];
- return(rd->argfltregs[v->varnum]);
- }
-
-#if defined(__POWERPC__)
- v->regoff += 6;
-#else
- v->regoff -= FLT_ARG_CNT;
-#endif
-
- } else {
-#if defined(__POWERPC__)
- if (v->varnum < INT_ARG_CNT - (IS_2_WORD_TYPE(v->type) != 0)) {
-#else
- if (v->varnum < INT_ARG_CNT) {
+ 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 -= INT_ARG_CNT;
+#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;
}
#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]=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
-
-#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