summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2014-05-21 12:08:39 +0100
committer Vladimir Marko <vmarko@google.com> 2014-05-22 09:26:41 +0100
commita51a0b0300268b605e3ad71b0e87ff394032c5e7 (patch)
treea0a7be25a285c9249f13b968de48f393f6ea8500
parentd3236731ca6145e0723ce8aab8c6ff634ab021c2 (diff)
Method inlining across dex files in boot image.
Fix LoadCodeAddress() and LoadMethodAddress() to use the dex file in addition to the method index to uniquely identify the literal. With that fix in place, when we have both the direct code and the direct method, we can safely pass the actual target method id instead of the method id from the same dex file in the method lowering info. This was already done for calls from apps into boot image (and thus there was a bug with a tiny risk of the wrong literal being used) and now we also do that for calls within the boot image. The latter allows the inlining pass to inline many more methods than before in the boot image. Bug: 15021903 Change-Id: Ic765ce9809b43ef07e7db32b8e3fbc9acb09147f
-rw-r--r--compiler/dex/quick/codegen_util.cc28
-rw-r--r--compiler/dex/quick/mir_to_lir.h1
-rw-r--r--compiler/driver/compiler_driver.cc34
3 files changed, 37 insertions, 26 deletions
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index d58015a979..a3c94ed103 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -364,6 +364,18 @@ LIR* Mir2Lir::ScanLiteralPoolWide(LIR* data_target, int val_lo, int val_hi) {
return NULL;
}
+/* Search the existing constants in the literal pool for an exact method match */
+LIR* Mir2Lir::ScanLiteralPoolMethod(LIR* data_target, const MethodReference& method) {
+ while (data_target) {
+ if (static_cast<uint32_t>(data_target->operands[0]) == method.dex_method_index &&
+ UnwrapPointer(data_target->operands[1]) == method.dex_file) {
+ return data_target;
+ }
+ data_target = data_target->next;
+ }
+ return nullptr;
+}
+
/*
* The following are building blocks to insert constants into the pool or
* instruction streams.
@@ -1143,11 +1155,13 @@ void Mir2Lir::AddSlowPath(LIRSlowPath* slowpath) {
void Mir2Lir::LoadCodeAddress(const MethodReference& target_method, InvokeType type,
SpecialTargetRegister symbolic_reg) {
- int target_method_idx = target_method.dex_method_index;
- LIR* data_target = ScanLiteralPool(code_literal_list_, target_method_idx, 0);
+ LIR* data_target = ScanLiteralPoolMethod(code_literal_list_, target_method);
if (data_target == NULL) {
- data_target = AddWordData(&code_literal_list_, target_method_idx);
+ data_target = AddWordData(&code_literal_list_, target_method.dex_method_index);
data_target->operands[1] = WrapPointer(const_cast<DexFile*>(target_method.dex_file));
+ // NOTE: The invoke type doesn't contribute to the literal identity. In fact, we can have
+ // the same method invoked with kVirtual, kSuper and kInterface but the class linker will
+ // resolve these invokes to the same method, so we don't care which one we record here.
data_target->operands[2] = type;
}
LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
@@ -1157,11 +1171,13 @@ void Mir2Lir::LoadCodeAddress(const MethodReference& target_method, InvokeType t
void Mir2Lir::LoadMethodAddress(const MethodReference& target_method, InvokeType type,
SpecialTargetRegister symbolic_reg) {
- int target_method_idx = target_method.dex_method_index;
- LIR* data_target = ScanLiteralPool(method_literal_list_, target_method_idx, 0);
+ LIR* data_target = ScanLiteralPoolMethod(method_literal_list_, target_method);
if (data_target == NULL) {
- data_target = AddWordData(&method_literal_list_, target_method_idx);
+ data_target = AddWordData(&method_literal_list_, target_method.dex_method_index);
data_target->operands[1] = WrapPointer(const_cast<DexFile*>(target_method.dex_file));
+ // NOTE: The invoke type doesn't contribute to the literal identity. In fact, we can have
+ // the same method invoked with kVirtual, kSuper and kInterface but the class linker will
+ // resolve these invokes to the same method, so we don't care which one we record here.
data_target->operands[2] = type;
}
LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg), data_target);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 7f0bf30e68..454365ae14 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -610,6 +610,7 @@ class Mir2Lir : public Backend {
LIR* NewLIR5(int opcode, int dest, int src1, int src2, int info1, int info2);
LIR* ScanLiteralPool(LIR* data_target, int value, unsigned int delta);
LIR* ScanLiteralPoolWide(LIR* data_target, int val_lo, int val_hi);
+ LIR* ScanLiteralPoolMethod(LIR* data_target, const MethodReference& method);
LIR* AddWordData(LIR* *constant_list_p, int value);
LIR* AddWideData(LIR* *constant_list_p, int val_lo, int val_hi);
void ProcessSwitchTables();
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index eb62f1b577..b8c33a07e0 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1152,28 +1152,22 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType
*type = sharp_type;
}
} else {
- if (compiling_boot) {
+ bool method_in_image = compiling_boot ||
+ Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace();
+ if (method_in_image) {
+ CHECK(!method->IsAbstract());
*type = sharp_type;
- *direct_method = -1;
- *direct_code = -1;
+ *direct_method = compiling_boot ? -1 : reinterpret_cast<uintptr_t>(method);
+ *direct_code = compiling_boot ? -1 : compiler_->GetEntryPointOf(method);
+ target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+ target_method->dex_method_index = method->GetDexMethodIndex();
+ } else if (!must_use_direct_pointers) {
+ // Set the code and rely on the dex cache for the method.
+ *type = sharp_type;
+ *direct_code = compiler_->GetEntryPointOf(method);
} else {
- bool method_in_image =
- Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace();
- if (method_in_image) {
- CHECK(!method->IsAbstract());
- *type = sharp_type;
- *direct_method = reinterpret_cast<uintptr_t>(method);
- *direct_code = compiler_->GetEntryPointOf(method);
- target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
- target_method->dex_method_index = method->GetDexMethodIndex();
- } else if (!must_use_direct_pointers) {
- // Set the code and rely on the dex cache for the method.
- *type = sharp_type;
- *direct_code = compiler_->GetEntryPointOf(method);
- } else {
- // Direct pointers were required but none were available.
- VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
- }
+ // Direct pointers were required but none were available.
+ VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
}
}
}