Add execute-inline/range instruction.
Like "execute-inline", this is an instruction generated by dexopt that
replaces a method invoke instruction. It's useful for small, frequently
called methods in the core libs.
As with execute-inline, we allow at most 4 arguments, but with /range
we're no longer limited to the low 16 registers.
Also: marked execute-inline as being able to throw an exception.
Needed: native x86 implementation; support in JIT.
For bug 2268232.
diff --git a/dexdump/DexDump.c b/dexdump/DexDump.c
index 6fed7aa..b3b0839 100644
--- a/dexdump/DexDump.c
+++ b/dexdump/DexDump.c
@@ -857,6 +857,18 @@
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 6a1a52a..97b707e 100644
--- a/dexdump/OpCodeNames.c
+++ b/dexdump/OpCodeNames.c
@@ -299,7 +299,7 @@
"^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 06e26bc..d1ebeec 100644
--- a/libdex/InstrUtils.c
+++ b/libdex/InstrUtils.c
@@ -302,6 +302,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 9728cd4..8449ae5 100644
--- a/libdex/InstrUtils.h
+++ b/libdex/InstrUtils.h
@@ -68,6 +68,7 @@
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 c3ed476..58d1702 100644
--- a/libdex/OpCode.h
+++ b/libdex/OpCode.h
@@ -343,7 +343,7 @@
/* 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 @@
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 eae335d..2e00ac4 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 911775c..942ac60 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -5412,6 +5412,7 @@
* 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 @@
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 b3e2d40..369d707 100644
--- a/vm/analysis/DexOptimize.c
+++ b/vm/analysis/DexOptimize.c
@@ -64,9 +64,11 @@
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 @@
}
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 @@
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 @@
* 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 @@
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 @@
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 bc314a2..758ebea 100644
--- a/vm/analysis/RegisterMap.c
+++ b/vm/analysis/RegisterMap.c
@@ -3000,6 +3000,7 @@
* 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 @@
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 fc5ecb9..d520d84 100644
--- a/vm/compiler/Dataflow.c
+++ b/vm/compiler/Dataflow.c
@@ -746,7 +746,7 @@
// 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 7ca905c..370c857 100644
--- a/vm/compiler/codegen/arm/Codegen.c
+++ b/vm/compiler/codegen/arm/Codegen.c
@@ -4005,6 +4005,13 @@
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 @@
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 eb0b76f..550bb83 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 0000000..4d62019
--- /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 faa7246..0000000
--- 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 0000000..a767106
--- /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 c5e1863..0000000
--- 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 b7139ca..cf5adb5 100644
--- a/vm/mterp/config-x86
+++ b/vm/mterp/config-x86
@@ -33,6 +33,8 @@
# 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 a4e5c43..9f9b9ff 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -7650,17 +7650,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 .LOP_EXECUTE_INLINE_continue @ make call; will return after
@@ -7673,12 +7674,33 @@
/* ------------------------------ */
.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 @@
.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 3bb5409..4a3f683 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -7310,17 +7310,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 .LOP_EXECUTE_INLINE_continue @ make call; will return after
@@ -7333,12 +7334,33 @@
/* ------------------------------ */
.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 @@
.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 52e536b..5fb231e 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -7650,17 +7650,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 .LOP_EXECUTE_INLINE_continue @ make call; will return after
@@ -7673,12 +7674,33 @@
/* ------------------------------ */
.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 @@
.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 401bb96..08d14d4 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -7254,17 +7254,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 .LOP_EXECUTE_INLINE_continue @ make call; will return after
@@ -7277,12 +7278,33 @@
/* ------------------------------ */
.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 @@
.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 4e6623c..3783abe 100644
--- a/vm/mterp/out/InterpAsm-x86.S
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -5857,12 +5857,18 @@
/* ------------------------------ */
.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 0ca466b..af45675 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -2888,8 +2888,49 @@
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 062eadc..fac2bea 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -3251,8 +3251,49 @@
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 52014f4..a46726f 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -2991,8 +2991,49 @@
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 30a4e1c..e84d8d0 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -1190,6 +1190,51 @@
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
similarity index 100%
rename from vm/mterp/x86/OP_UNUSED_EF.S
rename to vm/mterp/x86/OP_EXECUTE_INLINE_RANGE.S