summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
author Ian Rogers <irogers@google.com> 2012-10-08 17:46:47 -0700
committer Ian Rogers <irogers@google.com> 2012-10-09 14:16:35 -0700
commit137e88f798857321f4007631fdf052d2830ec2c4 (patch)
tree7ed6a166328adbc5109fbb5b07a1cdc4e3bbb739 /src/compiler
parent7469ebf3888b8037421cb6834f37f946646265ec (diff)
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
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/codegen/CodegenUtil.cc49
-rw-r--r--src/compiler/codegen/GenInvoke.cc90
-rw-r--r--src/compiler/codegen/MethodCodegenDriver.cc5
3 files changed, 101 insertions, 43 deletions
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index ccc2a83f7e..cf06c80643 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -650,38 +650,35 @@ void installLiteralPools(CompilationUnit* cUnit)
}
// Push code and method literals, record offsets for the compiler to patch.
dataLIR = cUnit->codeLiteralList;
- if (dataLIR != NULL) {
- while (dataLIR != NULL) {
- uint32_t target = dataLIR->operands[0];
- cUnit->compiler->AddCodePatch(cUnit->dex_file,
+ while (dataLIR != NULL) {
+ uint32_t target = dataLIR->operands[0];
+ cUnit->compiler->AddCodePatch(cUnit->dex_file,
+ cUnit->method_idx,
+ cUnit->invoke_type,
+ target,
+ static_cast<InvokeType>(dataLIR->operands[1]),
+ cUnit->codeBuffer.size());
+ const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
+ // unique based on target to ensure code deduplication works
+ uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
+ pushWord(cUnit->codeBuffer, unique_patch_value);
+ dataLIR = NEXT_LIR(dataLIR);
+ }
+ dataLIR = cUnit->methodLiteralList;
+ while (dataLIR != NULL) {
+ uint32_t target = dataLIR->operands[0];
+ cUnit->compiler->AddMethodPatch(cUnit->dex_file,
cUnit->method_idx,
cUnit->invoke_type,
target,
static_cast<InvokeType>(dataLIR->operands[1]),
cUnit->codeBuffer.size());
- const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
- // unique based on target to ensure code deduplication works
- uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
- pushWord(cUnit->codeBuffer, unique_patch_value);
- dataLIR = NEXT_LIR(dataLIR);
- }
- dataLIR = cUnit->methodLiteralList;
- while (dataLIR != NULL) {
- uint32_t target = dataLIR->operands[0];
- cUnit->compiler->AddMethodPatch(cUnit->dex_file,
- cUnit->method_idx,
- cUnit->invoke_type,
- target,
- static_cast<InvokeType>(dataLIR->operands[1]),
- cUnit->codeBuffer.size());
- const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
- // unique based on target to ensure code deduplication works
- uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
- pushWord(cUnit->codeBuffer, unique_patch_value);
- dataLIR = NEXT_LIR(dataLIR);
- }
+ const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
+ // unique based on target to ensure code deduplication works
+ uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
+ pushWord(cUnit->codeBuffer, unique_patch_value);
+ dataLIR = NEXT_LIR(dataLIR);
}
-
}
/* Write the switch tables to the output stream */
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index 3cc7c93511..0208a4afc5 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -188,7 +188,7 @@ int nextSDCallInsn(CompilationUnit* cUnit, CallInfo* info,
} 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 nextVCallInsn(CompilationUnit* cUnit, CallInfo* info,
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 @@ int nextVCallInsn(CompilationUnit* cUnit, CallInfo* info,
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 @@ int nextVCallInsnSP(CompilationUnit* cUnit, CallInfo* info, int state,
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,
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 3a80d1063c..3321c33cf6 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -83,8 +83,11 @@ void genInvoke(CompilationUnit* cUnit, CallInfo* info)
directMethod)
&& !SLOW_INVOKE_PATH;
if (info->type == kInterface) {
+ if (fastPath) {
+ pNullCk = &nullCk;
+ }
nextCallInsn = fastPath ? nextInterfaceCallInsn
- : nextInterfaceCallInsnWithAccessCheck;
+ : nextInterfaceCallInsnWithAccessCheck;
skipThis = false;
} else if (info->type == kDirect) {
if (fastPath) {