summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2024-04-08 09:16:01 +0000
committer Vladimir Marko <vmarko@google.com> 2024-04-08 13:15:12 +0000
commit68e9af2dd02a63d0b4f0bebabc4d76c91e2d84e0 (patch)
treee7096115d32e16b335e8baeeae86271d828e9253 /runtime/class_linker.cc
parentcfff041514b432f245907d0d1e0c10948759ffc9 (diff)
ART Faster `LinkCode()` in `ClassLinker`.
Make `LinkCode()` a member of `ClassLinker` and speed it up by avoiding a linear (but fast) method code lookup using the `BitVector::NumSetBits()`, avoiding related function call overhead as well as pulling some invariant checks out of the calling loops and eliminating redundant checks. For a test class with 1000 unannotated static methods and 400 @NeverCompile static methods, this change reduces the time needed by `ClassLinker::LoadClass()` by roughly 25%. Test: m test-art-host-gtest Test: testrunner.py --host --optimizing Bug: 329196666 Change-Id: Ifeae520113594acae2e5c19ba746f11ede2dfac2
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc84
1 files changed, 68 insertions, 16 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 9f463ada75..ce75c2dd35 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3744,10 +3744,67 @@ inline void EnsureThrowsInvocationError(ClassLinker* class_linker, ArtMethod* me
class_linker->GetImagePointerSize());
}
-static void LinkCode(ClassLinker* class_linker,
- ArtMethod* method,
- const OatFile::OatClass* oat_class,
- uint32_t class_def_method_index) REQUIRES_SHARED(Locks::mutator_lock_) {
+class ClassLinker::OatClassCodeIterator {
+ public:
+ explicit OatClassCodeIterator(const OatFile::OatClass& oat_class)
+ : begin_(oat_class.methods_pointer_ != nullptr && oat_class.oat_file_->IsExecutable()
+ ? oat_class.oat_file_->Begin()
+ : nullptr),
+ bitmap_(oat_class.bitmap_),
+ current_(oat_class.methods_pointer_ != nullptr && oat_class.oat_file_->IsExecutable()
+ ? oat_class.methods_pointer_
+ : nullptr),
+ method_index_(0u),
+ num_methods_(oat_class.num_methods_) {
+ DCHECK_EQ(bitmap_ != nullptr, oat_class.GetType() == OatClassType::kSomeCompiled);
+ }
+
+ const void* GetAndAdvance(uint32_t method_index) {
+ if (kIsDebugBuild) {
+ CHECK_EQ(method_index, method_index_);
+ ++method_index_;
+ }
+ if (current_ == nullptr) {
+ // We may not have a valid `num_methods_` to perform the next `DCHECK()`.
+ return nullptr;
+ }
+ DCHECK_LT(method_index, num_methods_);
+ DCHECK(begin_ != nullptr);
+ if (bitmap_ == nullptr || BitVector::IsBitSet(bitmap_, method_index)) {
+ DCHECK_NE(current_->code_offset_, 0u);
+ const void* result = begin_ + current_->code_offset_;
+ ++current_;
+ return result;
+ } else {
+ return nullptr;
+ }
+ }
+
+ void SkipAbstract(uint32_t method_index) {
+ if (kIsDebugBuild) {
+ CHECK_EQ(method_index, method_index_);
+ ++method_index_;
+ if (current_ != nullptr) {
+ CHECK_LT(method_index, num_methods_);
+ CHECK(bitmap_ != nullptr);
+ CHECK(!BitVector::IsBitSet(bitmap_, method_index));
+ }
+ }
+ }
+
+ private:
+ const uint8_t* const begin_;
+ const uint32_t* const bitmap_;
+ const OatMethodOffsets* current_;
+
+ // Debug mode members.
+ uint32_t method_index_;
+ const uint32_t num_methods_;
+};
+
+inline void ClassLinker::LinkCode(ArtMethod* method,
+ uint32_t class_def_method_index,
+ /*inout*/ OatClassCodeIterator* occi) {
ScopedAssertNoThreadSuspension sants(__FUNCTION__);
Runtime* const runtime = Runtime::Current();
if (runtime->IsAotCompiler()) {
@@ -3760,19 +3817,14 @@ static void LinkCode(ClassLinker* class_linker,
DCHECK(!method->GetDeclaringClass()->IsVisiblyInitialized()); // Actually ClassStatus::Idx.
if (!method->IsInvokable()) {
- EnsureThrowsInvocationError(class_linker, method);
+ EnsureThrowsInvocationError(this, method);
+ occi->SkipAbstract(class_def_method_index);
return;
}
- const void* quick_code = nullptr;
- if (oat_class != nullptr) {
- // Every kind of method should at least get an invoke stub from the oat_method.
- // non-abstract methods also get their code pointers.
- const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index);
- quick_code = oat_method.GetQuickCode();
- }
+ const void* quick_code = occi->GetAndAdvance(class_def_method_index);
if (method->IsNative() && quick_code == nullptr) {
- const void* boot_jni_stub = class_linker->FindBootJniStub(method);
+ const void* boot_jni_stub = FindBootJniStub(method);
if (boot_jni_stub != nullptr) {
// Use boot JNI stub if found.
quick_code = boot_jni_stub;
@@ -3926,7 +3978,7 @@ void ClassLinker::LoadClass(Thread* self,
const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler())
? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class)
: OatFile::OatClass::Invalid();
- const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;
+ OatClassCodeIterator occi(oat_class);
klass->SetMethodsPtr(
AllocArtMethodArray(self, allocator, accessor.NumMethods()),
accessor.NumDirectMethods(),
@@ -3963,7 +4015,7 @@ void ClassLinker::LoadClass(Thread* self,
ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index,
image_pointer_size_);
LoadMethod(dex_file, method, klass.Get(), &mai_direct, art_method);
- LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
+ LinkCode(art_method, class_def_method_index, &occi);
uint32_t it_method_index = method.GetIndex();
if (last_dex_method_index == it_method_index) {
// duplicate case
@@ -3981,7 +4033,7 @@ void ClassLinker::LoadClass(Thread* self,
image_pointer_size_);
art_method->ResetCounter(hotness_threshold);
LoadMethod(dex_file, method, klass.Get(), &mai_virtual, art_method);
- LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
+ LinkCode(art_method, class_def_method_index, &occi);
++class_def_method_index;
});