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