diff options
27 files changed, 643 insertions, 80 deletions
diff --git a/dexdump/DexDump.c b/dexdump/DexDump.c index 6fed7aaf4..b3b0839f7 100644 --- a/dexdump/DexDump.c +++ b/dexdump/DexDump.c @@ -857,6 +857,18 @@ void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx, printf("}, [%04x] // vtable #%04x", pDecInsn->vB, pDecInsn->vB); } break; + case kFmt3rinline: // [opt] execute-inline/range + { + fputs(" {", stdout); + for (i = 0; i < (int) pDecInsn->vA; i++) { + if (i == 0) + printf("v%d", pDecInsn->vC + i); + else + printf(", v%d", pDecInsn->vC + i); + } + printf("}, [%04x] // inline #%04x", pDecInsn->vB, pDecInsn->vB); + } + break; case kFmt3inline: // [opt] inline invoke { #if 0 diff --git a/dexdump/OpCodeNames.c b/dexdump/OpCodeNames.c index 6a1a52a41..97b707efe 100644 --- a/dexdump/OpCodeNames.c +++ b/dexdump/OpCodeNames.c @@ -299,7 +299,7 @@ static const char* gOpNames[256] = { "^breakpoint", // does not appear in DEX files "^throw-verification-error", // does not appear in DEX files "+execute-inline", - "UNUSED", + "+execute-inline/range", /* 0xf0 */ "+invoke-direct-empty", diff --git a/libdex/InstrUtils.c b/libdex/InstrUtils.c index 06e26bce4..d1ebeec16 100644 --- a/libdex/InstrUtils.c +++ b/libdex/InstrUtils.c @@ -302,6 +302,7 @@ InstructionWidth* dexCreateInstrWidthTable(void) case OP_INVOKE_SUPER_QUICK: case OP_INVOKE_SUPER_QUICK_RANGE: case OP_EXECUTE_INLINE: + case OP_EXECUTE_INLINE_RANGE: case OP_INVOKE_DIRECT_EMPTY: width = -3; break; @@ -326,7 +327,6 @@ InstructionWidth* dexCreateInstrWidthTable(void) case OP_UNUSED_EA: case OP_UNUSED_EB: case OP_BREAKPOINT: - case OP_UNUSED_EF: case OP_UNUSED_F1: case OP_UNUSED_FC: case OP_UNUSED_FD: @@ -616,7 +616,8 @@ InstructionFlags* dexCreateInstrFlagsTable(void) flags = kInstrCanThrow; break; case OP_EXECUTE_INLINE: - flags = kInstrCanContinue; + case OP_EXECUTE_INLINE_RANGE: + flags = kInstrCanContinue | kInstrCanThrow; break; case OP_IGET_QUICK: case OP_IGET_WIDE_QUICK: @@ -655,7 +656,6 @@ InstructionFlags* dexCreateInstrFlagsTable(void) case OP_UNUSED_EA: case OP_UNUSED_EB: case OP_BREAKPOINT: - case OP_UNUSED_EF: case OP_UNUSED_F1: case OP_UNUSED_FC: case OP_UNUSED_FD: @@ -985,6 +985,9 @@ InstructionFormat* dexCreateInstrFormatTable(void) case OP_EXECUTE_INLINE: fmt = kFmt3inline; break; + case OP_EXECUTE_INLINE_RANGE: + fmt = kFmt3rinline; + break; case OP_INVOKE_DIRECT_EMPTY: fmt = kFmt35c; break; @@ -1009,7 +1012,6 @@ InstructionFormat* dexCreateInstrFormatTable(void) case OP_UNUSED_EA: case OP_UNUSED_EB: case OP_BREAKPOINT: - case OP_UNUSED_EF: case OP_UNUSED_F1: case OP_UNUSED_FC: case OP_UNUSED_FD: @@ -1201,6 +1203,7 @@ void dexDecodeInstruction(const InstructionFormat* fmts, const u2* insns, break; case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB case kFmt3rms: // [opt] invoke-virtual+super/range + case kFmt3rinline: // [opt] execute-inline/range pDec->vA = INST_AA(inst); pDec->vB = FETCH(1); pDec->vC = FETCH(2); diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h index 9728cd453..8449ae5e8 100644 --- a/libdex/InstrUtils.h +++ b/libdex/InstrUtils.h @@ -68,6 +68,7 @@ enum InstructionFormat { kFmt3rms, // [opt] invoke-virtual+super/range kFmt3rfs, // [opt] invoke-interface/range kFmt3inline, // [opt] inline invoke + kFmt3rinline, // [opt] inline invoke/range kFmt51l, // op vAA, #+BBBBBBBBBBBBBBBB }; diff --git a/libdex/OpCode.h b/libdex/OpCode.h index c3ed476f5..58d17026b 100644 --- a/libdex/OpCode.h +++ b/libdex/OpCode.h @@ -343,7 +343,7 @@ typedef enum OpCode { /* optimizer output -- these are never generated by "dx" */ OP_THROW_VERIFICATION_ERROR = 0xed, OP_EXECUTE_INLINE = 0xee, - OP_UNUSED_EF = 0xef, /* OP_EXECUTE_INLINE_RANGE? */ + OP_EXECUTE_INLINE_RANGE = 0xef, OP_INVOKE_DIRECT_EMPTY = 0xf0, OP_UNUSED_F1 = 0xf1, /* OP_INVOKE_DIRECT_EMPTY_RANGE? */ @@ -639,7 +639,7 @@ typedef enum OpCode { H(OP_BREAKPOINT), \ H(OP_THROW_VERIFICATION_ERROR), \ H(OP_EXECUTE_INLINE), \ - H(OP_UNUSED_EF), \ + H(OP_EXECUTE_INLINE_RANGE), \ /* f0..ff */ \ H(OP_INVOKE_DIRECT_EMPTY), \ H(OP_UNUSED_F1), \ diff --git a/vm/DalvikVersion.h b/vm/DalvikVersion.h index eae335db8..2e00ac417 100644 --- a/vm/DalvikVersion.h +++ b/vm/DalvikVersion.h @@ -32,6 +32,6 @@ * way classes load changes, e.g. field ordering or vtable layout. Changing * this guarantees that the optimized form of the DEX file is regenerated. */ -#define DALVIK_VM_BUILD 18 +#define DALVIK_VM_BUILD 19 #endif /*_DALVIK_VERSION*/ diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c index 911775c7e..942ac600a 100644 --- a/vm/analysis/CodeVerify.c +++ b/vm/analysis/CodeVerify.c @@ -5412,6 +5412,7 @@ sput_1nr_common: * type, which is acceptable for any operation. */ case OP_EXECUTE_INLINE: + case OP_EXECUTE_INLINE_RANGE: case OP_INVOKE_DIRECT_EMPTY: case OP_IGET_QUICK: case OP_IGET_WIDE_QUICK: @@ -5446,7 +5447,6 @@ sput_1nr_common: case OP_UNUSED_EA: case OP_UNUSED_EB: case OP_BREAKPOINT: - case OP_UNUSED_EF: case OP_UNUSED_F1: case OP_UNUSED_FC: case OP_UNUSED_FD: diff --git a/vm/analysis/DexOptimize.c b/vm/analysis/DexOptimize.c index b3e2d40c1..369d70707 100644 --- a/vm/analysis/DexOptimize.c +++ b/vm/analysis/DexOptimize.c @@ -64,9 +64,11 @@ static void optimizeClass(ClassObject* clazz, const InlineSub* inlineSubs); static bool optimizeMethod(Method* method, const InlineSub* inlineSubs); static void rewriteInstField(Method* method, u2* insns, OpCode newOpc); static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc); -static bool rewriteDirectInvoke(Method* method, u2* insns); +static bool rewriteEmptyDirectInvoke(Method* method, u2* insns); static bool rewriteExecuteInline(Method* method, u2* insns, MethodType methodType, const InlineSub* inlineSubs); +static bool rewriteExecuteInlineRange(Method* method, u2* insns, + MethodType methodType, const InlineSub* inlineSubs); /* @@ -1565,8 +1567,15 @@ static bool optimizeMethod(Method* method, const InlineSub* inlineSubs) } break; case OP_INVOKE_VIRTUAL_RANGE: - if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_VIRTUAL_QUICK_RANGE)) - return false; + if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL, + inlineSubs)) + { + if (!rewriteVirtualInvoke(method, insns, + OP_INVOKE_VIRTUAL_QUICK_RANGE)) + { + return false; + } + } break; case OP_INVOKE_SUPER: if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK)) @@ -1580,13 +1589,20 @@ static bool optimizeMethod(Method* method, const InlineSub* inlineSubs) case OP_INVOKE_DIRECT: if (!rewriteExecuteInline(method, insns, METHOD_DIRECT, inlineSubs)) { - if (!rewriteDirectInvoke(method, insns)) + if (!rewriteEmptyDirectInvoke(method, insns)) return false; } break; + case OP_INVOKE_DIRECT_RANGE: + rewriteExecuteInlineRange(method, insns, METHOD_DIRECT, inlineSubs); + break; + case OP_INVOKE_STATIC: rewriteExecuteInline(method, insns, METHOD_STATIC, inlineSubs); break; + case OP_INVOKE_STATIC_RANGE: + rewriteExecuteInlineRange(method, insns, METHOD_STATIC, inlineSubs); + break; default: // ignore this instruction @@ -2107,7 +2123,7 @@ static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc) * This must only be used when the invoked method does nothing and has * no return value (the latter being very important for verification). */ -static bool rewriteDirectInvoke(Method* method, u2* insns) +static bool rewriteEmptyDirectInvoke(Method* method, u2* insns) { ClassObject* clazz = method->clazz; Method* calledMethod; @@ -2226,6 +2242,7 @@ Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx) return resMethod; } + /* * See if the method being called can be rewritten as an inline operation. * Works for invoke-virtual, invoke-direct, and invoke-static. @@ -2276,3 +2293,42 @@ static bool rewriteExecuteInline(Method* method, u2* insns, return false; } +/* + * See if the method being called can be rewritten as an inline operation. + * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range. + * + * Returns "true" if we replace it. + */ +static bool rewriteExecuteInlineRange(Method* method, u2* insns, + MethodType methodType, const InlineSub* inlineSubs) +{ + ClassObject* clazz = method->clazz; + Method* calledMethod; + u2 methodIdx = insns[1]; + + calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL); + if (calledMethod == NULL) { + LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx); + return false; + } + + while (inlineSubs->method != NULL) { + if (inlineSubs->method == calledMethod) { + assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE || + (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE || + (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE); + insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE_RANGE; + insns[1] = (u2) inlineSubs->inlineIdx; + + //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n", + // method->clazz->descriptor, method->name, + // calledMethod->clazz->descriptor, calledMethod->name); + return true; + } + + inlineSubs++; + } + + return false; +} + diff --git a/vm/analysis/RegisterMap.c b/vm/analysis/RegisterMap.c index bc314a243..758ebeadc 100644 --- a/vm/analysis/RegisterMap.c +++ b/vm/analysis/RegisterMap.c @@ -3000,6 +3000,7 @@ sget_1nr_common: * quickened. This is feasible but not currently supported. */ case OP_EXECUTE_INLINE: + case OP_EXECUTE_INLINE_RANGE: case OP_INVOKE_DIRECT_EMPTY: case OP_IGET_QUICK: case OP_IGET_WIDE_QUICK: @@ -3036,7 +3037,6 @@ sget_1nr_common: case OP_UNUSED_EB: case OP_BREAKPOINT: case OP_UNUSED_ED: - case OP_UNUSED_EF: case OP_UNUSED_F1: case OP_UNUSED_FC: case OP_UNUSED_FD: diff --git a/vm/compiler/Dataflow.c b/vm/compiler/Dataflow.c index fc5ecb9c4..d520d8454 100644 --- a/vm/compiler/Dataflow.c +++ b/vm/compiler/Dataflow.c @@ -746,7 +746,7 @@ int dvmCompilerDataFlowAttributes[kMirOpLast] = { // EE OP_EXECUTE_INLINE DF_FORMAT_35C, - // EF OP_UNUSED_EF + // EF OP_EXECUTE_INLINE_RANGE DF_NOP, // F0 OP_INVOKE_DIRECT_EMPTY diff --git a/vm/compiler/codegen/arm/Codegen.c b/vm/compiler/codegen/arm/Codegen.c index 7ca905cac..370c85781 100644 --- a/vm/compiler/codegen/arm/Codegen.c +++ b/vm/compiler/codegen/arm/Codegen.c @@ -4005,6 +4005,13 @@ static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir) return false; } +static bool handleFmt3rinline(CompilationUnit *cUnit, MIR *mir) +{ + /* For OP_EXECUTE_INLINE_RANGE */ + genInterpSingleStep(cUnit, mir); + return false; +} + static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir) { //TUNING: We're using core regs here - not optimal when target is a double @@ -4581,6 +4588,9 @@ void dvmCompilerMIR2LIR(CompilationUnit *cUnit) case kFmt3inline: notHandled = handleFmt3inline(cUnit, mir); break; + case kFmt3rinline: + notHandled = handleFmt3rinline(cUnit, mir); + break; case kFmt51l: notHandled = handleFmt51l(cUnit, mir); break; diff --git a/vm/mterp/armv5te/OP_EXECUTE_INLINE.S b/vm/mterp/armv5te/OP_EXECUTE_INLINE.S index eb0b76fad..550bb8304 100644 --- a/vm/mterp/armv5te/OP_EXECUTE_INLINE.S +++ b/vm/mterp/armv5te/OP_EXECUTE_INLINE.S @@ -3,17 +3,18 @@ /* * Execute a "native inline" instruction. * - * We need to call: - * dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref) + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) * - * The first four args are in r0-r3, but the last two must be pushed - * onto the stack. + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. */ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */ FETCH(r10, 1) @ r10<- BBBB add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval EXPORT_PC() @ can throw - sub sp, sp, #8 @ make room for arg(s) + sub sp, sp, #8 @ make room for arg, +64 bit align mov r0, rINST, lsr #12 @ r0<- B str r1, [sp] @ push &glue->retval bl .L${opcode}_continue @ make call; will return after diff --git a/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S b/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S new file mode 100644 index 000000000..4d62019d5 --- /dev/null +++ b/vm/mterp/armv5te/OP_EXECUTE_INLINE_RANGE.S @@ -0,0 +1,56 @@ +%verify "executed" +%verify "exception handled" + /* + * Execute a "native inline" instruction, using "/range" semantics. + * Same idea as execute-inline, but we get the args differently. + * + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) + * + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. + */ + /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */ + FETCH(r10, 1) @ r10<- BBBB + add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval + EXPORT_PC() @ can throw + sub sp, sp, #8 @ make room for arg, +64 bit align + mov r0, rINST, lsr #8 @ r0<- AA + str r1, [sp] @ push &glue->retval + bl .L${opcode}_continue @ make call; will return after + add sp, sp, #8 @ pop stack + cmp r0, #0 @ test boolean result of inline + beq common_exceptionThrown @ returned false, handle exception + FETCH_ADVANCE_INST(3) @ advance rPC, load rINST + GET_INST_OPCODE(ip) @ extract opcode from rINST + GOTO_OPCODE(ip) @ jump to next instruction +%break + + /* + * Extract args, call function. + * r0 = #of args (0-4) + * r10 = call index + * lr = return addr, above [DO NOT bl out of here w/o preserving LR] + */ +.L${opcode}_continue: + rsb r0, r0, #4 @ r0<- 4-r0 + FETCH(r9, 2) @ r9<- CCCC + add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each + bl common_abort @ (skipped due to ARM prefetch) +4: add ip, r9, #3 @ base+3 + GET_VREG(r3, ip) @ r3<- vBase[3] +3: add ip, r9, #2 @ base+2 + GET_VREG(r2, ip) @ r2<- vBase[2] +2: add ip, r9, #1 @ base+1 + GET_VREG(r1, ip) @ r1<- vBase[1] +1: add ip, r9, #0 @ (nop) + GET_VREG(r0, ip) @ r0<- vBase[0] +0: + ldr r9, .L${opcode}_table @ table of InlineOperation + LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry + @ (not reached) + +.L${opcode}_table: + .word gDvmInlineOpsTable + diff --git a/vm/mterp/armv5te/OP_UNUSED_EF.S b/vm/mterp/armv5te/OP_UNUSED_EF.S deleted file mode 100644 index faa7246f5..000000000 --- a/vm/mterp/armv5te/OP_UNUSED_EF.S +++ /dev/null @@ -1 +0,0 @@ -%include "armv5te/unused.S" diff --git a/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.c b/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.c new file mode 100644 index 000000000..a76710637 --- /dev/null +++ b/vm/mterp/c/OP_EXECUTE_INLINE_RANGE.c @@ -0,0 +1,43 @@ +HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/) + { + u4 arg0, arg1, arg2, arg3; + arg0 = arg1 = arg2 = arg3 = 0; /* placate gcc */ + + EXPORT_PC(); + + vsrc1 = INST_AA(inst); /* #of args */ + ref = FETCH(1); /* inline call "ref" */ + vdst = FETCH(2); /* range base */ + ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}", + vsrc1, ref, vdst, vdst+vsrc1-1); + + assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear + assert(vsrc1 <= 4); + + switch (vsrc1) { + case 4: + arg3 = GET_REGISTER(vdst+3); + /* fall through */ + case 3: + arg2 = GET_REGISTER(vdst+2); + /* fall through */ + case 2: + arg1 = GET_REGISTER(vdst+1); + /* fall through */ + case 1: + arg0 = GET_REGISTER(vdst+0); + /* fall through */ + default: // case 0 + ; + } + +#if INTERP_TYPE == INTERP_DBG + if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#else + if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#endif + } + FINISH(3); +OP_END diff --git a/vm/mterp/c/OP_UNUSED_EF.c b/vm/mterp/c/OP_UNUSED_EF.c deleted file mode 100644 index c5e1863cf..000000000 --- a/vm/mterp/c/OP_UNUSED_EF.c +++ /dev/null @@ -1,2 +0,0 @@ -HANDLE_OPCODE(OP_UNUSED_EF) -OP_END diff --git a/vm/mterp/config-x86 b/vm/mterp/config-x86 index b7139cad3..cf5adb57b 100644 --- a/vm/mterp/config-x86 +++ b/vm/mterp/config-x86 @@ -33,6 +33,8 @@ import c/opcommon.c # opcode list; argument to op-start is default directory op-start x86 + # stub -- need native impl + op OP_EXECUTE_INLINE_RANGE c op-end # arch-specific entry point to interpreter diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S index a4e5c43cc..9f9b9ff69 100644 --- a/vm/mterp/out/InterpAsm-armv4t.S +++ b/vm/mterp/out/InterpAsm-armv4t.S @@ -7650,17 +7650,18 @@ d2i_doconv: /* * Execute a "native inline" instruction. * - * We need to call: - * dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref) + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) * - * The first four args are in r0-r3, but the last two must be pushed - * onto the stack. + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. */ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */ FETCH(r10, 1) @ r10<- BBBB add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval EXPORT_PC() @ can throw - sub sp, sp, #8 @ make room for arg(s) + sub sp, sp, #8 @ make room for arg, +64 bit align mov r0, rINST, lsr #12 @ r0<- B str r1, [sp] @ push &glue->retval bl .LOP_EXECUTE_INLINE_continue @ make call; will return after @@ -7673,12 +7674,33 @@ d2i_doconv: /* ------------------------------ */ .balign 64 -.L_OP_UNUSED_EF: /* 0xef */ -/* File: armv5te/OP_UNUSED_EF.S */ -/* File: armv5te/unused.S */ - bl common_abort - - +.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */ +/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */ + /* + * Execute a "native inline" instruction, using "/range" semantics. + * Same idea as execute-inline, but we get the args differently. + * + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) + * + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. + */ + /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */ + FETCH(r10, 1) @ r10<- BBBB + add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval + EXPORT_PC() @ can throw + sub sp, sp, #8 @ make room for arg, +64 bit align + mov r0, rINST, lsr #8 @ r0<- AA + str r1, [sp] @ push &glue->retval + bl .LOP_EXECUTE_INLINE_RANGE_continue @ make call; will return after + add sp, sp, #8 @ pop stack + cmp r0, #0 @ test boolean result of inline + beq common_exceptionThrown @ returned false, handle exception + FETCH_ADVANCE_INST(3) @ advance rPC, load rINST + GET_INST_OPCODE(ip) @ extract opcode from rINST + GOTO_OPCODE(ip) @ jump to next instruction /* ------------------------------ */ .balign 64 @@ -9466,6 +9488,36 @@ d2l_doconv: .word gDvmInlineOpsTable +/* continuation for OP_EXECUTE_INLINE_RANGE */ + + /* + * Extract args, call function. + * r0 = #of args (0-4) + * r10 = call index + * lr = return addr, above [DO NOT bl out of here w/o preserving LR] + */ +.LOP_EXECUTE_INLINE_RANGE_continue: + rsb r0, r0, #4 @ r0<- 4-r0 + FETCH(r9, 2) @ r9<- CCCC + add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each + bl common_abort @ (skipped due to ARM prefetch) +4: add ip, r9, #3 @ base+3 + GET_VREG(r3, ip) @ r3<- vBase[3] +3: add ip, r9, #2 @ base+2 + GET_VREG(r2, ip) @ r2<- vBase[2] +2: add ip, r9, #1 @ base+1 + GET_VREG(r1, ip) @ r1<- vBase[1] +1: add ip, r9, #0 @ (nop) + GET_VREG(r0, ip) @ r0<- vBase[0] +0: + ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation + LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry + @ (not reached) + +.LOP_EXECUTE_INLINE_RANGE_table: + .word gDvmInlineOpsTable + + .size dvmAsmSisterStart, .-dvmAsmSisterStart .global dvmAsmSisterEnd dvmAsmSisterEnd: diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S index 3bb5409e8..4a3f683c5 100644 --- a/vm/mterp/out/InterpAsm-armv5te-vfp.S +++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S @@ -7310,17 +7310,18 @@ dalvik_inst: /* * Execute a "native inline" instruction. * - * We need to call: - * dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref) + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) * - * The first four args are in r0-r3, but the last two must be pushed - * onto the stack. + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. */ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */ FETCH(r10, 1) @ r10<- BBBB add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval EXPORT_PC() @ can throw - sub sp, sp, #8 @ make room for arg(s) + sub sp, sp, #8 @ make room for arg, +64 bit align mov r0, rINST, lsr #12 @ r0<- B str r1, [sp] @ push &glue->retval bl .LOP_EXECUTE_INLINE_continue @ make call; will return after @@ -7333,12 +7334,33 @@ dalvik_inst: /* ------------------------------ */ .balign 64 -.L_OP_UNUSED_EF: /* 0xef */ -/* File: armv5te/OP_UNUSED_EF.S */ -/* File: armv5te/unused.S */ - bl common_abort - - +.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */ +/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */ + /* + * Execute a "native inline" instruction, using "/range" semantics. + * Same idea as execute-inline, but we get the args differently. + * + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) + * + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. + */ + /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */ + FETCH(r10, 1) @ r10<- BBBB + add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval + EXPORT_PC() @ can throw + sub sp, sp, #8 @ make room for arg, +64 bit align + mov r0, rINST, lsr #8 @ r0<- AA + str r1, [sp] @ push &glue->retval + bl .LOP_EXECUTE_INLINE_RANGE_continue @ make call; will return after + add sp, sp, #8 @ pop stack + cmp r0, #0 @ test boolean result of inline + beq common_exceptionThrown @ returned false, handle exception + FETCH_ADVANCE_INST(3) @ advance rPC, load rINST + GET_INST_OPCODE(ip) @ extract opcode from rINST + GOTO_OPCODE(ip) @ jump to next instruction /* ------------------------------ */ .balign 64 @@ -8984,6 +9006,36 @@ d2l_doconv: .word gDvmInlineOpsTable +/* continuation for OP_EXECUTE_INLINE_RANGE */ + + /* + * Extract args, call function. + * r0 = #of args (0-4) + * r10 = call index + * lr = return addr, above [DO NOT bl out of here w/o preserving LR] + */ +.LOP_EXECUTE_INLINE_RANGE_continue: + rsb r0, r0, #4 @ r0<- 4-r0 + FETCH(r9, 2) @ r9<- CCCC + add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each + bl common_abort @ (skipped due to ARM prefetch) +4: add ip, r9, #3 @ base+3 + GET_VREG(r3, ip) @ r3<- vBase[3] +3: add ip, r9, #2 @ base+2 + GET_VREG(r2, ip) @ r2<- vBase[2] +2: add ip, r9, #1 @ base+1 + GET_VREG(r1, ip) @ r1<- vBase[1] +1: add ip, r9, #0 @ (nop) + GET_VREG(r0, ip) @ r0<- vBase[0] +0: + ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation + LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry + @ (not reached) + +.LOP_EXECUTE_INLINE_RANGE_table: + .word gDvmInlineOpsTable + + .size dvmAsmSisterStart, .-dvmAsmSisterStart .global dvmAsmSisterEnd dvmAsmSisterEnd: diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S index 52e536b90..5fb231e38 100644 --- a/vm/mterp/out/InterpAsm-armv5te.S +++ b/vm/mterp/out/InterpAsm-armv5te.S @@ -7650,17 +7650,18 @@ d2i_doconv: /* * Execute a "native inline" instruction. * - * We need to call: - * dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref) + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) * - * The first four args are in r0-r3, but the last two must be pushed - * onto the stack. + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. */ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */ FETCH(r10, 1) @ r10<- BBBB add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval EXPORT_PC() @ can throw - sub sp, sp, #8 @ make room for arg(s) + sub sp, sp, #8 @ make room for arg, +64 bit align mov r0, rINST, lsr #12 @ r0<- B str r1, [sp] @ push &glue->retval bl .LOP_EXECUTE_INLINE_continue @ make call; will return after @@ -7673,12 +7674,33 @@ d2i_doconv: /* ------------------------------ */ .balign 64 -.L_OP_UNUSED_EF: /* 0xef */ -/* File: armv5te/OP_UNUSED_EF.S */ -/* File: armv5te/unused.S */ - bl common_abort - - +.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */ +/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */ + /* + * Execute a "native inline" instruction, using "/range" semantics. + * Same idea as execute-inline, but we get the args differently. + * + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) + * + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. + */ + /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */ + FETCH(r10, 1) @ r10<- BBBB + add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval + EXPORT_PC() @ can throw + sub sp, sp, #8 @ make room for arg, +64 bit align + mov r0, rINST, lsr #8 @ r0<- AA + str r1, [sp] @ push &glue->retval + bl .LOP_EXECUTE_INLINE_RANGE_continue @ make call; will return after + add sp, sp, #8 @ pop stack + cmp r0, #0 @ test boolean result of inline + beq common_exceptionThrown @ returned false, handle exception + FETCH_ADVANCE_INST(3) @ advance rPC, load rINST + GET_INST_OPCODE(ip) @ extract opcode from rINST + GOTO_OPCODE(ip) @ jump to next instruction /* ------------------------------ */ .balign 64 @@ -9460,6 +9482,36 @@ d2l_doconv: .word gDvmInlineOpsTable +/* continuation for OP_EXECUTE_INLINE_RANGE */ + + /* + * Extract args, call function. + * r0 = #of args (0-4) + * r10 = call index + * lr = return addr, above [DO NOT bl out of here w/o preserving LR] + */ +.LOP_EXECUTE_INLINE_RANGE_continue: + rsb r0, r0, #4 @ r0<- 4-r0 + FETCH(r9, 2) @ r9<- CCCC + add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each + bl common_abort @ (skipped due to ARM prefetch) +4: add ip, r9, #3 @ base+3 + GET_VREG(r3, ip) @ r3<- vBase[3] +3: add ip, r9, #2 @ base+2 + GET_VREG(r2, ip) @ r2<- vBase[2] +2: add ip, r9, #1 @ base+1 + GET_VREG(r1, ip) @ r1<- vBase[1] +1: add ip, r9, #0 @ (nop) + GET_VREG(r0, ip) @ r0<- vBase[0] +0: + ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation + LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry + @ (not reached) + +.LOP_EXECUTE_INLINE_RANGE_table: + .word gDvmInlineOpsTable + + .size dvmAsmSisterStart, .-dvmAsmSisterStart .global dvmAsmSisterEnd dvmAsmSisterEnd: diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S index 401bb96cc..08d14d4f0 100644 --- a/vm/mterp/out/InterpAsm-armv7-a.S +++ b/vm/mterp/out/InterpAsm-armv7-a.S @@ -7254,17 +7254,18 @@ dalvik_inst: /* * Execute a "native inline" instruction. * - * We need to call: - * dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref) + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) * - * The first four args are in r0-r3, but the last two must be pushed - * onto the stack. + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. */ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */ FETCH(r10, 1) @ r10<- BBBB add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval EXPORT_PC() @ can throw - sub sp, sp, #8 @ make room for arg(s) + sub sp, sp, #8 @ make room for arg, +64 bit align mov r0, rINST, lsr #12 @ r0<- B str r1, [sp] @ push &glue->retval bl .LOP_EXECUTE_INLINE_continue @ make call; will return after @@ -7277,12 +7278,33 @@ dalvik_inst: /* ------------------------------ */ .balign 64 -.L_OP_UNUSED_EF: /* 0xef */ -/* File: armv5te/OP_UNUSED_EF.S */ -/* File: armv5te/unused.S */ - bl common_abort - - +.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */ +/* File: armv5te/OP_EXECUTE_INLINE_RANGE.S */ + /* + * Execute a "native inline" instruction, using "/range" semantics. + * Same idea as execute-inline, but we get the args differently. + * + * We need to call an InlineOp4Func: + * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) + * + * The first four args are in r0-r3, pointer to return value storage + * is on the stack. The function's return value is a flag that tells + * us if an exception was thrown. + */ + /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */ + FETCH(r10, 1) @ r10<- BBBB + add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval + EXPORT_PC() @ can throw + sub sp, sp, #8 @ make room for arg, +64 bit align + mov r0, rINST, lsr #8 @ r0<- AA + str r1, [sp] @ push &glue->retval + bl .LOP_EXECUTE_INLINE_RANGE_continue @ make call; will return after + add sp, sp, #8 @ pop stack + cmp r0, #0 @ test boolean result of inline + beq common_exceptionThrown @ returned false, handle exception + FETCH_ADVANCE_INST(3) @ advance rPC, load rINST + GET_INST_OPCODE(ip) @ extract opcode from rINST + GOTO_OPCODE(ip) @ jump to next instruction /* ------------------------------ */ .balign 64 @@ -8920,6 +8942,36 @@ d2l_doconv: .word gDvmInlineOpsTable +/* continuation for OP_EXECUTE_INLINE_RANGE */ + + /* + * Extract args, call function. + * r0 = #of args (0-4) + * r10 = call index + * lr = return addr, above [DO NOT bl out of here w/o preserving LR] + */ +.LOP_EXECUTE_INLINE_RANGE_continue: + rsb r0, r0, #4 @ r0<- 4-r0 + FETCH(r9, 2) @ r9<- CCCC + add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each + bl common_abort @ (skipped due to ARM prefetch) +4: add ip, r9, #3 @ base+3 + GET_VREG(r3, ip) @ r3<- vBase[3] +3: add ip, r9, #2 @ base+2 + GET_VREG(r2, ip) @ r2<- vBase[2] +2: add ip, r9, #1 @ base+1 + GET_VREG(r1, ip) @ r1<- vBase[1] +1: add ip, r9, #0 @ (nop) + GET_VREG(r0, ip) @ r0<- vBase[0] +0: + ldr r9, .LOP_EXECUTE_INLINE_RANGE_table @ table of InlineOperation + LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry + @ (not reached) + +.LOP_EXECUTE_INLINE_RANGE_table: + .word gDvmInlineOpsTable + + .size dvmAsmSisterStart, .-dvmAsmSisterStart .global dvmAsmSisterEnd dvmAsmSisterEnd: diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S index 4e6623c73..3783abeb2 100644 --- a/vm/mterp/out/InterpAsm-x86.S +++ b/vm/mterp/out/InterpAsm-x86.S @@ -5857,12 +5857,18 @@ dvmAsmInstructionStart = .L_OP_NOP /* ------------------------------ */ .balign 64 -.L_OP_UNUSED_EF: /* 0xef */ -/* File: x86/OP_UNUSED_EF.S */ -/* File: x86/unused.S */ - jmp common_abort - - +.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */ + /* (stub) */ + GET_GLUE(%ecx) + SAVE_PC_TO_GLUE(%ecx) # only need to export these two + SAVE_FP_TO_GLUE(%ecx) # only need to export these two + movl %ecx,OUT_ARG0(%esp) # glue is first arg to function + call dvmMterp_OP_EXECUTE_INLINE_RANGE # do the real work + GET_GLUE(%ecx) + LOAD_PC_FROM_GLUE(%ecx) # retrieve updated values + LOAD_FP_FROM_GLUE(%ecx) # retrieve updated values + FETCH_INST() + GOTO_NEXT /* ------------------------------ */ .balign 64 .L_OP_INVOKE_DIRECT_EMPTY: /* 0xf0 */ diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c index 0ca466bd2..af4567533 100644 --- a/vm/mterp/out/InterpC-allstubs.c +++ b/vm/mterp/out/InterpC-allstubs.c @@ -2888,8 +2888,49 @@ HANDLE_OPCODE(OP_EXECUTE_INLINE /*vB, {vD, vE, vF, vG}, inline@CCCC*/) FINISH(3); OP_END -/* File: c/OP_UNUSED_EF.c */ -HANDLE_OPCODE(OP_UNUSED_EF) +/* File: c/OP_EXECUTE_INLINE_RANGE.c */ +HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/) + { + u4 arg0, arg1, arg2, arg3; + arg0 = arg1 = arg2 = arg3 = 0; /* placate gcc */ + + EXPORT_PC(); + + vsrc1 = INST_AA(inst); /* #of args */ + ref = FETCH(1); /* inline call "ref" */ + vdst = FETCH(2); /* range base */ + ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}", + vsrc1, ref, vdst, vdst+vsrc1-1); + + assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear + assert(vsrc1 <= 4); + + switch (vsrc1) { + case 4: + arg3 = GET_REGISTER(vdst+3); + /* fall through */ + case 3: + arg2 = GET_REGISTER(vdst+2); + /* fall through */ + case 2: + arg1 = GET_REGISTER(vdst+1); + /* fall through */ + case 1: + arg0 = GET_REGISTER(vdst+0); + /* fall through */ + default: // case 0 + ; + } + +#if INTERP_TYPE == INTERP_DBG + if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#else + if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#endif + } + FINISH(3); OP_END /* File: c/OP_INVOKE_DIRECT_EMPTY.c */ diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c index 062eadc31..fac2bead8 100644 --- a/vm/mterp/out/InterpC-portdbg.c +++ b/vm/mterp/out/InterpC-portdbg.c @@ -3251,8 +3251,49 @@ HANDLE_OPCODE(OP_EXECUTE_INLINE /*vB, {vD, vE, vF, vG}, inline@CCCC*/) FINISH(3); OP_END -/* File: c/OP_UNUSED_EF.c */ -HANDLE_OPCODE(OP_UNUSED_EF) +/* File: c/OP_EXECUTE_INLINE_RANGE.c */ +HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/) + { + u4 arg0, arg1, arg2, arg3; + arg0 = arg1 = arg2 = arg3 = 0; /* placate gcc */ + + EXPORT_PC(); + + vsrc1 = INST_AA(inst); /* #of args */ + ref = FETCH(1); /* inline call "ref" */ + vdst = FETCH(2); /* range base */ + ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}", + vsrc1, ref, vdst, vdst+vsrc1-1); + + assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear + assert(vsrc1 <= 4); + + switch (vsrc1) { + case 4: + arg3 = GET_REGISTER(vdst+3); + /* fall through */ + case 3: + arg2 = GET_REGISTER(vdst+2); + /* fall through */ + case 2: + arg1 = GET_REGISTER(vdst+1); + /* fall through */ + case 1: + arg0 = GET_REGISTER(vdst+0); + /* fall through */ + default: // case 0 + ; + } + +#if INTERP_TYPE == INTERP_DBG + if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#else + if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#endif + } + FINISH(3); OP_END /* File: c/OP_INVOKE_DIRECT_EMPTY.c */ diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c index 52014f4e8..a46726f45 100644 --- a/vm/mterp/out/InterpC-portstd.c +++ b/vm/mterp/out/InterpC-portstd.c @@ -2991,8 +2991,49 @@ HANDLE_OPCODE(OP_EXECUTE_INLINE /*vB, {vD, vE, vF, vG}, inline@CCCC*/) FINISH(3); OP_END -/* File: c/OP_UNUSED_EF.c */ -HANDLE_OPCODE(OP_UNUSED_EF) +/* File: c/OP_EXECUTE_INLINE_RANGE.c */ +HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/) + { + u4 arg0, arg1, arg2, arg3; + arg0 = arg1 = arg2 = arg3 = 0; /* placate gcc */ + + EXPORT_PC(); + + vsrc1 = INST_AA(inst); /* #of args */ + ref = FETCH(1); /* inline call "ref" */ + vdst = FETCH(2); /* range base */ + ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}", + vsrc1, ref, vdst, vdst+vsrc1-1); + + assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear + assert(vsrc1 <= 4); + + switch (vsrc1) { + case 4: + arg3 = GET_REGISTER(vdst+3); + /* fall through */ + case 3: + arg2 = GET_REGISTER(vdst+2); + /* fall through */ + case 2: + arg1 = GET_REGISTER(vdst+1); + /* fall through */ + case 1: + arg0 = GET_REGISTER(vdst+0); + /* fall through */ + default: // case 0 + ; + } + +#if INTERP_TYPE == INTERP_DBG + if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#else + if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#endif + } + FINISH(3); OP_END /* File: c/OP_INVOKE_DIRECT_EMPTY.c */ diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c index 30a4e1ca7..e84d8d02a 100644 --- a/vm/mterp/out/InterpC-x86.c +++ b/vm/mterp/out/InterpC-x86.c @@ -1190,6 +1190,51 @@ GOTO_TARGET_DECL(exceptionThrown); FINISH(2); +/* File: c/OP_EXECUTE_INLINE_RANGE.c */ +HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/) + { + u4 arg0, arg1, arg2, arg3; + arg0 = arg1 = arg2 = arg3 = 0; /* placate gcc */ + + EXPORT_PC(); + + vsrc1 = INST_AA(inst); /* #of args */ + ref = FETCH(1); /* inline call "ref" */ + vdst = FETCH(2); /* range base */ + ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}", + vsrc1, ref, vdst, vdst+vsrc1-1); + + assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear + assert(vsrc1 <= 4); + + switch (vsrc1) { + case 4: + arg3 = GET_REGISTER(vdst+3); + /* fall through */ + case 3: + arg2 = GET_REGISTER(vdst+2); + /* fall through */ + case 2: + arg1 = GET_REGISTER(vdst+1); + /* fall through */ + case 1: + arg0 = GET_REGISTER(vdst+0); + /* fall through */ + default: // case 0 + ; + } + +#if INTERP_TYPE == INTERP_DBG + if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#else + if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)) + GOTO_exceptionThrown(); +#endif + } + FINISH(3); +OP_END + /* File: c/gotoTargets.c */ /* * C footer. This has some common code shared by the various targets. diff --git a/vm/mterp/x86/OP_UNUSED_EF.S b/vm/mterp/x86/OP_EXECUTE_INLINE_RANGE.S index 31d98c1f3..31d98c1f3 100644 --- a/vm/mterp/x86/OP_UNUSED_EF.S +++ b/vm/mterp/x86/OP_EXECUTE_INLINE_RANGE.S |
