Optimize IMT
* Remove IMT for classes which do not implement interfaces
* Remove IMT for array classes
* Share same IMT
Saved memory (measured on hammerhead):
boot.art:
Total number of classes: 3854
Number of affected classes: 1637
Saved memory: 409kB
Chrome (excluding classes in boot.art):
Total number of classes: 2409
Number of affected classes: 1259
Saved memory: 314kB
Google Maps (excluding classes in boot.art):
Total number of classes: 6988
Number of affected classes: 2574
Saved memory: 643kB
Performance regression on benchmarks/InvokeInterface.java benchmark
(measured timeCall10Interface)
1st launch: 9.6%
2nd launch: 6.8%
Change-Id: If07e45390014a6ee8f3c1c4ca095b43046f0871f
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index fc62573..916ca29 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -559,9 +559,10 @@
}
}
case kInterface: {
- uint32_t imt_index = resolved_method->GetDexMethodIndex() % mirror::Class::kImtSize;
- ArtMethod* imt_method = (*this_object)->GetClass()->GetEmbeddedImTableEntry(
- imt_index, class_linker->GetImagePointerSize());
+ uint32_t imt_index = resolved_method->GetDexMethodIndex() % ImTable::kSize;
+ size_t pointer_size = class_linker->GetImagePointerSize();
+ ArtMethod* imt_method = (*this_object)->GetClass()->GetImt(pointer_size)->
+ Get(imt_index, pointer_size);
if (!imt_method->IsRuntimeMethod()) {
if (kIsDebugBuild) {
mirror::Class* klass = (*this_object)->GetClass();
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 03771aa..7175d54 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2169,13 +2169,13 @@
dex_method_idx, sizeof(void*));
DCHECK(interface_method != nullptr) << dex_method_idx << " " << PrettyMethod(caller_method);
ArtMethod* method = nullptr;
+ ImTable* imt = cls->GetImt(sizeof(void*));
if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
// If the dex cache already resolved the interface method, look whether we have
// a match in the ImtConflictTable.
uint32_t imt_index = interface_method->GetDexMethodIndex();
- ArtMethod* conflict_method = cls->GetEmbeddedImTableEntry(
- imt_index % mirror::Class::kImtSize, sizeof(void*));
+ ArtMethod* conflict_method = imt->Get(imt_index % ImTable::kSize, sizeof(void*));
if (LIKELY(conflict_method->IsRuntimeMethod())) {
ImtConflictTable* current_table = conflict_method->GetImtConflictTable(sizeof(void*));
DCHECK(current_table != nullptr);
@@ -2227,8 +2227,7 @@
// We arrive here if we have found an implementation, and it is not in the ImtConflictTable.
// We create a new table with the new pair { interface_method, method }.
uint32_t imt_index = interface_method->GetDexMethodIndex();
- ArtMethod* conflict_method = cls->GetEmbeddedImTableEntry(
- imt_index % mirror::Class::kImtSize, sizeof(void*));
+ ArtMethod* conflict_method = imt->Get(imt_index % ImTable::kSize, sizeof(void*));
if (conflict_method->IsRuntimeMethod()) {
ArtMethod* new_conflict_method = Runtime::Current()->GetClassLinker()->AddMethodToConflictTable(
cls.Get(),
@@ -2239,9 +2238,9 @@
if (new_conflict_method != conflict_method) {
// Update the IMT if we create a new conflict method. No fence needed here, as the
// data is consistent.
- cls->SetEmbeddedImTableEntry(imt_index % mirror::Class::kImtSize,
- new_conflict_method,
- sizeof(void*));
+ imt->Set(imt_index % ImTable::kSize,
+ new_conflict_method,
+ sizeof(void*));
}
}