X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fcodegen-common.cpp;h=9b1dad8cdd3d5b9d443a96adca228a0d7e14a0a5;hb=67702ed5605e84f33724aeee9ccf5f82ea774084;hp=df864923a91eaecb5a5c00f158e48ffd0b830b46;hpb=7fbc0badfc433e0113f7044baa760916b987500a;p=cacao.git diff --git a/src/vm/jit/codegen-common.cpp b/src/vm/jit/codegen-common.cpp index df864923a..9b1dad8cd 100644 --- a/src/vm/jit/codegen-common.cpp +++ b/src/vm/jit/codegen-common.cpp @@ -1,7 +1,8 @@ /* src/vm/jit/codegen-common.cpp - architecture independent code generator stuff - Copyright (C) 1996-2005, 2006, 2007, 2008 + Copyright (C) 1996-2005, 2006, 2007, 2008, 2009, 2010 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -51,27 +52,25 @@ #include "md.h" #include "md-abi.h" -#include "mm/memory.h" +#include "mm/memory.hpp" #include "toolbox/avl.h" #include "toolbox/list.hpp" -#include "toolbox/logging.h" +#include "toolbox/logging.hpp" #include "native/llni.h" -#include "native/localref.h" -#include "native/native.h" +#include "native/localref.hpp" +#include "native/native.hpp" #include "threads/thread.hpp" #include "vm/jit/builtin.hpp" #include "vm/exceptions.hpp" -#include "vm/method.h" +#include "vm/method.hpp" #include "vm/options.h" +#include "vm/statistics.h" #include "vm/string.hpp" -# include "vm/statistics.h" - - #include "vm/jit/abi.h" #include "vm/jit/asmpart.h" #include "vm/jit/code.hpp" @@ -89,12 +88,18 @@ #include "vm/jit/methodtree.h" #include "vm/jit/patcher-common.hpp" #include "vm/jit/replace.hpp" +#include "vm/jit/show.hpp" +#include "vm/jit/stacktrace.hpp" +#include "vm/jit/trace.hpp" + +#include "vm/jit/optimizing/profile.hpp" + #if defined(ENABLE_SSA) # include "vm/jit/optimizing/lsra.h" # include "vm/jit/optimizing/ssa.h" +#elif defined(ENABLE_LSRA) +# include "vm/jit/allocator/lsra.h" #endif -#include "vm/jit/stacktrace.hpp" -#include "vm/jit/trace.hpp" #if defined(ENABLE_INTRP) #include "vm/jit/intrp/intrp.h" @@ -104,8 +109,6 @@ #include #endif -#include "show.hpp" - /* codegen_init **************************************************************** @@ -136,7 +139,13 @@ void codegen_setup(jitdata *jd) /* initialize members */ - cd->flags = 0; + // Set flags as requested. + if (opt_AlwaysEmitLongBranches) { + cd->flags = CODEGENDATA_FLAG_LONGBRANCHES; + } + else { + cd->flags = 0; + } cd->mcodebase = (u1*) DumpMemory::allocate(MCODEINITSIZE); cd->mcodeend = cd->mcodebase + MCODEINITSIZE; @@ -282,7 +291,7 @@ bool codegen_generate(jitdata *jd) return false; } else { - vm_abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags); + os::abort("codegen_generate: unknown error occurred during codegen_emit: flags=%x\n", cd->flags); } #if !defined(NDEBUG) @@ -538,21 +547,20 @@ void codegen_set_replacement_point(codegendata *cd) void codegen_finish(jitdata *jd) { - codeinfo *code; - codegendata *cd; - s4 mcodelen; + s4 mcodelen; #if defined(ENABLE_INTRP) - s4 ncodelen; + s4 ncodelen; #endif - s4 alignedmcodelen; - jumpref *jr; - u1 *epoint; - s4 alignedlen; + s4 alignedmcodelen; + jumpref *jr; + u1 *epoint; + s4 alignedlen; - /* get required compiler data */ + /* Get required compiler data. */ - code = jd->code; - cd = jd->cd; + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; /* prevent compiler warning */ @@ -635,6 +643,16 @@ void codegen_finish(jitdata *jd) } #endif + /* Fill runtime information about generated code. */ + + code->stackframesize = cd->stackframesize; + code->synchronizedoffset = rd->memuse * 8; + code->savedintcount = INT_SAV_CNT - rd->savintreguse; + code->savedfltcount = FLT_SAV_CNT - rd->savfltreguse; +#if defined(HAS_ADDRESS_REGISTER_FILE) + code->savedadrcount = ADR_SAV_CNT - rd->savadrreguse; +#endif + /* Create the exception table. */ exceptiontable_create(jd); @@ -717,6 +735,7 @@ java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) { stackframeinfo_t *sfi; localref_table *lrt; + codeinfo *code; methodinfo *m; int32_t framesize; @@ -727,16 +746,17 @@ java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) STATISTICS(count_calls_java_to_native++); - /* Get the methodinfo. */ + // Get information from method header. + code = code_get_codeinfo_for_pv(pv); + assert(code != NULL); - m = code_get_methodinfo_for_pv(pv); + framesize = md_stacktrace_get_framesize(code); + assert(framesize >= (int32_t) (sizeof(stackframeinfo_t) + sizeof(localref_table))); + // Get the methodinfo. + m = code_get_methodinfo_for_pv(pv); assert(m); - framesize = *((int32_t *) (pv + FrameSize)); - - assert(framesize >= (int32_t) (sizeof(stackframeinfo_t) + sizeof(localref_table))); - /* calculate needed values */ #if defined(__ALPHA__) || defined(__ARM__) @@ -748,6 +768,12 @@ java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) /* MIPS always uses 8 bytes to store the RA */ datasp = sp + framesize - 8; javasp = sp + framesize; +# if SIZEOF_VOID_P == 8 + arg_regs = (uint64_t *) sp; +# else + arg_regs = (uint64_t *) (sp + 5 * 8); +# endif + arg_stack = (uint64_t *) javasp; #elif defined(__S390__) datasp = sp + framesize - 8; javasp = sp + framesize; @@ -771,7 +797,7 @@ java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) #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"); + os::abort("codegen_start_native_call: unsupported architecture"); #endif /* get data structures from stack */ @@ -787,11 +813,11 @@ java_handle_t *codegen_start_native_call(u1 *sp, u1 *pv) #endif #if !defined(NDEBUG) -# if defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) +# if defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) /* print the call-trace if necesarry */ /* BEFORE: filling the local reference table */ - if (opt_TraceJavaCalls) + if (opt_TraceJavaCalls || opt_TraceBuiltinCalls) trace_java_call_enter(m, arg_regs, arg_stack); # endif #endif @@ -838,18 +864,15 @@ java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) uint8_t *datasp; uint64_t *ret_regs; - /* get information from method header */ - + // Get information from method header. code = code_get_codeinfo_for_pv(pv); + assert(code != NULL); - framesize = *((int32_t *) (pv + FrameSize)); - - assert(code); - - /* get the methodinfo */ + framesize = md_stacktrace_get_framesize(code); + // Get the methodinfo. m = code->m; - assert(m); + assert(m != NULL); /* calculate needed values */ @@ -859,6 +882,11 @@ java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) #elif defined(__MIPS__) /* MIPS always uses 8 bytes to store the RA */ datasp = sp + framesize - 8; +# if SIZEOF_VOID_P == 8 + ret_regs = (uint64_t *) sp; +# else + ret_regs = (uint64_t *) (sp + 1 * 8); +# endif #elif defined(__S390__) datasp = sp + framesize - 8; ret_regs = (uint64_t *) (sp + 96); @@ -878,7 +906,7 @@ java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) datasp = sp + framesize; ret_regs = (uint64_t *) (sp + PA_SIZE + LA_SIZE + 2 * SIZEOF_VOID_P); #else - vm_abort("codegen_finish_native_call: unsupported architecture"); + os::abort("codegen_finish_native_call: unsupported architecture"); #endif /* get data structures from stack */ @@ -912,11 +940,11 @@ java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) #endif #if !defined(NDEBUG) -# if defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) +# if defined(__ALPHA__) || defined(__I386__) || defined(__M68K__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__POWERPC64__) || defined(__S390__) || defined(__X86_64__) /* print the call-trace if necesarry */ /* AFTER: unwrapping the return value */ - if (opt_TraceJavaCalls) + if (opt_TraceJavaCalls || opt_TraceBuiltinCalls) trace_java_call_exit(m, ret_regs); # endif #endif @@ -933,7 +961,7 @@ java_object_t *codegen_finish_native_call(u1 *sp, u1 *pv) 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. - + *******************************************************************************/ s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum) @@ -953,7 +981,7 @@ s4 codegen_reg_of_var(u2 opcode, varinfo *v, s4 tempregnum) register, this register will be returned. Otherwise (when it is spilled) this function returns tempregnum. If not already done, regoff and flags are set in the stack location. - + *******************************************************************************/ s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum) @@ -962,6 +990,1300 @@ s4 codegen_reg_of_dst(jitdata *jd, instruction *iptr, s4 tempregnum) } +/** + * Generates machine code. + */ +bool codegen_emit(jitdata *jd) +{ + varinfo* var; + builtintable_entry* bte = 0; + methoddesc* md; + int32_t s1, s2, /*s3,*/ d; + int32_t fieldtype; + int32_t disp; + int i; + + // Get required compiler data. + //methodinfo* m = jd->m; + codeinfo* code = jd->code; + codegendata* cd = jd->cd; + registerdata* rd = jd->rd; +#if defined(ENABLE_SSA) + lsradata* ls = jd->ls; + bool last_cmd_was_goto = false; +#endif + + // Space to save used callee saved registers. + int32_t savedregs_num = 0; + savedregs_num += (INT_SAV_CNT - rd->savintreguse); + savedregs_num += (FLT_SAV_CNT - rd->savfltreguse); +#ifdef HAS_ADDRESS_REGISTER_FILE + savedregs_num += (ADR_SAV_CNT - rd->savadrreguse); +#endif + + // Calculate size of stackframe. + cd->stackframesize = rd->memuse + savedregs_num; + + // Space to save the return address. +#if STACKFRAME_RA_TOP_OF_FRAME +# if STACKFRAME_LEAFMETHODS_RA_REGISTER + if (!code_is_leafmethod(code)) +# endif + cd->stackframesize += 1; +#endif + + // Space to save argument of monitor_enter. +#if defined(ENABLE_THREADS) + if (checksync && code_is_synchronized(code)) +# if STACKFRAME_SYNC_NEEDS_TWO_SLOTS + /* On some architectures the stack position for the argument can + not be shared with place to save the return register values to + survive monitor_exit since both values reside in the same register. */ + cd->stackframesize += 2; +# else + cd->stackframesize += 1; +# endif +#endif + + // Keep stack of non-leaf functions 16-byte aligned for calls into + // native code. + if (!code_is_leafmethod(code) || JITDATA_HAS_FLAG_VERBOSECALL(jd)) +#if STACKFRMAE_RA_BETWEEN_FRAMES + ALIGN_ODD(cd->stackframesize); +#else + ALIGN_EVEN(cd->stackframesize); +#endif + +#if defined(SPECIALMEMUSE) + // On architectures having a linkage area, we can get rid of the whole + // stackframe in leaf functions without saved registers. + if (code_is_leafmethod(code) && (cd->stackframesize == LA_SIZE_IN_POINTERS)) + cd->stackframesize = 0; +#endif + + /* + * SECTION 1: Method header generation. + */ + + // The method header was reduced to the bare minimum of one pointer + // to the codeinfo structure, which in turn contains all runtime + // information. However this section together with the methodheader.h + // file will be kept alive for historical reasons. It might come in + // handy at some point. + + (void) dseg_add_unique_address(cd, code); ///< CodeinfoPointer + + // XXX, REMOVEME: We still need it for exception handling in assembler. + // XXX ARM, M68K: (void) dseg_add_unique_s4(cd, cd->stackframesize); +#if defined(__I386__) + int align_off = (cd->stackframesize != 0) ? 4 : 0; + (void) dseg_add_unique_s4(cd, cd->stackframesize * 8 + align_off); /* FrameSize */ +#else + (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */ +#endif + // XXX M68K: We use the IntSave as a split field for the adr now + // (void) dseg_add_unique_s4(cd, (ADR_SAV_CNT - rd->savadrreguse) << 16 | (INT_SAV_CNT - rd->savintreguse)); /* IntSave */ + (void) dseg_add_unique_s4(cd, code_is_leafmethod(code) ? 1 : 0); + (void) dseg_add_unique_s4(cd, INT_SAV_CNT - rd->savintreguse); /* IntSave */ + (void) dseg_add_unique_s4(cd, FLT_SAV_CNT - rd->savfltreguse); /* FltSave */ + + /* + * SECTION 2: Method prolog generation. + */ + +#if defined(ENABLE_PROFILING) + // Generate method profiling code. + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { + + // Count method frequency. + emit_profile_method(cd, code); + + // Start CPU cycle counting. + emit_profile_cycle_start(cd, code); + } +#endif + + // Emit code for the method prolog. + codegen_emit_prolog(jd); + +#if defined(ENABLE_THREADS) + // Emit code to call monitorenter function. + if (checksync && code_is_synchronized(code)) + emit_monitor_enter(jd, rd->memuse * 8); +#endif + +#if !defined(NDEBUG) + // Call trace function. + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + emit_verbosecall_enter(jd); +#endif + +#if defined(ENABLE_SSA) + // With SSA the header is basicblock 0, insert phi moves if necessary. + if (ls != NULL) + codegen_emit_phi_moves(jd, ls->basicblocks[0]); +#endif + + // Create replacement points. + REPLACEMENT_POINTS_INIT(cd, jd); + + /* + * SECTION 3: ICMD code generation. + */ + + // Walk through all basic blocks. + for (basicblock* bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) { + + bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase); + + // Is this basic block reached? + if (bptr->flags < BBREACHED) + continue; + + // Branch resolving. + codegen_resolve_branchrefs(cd, bptr); + + // Handle replacement points. + REPLACEMENT_POINT_BLOCK_START(cd, bptr); + +#if defined(ENABLE_REPLACEMENT) && defined(__I386__) + // Generate countdown trap code. + methodinfo* m = jd->m; + if (bptr->bitflags & BBFLAG_REPLACEMENT) { + if (cd->replacementpoint[-1].flags & RPLPOINT_FLAG_COUNTDOWN) { + MCODECHECK(32); + emit_trap_countdown(cd, &(m->hitcountdown)); + } + } +#endif + +#if defined(ENABLE_PROFILING) + // Generate basicblock profiling code. + if (JITDATA_HAS_FLAG_INSTRUMENT(jd)) { + + // Count basicblock frequency. + emit_profile_basicblock(cd, code, bptr); + + // If this is an exception handler, start profiling again. + if (bptr->type == BBTYPE_EXH) + emit_profile_cycle_start(cd, code); + } +#endif + + // Copy interface registers to their destination. + int32_t indepth = bptr->indepth; + // XXX Check if this is true for all archs. + MCODECHECK(64+indepth); // All + MCODECHECK(128+indepth); // PPC64 + MCODECHECK(512); // I386, X86_64, S390 +#if defined(ENABLE_SSA) + // XXX Check if this is correct and add a propper comment! + if (ls != NULL) { + last_cmd_was_goto = false; + } else { +#elif defined(ENABLE_LSRA) + if (opt_lsra) { + while (indepth > 0) { + indepth--; + var = VAR(bptr->invars[indepth]); + if ((indepth == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { + if (!IS_INMEMORY(src->flags)) + d = var->vv.regoff; + else + d = REG_ITMP1_XPTR; + // XXX M68K: Actually this is M_ADRMOVE(REG_ATMP1_XPTR, d); + // XXX Sparc64: Here we use REG_ITMP2_XPTR, fix this! + // XXX S390: Here we use REG_ITMP3_XPTR, fix this! + emit_imove(cd, REG_ITMP1_XPTR, d); + emit_store(jd, NULL, var, d); + } + } + } else { +#endif + while (indepth > 0) { + indepth--; + var = VAR(bptr->invars[indepth]); + if ((indepth == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) { + d = codegen_reg_of_var(0, var, REG_ITMP1_XPTR); + // XXX M68K: Actually this is M_ADRMOVE(REG_ATMP1_XPTR, d); + // XXX Sparc64: Here we use REG_ITMP2_XPTR, fix this! + // XXX S390: Here we use REG_ITMP3_XPTR, fix this! + emit_imove(cd, REG_ITMP1_XPTR, d); + emit_store(jd, NULL, var, d); + } + else { + assert((var->flags & INOUT)); + } + } +#if defined(ENABLE_SSA) || defined(ENABLE_LSRA) + } +#endif + + // Walk through all instructions. + int32_t len = bptr->icount; + uint16_t currentline = 0; + for (instruction* iptr = bptr->iinstr; len > 0; len--, iptr++) { + + // Add line number. + if (iptr->line != currentline) { + linenumbertable_list_entry_add(cd, iptr->line); + currentline = iptr->line; + } + + // An instruction usually needs < 64 words. + // XXX Check if this is true for all archs. + MCODECHECK(64); // All + MCODECHECK(128); // PPC64 + MCODECHECK(1024); // I386, X86_64, M68K, S390 /* 1kB should be enough */ + + // The big switch. + switch (iptr->opc) { + + case ICMD_NOP: /* ... ==> ... */ + case ICMD_POP: /* ..., value ==> ... */ + case ICMD_POP2: /* ..., value, value ==> ... */ + break; + + case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */ + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + emit_nullpointer_check(cd, iptr, s1); + break; + + case ICMD_BREAKPOINT: /* ... ==> ... */ + /* sx.val.anyptr = Breakpoint */ + + patcher_add_patch_ref(jd, PATCHER_breakpoint, iptr->sx.val.anyptr, 0); + PATCHER_NOPS; + break; + +#if defined(ENABLE_SSA) + case ICMD_GETEXCEPTION: + + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + emit_imove(cd, REG_ITMP1, d); + emit_store_dst(jd, iptr, d); + break; +#endif + + /* inline operations **********************************************/ + + case ICMD_INLINE_START: + + REPLACEMENT_POINT_INLINE_START(cd, iptr); + break; + + case ICMD_INLINE_BODY: + + REPLACEMENT_POINT_INLINE_BODY(cd, iptr); + linenumbertable_list_entry_add_inline_start(cd, iptr); + linenumbertable_list_entry_add(cd, iptr->line); + break; + + case ICMD_INLINE_END: + + linenumbertable_list_entry_add_inline_end(cd, iptr); + linenumbertable_list_entry_add(cd, iptr->line); + break; + + + /* constant operations ********************************************/ + + case ICMD_ICONST: /* ... ==> ..., constant */ + + d = codegen_reg_of_dst(jd, iptr, REG_ITMP1); + ICONST(d, iptr->sx.val.i); + emit_store_dst(jd, iptr, d); + break; + + case ICMD_LCONST: /* ... ==> ..., constant */ + + d = codegen_reg_of_dst(jd, iptr, REG_LTMP12); + LCONST(d, iptr->sx.val.l); + emit_store_dst(jd, iptr, d); + break; + + + /* load/store/copy/move operations ********************************/ + + case ICMD_COPY: + case ICMD_MOVE: + case ICMD_ILOAD: /* ... ==> ..., content of local variable */ + case ICMD_LLOAD: /* s1 = local variable */ + case ICMD_FLOAD: + case ICMD_DLOAD: + case ICMD_ALOAD: + case ICMD_ISTORE: /* ..., value ==> ... */ + case ICMD_LSTORE: + case ICMD_FSTORE: + case ICMD_DSTORE: + + emit_copy(jd, iptr); + break; + + case ICMD_ASTORE: + + if (!(iptr->flags.bits & INS_FLAG_RETADDR)) + emit_copy(jd, iptr); + break; + + + /* integer operations *********************************************/ + + case ICMD_FCONST: /* ... ==> ..., constant */ + case ICMD_DCONST: /* ... ==> ..., constant */ + case ICMD_ACONST: /* ... ==> ..., constant */ + case ICMD_INEG: /* ..., value ==> ..., - value */ + case ICMD_LNEG: /* ..., value ==> ..., - value */ + case ICMD_I2L: /* ..., value ==> ..., value */ + case ICMD_L2I: /* ..., value ==> ..., value */ + case ICMD_INT2BYTE: /* ..., value ==> ..., value */ + case ICMD_INT2CHAR: /* ..., value ==> ..., value */ + case ICMD_INT2SHORT: /* ..., value ==> ..., value */ + case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + case ICMD_IINC: + case ICMD_IADDCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.i = constant */ + case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.l = constant */ + case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */ + /* sx.val.i = constant */ + case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */ + /* sx.val.l = constant */ + case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */ + /* sx.val.i = constant */ + case ICMD_IMULPOW2: /* ..., value ==> ..., value * (2 ^ constant) */ + /* sx.val.i = constant */ + case ICMD_LMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + case ICMD_LMULCONST: /* ..., value ==> ..., value * constant */ + /* sx.val.l = constant */ + case ICMD_LMULPOW2: /* ..., value ==> ..., value * (2 ^ constant) */ + /* sx.val.l = constant */ + case ICMD_IDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + case ICMD_IREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + case ICMD_IDIVPOW2: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + case ICMD_IREMPOW2: /* ..., value ==> ..., value % constant */ + /* sx.val.i = constant */ + case ICMD_LDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + case ICMD_LREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + case ICMD_LDIVPOW2: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + case ICMD_LREMPOW2: /* ..., value ==> ..., value % constant */ + /* sx.val.l = constant */ + case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */ + /* sx.val.i = constant */ + case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* sx.val.i = constant */ + case ICMD_LSHL: /* ..., val1, val2 ==> ..., val1 << val2 */ + case ICMD_LSHLCONST: /* ..., value ==> ..., value << constant */ + /* sx.val.i = constant */ + case ICMD_LSHR: /* ..., val1, val2 ==> ..., val1 >> val2 */ + case ICMD_LSHRCONST: /* ..., value ==> ..., value >> constant */ + /* sx.val.i = constant */ + case ICMD_LUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */ + case ICMD_LUSHRCONST: /* ..., value ==> ..., value >>> constant */ + /* sx.val.l = constant */ + case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */ + /* sx.val.i = constant */ + case ICMD_LAND: /* ..., val1, val2 ==> ..., val1 & val2 */ + case ICMD_LANDCONST: /* ..., value ==> ..., value & constant */ + /* sx.val.l = constant */ + case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + case ICMD_IORCONST: /* ..., value ==> ..., value | constant */ + /* sx.val.i = constant */ + case ICMD_LOR: /* ..., val1, val2 ==> ..., val1 | val2 */ + case ICMD_LORCONST: /* ..., value ==> ..., value | constant */ + /* sx.val.l = constant */ + case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + case ICMD_IXORCONST: /* ..., value ==> ..., value ^ constant */ + /* sx.val.i = constant */ + case ICMD_LXOR: /* ..., val1, val2 ==> ..., val1 ^ val2 */ + case ICMD_LXORCONST: /* ..., value ==> ..., value ^ constant */ + /* sx.val.l = constant */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + + /* floating operations ********************************************/ + +#if !defined(ENABLE_SOFTFLOAT) + case ICMD_FNEG: /* ..., value ==> ..., - value */ + case ICMD_DNEG: + case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */ + case ICMD_DADD: + case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */ + case ICMD_DSUB: + case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */ + case ICMD_DMUL: + case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */ + case ICMD_DDIV: + case ICMD_FREM: /* ..., val1, val2 ==> ..., val1 % val2 */ + case ICMD_DREM: + case ICMD_I2F: /* ..., value ==> ..., (float) value */ + case ICMD_I2D: /* ..., value ==> ..., (double) value */ + case ICMD_L2F: /* ..., value ==> ..., (float) value */ + case ICMD_L2D: /* ..., value ==> ..., (double) value */ + case ICMD_F2I: /* ..., value ==> ..., (int) value */ + case ICMD_D2I: + case ICMD_F2L: /* ..., value ==> ..., (long) value */ + case ICMD_D2L: + case ICMD_F2D: /* ..., value ==> ..., (double) value */ + case ICMD_D2F: /* ..., value ==> ..., (float) value */ + case ICMD_FCMPL: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */ + case ICMD_DCMPL: /* == => 0, < => 1, > => -1 */ + case ICMD_FCMPG: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */ + case ICMD_DCMPG: /* == => 0, < => 1, > => -1 */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; +#endif /* !defined(ENABLE_SOFTFLOAT) */ + + + /* memory operations **********************************************/ + + case ICMD_ARRAYLENGTH:/* ..., arrayref ==> ..., length */ + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + /* implicit null-pointer check */ + // XXX PPC64: Here we had an explicit null-pointer check + // which I think was obsolete, please confirm. Otherwise: + // emit_nullpointer_check(cd, iptr, s1); + M_ILD(d, s1, OFFSET(java_array_t, size)); + emit_store_dst(jd, iptr, d); + break; + + case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */ + case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */ + case ICMD_BASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_CASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_SASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_IASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_LASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_FASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_DASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_AASTORECONST: /* ..., arrayref, index ==> ... */ + case ICMD_GETFIELD: /* ... ==> ..., value */ + case ICMD_PUTFIELD: /* ..., value ==> ... */ + case ICMD_PUTFIELDCONST: /* ..., objectref ==> ... */ + /* val = value (in current instruction) */ + case ICMD_PUTSTATICCONST: /* ... ==> ... */ + /* val = value (in current instruction) */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + case ICMD_GETSTATIC: /* ... ==> ..., value */ + +#if defined(__I386__) + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; +#else + { + fieldinfo* fi; + patchref_t* pr; + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + unresolved_field* uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = dseg_add_unique_address(cd, 0); + + pr = patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); + + fi = NULL; /* Silence compiler warning */ + } + else { + fi = iptr->sx.s23.s3.fmiref->p.field; + fieldtype = fi->type; + disp = dseg_add_address(cd, fi->value); + + if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) { + PROFILE_CYCLE_STOP; + patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); + PROFILE_CYCLE_START; + } + + pr = NULL; /* Silence compiler warning */ + } + +#if defined(USES_PATCHABLE_MEMORY_BARRIER) + codegen_emit_patchable_barrier(iptr, cd, pr, fi); +#endif + + // XXX X86_64: Here We had this: + /* This approach is much faster than moving the field + address inline into a register. */ + + M_ALD_DSEG(REG_ITMP1, disp); + + switch (fieldtype) { + case TYPE_ADR: + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_ALD(d, REG_ITMP1, 0); + break; + case TYPE_INT: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#endif + d = codegen_reg_of_dst(jd, iptr, REG_ITMP2); + M_ILD(d, REG_ITMP1, 0); + break; + case TYPE_LNG: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_DBL: +#endif + d = codegen_reg_of_dst(jd, iptr, REG_LTMP23); + M_LLD(d, REG_ITMP1, 0); + break; +#if !defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_FLD(d, REG_ITMP1, 0); + break; + case TYPE_DBL: + d = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_DLD(d, REG_ITMP1, 0); + break; +#endif + default: + // Silence compiler warning. + d = 0; + } + emit_store_dst(jd, iptr, d); + break; + } +#endif + + case ICMD_PUTSTATIC: /* ..., value ==> ... */ + +#if defined(__I386__) + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; +#else + { + fieldinfo* fi; + patchref_t* pr; + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + unresolved_field* uf = iptr->sx.s23.s3.uf; + fieldtype = uf->fieldref->parseddesc.fd->type; + disp = dseg_add_unique_address(cd, 0); + + pr = patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, disp); + + fi = NULL; /* Silence compiler warning */ + } + else { + fi = iptr->sx.s23.s3.fmiref->p.field; + fieldtype = fi->type; + disp = dseg_add_address(cd, fi->value); + + if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->clazz)) { + PROFILE_CYCLE_STOP; + patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->clazz, 0); + PROFILE_CYCLE_START; + } + + pr = NULL; /* Silence compiler warning */ + } + + // XXX X86_64: Here We had this: + /* This approach is much faster than moving the field + address inline into a register. */ + + M_ALD_DSEG(REG_ITMP1, disp); + + switch (fieldtype) { + case TYPE_ADR: + s1 = emit_load_s1(jd, iptr, REG_ITMP2); + M_AST(s1, REG_ITMP1, 0); + break; + case TYPE_INT: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#endif + s1 = emit_load_s1(jd, iptr, REG_ITMP2); + M_IST(s1, REG_ITMP1, 0); + break; + case TYPE_LNG: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_DBL: +#endif + s1 = emit_load_s1(jd, iptr, REG_LTMP23); + M_LST(s1, REG_ITMP1, 0); + break; +#if !defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: + s1 = emit_load_s1(jd, iptr, REG_FTMP2); + M_FST(s1, REG_ITMP1, 0); + break; + case TYPE_DBL: + s1 = emit_load_s1(jd, iptr, REG_FTMP2); + M_DST(s1, REG_ITMP1, 0); + break; +#endif + } +#if defined(USES_PATCHABLE_MEMORY_BARRIER) + codegen_emit_patchable_barrier(iptr, cd, pr, fi); +#endif + break; + } +#endif + + /* branch operations **********************************************/ + + case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */ + + // We might leave this method, stop profiling. + PROFILE_CYCLE_STOP; + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + // XXX M68K: Actually this is M_ADRMOVE(s1, REG_ATMP1_XPTR); + // XXX Sparc64: We use REG_ITMP2_XPTR here, fix me! + emit_imove(cd, s1, REG_ITMP1_XPTR); + +#ifdef ENABLE_VERIFIER + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + unresolved_class *uc = iptr->sx.s23.s2.uc; + patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); + } +#endif /* ENABLE_VERIFIER */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + ALIGNCODENOP; + break; + + case ICMD_GOTO: /* ... ==> ... */ + case ICMD_RET: /* ... ==> ... */ + +#if defined(ENABLE_SSA) + // In case of a goto, phimoves have to be inserted + // before the jump. + if (ls != NULL) { + last_cmd_was_goto = true; + codegen_emit_phi_moves(jd, bptr); + } +#endif + emit_br(cd, iptr->dst.block); + ALIGNCODENOP; + break; + + case ICMD_JSR: /* ... ==> ... */ + + emit_br(cd, iptr->sx.s23.s3.jsrtarget.block); + ALIGNCODENOP; + break; + + case ICMD_IFNULL: /* ..., value ==> ... */ + case ICMD_IFNONNULL: + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); +#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + emit_bccz(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, s1, BRANCH_OPT_NONE); +#elif SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + M_TEST(s1); + emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, BRANCH_OPT_NONE); +#else +# error Unable to generate code for this configuration! +#endif + break; + + case ICMD_IFEQ: /* ..., value ==> ... */ + case ICMD_IFNE: + case ICMD_IFLT: + case ICMD_IFLE: + case ICMD_IFGT: + case ICMD_IFGE: + + // XXX Sparc64: int compares must not branch on the + // register directly. Reason is, that register content is + // not 32-bit clean. Fix this! + +#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + if (iptr->sx.val.i == 0) { + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + emit_bccz(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, s1, BRANCH_OPT_NONE); + } else { + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + } +#elif SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + emit_icmp_imm(cd, s1, iptr->sx.val.i); + emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE); +#else +# error Unable to generate code for this configuration! +#endif + break; + + case ICMD_IF_LEQ: /* ..., value ==> ... */ + case ICMD_IF_LNE: + case ICMD_IF_LLT: + case ICMD_IF_LGE: + case ICMD_IF_LGT: + case ICMD_IF_LLE: + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + case ICMD_IF_ACMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_ACMPNE: /* op1 = target JavaVM pc */ + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); +#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS + switch (iptr->opc) { + case ICMD_IF_ACMPEQ: + emit_beq(cd, iptr->dst.block, s1, s2); + break; + case ICMD_IF_ACMPNE: + emit_bne(cd, iptr->dst.block, s1, s2); + break; + } +#elif SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + M_ACMP(s1, s2); + emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ACMPEQ, BRANCH_OPT_NONE); +#elif SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + M_CMPEQ(s1, s2, REG_ITMP1); + switch (iptr->opc) { + case ICMD_IF_ACMPEQ: + emit_bnez(cd, iptr->dst.block, REG_ITMP1); + break; + case ICMD_IF_ACMPNE: + emit_beqz(cd, iptr->dst.block, REG_ITMP1); + break; + } +#else +# error Unable to generate code for this configuration! +#endif + break; + + case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_ICMPNE: /* op1 = target JavaVM pc */ + +#if SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); + switch (iptr->opc) { + case ICMD_IF_ICMPEQ: + emit_beq(cd, iptr->dst.block, s1, s2); + break; + case ICMD_IF_ICMPNE: + emit_bne(cd, iptr->dst.block, s1, s2); + break; + } + break; +#else + /* fall-through */ +#endif + + case ICMD_IF_ICMPLT: /* ..., value, value ==> ... */ + case ICMD_IF_ICMPGT: /* op1 = target JavaVM pc */ + case ICMD_IF_ICMPLE: + case ICMD_IF_ICMPGE: + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + s2 = emit_load_s2(jd, iptr, REG_ITMP2); +#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER +# if defined(__I386__) || defined(__M68K__) || defined(__X86_64__) + // XXX Fix this soon!!! + M_ICMP(s2, s1); +# else + M_ICMP(s1, s2); +# endif + emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ICMPEQ, BRANCH_OPT_NONE); +#elif SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); +#else +# error Unable to generate code for this configuration! +#endif + break; + + case ICMD_IF_LCMPEQ: /* ..., value, value ==> ... */ + case ICMD_IF_LCMPNE: /* op1 = target JavaVM pc */ + case ICMD_IF_LCMPLT: + case ICMD_IF_LCMPGT: + case ICMD_IF_LCMPLE: + case ICMD_IF_LCMPGE: + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + case ICMD_RETURN: /* ... ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + goto nowperformreturn; + + case ICMD_ARETURN: /* ..., retvalue ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_RESULT); + // XXX M68K: This should actually be M_ADR2INTMOVE(s1, REG_RESULT); + // XXX Sparc64: Here this should be REG_RESULT_CALLEE! + emit_imove(cd, s1, REG_RESULT); + +#ifdef ENABLE_VERIFIER + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + PROFILE_CYCLE_STOP; + unresolved_class *uc = iptr->sx.s23.s2.uc; + patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0); + PROFILE_CYCLE_START; + } +#endif /* ENABLE_VERIFIER */ + goto nowperformreturn; + + case ICMD_IRETURN: /* ..., retvalue ==> ... */ +#if defined(ENABLE_SOFTFLOAT) + case ICMD_FRETURN: +#endif + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_RESULT); + // XXX Sparc64: Here this should be REG_RESULT_CALLEE! + emit_imove(cd, s1, REG_RESULT); + goto nowperformreturn; + + case ICMD_LRETURN: /* ..., retvalue ==> ... */ +#if defined(ENABLE_SOFTFLOAT) + case ICMD_DRETURN: +#endif + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_LRESULT); + // XXX Sparc64: Here this should be REG_RESULT_CALLEE! + emit_lmove(cd, s1, REG_LRESULT); + goto nowperformreturn; + +#if !defined(ENABLE_SOFTFLOAT) + case ICMD_FRETURN: /* ..., retvalue ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_FRESULT); +#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) + emit_fmove(cd, s1, REG_FRESULT); +#else + M_CAST_F2I(s1, REG_RESULT); +#endif + goto nowperformreturn; + + case ICMD_DRETURN: /* ..., retvalue ==> ... */ + + REPLACEMENT_POINT_RETURN(cd, iptr); + s1 = emit_load_s1(jd, iptr, REG_FRESULT); +#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) + emit_dmove(cd, s1, REG_FRESULT); +#else + M_CAST_D2L(s1, REG_LRESULT); +#endif + goto nowperformreturn; +#endif + +nowperformreturn: +#if !defined(NDEBUG) + // Call trace function. + if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) + emit_verbosecall_exit(jd); +#endif + +#if defined(ENABLE_THREADS) + // Emit code to call monitorexit function. + if (checksync && code_is_synchronized(code)) { + emit_monitor_exit(jd, rd->memuse * 8); + } +#endif + + // Generate method profiling code. + PROFILE_CYCLE_STOP; + + // Emit code for the method epilog. + codegen_emit_epilog(jd); + ALIGNCODENOP; + break; + + case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */ + + REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr); + + bte = iptr->sx.s23.s3.bte; + md = bte->md; + +#if defined(ENABLE_ESCAPE_REASON) && defined(__I386__) + if (bte->fp == BUILTIN_escape_reason_new) { + void set_escape_reasons(void *); + M_ASUB_IMM(8, REG_SP); + M_MOV_IMM(iptr->escape_reasons, REG_ITMP1); + M_AST(EDX, REG_SP, 4); + M_AST(REG_ITMP1, REG_SP, 0); + M_MOV_IMM(set_escape_reasons, REG_ITMP1); + M_CALL(REG_ITMP1); + M_ALD(EDX, REG_SP, 4); + M_AADD_IMM(8, REG_SP); + } +#endif + + // Emit the fast-path if available. + if (bte->emit_fastpath != NULL) { + void (*emit_fastpath)(jitdata* jd, instruction* iptr, int d); + emit_fastpath = (void (*)(jitdata* jd, instruction* iptr, int d)) bte->emit_fastpath; + + assert(md->returntype.type == TYPE_VOID); + d = REG_ITMP1; + + // Actually call the fast-path emitter. + emit_fastpath(jd, iptr, d); + + // If fast-path succeeded, jump to the end of the builtin + // invocation. + // XXX Actually the slow-path block below should be moved + // out of the instruction stream and the jump below should be + // inverted. +#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + os::abort("codegen_emit: Implement jump over slow-path for this configuration."); +#elif SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + M_TEST(d); + emit_label_bne(cd, BRANCH_LABEL_10); +#else +# error Unable to generate code for this configuration! +#endif + } + + goto gen_method; + + case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */ + case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */ + case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */ + case ICMD_INVOKEINTERFACE: + + REPLACEMENT_POINT_INVOKE(cd, iptr); + + if (INSTRUCTION_IS_UNRESOLVED(iptr)) { + unresolved_method* um = iptr->sx.s23.s3.um; + md = um->methodref->parseddesc.md; + } + else { + methodinfo* lm = iptr->sx.s23.s3.fmiref->p.method; + md = lm->parseddesc; + } + +gen_method: + i = md->paramcount; + + // XXX Check this again! + MCODECHECK((i << 1) + 64); // PPC + + // Copy arguments to registers or stack location. + for (i = i - 1; i >= 0; i--) { + var = VAR(iptr->sx.s23.s2.args[i]); + d = md->params[i].regoff; + + // Already pre-allocated? + if (var->flags & PREALLOC) + continue; + + if (!md->params[i].inmemory) { + switch (var->type) { + case TYPE_ADR: + case TYPE_INT: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#endif + s1 = emit_load(jd, iptr, var, d); + emit_imove(cd, s1, d); + break; + + case TYPE_LNG: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_DBL: +#endif + s1 = emit_load(jd, iptr, var, d); + emit_lmove(cd, s1, d); + break; + +#if !defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) + s1 = emit_load(jd, iptr, var, d); + emit_fmove(cd, s1, d); +#else + s1 = emit_load(jd, iptr, var, REG_FTMP1); + M_CAST_F2I(s1, d); +#endif + break; + + case TYPE_DBL: +#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) + s1 = emit_load(jd, iptr, var, d); + emit_dmove(cd, s1, d); +#else + s1 = emit_load(jd, iptr, var, REG_FTMP1); + M_CAST_D2L(s1, d); +#endif + break; +#endif + } + } + else { + switch (var->type) { + case TYPE_ADR: + s1 = emit_load(jd, iptr, var, REG_ITMP1); + // XXX M68K: This should actually be like this: + // s1 = emit_load(jd, iptr, var, REG_ATMP1); + // XXX Sparc64: Here this actually was: + // M_STX(s1, REG_SP, JITSTACK + d); + M_AST(s1, REG_SP, d); + break; + + case TYPE_INT: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#endif +#if SIZEOF_VOID_P == 4 + s1 = emit_load(jd, iptr, var, REG_ITMP1); + M_IST(s1, REG_SP, d); + break; +#else + /* fall-through */ +#endif + + case TYPE_LNG: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_DBL: +#endif + s1 = emit_load(jd, iptr, var, REG_LTMP12); + // XXX Sparc64: Here this actually was: + // M_STX(s1, REG_SP, JITSTACK + d); + M_LST(s1, REG_SP, d); + break; + +#if !defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#if SIZEOF_VOID_P == 4 + s1 = emit_load(jd, iptr, var, REG_FTMP1); + M_FST(s1, REG_SP, d); + break; +#else + /* fall-through */ +#endif + + case TYPE_DBL: + s1 = emit_load(jd, iptr, var, REG_FTMP1); + // XXX Sparc64: Here this actually was: + // M_DST(s1, REG_SP, JITSTACK + d); + M_DST(s1, REG_SP, d); + break; +#endif + } + } + } + + // Generate method profiling code. + PROFILE_CYCLE_STOP; + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + + // Generate method profiling code. + PROFILE_CYCLE_START; + + // Store size of call code in replacement point. + REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr); + REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr); + + // Recompute the procedure vector (PV). + emit_recompute_pv(cd); + + // Store return value. +#if defined(ENABLE_SSA) + if ((ls == NULL) /* || (!IS_TEMPVAR_INDEX(iptr->dst.varindex)) */ || + (ls->lifetime[iptr->dst.varindex].type != UNUSED)) + /* a "living" stackslot */ +#endif + switch (md->returntype.type) { + case TYPE_INT: + case TYPE_ADR: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#endif + s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT); + // XXX Sparc64: This should actually be REG_RESULT_CALLER, fix this! + emit_imove(cd, REG_RESULT, s1); + emit_store_dst(jd, iptr, s1); + break; + + case TYPE_LNG: +#if defined(ENABLE_SOFTFLOAT) + case TYPE_DBL: +#endif + s1 = codegen_reg_of_dst(jd, iptr, REG_LRESULT); + // XXX Sparc64: This should actually be REG_RESULT_CALLER, fix this! + emit_lmove(cd, REG_LRESULT, s1); + emit_store_dst(jd, iptr, s1); + break; + +#if !defined(ENABLE_SOFTFLOAT) + case TYPE_FLT: +#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) + s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); + emit_fmove(cd, REG_FRESULT, s1); +#else + s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_CAST_I2F(REG_RESULT, s1); +#endif + emit_store_dst(jd, iptr, s1); + break; + + case TYPE_DBL: +#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS) + s1 = codegen_reg_of_dst(jd, iptr, REG_FRESULT); + emit_dmove(cd, REG_FRESULT, s1); +#else + s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1); + M_CAST_L2D(REG_LRESULT, s1); +#endif + emit_store_dst(jd, iptr, s1); + break; +#endif + + case TYPE_VOID: + break; + } + + // If we are emitting a fast-path block, this is the label for + // successful fast-path execution. + if ((iptr->opc == ICMD_BUILTIN) && (bte->emit_fastpath != NULL)) { + emit_label(cd, BRANCH_LABEL_10); + } + + break; + + case ICMD_TABLESWITCH: /* ..., index ==> ... */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */ + + s1 = emit_load_s1(jd, iptr, REG_ITMP1); + i = iptr->sx.s23.s2.lookupcount; + + // XXX Again we need to check this + MCODECHECK((i<<2)+8); // Alpha, ARM, i386, MIPS, M68K, Sparc64 + MCODECHECK((i<<3)+8); // PPC64 + MCODECHECK(8 + ((7 + 6) * i) + 5); // X86_64, S390 + + // Compare keys. + for (lookup_target_t* lookup = iptr->dst.lookup; i > 0; ++lookup, --i) { +#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER + emit_icmp_imm(cd, s1, lookup->value); + emit_beq(cd, lookup->target.block); +#elif SUPPORT_BRANCH_CONDITIONAL_TWO_INTEGER_REGISTERS + ICONST(REG_ITMP2, lookup->value); + emit_beq(cd, lookup->target.block, s1, REG_ITMP2); +#elif SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER + emit_icmpeq_imm(cd, s1, lookup->value, REG_ITMP2); + emit_bnez(cd, lookup->target.block, REG_ITMP2); +#else +# error Unable to generate code for this configuration! +#endif + } + + // Default branch. + emit_br(cd, iptr->sx.s23.s3.lookupdefault.block); + ALIGNCODENOP; + break; + + case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */ + case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */ + case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */ + + // Generate architecture specific instructions. + codegen_emit_instruction(jd, iptr); + break; + + default: + exceptions_throw_internalerror("Unknown ICMD %d during code generation", + iptr->opc); + return false; + + } // the big switch + + } // for all instructions + +#if defined(ENABLE_SSA) + // By edge splitting, in blocks with phi moves there can only + // be a goto as last command, no other jump/branch command. + if (ls != NULL) { + if (!last_cmd_was_goto) + codegen_emit_phi_moves(jd, bptr); + } +#endif + +#if defined(__I386__) || defined(__M68K__) || defined(__MIPS__) || defined(__S390__) || defined(__SPARC_64__) || defined(__X86_64__) + // XXX Again!!! + /* XXX require a lower number? */ + MCODECHECK(64); // I386, MIPS, Sparc64 + MCODECHECK(512); // S390, X86_64 + + /* XXX We can remove that when we don't use UD2 anymore on i386 + and x86_64. */ + + /* At the end of a basic block we may have to append some nops, + because the patcher stub calling code might be longer than the + actual instruction. So codepatching does not change the + following block unintentionally. */ + + if (cd->mcodeptr < cd->lastmcodeptr) { + while (cd->mcodeptr < cd->lastmcodeptr) { + M_NOP; + } + } +#endif + + } // for all basic blocks + + // Generate traps. + emit_patcher_traps(jd); + + // Everything's ok. + return true; +} + + /* codegen_emit_phi_moves **************************************************** Emits phi moves at the end of the basicblock.