/* src/vm/jit/codegen-common.c - architecture independent code generator stuff
- Copyright (C) 1996-2005, 2006, 2007 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
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
#include "vm/types.h"
#include "codegen.h"
+#include "md.h"
#include "md-abi.h"
#include "mm/memory.h"
#include "native/localref.h"
#include "native/native.h"
-#if defined(WITH_CLASSPATH_SUN)
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
# include "native/include/java_lang_Object.h"
-# include "native/include/java_lang_String.h"
+# include "native/include/java_lang_String.h" /* required by j.l.CL */
# include "native/include/java_nio_ByteBuffer.h" /* required by j.l.CL */
# include "native/include/java_lang_ClassLoader.h"
#endif
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
+# include "native/include/java_lang_String.h"
+#endif
+
#include "native/include/java_lang_Class.h"
-#include "threads/threads-common.h"
+#include "threads/thread.hpp"
#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/jit/abi.h"
#include "vm/jit/asmpart.h"
+#include "vm/jit/code.h"
#include "vm/jit/codegen-common.h"
#if defined(ENABLE_DISASSEMBLER)
#include "vm/jit/emit-common.h"
#include "vm/jit/jit.h"
#include "vm/jit/linenumbertable.h"
-#include "vm/jit/md.h"
#include "vm/jit/methodheader.h"
+#include "vm/jit/methodtree.h"
#include "vm/jit/patcher-common.h"
#include "vm/jit/replace.h"
#if defined(ENABLE_SSA)
# include "vm/jit/optimizing/lsra.h"
# include "vm/jit/optimizing/ssa.h"
#endif
-#include "vm/jit/stacktrace.h"
-#include "vm/jit/trace.h"
+#include "vm/jit/stacktrace.hpp"
+#include "vm/jit/trace.hpp"
#if defined(ENABLE_INTRP)
#include "vm/jit/intrp/intrp.h"
#include "show.h"
-/* in this tree we store all method addresses *********************************/
-
-static avl_tree_t *methodtree = NULL;
-static s4 methodtree_comparator(const void *treenode, const void *node);
-
/* codegen_init ****************************************************************
void codegen_init(void)
{
- /* this tree is global, not method specific */
-
- if (!methodtree) {
-#if defined(ENABLE_JIT)
- methodtree_element *mte;
-#endif
-
- methodtree = avl_create(&methodtree_comparator);
-
-#if defined(ENABLE_JIT)
- /* insert asm_vm_call_method */
-
- mte = NEW(methodtree_element);
-
- mte->startpc = (u1 *) (ptrint) asm_vm_call_method;
- mte->endpc = (u1 *) (ptrint) asm_vm_call_method_end;
-
- avl_insert(methodtree, mte);
-#endif /* defined(ENABLE_JIT) */
-
- }
-
}
#endif
cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
- cd->listcritical = list_create_dump(OFFSET(critical_section_ref_t, linkage));
cd->linenumbers = list_create_dump(OFFSET(linenumbertable_list_entry_t, linkage));
}
#endif
cd->brancheslabel = list_create_dump(OFFSET(branch_label_ref_t, linkage));
- cd->listcritical = list_create_dump(OFFSET(critical_section_ref_t, linkage));
cd->linenumbers = list_create_dump(OFFSET(linenumbertable_list_entry_t, linkage));
/* We need to clear the mpc and the branch references from all
void codegen_branch_label_add(codegendata *cd, s4 label, s4 condition, s4 reg, u4 options)
{
- list_t *list;
+ list_t *l;
branch_label_ref_t *br;
s4 mpc;
- /* get the label list */
+ /* Get the label list. */
- list = cd->brancheslabel;
+ l = cd->brancheslabel;
/* calculate the current mpc */
br->reg = reg;
br->options = options;
- /* add the branch to the list */
-
- list_add_last_unsynced(list, br);
-}
-
-
-/* codegen_critical_section_new ************************************************
-
- Allocates a new critical-section reference and adds it to the
- critical-section list.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS)
-void codegen_critical_section_new(codegendata *cd)
-{
- list_t *list;
- critical_section_ref_t *csr;
- s4 mpc;
-
- /* get the critical section list */
-
- list = cd->listcritical;
-
- /* calculate the current mpc */
-
- mpc = cd->mcodeptr - cd->mcodebase;
-
- csr = DNEW(critical_section_ref_t);
-
- /* We only can set restart right now, as start and end are set by
- the following, corresponding functions. */
-
- csr->start = -1;
- csr->end = -1;
- csr->restart = mpc;
-
- /* add the branch to the list */
-
- list_add_last_unsynced(list, csr);
-}
-#endif
-
-
-/* codegen_critical_section_start **********************************************
-
- Set the start-point of the current critical section (which is the
- last element of the list).
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS)
-void codegen_critical_section_start(codegendata *cd)
-{
- list_t *list;
- critical_section_ref_t *csr;
- s4 mpc;
-
- /* get the critical section list */
-
- list = cd->listcritical;
-
- /* calculate the current mpc */
-
- mpc = cd->mcodeptr - cd->mcodebase;
-
- /* get the current critical section */
-
- csr = list_last_unsynced(list);
-
- /* set the start point */
-
- assert(csr->start == -1);
-
- csr->start = mpc;
-}
-#endif
-
-
-/* codegen_critical_section_end ************************************************
-
- Set the end-point of the current critical section (which is the
- last element of the list).
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS)
-void codegen_critical_section_end(codegendata *cd)
-{
- list_t *list;
- critical_section_ref_t *csr;
- s4 mpc;
-
- /* get the critical section list */
-
- list = cd->listcritical;
-
- /* calculate the current mpc */
-
- mpc = cd->mcodeptr - cd->mcodebase;
-
- /* get the current critical section */
-
- csr = list_last_unsynced(list);
-
- /* set the end point */
-
- assert(csr->end == -1);
-
- csr->end = mpc;
-}
-#endif
-
-
-/* codegen_critical_section_finish *********************************************
-
- Finish the critical sections, create the critical section nodes for
- the AVL tree and insert them into the tree.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS)
-static void codegen_critical_section_finish(jitdata *jd)
-{
- codeinfo *code;
- codegendata *cd;
- list_t *list;
- critical_section_ref_t *csr;
- critical_section_node_t *csn;
-
- /* get required compiler data */
-
- code = jd->code;
- cd = jd->cd;
-
- /* get the critical section list */
-
- list = cd->listcritical;
-
- /* iterate over all critical sections */
-
- for (csr = list_first_unsynced(list); csr != NULL;
- csr = list_next_unsynced(list, csr)) {
- /* check if all points are set */
+ /* Add the branch to the list. */
- assert(csr->start != -1);
- assert(csr->end != -1);
- assert(csr->restart != -1);
-
- /* allocate tree node */
-
- csn = NEW(critical_section_node_t);
-
- csn->start = code->entrypoint + csr->start;
- csn->end = code->entrypoint + csr->end;
- csn->restart = code->entrypoint + csr->restart;
-
- /* insert into the tree */
-
- critical_section_register(csn);
- }
-}
-#endif
-
-
-/* methodtree_comparator *******************************************************
-
- Comparator function used for the AVL tree of methods.
-
- ARGUMENTS:
- treenode....the node from the tree
- node........the node to compare to the tree-node
-
-*******************************************************************************/
-
-static s4 methodtree_comparator(const void *treenode, const void *node)
-{
- methodtree_element *mte;
- methodtree_element *mtepc;
-
- mte = (methodtree_element *) treenode;
- mtepc = (methodtree_element *) node;
-
- /* 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 */
-
-#ifdef __S390__
- /* On S390 addresses are 31 bit. Compare only 31 bits of value.
- */
-# define ADDR_MASK(a) ((a) & 0x7FFFFFFF)
-#else
-# define ADDR_MASK(a) (a)
-#endif
-
- if (ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->startpc) &&
- ADDR_MASK((long) mtepc->startpc) <= ADDR_MASK((long) mte->endpc) &&
- ADDR_MASK((long) mte->startpc) <= ADDR_MASK((long) mtepc->endpc) &&
- ADDR_MASK((long) mtepc->endpc) <= ADDR_MASK((long) mte->endpc)) {
- return 0;
-
- } else if (ADDR_MASK((long) mtepc->startpc) < ADDR_MASK((long) mte->startpc)) {
- return -1;
-
- } else {
- return 1;
- }
-
-# undef ADDR_MASK
-}
-
-
-/* codegen_insertmethod ********************************************************
-
- Insert the machine code range of a method into the AVL tree of methods.
-
-*******************************************************************************/
-
-void codegen_insertmethod(u1 *startpc, u1 *endpc)
-{
- methodtree_element *mte;
-
- /* allocate new method entry */
-
- mte = NEW(methodtree_element);
-
- mte->startpc = startpc;
- mte->endpc = endpc;
-
- /* this function does not return an error, but asserts for
- duplicate entries */
-
- avl_insert(methodtree, mte);
-}
-
-
-/* codegen_get_pv_from_pc ******************************************************
-
- Find the PV for the given PC by searching in the AVL tree of
- methods.
-
-*******************************************************************************/
-
-u1 *codegen_get_pv_from_pc(u1 *pc)
-{
- methodtree_element mtepc;
- methodtree_element *mte;
-
- /* allocation of the search structure on the stack is much faster */
-
- mtepc.startpc = pc;
- mtepc.endpc = pc;
-
- mte = avl_find(methodtree, &mtepc);
-
- if (mte == NULL) {
- /* No method was found. Let's dump a stacktrace. */
-
-#if defined(ENABLE_VMLOG)
- vmlog_cacao_signl("SIGSEGV");
-#endif
-
- log_println("We received a SIGSEGV and tried to handle it, but we were");
- log_println("unable to find a Java method at:");
- log_println("");
-#if SIZEOF_VOID_P == 8
- log_println("PC=0x%016lx", pc);
-#else
- log_println("PC=0x%08x", pc);
-#endif
- log_println("");
- assert(0);
- log_println("Dumping the current stacktrace:");
-
-#if defined(ENABLE_THREADS)
- /* XXX michi: This should be available even without threads! */
- threads_print_stacktrace();
-#endif
-
- vm_abort("Exiting...");
- }
-
- return mte->startpc;
-}
-
-
-/* codegen_get_pv_from_pc_nocheck **********************************************
-
- Find the PV for the given PC by searching in the AVL tree of
- methods. This method does not check the return value and is used
- by the profiler.
-
-*******************************************************************************/
-
-u1 *codegen_get_pv_from_pc_nocheck(u1 *pc)
-{
- methodtree_element mtepc;
- methodtree_element *mte;
-
- /* allocation of the search structure on the stack is much faster */
-
- mtepc.startpc = pc;
- mtepc.endpc = pc;
-
- mte = avl_find(methodtree, &mtepc);
-
- if (mte == NULL)
- return NULL;
- else
- return mte->startpc;
+ list_add_last(l, br);
}
#endif
s4 alignedmcodelen;
jumpref *jr;
- patchref_t *pr;
u1 *epoint;
s4 alignedlen;
/* patcher resolving */
- pr = list_first_unsynced(code->patchers);
- while (pr) {
- pr->mpc += (ptrint) epoint;
- pr->datap = (ptrint) (pr->disp + epoint);
- pr = list_next_unsynced(code->patchers, pr);
- }
+ patcher_resolve(jd);
#if defined(ENABLE_REPLACEMENT)
/* replacement point resolving */
}
#endif /* defined(ENABLE_REPLACEMENT) */
- /* add method into methodtree to find the entrypoint */
+ /* Insert method into methodtree to find the entrypoint. */
- codegen_insertmethod(code->entrypoint, code->entrypoint + mcodelen);
+ methodtree_insert(code->entrypoint, code->entrypoint + mcodelen);
#if defined(__I386__) || defined(__X86_64__) || defined(__XDSPCORE__) || defined(__M68K__) || defined(ENABLE_INTRP)
/* resolve data segment references */
dseg_resolve_datareferences(jd);
#endif
-#if defined(ENABLE_THREADS)
- /* create cirtical sections */
-
- codegen_critical_section_finish(jd);
-#endif
-
/* flush the instruction and data caches */
md_cacheflush(code->mcode, code->mcodelength);
codegendata *cd;
ptrint *d; /* pointer to data memory */
u1 *c; /* pointer to code memory */
- s4 dumpsize;
+ int32_t dumpmarker;
/* mark dump memory */
- dumpsize = dump_size();
+ DMARKER;
/* allocate required data structures */
/* release dump memory */
- dump_release(dumpsize);
+ DRELEASE;
/* return native stub code */
jitdata *jd;
codeinfo *code;
int skipparams;
- s4 dumpsize;
+ int32_t dumpmarker;
/* mark dump memory */
- dumpsize = dump_size();
+ DMARKER;
/* Create JIT data structure. */
code = jd->code;
+ /* Stubs are non-leaf methods. */
+
+ code_unflag_leafmethod(code);
+
/* setup code generation stuff */
codegen_setup(jd);
/* release memory */
- dump_release(dumpsize);
+ DRELEASE;
}
{
jitdata *jd;
codeinfo *code;
- s4 dumpsize;
methoddesc *md;
methoddesc *nmd;
int skipparams;
+ int32_t dumpmarker;
/* mark dump memory */
- dumpsize = dump_size();
+ DMARKER;
/* Create JIT data structure. */
code = jd->code;
+ /* Stubs are non-leaf methods. */
+
+ code_unflag_leafmethod(code);
+
/* set the flags for the current JIT run */
#if defined(ENABLE_PROFILING)
/* release memory */
- dump_release(dumpsize);
+ DRELEASE;
/* return native stub code */
void codegen_disassemble_stub(methodinfo *m, u1 *start, u1 *end)
{
printf("Stub code: ");
- if (m->class != NULL)
- utf_fprint_printable_ascii_classname(stdout, m->class->name);
+ if (m->clazz != NULL)
+ utf_fprint_printable_ascii_classname(stdout, m->clazz->name);
else
printf("NULL");
printf(".");
#endif
#if !defined(NDEBUG)
-# if defined(__ALPHA__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__) || defined(__S390__)
+# if defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
/* print the call-trace if necesarry */
/* BEFORE: filling the local reference table */
/* Return a wrapped classinfo for static methods. */
if (m->flags & ACC_STATIC)
- return LLNI_classinfo_wrap(m->class);
+ return (java_handle_t *) LLNI_classinfo_wrap(m->clazz);
else
return NULL;
}
/* get information from method header */
- code = *((codeinfo **) (pv + CodeinfoPointer));
- framesize = *((int32_t *) (pv + FrameSize));
+ code = code_get_codeinfo_for_pv(pv);
+
+ framesize = *((int32_t *) (pv + FrameSize));
+
assert(code);
/* get the methodinfo */
#elif defined(__I386__)
datasp = sp + framesize;
ret_regs = (uint64_t *) (sp + 2 * SIZEOF_VOID_P);
-#elif defined(__M68K__) || defined(__X86_64__)
+#elif defined(__M68K__)
+ datasp = sp + framesize;
+ ret_regs = (uint64_t *) (sp + 2 * 8);
+#elif defined(__X86_64__)
datasp = sp + framesize;
ret_regs = (uint64_t *) sp;
#elif defined(__POWERPC__)
#endif
#if !defined(NDEBUG)
-# if defined(__ALPHA__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__X86_64__) || defined(__S390__)
+# if defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__)
/* print the call-trace if necesarry */
/* AFTER: unwrapping the return value */
s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
{
-
-#if 0
- /* Do we have to generate a conditional move? Yes, then always
- return the temporary register. The real register is identified
- during the store. */
-
- if (opcode & ICMD_CONDITION_MASK)
- return tempregnum;
-#endif
-
if (!(v->flags & INMEMORY))
return v->vv.regoff;
if (compileverbose)
printf("...returning - phi lifetimes where joined\n");
#endif
- return;
+ continue;
}
if (s->type == -1) {
if (compileverbose)
printf("...returning - phi lifetimes where joined\n");
#endif
- return;
+ continue;
}
tmp_i.opc = 0;
#endif /* defined(ENABLE_SSA) */
+/* REMOVEME When we have exception handling in C. */
+
+void *md_asm_codegen_get_pv_from_pc(void *ra)
+{
+ return md_codegen_get_pv_from_pc(ra);
+}
+
/*
* These are local overrides for various environment variables in Emacs.