memory. All functions writing values into the data area return the offset
relative the begin of the code area (start of procedure).
- $Id: codegen-common.c 7940 2007-05-23 09:42:08Z michi $
-
*/
# include "codegen.h"
#endif
-#if defined(__ARM__)
-/* this is required for REG_SPLIT */
-# include "md-abi.h"
-#endif
+#include "md-abi.h"
#include "mm/memory.h"
#include "toolbox/logging.h"
#include "native/jni.h"
+#include "native/llni.h"
+#include "native/localref.h"
#include "native/native.h"
+#include "native/include/java_lang_Class.h"
+
#include "threads/threads-common.h"
#include "vm/builtin.h"
#include "vm/jit/emit-common.h"
#include "vm/jit/jit.h"
#include "vm/jit/md.h"
+#include "vm/jit/methodheader.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"
#if defined(ENABLE_INTRP)
#include "vm/jit/intrp/intrp.h"
#include <vmlog_cacao.h>
#endif
+#include "show.h"
/* in this tree we store all method addresses *********************************/
avl_insert(methodtree, mte);
#endif /* defined(ENABLE_JIT) */
+
}
+
}
bptr->branchrefs = NULL;
}
+ /* We need to clear all the patcher references from the codeinfo
+ since they all will be regenerated */
+
+ patcher_list_reset(code);
+
#if defined(ENABLE_REPLACEMENT)
code->rplpoints = NULL;
code->rplpointcount = 0;
cd->mcodeptr = cd->mcodebase + (cd->mcodeptr - oldmcodebase);
-#if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(__M68K__) || defined(ENABLE_INTRP)
+#if defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(__M68K__) || defined(ENABLE_INTRP) \
+ || defined(__SPARC_64__)
/* adjust the pointer to the last patcher position */
if (cd->lastmcodeptr != NULL)
if (opt_shownops)
PATCHER_NOPS;
-#if defined(ENABLE_JIT) && (defined(__I386__) || defined(__MIPS__) || defined(__X86_64__) || defined(__M68K__))
+#if defined(ENABLE_JIT) && (defined(__I386__) || defined(__M68K__) || defined(__MIPS__) \
+ || defined(__SPARC_64__) || defined(__X86_64__))
+
/* On some architectures the patcher stub call instruction might
be longer than the actual instruction generated. On this
architectures we store the last patcher call position and after
log_println("PC=0x%08x", pc);
#endif
log_println("");
+ assert(0);
log_println("Dumping the current stacktrace:");
#if defined(ENABLE_THREADS)
#endif
s4 alignedmcodelen;
jumpref *jr;
+ patchref_t *pr;
u1 *epoint;
s4 alignedlen;
*((ptrint *) ((ptrint) epoint + cd->linenumbertablesizepos)) = lrtlen;
}
+ /* 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);
+ }
+
#if defined(ENABLE_REPLACEMENT)
/* replacement point resolving */
{
int i;
rplpoint *rp;
- code->replacementstubs += (ptrint) epoint;
-
rp = code->rplpoints;
for (i=0; i<code->rplpointcount; ++i, ++rp) {
rp->pc = (u1*) ((ptrint) epoint + (ptrint) rp->pc);
Wrapper for codegen_emit_stub_builtin.
- Returns:
- Pointer to the entrypoint of the stub.
-
*******************************************************************************/
-void codegen_generate_stub_builtin(builtintable_entry *bte)
+void codegen_generate_stub_builtin(methodinfo *m, builtintable_entry *bte)
{
+#if defined(__ARM__) || defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__POWERPC__) || defined(__SPARC64__) || defined(__X86_64__)
jitdata *jd;
codeinfo *code;
s4 dumpsize;
jd = DNEW(jitdata);
- jd->m = NULL;
+ jd->m = m;
jd->cd = DNEW(codegendata);
jd->rd = NULL;
jd->flags = 0;
/* Allocate codeinfo memory from the heap as we need to keep them. */
- jd->code = code_codeinfo_new(NULL);
+ jd->code = code_codeinfo_new(m); /* XXX check allocation */
/* get required compiler data */
#if defined(ENABLE_JIT)
# if defined(ENABLE_INTRP)
- if (!opt_intrp)
+ if (!opt_intrp) {
+# endif
+ assert(bte->fp != NULL);
+ codegen_emit_stub_native(jd, bte->md, bte->fp);
+# if defined(ENABLE_INTRP)
+ }
# endif
- codegen_emit_stub_builtin(jd, bte);
#endif
/* reallocate the memory and finish the code generation */
size_stub_native += code->mcodelength;
#endif
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
+ /* disassemble native stub */
+
+ if (opt_DisassembleStubs) {
+ codegen_disassemble_stub(m,
+ (u1 *) (ptrint) code->entrypoint,
+ (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
+
+ /* show data segment */
+
+ if (opt_showddatasegment)
+ dseg_display(jd);
+ }
+#endif /* !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) */
+
/* release memory */
dump_release(dumpsize);
+#endif /* architecture list */
}
size_stub_native += code->mcodelength;
#endif
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
/* disassemble native stub */
- if (opt_shownativestub) {
-#if defined(ENABLE_DISASSEMBLER)
- codegen_disassemble_nativestub(m,
- (u1 *) (ptrint) code->entrypoint,
- (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
-#endif
+ if (opt_DisassembleStubs) {
+# if defined(ENABLE_DEBUG_FILTER)
+ if (m->filtermatches & SHOW_FILTER_FLAG_SHOW_METHOD)
+# endif
+ {
+ codegen_disassemble_stub(m,
+ (u1 *) (ptrint) code->entrypoint,
+ (u1 *) (ptrint) code->entrypoint + (code->mcodelength - jd->cd->dseglen));
- /* show data segment */
+ /* show data segment */
- if (opt_showddatasegment)
- dseg_display(jd);
+ if (opt_showddatasegment)
+ dseg_display(jd);
+ }
}
-#endif /* !defined(NDEBUG) */
+#endif /* !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) */
/* release memory */
/* codegen_disassemble_nativestub **********************************************
- Disassembles the generated native stub.
+ Disassembles the generated builtin or native stub.
*******************************************************************************/
#if defined(ENABLE_DISASSEMBLER)
-void codegen_disassemble_nativestub(methodinfo *m, u1 *start, u1 *end)
+void codegen_disassemble_stub(methodinfo *m, u1 *start, u1 *end)
{
- printf("Native stub: ");
- utf_fprint_printable_ascii_classname(stdout, m->class->name);
+ printf("Stub code: ");
+ if (m->class != NULL)
+ utf_fprint_printable_ascii_classname(stdout, m->class->name);
+ else
+ printf("NULL");
printf(".");
utf_fprint_printable_ascii(stdout, m->name);
utf_fprint_printable_ascii(stdout, m->descriptor);
- printf("\n\nLength: %d\n\n", (s4) (end - start));
+ printf("\nLength: %d\n\n", (s4) (end - start));
DISASSEMBLE(start, end);
}
#endif
-/* codegen_stub_builtin_enter **************************************************
-
- Prepares the stuff required for a builtin function call:
-
- - adds a stackframe info structure to the chain, for stacktraces
-
- The layout of the builtin stub stackframe should look like this:
-
- +---------------------------+ <- SP (of parent Java function)
- | return address |
- +---------------------------+
- | |
- | stackframe info structure |
- | |
- +---------------------------+
- | |
- | arguments (if any) |
- | |
- +---------------------------+ <- SP (native stub)
-
-*******************************************************************************/
-
-void codegen_stub_builtin_enter(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
-{
- stackframeinfo *sfi;
-
- /* get data structures from stack */
-
- sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
-
- /* add a stackframeinfo to the chain */
-
- stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
- /* set the native world flag */
-
- THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
-#endif
-}
-
-
-/* codegen_stub_builtin_exit ***************************************************
-
- Removes the stuff required for a builtin function call.
-
-*******************************************************************************/
-
-void codegen_stub_builtin_exit(u1 *datasp)
-{
- stackframeinfo *sfi;
- stackframeinfo **psfi;
-
- /* get data structures from stack */
-
- sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
-
- /* remove current stackframeinfo from chain */
-
- psfi = &STACKFRAMEINFO;
-
- *psfi = sfi->prev;
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
- /* clear the native world flag */
-
- THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
-#endif
-}
-
-
/* codegen_start_native_call ***************************************************
Prepares the stuff required for a native (JNI) function call:
The layout of the native stub stackframe should look like this:
- +---------------------------+ <- SP (of parent Java function)
+ +---------------------------+ <- java SP (of parent Java function)
| return address |
- +---------------------------+
+ +---------------------------+ <- data SP
| |
| stackframe info structure |
| |
| |
+---------------------------+
| |
+ | saved registers (if any) |
+ | |
+ +---------------------------+
+ | |
| arguments (if any) |
| |
- +---------------------------+ <- SP (native stub)
+ +---------------------------+ <- current SP (native stub)
*******************************************************************************/
-void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra)
+java_handle_t *codegen_start_native_call(u1 *currentsp, u1 *pv)
{
stackframeinfo *sfi;
localref_table *lrt;
+ codeinfo *code;
+ methodinfo *m;
+ int32_t framesize;
+
+ uint8_t *datasp;
+ uint8_t *javasp;
+ uint8_t *javara;
+ uint64_t *arg_regs;
+ uint64_t *arg_stack;
+
+ STATISTICS(count_calls_java_to_native++);
+
+ /* get information from method header */
+
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+ framesize = *((int32_t *) (pv + FrameSize));
+ assert(code);
+ assert(framesize > sizeof(stackframeinfo) + sizeof(localref_table));
+
+ /* get the methodinfo */
+
+ m = code->m;
+ assert(m);
+
+ /* calculate needed values */
+
+#if defined(__ALPHA__) || defined(__ARM__)
+ datasp = currentsp + framesize - SIZEOF_VOID_P;
+ javasp = currentsp + framesize;
+ javara = *((uint8_t **) datasp);
+ arg_regs = (uint64_t *) currentsp;
+ arg_stack = (uint64_t *) javasp;
+#elif defined(__MIPS__) || defined(__S390__)
+ /* MIPS and S390 always uses 8 bytes to store the RA */
+ datasp = currentsp + framesize - 8;
+ javasp = currentsp + framesize;
+ javara = *((uint8_t **) datasp);
+#elif defined(__I386__) || defined (__M68K__) || defined (__X86_64__)
+ datasp = currentsp + framesize;
+ javasp = currentsp + framesize + SIZEOF_VOID_P;
+ javara = *((uint8_t **) datasp);
+ arg_regs = (uint64_t *) currentsp;
+ arg_stack = (uint64_t *) javasp;
+#elif defined(__POWERPC__) || defined(__POWERPC64__)
+ datasp = currentsp + framesize;
+ javasp = currentsp + framesize;
+ javara = *((uint8_t **) (datasp + LA_LR_OFFSET));
+ arg_regs = (uint64_t *) (currentsp + LA_SIZE + 4 * SIZEOF_VOID_P);
+ arg_stack = (uint64_t *) javasp;
+#else
+ /* XXX is was unable to do this port for SPARC64, sorry. (-michi) */
+ /* XXX maybe we need to pass the RA as argument there */
+ vm_abort("codegen_start_native_call: unsupported architecture");
+#endif
+
+#if !defined(NDEBUG)
+# if defined(__POWERPC__) || defined (__X86_64__)
+ /* print the call-trace if necesarry */
+
+ if (opt_TraceJavaCalls)
+ trace_java_call_enter(m, arg_regs, arg_stack);
+# endif
+#endif
/* get data structures from stack */
lrt = (localref_table *) (datasp - sizeof(stackframeinfo) -
sizeof(localref_table));
- /* add a stackframeinfo to the chain */
-
- stacktrace_create_native_stackframeinfo(sfi, pv, sp, ra);
-
#if defined(ENABLE_JNI)
/* add current JNI local references table to this thread */
- lrt->capacity = LOCALREFTABLE_CAPACITY;
- lrt->used = 0;
- lrt->localframes = 1;
- lrt->prev = LOCALREFTABLE;
-
- /* clear the references array (memset is faster the a for-loop) */
+ localref_table_add(lrt);
+#endif
- MSET(lrt->refs, 0, java_objectheader*, LOCALREFTABLE_CAPACITY);
+#if defined(ENABLE_HANDLES)
+ /* place all references into the local reference table */
- LOCALREFTABLE = lrt;
+ localref_fill(m, arg_regs, arg_stack);
#endif
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
- /* set the native world flag */
+ /* add a stackframeinfo to the chain */
- THREADOBJECT->flags |= THREAD_FLAG_IN_NATIVE;
-#endif
+ stacktrace_create_native_stackframeinfo(sfi, pv, javasp, javara);
+
+ /* return a wrapped classinfo for static native methods */
+
+ if (m->flags & ACC_STATIC)
+ return LLNI_classinfo_wrap(m->class);
+ else
+ return NULL;
}
*******************************************************************************/
-java_objectheader *codegen_finish_native_call(u1 *datasp)
+java_object_t *codegen_finish_native_call(u1 *currentsp, u1 *pv)
{
- stackframeinfo *sfi;
- stackframeinfo **psfi;
-#if defined(ENABLE_JNI)
- localref_table *lrt;
- localref_table *plrt;
- s4 localframes;
+ stackframeinfo *sfi;
+ java_handle_t *e;
+ java_object_t *o;
+ codeinfo *code;
+ methodinfo *m;
+ int32_t framesize;
+
+ uint8_t *datasp;
+ uint64_t *ret_regs;
+
+ /* get information from method header */
+
+ code = *((codeinfo **) (pv + CodeinfoPointer));
+ framesize = *((int32_t *) (pv + FrameSize));
+ assert(code);
+
+ /* get the methodinfo */
+
+ m = code->m;
+ assert(m);
+
+ /* calculate needed values */
+
+#if defined(__ALPHA__) || defined(__ARM__)
+ datasp = currentsp + framesize - SIZEOF_VOID_P;
+ ret_regs = (uint64_t *) currentsp;
+#elif defined(__MIPS__) || defined(__S390__)
+ /* MIPS and S390 always uses 8 bytes to store the RA */
+ datasp = currentsp + framesize - 8;
+#elif defined(__I386__)
+ datasp = currentsp + framesize;
+ ret_regs = (uint64_t *) (currentsp + 2 * SIZEOF_VOID_P);
+#elif defined (__M68K__) || defined (__X86_64__)
+ datasp = currentsp + framesize;
+ ret_regs = (uint64_t *) currentsp;
+#elif defined(__POWERPC__) || defined(__POWERPC64__)
+ datasp = currentsp + framesize;
+ ret_regs = (uint64_t *) (currentsp + LA_SIZE + 2 * SIZEOF_VOID_P);
+#else
+ vm_abort("codegen_finish_native_call: unsupported architecture");
#endif
- java_objectheader *e;
- /* get data structures from stack */
- sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
- /* clear the native world flag */
+#if !defined(NDEBUG)
+# if defined(__POWERPC__) || defined (__X86_64__)
+ /* print the call-trace if necesarry */
- THREADOBJECT->flags &= ~THREAD_FLAG_IN_NATIVE;
+ if (opt_TraceJavaCalls)
+ trace_java_call_exit(m, ret_regs);
+# endif
#endif
- /* remove current stackframeinfo from chain */
-
- psfi = &STACKFRAMEINFO;
-
- *psfi = sfi->prev;
-
-#if defined(ENABLE_JNI)
- /* release JNI local references tables for this thread */
-
- lrt = LOCALREFTABLE;
-
- /* release all current local frames */
-
- for (localframes = lrt->localframes; localframes >= 1; localframes--) {
- /* get previous frame */
+ /* get data structures from stack */
- plrt = lrt->prev;
+ sfi = (stackframeinfo *) (datasp - sizeof(stackframeinfo));
- /* Clear all reference entries (only for tables allocated on
- the Java heap). */
+ /* remove current stackframeinfo from chain */
- if (localframes > 1)
- MSET(&lrt->refs[0], 0, java_objectheader*, lrt->capacity);
+ stacktrace_remove_stackframeinfo(sfi);
- lrt->prev = NULL;
+ /* XXX unfill lrt here!!! */
- /* set new local references table */
+ /* get and unwrap the exception */
+ /* ATTENTION: do the this _after_ the stackframeinfo was
+ removed but _before_ the localref_table gets removed! */
- lrt = plrt;
- }
+ e = exceptions_get_and_clear_exception();
+ o = LLNI_UNWRAP(e);
- /* now store the previous local frames in the thread structure */
+#if defined(ENABLE_JNI)
+ /* release JNI local references table for this thread */
- LOCALREFTABLE = lrt;
+ localref_frame_pop_all();
+ localref_table_remove();
#endif
- /* get the exception and return it */
-
- e = exceptions_get_and_clear_exception();
-
- return e;
+ return o;
}
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)
-
*******************************************************************************/
s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum)
return tempregnum;
#endif
- if (!(v->flags & INMEMORY)) {
-#if defined(__ARM__) && defined(__ARMEL__)
- if (IS_2_WORD_TYPE(v->type) && (GET_HIGH_REG(v->vv.regoff) == REG_SPLIT))
- return PACK_REGS(GET_LOW_REG(v->vv.regoff),
- GET_HIGH_REG(tempregnum));
-#endif
-#if defined(__ARM__) && defined(__ARMEB__)
- if (IS_2_WORD_TYPE(v->type) && (GET_LOW_REG(v->vv.regoff) == REG_SPLIT))
- return PACK_REGS(GET_LOW_REG(tempregnum),
- GET_HIGH_REG(v->vv.regoff));
-#endif
+ if (!(v->flags & INMEMORY))
return v->vv.regoff;
- }
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- count_spills_read++;
-#endif
return tempregnum;
}
+
/* codegen_reg_of_dst **********************************************************
This function determines a register, to which the result of an
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 dst.var for LOW_REG and the tempregnum for HIGH_REG in such
- cases. (michi 2005/07/24)
-
*******************************************************************************/
s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum)