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/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: