Fast path interface dispatch.
Interface dispatch when the method we're dispatching against is known
currently goes slow path. This change makes the load of the interface
method either a load of a constant or from the resolve methods table. It
also makes the null check on the "this" pointer inline.
Change-Id: I69571a062d3d693bee2dec6e46a456e0f74411cd
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index 3cc7c93..0208a4a 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -188,7 +188,7 @@
} else {
switch (state) {
case 0: // Get the current Method* [sets rARG0]
- // TUNING: we can save a reg copy if Method* has been promoted
+ // TUNING: we can save a reg copy if Method* has been promoted.
loadCurrMethodDirect(cUnit, rARG0);
break;
case 1: // Get method->dex_cache_resolved_methods_
@@ -247,16 +247,16 @@
int state, uint32_t dexIdx, uint32_t methodIdx,
uintptr_t unused, uintptr_t unused2, InvokeType unused3)
{
- RegLocation rlArg;
/*
* This is the fast path in which the target virtual method is
* fully resolved at compile time.
*/
switch (state) {
- case 0: // Get "this" [set rARG1]
- rlArg = info->args[0];
+ case 0: { // Get "this" [set rARG1]
+ RegLocation rlArg = info->args[0];
loadValueDirectFixed(cUnit, rlArg, rARG1);
break;
+ }
case 1: // Is "this" null? [use rARG1]
genNullCheck(cUnit, info->args[0].sRegLow, rARG1, info->optFlags);
// get this->klass_ [use rARG1, set rINVOKE_TGT]
@@ -283,6 +283,76 @@
return state + 1;
}
+/*
+ * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
+ * which will locate the target and continue on via a tail call.
+ */
+int nextInterfaceCallInsn(CompilationUnit* cUnit, CallInfo* info, int state,
+ uint32_t dexIdx, uint32_t unused, uintptr_t unused2,
+ uintptr_t directMethod, InvokeType unused4)
+{
+#if !defined(TARGET_ARM)
+ directMethod = 0;
+#endif
+#if !defined(TARGET_X86)
+ int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
+#endif
+
+ if (directMethod != 0) {
+ switch (state) {
+ case 0: // Load the trampoline target [sets rINVOKE_TGT].
+#if !defined(TARGET_X86)
+ loadWordDisp(cUnit, rSELF, trampoline, rINVOKE_TGT);
+#endif
+ // Get the interface Method* [sets rARG0]
+ if (directMethod != (uintptr_t)-1) {
+ loadConstant(cUnit, rARG0, directMethod);
+ } else {
+ LIR* dataTarget = scanLiteralPool(cUnit->methodLiteralList, dexIdx, 0);
+ if (dataTarget == NULL) {
+ dataTarget = addWordData(cUnit, &cUnit->methodLiteralList, dexIdx);
+ dataTarget->operands[1] = kInterface;
+ }
+#if defined(TARGET_ARM)
+ LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
+ kThumb2LdrPcRel12, rARG0, 0, 0, 0, 0,
+ dataTarget);
+ oatAppendLIR(cUnit, loadPcRel);
+#else
+ UNIMPLEMENTED(FATAL) << (void*)dataTarget;
+#endif
+ }
+ break;
+ default:
+ return -1;
+ }
+ } else {
+ switch (state) {
+ case 0:
+ // Get the current Method* [sets rARG0] - TUNING: remove copy of method if it is promoted.
+ loadCurrMethodDirect(cUnit, rARG0);
+ // Load the trampoline target [sets rINVOKE_TGT].
+#if !defined(TARGET_X86)
+ loadWordDisp(cUnit, rSELF, trampoline, rINVOKE_TGT);
+#endif
+ break;
+ case 1: // Get method->dex_cache_resolved_methods_ [set/use rARG0]
+ loadWordDisp(cUnit, rARG0,
+ AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
+ rARG0);
+ break;
+ case 2: // Grab target method* [set/use rARG0]
+ loadWordDisp(cUnit, rARG0,
+ Array::DataOffset(sizeof(Object*)).Int32Value() + dexIdx * 4,
+ rARG0);
+ break;
+ default:
+ return -1;
+ }
+ }
+ return state + 1;
+}
+
int nextInvokeInsnSP(CompilationUnit* cUnit, CallInfo* info, int trampoline,
int state, uint32_t dexIdx, uint32_t methodIdx)
{
@@ -335,18 +405,6 @@
return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
}
-/*
- * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
- * which will locate the target and continue on via a tail call.
- */
-int nextInterfaceCallInsn(CompilationUnit* cUnit, CallInfo* info, int state,
- uint32_t dexIdx, uint32_t unused, uintptr_t unused2,
- uintptr_t unused3, InvokeType unused4)
-{
- int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
- return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
-}
-
int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
CallInfo* info, int state,
uint32_t dexIdx, uint32_t unused,