-/* jit/codegen.inc - architecture independent code generator
+/* 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.
Authors: Reinhard Grafl
Andreas Krall
- Changes: Michael Gschwind
- Christian Thalinger
+ 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 1037 2004-04-26 16:36:48Z twisti $
+ $Id: codegen.inc 1735 2004-12-07 14:33:27Z twisti $
*/
+#ifndef _CODEGEN_INC_H_
+#define _CODEGEN_INC_H_
#include <string.h>
-#include "toolbox/memory.h"
-#include "toolbox/loging.h"
-#include "threads/thread.h"
-
-
-/************************* critical sections *********************************/
-
-struct threadcritnodetemp {
- struct threadcritnodetemp *next;
- int mcodebegin, mcodeend;
-};
-
-#define MCODEINITSIZE (1<<15) /* 32 Kbyte code area initialization size */
-#define DSEGINITSIZE (1<<12) /* 4 Kbyte data area initialization size */
-
-static u1* mcodebase = NULL; /* base pointer of code area */
-static s4* mcodeend = NULL; /* pointer to end of code area */
-static int mcodesize; /* complete size of code area (bytes) */
-
-static u1* dsegtop = NULL; /* pointer to top (end) of data area */
-static int dsegsize; /* complete size of data area (bytes) */
-int dseglen; /* used size of data area (bytes) */
- /* data area grows from top to bottom */
-
-static jumpref *jumpreferences; /* list of jumptable target addresses */
-static dataref *datareferences; /* list of data segment references */
-static branchref *xboundrefs; /* list of bound check branches */
-static branchref *xcheckarefs; /* list of array size check branches */
-static branchref *xnullrefs; /* list of null check branches */
-static branchref *xcastrefs; /* list of cast check branches */
-static branchref *xdivrefs; /* list of divide by zero branches */
-static branchref *xoomrefs; /* list of out of memory branches */
-static linenumberref *linenumberreferences; /*list of line numbers and the program counters of their first instruction*/
-static s4 linenumbertablesizepos;
-static s4 linenumbertablestartpos;
-static s4 linenumbertab;
-
-static struct threadcritnodetemp *threadcrit;
- /* List of critical code regions */
-static struct threadcritnodetemp threadcritcurrent;
-static int threadcritcount; /* Number of critical regions */
-
-int parentargs_base; /* offset in stackframe for the parameter from the caller*/
-
-void codegen_init(); /* allocates code and data area */
-void codegen_close(); /* releases temporary storage */
-static void codegen_finish(); /* makes code and data area permanent and */
- /* updates branch references to code/data */
-
-static s4 dseg_adds4(s4 value); /* adds an int to data area */
-static s4 dseg_adds8(s8 value); /* adds an long to data area */
-static s4 dseg_addfloat (float value); /* adds an float to data area */
-static s4 dseg_adddouble(double value); /* adds an double to data area */
-#if POINTERSIZE == 8
-#define dseg_addaddress(value) dseg_adds8((s8)(value))
-#else
-#define dseg_addaddress(value) dseg_adds4((s4)(value))
+#if !defined(STATIC_CLASSPATH)
+# include <dlfcn.h>
+#endif
+
+#include "mm/memory.h"
+#include "toolbox/avl.h"
+#include "toolbox/logging.h"
+#include "native/native.h"
+
+#if defined(USE_THREADS)
+# if defined(NATIVE_THREADS)
+# include "threads/native/threads.h"
+# else
+# include "threads/green/threads.h"
+# endif
#endif
-static void dseg_addtarget(basicblock *target);
-static void dseg_adddata(u1 *ptr);
-static void codegen_addreference(basicblock *target, void *branchptr);
-static void codegen_addxboundrefs(void *branchptr, s4 reg);
-static void codegen_addxnullrefs(void *branchptr);
-static void codegen_addxcastrefs(void *branchptr);
-static void codegen_addxdivrefs(void *branchptr);
-static void codegen_addxoomrefs(void *branchptr);
-static void codegen_threadcritstart(int offset);
-static void codegen_threadcritstop(int offset);
+#include "vm/exceptions.h"
+#include "vm/options.h"
+#include "vm/statistics.h"
+#include "vm/jit/codegen.inc.h"
+
+
+/* in this tree we store all method addresses *********************************/
+
+#if defined(__I386__) || defined(__X86_64__)
+static struct avl_table *methodtree = NULL;
+static int methodtree_comparator(const void *pc, const void *element,
+ void *param);
+#endif
-void dseg_display(s4 *s4ptr);
+/* codegen_init ****************************************************************
+ TODO
-/* codegen_init allocates and initialises code area, data area and references */
+*******************************************************************************/
void codegen_init()
{
- if (!mcodebase) {
- mcodebase = MNEW(u1, MCODEINITSIZE);
- mcodesize = MCODEINITSIZE;
- }
+#if defined(__I386__) || defined(__X86_64__)
+ /* this tree is global, not method specific */
+ if (!methodtree) {
+ methodtree_element *mte;
- if (!dsegtop) {
- dsegtop = MNEW(u1, DSEGINITSIZE);
- dsegsize = DSEGINITSIZE;
- dsegtop += dsegsize;
- }
+ methodtree = avl_create(methodtree_comparator, NULL, NULL);
- dseglen = 0;
+ mte = NEW(methodtree_element);
- linenumberreferences=NULL;
- linenumbertablesizepos=0;
- linenumbertablestartpos=0;
- linenumbertab=0;
- jumpreferences = NULL;
- datareferences = NULL;
- xboundrefs = NULL;
- xnullrefs = NULL;
- xcastrefs = NULL;
- xdivrefs = NULL;
- xoomrefs = NULL;
+ mte->startpc = (functionptr) asm_calljavafunction;
+ mte->endpc = (functionptr) ((long) asm_calljavafunction2 - 1);
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- threadcritcurrent.next = NULL;
- threadcritcount = 0;
+ avl_insert(methodtree, mte);
+
+ mte = NEW(methodtree_element);
+
+ mte->startpc = (functionptr) asm_calljavafunction2;
+ mte->endpc = (functionptr) ((long) asm_call_jit_compiler - 1);
+
+ avl_insert(methodtree, mte);
+ }
#endif
}
+/* codegen_setup **************************************************************
-/* codegen_close releases temporary code and data area */
+ allocates and initialises code area, data area and references
-void codegen_close()
+*******************************************************************************/
+
+void codegen_setup(methodinfo *m, codegendata *cd, t_inlining_globals *id)
{
- if (mcodebase) {
- MFREE(mcodebase, u1, mcodesize);
- mcodebase = NULL;
+ cd->mcodebase = MNEW(u1, MCODEINITSIZE);
+ cd->mcodesize = MCODEINITSIZE;
+
+ cd->dsegtop = MNEW(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->xdivrefs = NULL;
+ cd->xexceptionrefs = NULL;
+ cd->clinitrefs = NULL;
+
+ cd->linenumberreferences = NULL;
+ cd->linenumbertablesizepos = 0;
+ cd->linenumbertablestartpos = 0;
+ cd->linenumbertab = 0;
+
+ cd->method = m;
+ cd->exceptiontable = 0;
+ cd->exceptiontablelength = 0;
+
+ if (useinlining && id) {
+ if (id->cumextablelength > 0) {
+ cd->exceptiontablelength = id->cumextablelength;
+ cd->exceptiontable = DMNEW(exceptiontable, id->cumextablelength + 1);
+ }
+
+ } else if (id && (id->method->exceptiontablelength >0)) {
+ cd->exceptiontablelength = m->exceptiontablelength;
+ cd->exceptiontable = DMNEW(exceptiontable, m->exceptiontablelength + 1);
}
- if (dsegtop) {
- MFREE(dsegtop - dsegsize, u1, dsegsize);
- dsegtop = NULL;
+ if (id) {
+ cd->maxstack = id->cummaxstack;
+ cd->maxlocals = id->cumlocals;
+ } else {
+ cd->maxstack = m->maxstack;
+ cd->maxlocals = m->maxlocals;
}
+
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+ cd->threadcritcurrent.next = NULL;
+ cd->threadcritcount = 0;
+#endif
}
+/* codegen_free ****************************************************************
+
+ releases temporary code and data area
-/* codegen_increase doubles code area */
+*******************************************************************************/
-static s4 *codegen_increase(u1 *codeptr)
+void codegen_free(methodinfo *m, codegendata *cd)
{
- long len;
+ 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
- len = codeptr - mcodebase;
- mcodebase = MREALLOC(mcodebase, u1, mcodesize, mcodesize * 2);
- mcodesize *= 2;
- mcodeend = (s4*) (mcodebase + mcodesize);
- return (s4*) (mcodebase + len);
+ if (cd->mcodebase) {
+ MFREE(cd->mcodebase, u1, cd->mcodesize);
+ cd->mcodebase = NULL;
+ }
+
+ if (cd->dsegtop) {
+ MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
+ cd->dsegtop = NULL;
+ }
+ }
}
+/* codegen_close ***************************************************************
-/* desg_increase doubles data area */
+ TODO
+
+*******************************************************************************/
-static void dseg_increase()
+void codegen_close()
{
- u1 *newstorage = MNEW(u1, dsegsize * 2);
- memcpy(newstorage + dsegsize, dsegtop - dsegsize, dsegsize);
- MFREE(dsegtop - dsegsize, u1, dsegsize);
- dsegtop = newstorage;
- dsegsize *= 2;
- dsegtop += dsegsize;
+ /* TODO: release avl tree on i386 and x86_64 */
}
+/* codegen_increase doubles code area */
-static s4 dseg_adds4_increase(s4 value)
+static s4 *codegen_increase(codegendata *cd, u1 *codeptr)
{
- dseg_increase();
- *((s4 *) (dsegtop - dseglen)) = value;
- return -dseglen;
+ long len;
+
+ len = codeptr - cd->mcodebase;
+ cd->mcodebase = MREALLOC(cd->mcodebase,
+ u1,
+ cd->mcodesize,
+ cd->mcodesize * 2);
+ cd->mcodesize *= 2;
+ cd->mcodeend = (s4 *) (cd->mcodebase + cd->mcodesize);
+
+ return (s4 *) (cd->mcodebase + len);
}
+/* desg_increase doubles data area */
-static s4 dseg_adds4(s4 value)
+static void dseg_increase(codegendata *cd)
{
- s4 *dataptr;
+ u1 *newstorage;
- dseglen += 4;
- dataptr = (s4 *) (dsegtop - dseglen);
- if (dseglen > dsegsize)
- return dseg_adds4_increase(value);
- *dataptr = value;
- return -dseglen;
+ newstorage = MNEW(u1, cd->dsegsize * 2);
+
+ memcpy(newstorage + cd->dsegsize, cd->dsegtop - cd->dsegsize, cd->dsegsize);
+ MFREE(cd->dsegtop - cd->dsegsize, u1, cd->dsegsize);
+
+ cd->dsegtop = newstorage;
+ cd->dsegsize *= 2;
+ cd->dsegtop += cd->dsegsize;
}
+static s4 dseg_adds4_increase(codegendata *cd, s4 value)
+{
+ dseg_increase(cd);
+
+ *((s4 *) (cd->dsegtop - cd->dseglen)) = value;
-static s4 dseg_adds8_increase(s8 value)
+ return -(cd->dseglen);
+}
+
+
+static s4 dseg_adds4(codegendata *cd, s4 value)
{
- dseg_increase();
- *((s8 *) (dsegtop - dseglen)) = value;
- return -dseglen;
+ s4 *dataptr;
+
+ cd->dseglen += 4;
+ dataptr = (s4 *) (cd->dsegtop - cd->dseglen);
+
+ if (cd->dseglen > cd->dsegsize)
+ return dseg_adds4_increase(cd, value);
+
+ *dataptr = value;
+
+ return -(cd->dseglen);
}
+#if !defined(__I386__)
+static s4 dseg_adds8_increase(codegendata *cd, s8 value)
+{
+ dseg_increase(cd);
+
+ *((s8 *) (cd->dsegtop - cd->dseglen)) = value;
+
+ return -(cd->dseglen);
+}
+
-static s4 dseg_adds8(s8 value)
+static s4 dseg_adds8(codegendata *cd, s8 value)
{
s8 *dataptr;
- dseglen = ALIGN (dseglen + 8, 8);
- dataptr = (s8 *) (dsegtop - dseglen);
- if (dseglen > dsegsize)
- return dseg_adds8_increase(value);
+ cd->dseglen = ALIGN(cd->dseglen + 8, 8);
+ dataptr = (s8 *) (cd->dsegtop - cd->dseglen);
+
+ if (cd->dseglen > cd->dsegsize)
+ return dseg_adds8_increase(cd, value);
+
*dataptr = value;
- return -dseglen;
-}
+ return -(cd->dseglen);
+}
+#endif
-static s4 dseg_addfloat_increase(float value)
+static s4 dseg_addfloat_increase(codegendata *cd, float value)
{
- dseg_increase();
- *((float *) (dsegtop - dseglen)) = value;
- return -dseglen;
-}
+ dseg_increase(cd);
+ *((float *) (cd->dsegtop - cd->dseglen)) = value;
+ return -(cd->dseglen);
+}
-static s4 dseg_addfloat(float value)
+
+static s4 dseg_addfloat(codegendata *cd, float value)
{
float *dataptr;
- dseglen += 4;
- dataptr = (float *) (dsegtop - dseglen);
- if (dseglen > dsegsize)
- return dseg_addfloat_increase(value);
+ cd->dseglen += 4;
+ dataptr = (float *) (cd->dsegtop - cd->dseglen);
+
+ if (cd->dseglen > cd->dsegsize)
+ return dseg_addfloat_increase(cd, value);
+
*dataptr = value;
- return -dseglen;
-}
+ return -(cd->dseglen);
+}
-static s4 dseg_adddouble_increase(double value)
+static s4 dseg_adddouble_increase(codegendata *cd, double value)
{
- dseg_increase();
- *((double *) (dsegtop - dseglen)) = value;
- return -dseglen;
-}
+ dseg_increase(cd);
+ *((double *) (cd->dsegtop - cd->dseglen)) = value;
+ return -(cd->dseglen);
+}
-static s4 dseg_adddouble(double value)
+
+static s4 dseg_adddouble(codegendata *cd, double value)
{
double *dataptr;
- dseglen = ALIGN (dseglen + 8, 8);
- dataptr = (double *) (dsegtop - dseglen);
- if (dseglen > dsegsize)
- return dseg_adddouble_increase(value);
+ cd->dseglen = ALIGN(cd->dseglen + 8, 8);
+ dataptr = (double *) (cd->dsegtop - cd->dseglen);
+
+ if (cd->dseglen > cd->dsegsize)
+ return dseg_adddouble_increase(cd, value);
+
*dataptr = value;
- return -dseglen;
-}
+ return -(cd->dseglen);
+}
-static void dseg_addtarget(basicblock *target)
+static void dseg_addtarget(codegendata *cd, basicblock *target)
{
- jumpref *jr = DNEW(jumpref);
-
- jr->tablepos = dseg_addaddress(NULL);
+ jumpref *jr;
+
+ jr = DNEW(jumpref);
+ jr->tablepos = dseg_addaddress(cd, NULL);
jr->target = target;
- jr->next = jumpreferences;
- jumpreferences = jr;
+ jr->next = cd->jumpreferences;
+ cd->jumpreferences = jr;
}
-
-static void dseg_adddata(u1 *ptr)
+static void dseg_adddata(codegendata *cd, u1 *ptr)
{
- dataref *dr = DNEW(dataref);
+ dataref *dr;
- dr->pos = (u1 *) (ptr - mcodebase);
- dr->next = datareferences;
- datareferences = dr;
+ dr = DNEW(dataref);
+ dr->pos = (u1 *) (ptr - cd->mcodebase);
+ dr->next = cd->datareferences;
+ cd->datareferences = dr;
}
-static void dseg_addlinenumbertablesize() {
+
+static void dseg_addlinenumbertablesize(codegendata *cd)
+{
#ifdef __ALPHA__
- dseg_adds4(0); /*PADDING*/
+ dseg_adds4(cd, 0); /*PADDING*/
#endif
- linenumbertablesizepos=dseg_addaddress(NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
+ cd->linenumbertablesizepos = dseg_addaddress(cd, NULL); /*it could be considered to use adds4 here, to avoid 1 double word padding on ALPHA */
- linenumbertablestartpos=dseg_addaddress(NULL);
+ cd->linenumbertablestartpos = dseg_addaddress(cd, NULL);
#ifdef __ALPHA__
- dseg_adds4(0); /*PADDING*/
+ dseg_adds4(cd, 0); /*PADDING*/
#endif
}
-static void dseg_addlinenumber(u2 linenumber,u1 *ptr) {
- linenumberref *lr=DNEW(linenumberref);
- lr->linenumber=linenumber;
- lr->tablepos=0;
- lr->targetmpc=(ptr-mcodebase);
- lr->next=linenumberreferences;
- linenumberreferences=lr;
+
+static void dseg_addlinenumber(codegendata *cd, u2 linenumber, u1 *ptr)
+{
+ linenumberref *lr;
+
+ lr = DNEW(linenumberref);
+ lr->linenumber = linenumber;
+ lr->tablepos = 0;
+ lr->targetmpc = (ptr - cd->mcodebase);
+ lr->next = cd->linenumberreferences;
+ cd->linenumberreferences = lr;
}
-static void codegen_addreference(basicblock *target, void *branchptr)
+
+/* we need this function externally on i386 and x86_64, but keep the call fast
+ on alpha... */
+
+#if defined(__I386__) || defined(__X86_64__)
+void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
+#else
+static void codegen_addreference(codegendata *cd, basicblock *target, void *branchptr)
+#endif
{
- s4 branchpos = (u1*) branchptr - mcodebase;
+ s4 branchpos;
+
+ branchpos = (u1 *) branchptr - cd->mcodebase;
if (target->mpc >= 0) {
- gen_resolvebranch((u1*) mcodebase + branchpos, branchpos, target->mpc);
- }
- else {
+ gen_resolvebranch((u1 *) cd->mcodebase + branchpos,
+ branchpos,
+ target->mpc);
+
+ } else {
branchref *br = DNEW(branchref);
br->branchpos = branchpos;
br->next = target->branchrefs;
- target->branchrefs= br;
+ target->branchrefs = br;
}
}
-
-static void codegen_addxboundrefs(void *branchptr, s4 reg)
+static void codegen_addxboundrefs(codegendata *cd, void *branchptr, s4 reg)
{
- s4 branchpos = (u1*) branchptr - mcodebase;
+ s4 branchpos;
+ branchref *br;
- branchref *br = DNEW(branchref);
+ branchpos = (u1 *) branchptr - cd->mcodebase;
+ br = DNEW(branchref);
br->branchpos = branchpos;
br->reg = reg;
- br->next = xboundrefs;
- xboundrefs = br;
+ br->next = cd->xboundrefs;
+ cd->xboundrefs = br;
}
-
-static void codegen_addxcheckarefs(void *branchptr)
+static void codegen_addxcheckarefs(codegendata *cd, void *branchptr)
{
- s4 branchpos = (u1*) branchptr - mcodebase;
+ s4 branchpos;
+ branchref *br;
- branchref *br = DNEW(branchref);
+ branchpos = (u1 *) branchptr - cd->mcodebase;
+ br = DNEW(branchref);
br->branchpos = branchpos;
- br->next = xcheckarefs;
- xcheckarefs = br;
+ br->next = cd->xcheckarefs;
+ cd->xcheckarefs = br;
}
+static void codegen_addxnullrefs(codegendata *cd, void *branchptr)
+{
+ s4 branchpos;
+ branchref *br;
+
+ branchpos = (u1 *) branchptr - cd->mcodebase;
-static void codegen_addxnullrefs(void *branchptr)
+ br = DNEW(branchref);
+ br->branchpos = branchpos;
+ br->next = cd->xnullrefs;
+ cd->xnullrefs = br;
+}
+
+
+static void codegen_addxcastrefs(codegendata *cd, void *branchptr)
{
- s4 branchpos = (u1*) branchptr - mcodebase;
+ s4 branchpos;
+ branchref *br;
- branchref *br = DNEW(branchref);
+ branchpos = (u1 *) branchptr - cd->mcodebase;
+ br = DNEW(branchref);
br->branchpos = branchpos;
- br->next = xnullrefs;
- xnullrefs = br;
+ br->next = cd->xcastrefs;
+ cd->xcastrefs = br;
}
+static void codegen_addxexceptionrefs(codegendata *cd, void *branchptr)
+{
+ s4 branchpos;
+ branchref *br;
+
+ branchpos = (u1 *) branchptr - cd->mcodebase;
+
+ br = DNEW(branchref);
+ br->branchpos = branchpos;
+ br->next = cd->xexceptionrefs;
+ cd->xexceptionrefs = br;
+}
-static void codegen_addxcastrefs(void *branchptr)
+
+#if defined(__I386__) || defined(__X86_64__)
+static void codegen_addxdivrefs(codegendata *cd, void *branchptr)
{
- s4 branchpos = (u1*) branchptr - mcodebase;
+ s4 branchpos;
+ branchref *br;
- branchref *br = DNEW(branchref);
+ branchpos = (u1 *) branchptr - cd->mcodebase;
+ br = DNEW(branchref);
br->branchpos = branchpos;
- br->next = xcastrefs;
- xcastrefs = br;
+ br->next = cd->xdivrefs;
+ cd->xdivrefs = br;
}
+#endif
+
+
+static void codegen_addclinitref(codegendata *cd,
+ void *branchptr,
+ classinfo *class)
+{
+ s4 branchpos;
+ clinitref *cr;
+
+ branchpos = (u1 *) branchptr - cd->mcodebase;
+ cr = DNEW(clinitref);
+ cr->branchpos = branchpos;
+ cr->class = class;
+ cr->next = cd->clinitrefs;
+ cd->clinitrefs = cr;
+}
-static void codegen_addxoomrefs(void *branchptr)
+static void codegen_createlinenumbertable(codegendata *cd)
{
- s4 branchpos = (u1*) branchptr - mcodebase;
+#if defined(__I386__) || defined(__ALPHA__)
+ linenumberref *lr;
- branchref *br = DNEW(branchref);
+ for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
+ lr->tablepos = dseg_addaddress(cd, NULL);
- br->branchpos = branchpos;
- br->next = xoomrefs;
- xoomrefs = br;
+ if (cd->linenumbertab == 0)
+ cd->linenumbertab = lr->tablepos;
+
+ dseg_addaddress(cd, lr->linenumber);
+ }
+#endif
}
-static void codegen_addxdivrefs(void *branchptr)
+#if defined(__I386__) || defined(__X86_64__)
+static int methodtree_comparator(const void *pc, const void *element, void *param)
{
- s4 branchpos = (u1*) branchptr - mcodebase;
+ methodtree_element *mte;
+ methodtree_element *mtepc;
+
+ mte = (methodtree_element *) element;
+ mtepc = (methodtree_element *) pc;
+
+ /* 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 &&
+ (long) mtepc->endpc <= (long) mte->endpc) {
+ return 0;
+
+ } else if ((long) mtepc->startpc < (long) mte->startpc) {
+ return -1;
+
+ } else {
+ return 1;
+ }
+}
- branchref *br = DNEW(branchref);
- br->branchpos = branchpos;
- br->next = xdivrefs;
- xdivrefs = br;
+#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
-static void codegen_createlinenumbertable() {
-#ifdef __I386__
- /*log_text("codegen_createlinnumbertable");*/
- {
- linenumberref *lr;
- for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
- /*log_text("Adding line number entry");*/
- lr->tablepos=dseg_addaddress(NULL);
- if (linenumbertab==0) linenumbertab=lr->tablepos;
- dseg_addaddress(lr->linenumber);
- }
+void codegen_insertmethod(functionptr startpc, functionptr endpc)
+{
+ methodtree_element *mte;
+
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+ tables_lock();
+#endif
+#endif
+
+ mte = NEW(methodtree_element);
+ mte->startpc = startpc;
+ mte->endpc = endpc;
+
+ if (avl_insert(methodtree, mte)) {
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+ tables_unlock();
+#endif
+#endif
+ throw_cacao_exception_exit(string_java_lang_InternalError,
+ "duplicate entry");
}
+
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+ tables_unlock();
+#endif
#endif
}
-static void codegen_finish(int mcodelen)
+functionptr codegen_findmethod(functionptr pc)
{
- jumpref *jr;
- u1 *epoint;
+ methodtree_element *mtepc;
+ methodtree_element *mte;
- int extralen = 0;
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+ tables_lock();
+#endif
+#endif
+
+ mtepc = NEW(methodtree_element);
+ mtepc->startpc = pc;
+ mtepc->endpc = pc;
+
+ mte = avl_find(methodtree, mtepc);
+
+ FREE(mtepc, methodtree_element);
+
+ if (!mte) {
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+ tables_unlock();
+#endif
+#endif
+ throw_cacao_exception_exit(string_java_lang_InternalError,
+ "cannot find function");
+ }
+
+#if defined(USE_THREADS)
+#if defined(NATIVE_THREADS)
+ tables_unlock();
+#endif
+#endif
+
+ return mte->startpc;
+}
+#endif
+
+#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
+
+
+static void codegen_finish(methodinfo *m, codegendata *cd, s4 mcodelen)
+{
+ jumpref *jr;
+ functionptr epoint;
+ s4 extralen;
+ s4 alignedlen;
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- extralen += sizeof(threadcritnode) * threadcritcount;
+ extralen = sizeof(threadcritnode) * cd->threadcritcount;
+#else
+ extralen = 0;
#endif
- count_code_len += mcodelen;
- count_data_len += dseglen;
+#if defined(STATISTICS)
+ if (opt_stat) {
+ count_code_len += mcodelen;
+ count_data_len += cd->dseglen;
+ }
+#endif
- dseglen = ALIGN(dseglen, MAX_ALIGN);
+ cd->dseglen = ALIGN(cd->dseglen, MAX_ALIGN);
+ alignedlen = ALIGN(mcodelen, MAX_ALIGN) + cd->dseglen;
- method -> mcodelength = mcodelen + dseglen;
- method -> mcode = CNEW(u1, mcodelen + dseglen + extralen);
+ m->mcodelength = mcodelen + cd->dseglen;
+ m->mcode = (functionptr) (long) CNEW(u1, alignedlen + extralen);
- memcpy ( method->mcode, dsegtop - dseglen, dseglen);
- memcpy ( method->mcode + dseglen, mcodebase, mcodelen);
+ memcpy((void *) (long) m->mcode, cd->dsegtop - cd->dseglen, cd->dseglen);
+ memcpy((void *) ((long) m->mcode + cd->dseglen), cd->mcodebase, mcodelen);
- method -> entrypoint = epoint = (u1*) (method->mcode + dseglen);
+ m->entrypoint = epoint = (functionptr) ((long) m->mcode + cd->dseglen);
/* jump table resolving */
- jr = jumpreferences;
+ jr = cd->jumpreferences;
while (jr != NULL) {
- *((void**) (epoint + jr->tablepos)) = epoint + jr->target->mpc;
- jr = jr->next;
+ *((functionptr *) ((long) epoint + jr->tablepos)) =
+ (functionptr) ((long) epoint + (long) jr->target->mpc);
+ jr = jr->next;
}
-#ifdef __I386__
+#if defined(__I386__) || defined(__ALPHA__)
/* line number table resolving */
{
linenumberref *lr;
- #if POINTERSIZE == 8
- s8 lrtlen=0;
- #else
- s4 lrtlen=0;
- #endif
+#if POINTERSIZE == 8
+ s8 lrtlen = 0;
+#else
+ s4 lrtlen = 0;
+#endif
- for (lr=linenumberreferences;lr!=NULL;lr=lr->next) {
+ for (lr = cd->linenumberreferences; lr != NULL; lr = lr->next) {
lrtlen++;
- *((void**)(epoint+lr->tablepos))=epoint+lr->targetmpc;
- /*log_text("resolving line number information");*/
+ *((functionptr *) ((long) epoint + (long) lr->tablepos)) =
+ (functionptr) ((long) epoint + (long) lr->targetmpc);
}
- *((void**)(epoint+linenumbertablestartpos))=epoint+linenumbertab;
+ *((functionptr *) ((long) epoint + cd->linenumbertablestartpos)) =
+ (functionptr) ((long) epoint + cd->linenumbertab);
#if POINTERSIZE == 8
- *((s8*)(epoint+linenumbertablesizepos))=lrtlen;
+ *((s8 *) ((s8) epoint + cd->linenumbertablesizepos)) = lrtlen;
#else
- *((s4*)(epoint+linenumbertablesizepos))=lrtlen;
+ *((s4 *) ((s4) epoint + cd->linenumbertablesizepos)) = lrtlen;
#endif
-
}
#endif
+
#if defined(__I386__) || defined(__X86_64__)
{
dataref *dr;
- /* add method into datastructure to find the entrypoint */
- addmethod(method->entrypoint, method->entrypoint + mcodelen);
-
+
+ /* add method into methodtree to find the entrypoint */
+ codegen_insertmethod(m->entrypoint,
+ (functionptr) ((long) m->entrypoint + mcodelen));
+
/* data segment references resolving */
- dr = datareferences;
+ dr = cd->datareferences;
while (dr != NULL) {
- *((void**) ((long) epoint + (long) dr->pos - POINTERSIZE)) = epoint;
+ *((functionptr *) ((long) epoint + (long) dr->pos - POINTERSIZE)) =
+ epoint;
dr = dr->next;
}
}
#endif
-
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
{
- threadcritnode *n = (threadcritnode*) (method->mcode + mcodelen + dseglen);
- int i;
- struct threadcritnodetemp *nt = threadcrit;
-
- for (i=0; i<threadcritcount; i++)
- {
- n->mcodebegin = method->mcode + nt->mcodebegin;
- n->mcodeend = method->mcode + nt->mcodeend;
+ threadcritnode *n = (threadcritnode *) ((long) 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;
thread_registercritical(n);
n++;
nt = nt->next;
}
-
-void dseg_display(s4 *s4ptr)
+void dseg_display(methodinfo *m, codegendata *cd)
{
- int i;
+ s4 *s4ptr;
+ s4 i;
+ s4ptr = (s4 *) (long) m->mcode;
+
printf(" --- dump of datasegment\n");
- for (i = dseglen; i > 0 ; i -= 4) {
- printf("-%6x: %8x\n", i, (int)(*s4ptr++));
+ for (i = cd->dseglen; i > 0 ; i -= 4) {
+ printf("-%6x: %8x\n", i, (s4) (*s4ptr++));
}
- printf(" --- begin of data segment: %p\n", s4ptr);
+ printf(" --- begin of data segment: %p\n", (void *) s4ptr);
}
+
+/* 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
+ pseudoregister v.
+ If v is assigned to an actual register, this register will be returned.
+ Otherwise (when v is spilled) this function returns tempregnum.
+ If not already done, regoff and flags are set in the stack location.
+*/
+
+static int reg_of_var(registerdata *rd, stackptr v, int tempregnum)
+{
+ varinfo *var;
+
+ switch (v->varkind) {
+ case TEMPVAR:
+ 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))
+ 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) {
+#endif
+ v->regoff = rd->argintregs[v->varnum];
+ return (rd->argintregs[v->varnum]);
+ }
+ }
+#if defined(__POWERPC__)
+ v->regoff += 6;
+#else
+ v->regoff -= rd->intreg_argnum;
+#endif
+ break;
+ }
+ v->flags |= INMEMORY;
+ return tempregnum;
+}
+
+
#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-void codegen_threadcritstart(int offset)
+static void codegen_threadcritrestart(codegendata *cd, int offset)
{
- threadcritcurrent.mcodebegin = offset;
+ cd->threadcritcurrent.mcoderestart = offset;
}
-void codegen_threadcritstop(int offset)
+
+static void codegen_threadcritstart(codegendata *cd, int offset)
+{
+ cd->threadcritcurrent.mcodebegin = offset;
+}
+
+
+static void codegen_threadcritstop(codegendata *cd, int offset)
{
- threadcritcurrent.next = threadcrit;
- threadcritcurrent.mcodeend = offset;
- threadcrit = DNEW(struct threadcritnodetemp);
- *threadcrit = threadcritcurrent;
- threadcritcount++;
+ cd->threadcritcurrent.next = cd->threadcrit;
+ cd->threadcritcurrent.mcodeend = offset;
+ cd->threadcrit = DNEW(threadcritnodetemp);
+ *(cd->threadcrit) = cd->threadcritcurrent;
+ cd->threadcritcount++;
+}
+#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
/*