diff options
author | David Srbecky <dsrbecky@google.com> | 2018-11-14 14:21:23 +0000 |
---|---|---|
committer | David Srbecky <dsrbecky@google.com> | 2018-11-27 17:31:01 +0000 |
commit | e36e7f2226e4e08b7a7094f78cb80bbe0e729c2b (patch) | |
tree | 0787ae19a232728121a60791f3a18094529120f1 | |
parent | 244470afafdb1c5aba17507ef793d316b9c4d038 (diff) | |
download | android_art-e36e7f2226e4e08b7a7094f78cb80bbe0e729c2b.tar.gz android_art-e36e7f2226e4e08b7a7094f78cb80bbe0e729c2b.tar.bz2 android_art-e36e7f2226e4e08b7a7094f78cb80bbe0e729c2b.zip |
Store ImtIndex in ArtMethod.
This avoids recalculation and reduces pressure on the thread local cache.
This halves the time we spend hashing from 2% to 1% (maps on device).
Test: ./art/test.py -b --host --64
Change-Id: I2407bd9c222de4ddc6eea938908a1ac6d7abc35b
-rw-r--r-- | runtime/art_method-inl.h | 26 | ||||
-rw-r--r-- | runtime/art_method.h | 30 | ||||
-rw-r--r-- | runtime/class_linker.cc | 10 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils-inl.h | 8 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 2 | ||||
-rw-r--r-- | runtime/image.cc | 2 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_cache.h | 1 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 5 | ||||
-rw-r--r-- | runtime/jit/profile_saver.cc | 2 |
9 files changed, 52 insertions, 34 deletions
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index f2541160ff..c240017900 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -31,6 +31,7 @@ #include "dex/invoke_type.h" #include "dex/primitive.h" #include "gc_root-inl.h" +#include "imtable-inl.h" #include "intrinsics_enum.h" #include "jit/profiling_info.h" #include "mirror/class-inl.h" @@ -421,6 +422,31 @@ inline CodeItemDebugInfoAccessor ArtMethod::DexInstructionDebugInfo() { return CodeItemDebugInfoAccessor(*GetDexFile(), GetCodeItem(), GetDexMethodIndex()); } +inline void ArtMethod::SetCounter(int16_t hotness_count) { + DCHECK(!IsAbstract()) << PrettyMethod(); + hotness_count_ = hotness_count; +} + +inline uint16_t ArtMethod::GetCounter() { + DCHECK(!IsAbstract()) << PrettyMethod(); + return hotness_count_; +} + +inline uint32_t ArtMethod::GetImtIndex() { + if (LIKELY(IsAbstract() && imt_index_ != 0)) { + uint16_t imt_index = ~imt_index_; + DCHECK_EQ(imt_index, ImTable::GetImtIndex(this)) << PrettyMethod(); + return imt_index; + } else { + return ImTable::GetImtIndex(this); + } +} + +inline void ArtMethod::CalculateAndSetImtIndex() { + DCHECK(IsAbstract()) << PrettyMethod(); + imt_index_ = ~ImTable::GetImtIndex(this); +} + } // namespace art #endif // ART_RUNTIME_ART_METHOD_INL_H_ diff --git a/runtime/art_method.h b/runtime/art_method.h index 5bbee92c14..cc214f7ca3 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -650,24 +650,13 @@ class ArtMethod final { void CopyFrom(ArtMethod* src, PointerSize image_pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); - // Note, hotness_counter_ updates are non-atomic but it doesn't need to be precise. Also, - // given that the counter is only 16 bits wide we can expect wrap-around in some - // situations. Consumers of hotness_count_ must be able to deal with that. - uint16_t IncrementCounter() { - return ++hotness_count_; - } + ALWAYS_INLINE void SetCounter(int16_t hotness_count) REQUIRES_SHARED(Locks::mutator_lock_); - void ClearCounter() { - hotness_count_ = 0; - } + ALWAYS_INLINE uint16_t GetCounter() REQUIRES_SHARED(Locks::mutator_lock_); - void SetCounter(int16_t hotness_count) { - hotness_count_ = hotness_count; - } + ALWAYS_INLINE uint32_t GetImtIndex() REQUIRES_SHARED(Locks::mutator_lock_); - uint16_t GetCounter() const { - return hotness_count_; - } + void CalculateAndSetImtIndex() REQUIRES_SHARED(Locks::mutator_lock_); static constexpr MemberOffset HotnessCountOffset() { return MemberOffset(OFFSETOF_MEMBER(ArtMethod, hotness_count_)); @@ -772,9 +761,14 @@ class ArtMethod final { // ifTable. uint16_t method_index_; - // The hotness we measure for this method. Not atomic, as we allow - // missing increments: if the method is hot, we will see it eventually. - uint16_t hotness_count_; + union { + // Non-abstract methods: The hotness we measure for this method. Not atomic, + // as we allow missing increments: if the method is hot, we will see it eventually. + uint16_t hotness_count_; + // Abstract methods: IMT index (bitwise negated) or zero if it was not cached. + // The negation is needed to distinguish zero index and missing cached entry. + uint16_t imt_index_; + }; // Fake padding field gets inserted here. diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 03cb95ccaa..820dea3ef4 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3634,6 +3634,10 @@ void ClassLinker::LoadMethod(const DexFile& dex_file, dex_file, dst->GetClassDef(), dex_method_idx); } dst->SetAccessFlags(access_flags); + // Must be done after SetAccessFlags since IsAbstract depends on it. + if (klass->IsInterface() && dst->IsAbstract()) { + dst->CalculateAndSetImtIndex(); + } } void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) { @@ -6723,7 +6727,7 @@ void ClassLinker::FillIMTFromIfTable(ObjPtr<mirror::IfTable> if_table, // or interface methods in the IMT here they will not create extra conflicts since we compare // names and signatures in SetIMTRef. ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_); - const uint32_t imt_index = ImTable::GetImtIndex(interface_method); + const uint32_t imt_index = interface_method->GetImtIndex(); // There is only any conflicts if all of the interface methods for an IMT slot don't have // the same implementation method, keep track of this to avoid creating a conflict table in @@ -6777,7 +6781,7 @@ void ClassLinker::FillIMTFromIfTable(ObjPtr<mirror::IfTable> if_table, } DCHECK(implementation_method != nullptr); ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_); - const uint32_t imt_index = ImTable::GetImtIndex(interface_method); + const uint32_t imt_index = interface_method->GetImtIndex(); if (!imt[imt_index]->IsRuntimeMethod() || imt[imt_index] == unimplemented_method || imt[imt_index] == imt_conflict_method) { @@ -7703,7 +7707,7 @@ bool ClassLinker::LinkInterfaceMethods( auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, image_pointer_size_); MethodNameAndSignatureComparator interface_name_comparator( interface_method->GetInterfaceMethodIfProxy(image_pointer_size_)); - uint32_t imt_index = ImTable::GetImtIndex(interface_method); + uint32_t imt_index = interface_method->GetImtIndex(); ArtMethod** imt_ptr = &out_imt[imt_index]; // For each method listed in the interface's method list, find the // matching method in our class's method list. We want to favor the diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 2236e61d75..a18cca4cb2 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -533,13 +533,7 @@ ALWAYS_INLINE ArtMethod* FindMethodToCall(uint32_t method_idx, UNREACHABLE(); } case kInterface: { - size_t imt_index; - InterpreterCache* tls_cache = self->GetInterpreterCache(); - if (UNLIKELY(!tls_cache->Get(resolved_method, &imt_index))) { - imt_index = ImTable::GetImtIndex(resolved_method); - tls_cache->Set(resolved_method, imt_index); - } - DCHECK_EQ(imt_index, ImTable::GetImtIndex(resolved_method)); + size_t imt_index = resolved_method->GetImtIndex(); PointerSize pointer_size = class_linker->GetImagePointerSize(); ObjPtr<mirror::Class> klass = (*this_object)->GetClass(); ArtMethod* imt_method = klass->GetImt(pointer_size)->Get(imt_index, pointer_size); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 147249000f..b6adcf070d 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -2671,7 +2671,7 @@ extern "C" TwoWordReturn artInvokeInterfaceTrampoline(ArtMethod* interface_metho DCHECK(!interface_method->IsRuntimeMethod()); // Look whether we have a match in the ImtConflictTable. - uint32_t imt_index = ImTable::GetImtIndex(interface_method); + uint32_t imt_index = interface_method->GetImtIndex(); ArtMethod* conflict_method = imt->Get(imt_index, kRuntimePointerSize); if (LIKELY(conflict_method->IsRuntimeMethod())) { ImtConflictTable* current_table = conflict_method->GetImtConflictTable(kRuntimePointerSize); diff --git a/runtime/image.cc b/runtime/image.cc index 3023cefd66..f50c39c3d5 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -26,7 +26,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '9', '\0' }; // Remove boot oat extents. +const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '0', '\0' }; // Store ImtIndex. ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/interpreter/interpreter_cache.h b/runtime/interpreter/interpreter_cache.h index 355058f4f6..003ea6c8d3 100644 --- a/runtime/interpreter/interpreter_cache.h +++ b/runtime/interpreter/interpreter_cache.h @@ -38,7 +38,6 @@ class Thread; // iget/iput: The field offset. The field must be non-volatile. // sget/sput: The ArtField* pointer. The field must be non-volitile. // invoke: The ArtMethod* pointer (before vtable indirection, etc). -// ArtMethod*: The ImtIndex of the method. // // We ensure consistency of the cache by clearing it // whenever any dex file is unloaded. diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index ff39a66906..28978c5819 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -892,7 +892,8 @@ void JitCodeCache::CopyInlineCacheInto(const InlineCache& ic, } } -static void ClearMethodCounter(ArtMethod* method, bool was_warm) { +static void ClearMethodCounter(ArtMethod* method, bool was_warm) + REQUIRES_SHARED(Locks::mutator_lock_) { if (was_warm) { method->SetPreviouslyWarm(); } @@ -1128,7 +1129,7 @@ bool JitCodeCache::RemoveMethod(ArtMethod* method, bool release_memory) { return false; } - method->ClearCounter(); + method->SetCounter(0); Runtime::Current()->GetInstrumentation()->UpdateMethodsCode( method, GetQuickToInterpreterBridge()); VLOG(jit) diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc index e3248eaf24..c8d4728589 100644 --- a/runtime/jit/profile_saver.cc +++ b/runtime/jit/profile_saver.cc @@ -362,7 +362,7 @@ static void SampleClassesAndExecutedMethods(pthread_t profiler_pthread, } // Visit all of the methods in the class to see which ones were executed. for (ArtMethod& method : klass->GetMethods(kRuntimePointerSize)) { - if (!method.IsNative()) { + if (!method.IsNative() && !method.IsAbstract()) { DCHECK(!method.IsProxyMethod()); const uint16_t counter = method.GetCounter(); // Mark startup methods as hot if they have more than hot_method_sample_threshold |