diff options
author | 2025-02-05 11:36:53 +0000 | |
---|---|---|
committer | 2025-02-05 07:41:24 -0800 | |
commit | ef5054636ca350b94adef6906d2d51992ca4531c (patch) | |
tree | 63db24be4c8530617bfda39dd5085e5e7bd127fa /runtime/class_linker.cc | |
parent | a7045d8fd8a38b447b176e93c81765540863c1c9 (diff) |
Refactor `ImTable::GetImtIndex()`.
Make it easier to calculate the IMT index without an actual
`ArtMethod` in preparation for a significant refactoring of
`ClassLinker::LoadClass()`.
Update documentation of `ArtMethod::imt_index_` which is
actually unused for abstract non-interface methods.
Also reorder code in `ClassLinker` without any modification
to make it easier to compare the differences in the upcoming
refactoring.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 329196666
Change-Id: Ic71ff323ea92325958d59536e83ab70d057b94df
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 294 |
1 files changed, 147 insertions, 147 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 73c90f58ac..57eb72dea5 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3827,44 +3827,6 @@ class ClassLinker::OatClassCodeIterator { 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()) { - // The following code only applies to a non-compiler runtime. - return; - } - - // Method shouldn't have already been linked. - DCHECK_EQ(method->GetEntryPointFromQuickCompiledCode(), nullptr); - DCHECK(!method->GetDeclaringClass()->IsVisiblyInitialized()); // Actually ClassStatus::Idx. - - if (!method->IsInvokable()) { - EnsureThrowsInvocationError(this, method); - occi->SkipAbstract(class_def_method_index); - return; - } - - const void* quick_code = occi->GetAndAdvance(class_def_method_index); - if (method->IsNative() && quick_code == nullptr) { - const void* boot_jni_stub = FindBootJniStub(method); - if (boot_jni_stub != nullptr) { - // Use boot JNI stub if found. - quick_code = boot_jni_stub; - } - } - runtime->GetInstrumentation()->InitializeMethodsCode(method, quick_code); - - if (method->IsNative()) { - // Set up the dlsym lookup stub. Do not go through `UnregisterNative()` - // as the extra processing for @CriticalNative is not needed yet. - method->SetEntryPointFromJni( - method->IsCriticalNative() ? GetJniDlsymLookupCriticalStub() : GetJniDlsymLookupStub()); - } -} - void ClassLinker::SetupClass(const DexFile& dex_file, const dex::ClassDef& dex_class_def, Handle<mirror::Class> klass, @@ -3968,6 +3930,153 @@ class ClassLinker::MethodAnnotationsIterator { const dex::MethodAnnotationsItem* const end_; }; +void ClassLinker::LoadField(const ClassAccessor::Field& field, + Handle<mirror::Class> klass, + ArtField* dst) { + const uint32_t field_idx = field.GetIndex(); + dst->SetDexFieldIndex(field_idx); + dst->SetDeclaringClass(klass.Get()); + + // Get access flags from the DexFile and set hiddenapi runtime access flags. + dst->SetAccessFlags(field.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(field)); +} + +void ClassLinker::LoadMethod(const DexFile& dex_file, + const ClassAccessor::Method& method, + ObjPtr<mirror::Class> klass, + /*inout*/ MethodAnnotationsIterator* mai, + /*out*/ ArtMethod* dst) { + ScopedAssertNoThreadSuspension sants(__FUNCTION__); + + const uint32_t dex_method_idx = method.GetIndex(); + const dex::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); + uint32_t name_utf16_length; + const char* method_name = dex_file.GetStringDataAndUtf16Length(method_id.name_idx_, + &name_utf16_length); + std::string_view shorty = dex_file.GetShortyView(dex_file.GetProtoId(method_id.proto_idx_)); + + dst->SetDexMethodIndex(dex_method_idx); + dst->SetDeclaringClass(klass); + + // Get access flags from the DexFile and set hiddenapi runtime access flags. + uint32_t access_flags = method.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(method); + + auto has_ascii_name = [method_name, name_utf16_length](const char* ascii_name, + size_t length) ALWAYS_INLINE { + DCHECK_EQ(strlen(ascii_name), length); + return length == name_utf16_length && + method_name[length] == 0 && // Is `method_name` an ASCII string? + memcmp(ascii_name, method_name, length) == 0; + }; + if (UNLIKELY(has_ascii_name("finalize", sizeof("finalize") - 1u))) { + // Set finalizable flag on declaring class if the method has the right signature. + // When initializing without a boot image, `Object` and `Enum` shall have the finalizable + // flag cleared immediately after loading these classes, see `InitWithoutImage()`. + if (shorty == "V") { + klass->SetFinalizable(); + } + } else if (method_name[0] == '<') { + // Fix broken access flags for initializers. Bug 11157540. + // `DexFileVerifier` rejects method names starting with '<' other than constructors. + DCHECK(has_ascii_name("<init>", sizeof("<init>") - 1u) || + has_ascii_name("<clinit>", sizeof("<clinit>") - 1u)) << method_name; + if (UNLIKELY((access_flags & kAccConstructor) == 0)) { + LOG(WARNING) << method_name << " didn't have expected constructor access flag in class " + << klass->PrettyDescriptor() << " in dex file " << dex_file.GetLocation(); + access_flags |= kAccConstructor; + } + } + + access_flags |= GetNterpFastPathFlags(shorty, access_flags, kRuntimeQuickCodeISA); + + if (UNLIKELY((access_flags & kAccNative) != 0u)) { + // Check if the native method is annotated with @FastNative or @CriticalNative. + const dex::MethodAnnotationsItem* method_annotations = mai->AdvanceTo(dex_method_idx); + if (method_annotations != nullptr) { + access_flags |= + annotations::GetNativeMethodAnnotationAccessFlags(dex_file, *method_annotations); + } + dst->SetAccessFlags(access_flags); + DCHECK(!dst->IsAbstract()); + DCHECK(!dst->HasCodeItem()); + DCHECK_EQ(method.GetCodeItemOffset(), 0u); + dst->SetDataPtrSize(nullptr, image_pointer_size_); // JNI stub/trampoline not linked yet. + } else if ((access_flags & kAccAbstract) != 0u) { + dst->SetAccessFlags(access_flags); + // Must be done after SetAccessFlags since IsAbstract depends on it. + DCHECK(dst->IsAbstract()); + if (klass->IsInterface()) { + dst->CalculateAndSetImtIndex(); + } + DCHECK(!dst->HasCodeItem()); + DCHECK_EQ(method.GetCodeItemOffset(), 0u); + dst->SetDataPtrSize(nullptr, image_pointer_size_); // Single implementation not set yet. + } else { + const dex::MethodAnnotationsItem* method_annotations = mai->AdvanceTo(dex_method_idx); + if (method_annotations != nullptr && + annotations::MethodIsNeverCompile(dex_file, *method_annotations)) { + access_flags |= kAccCompileDontBother; + } + dst->SetAccessFlags(access_flags); + DCHECK(!dst->IsAbstract()); + DCHECK(dst->HasCodeItem()); + uint32_t code_item_offset = method.GetCodeItemOffset(); + DCHECK_NE(code_item_offset, 0u); + if (Runtime::Current()->IsAotCompiler()) { + dst->SetDataPtrSize(reinterpret_cast32<void*>(code_item_offset), image_pointer_size_); + } else { + dst->SetCodeItem(dex_file.GetCodeItem(code_item_offset), dex_file.IsCompactDexFile()); + } + } + + if ((access_flags & kAccAbstract) == 0u && + Runtime::Current()->IsZygote() && + !Runtime::Current()->GetJITOptions()->GetProfileSaverOptions().GetProfileBootClassPath()) { + DCHECK(!ArtMethod::IsAbstract(access_flags)); + DCHECK(!ArtMethod::IsIntrinsic(access_flags)); + dst->SetMemorySharedMethod(); + dst->SetHotCounter(); + } +} + +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()) { + // The following code only applies to a non-compiler runtime. + return; + } + + // Method shouldn't have already been linked. + DCHECK_EQ(method->GetEntryPointFromQuickCompiledCode(), nullptr); + DCHECK(!method->GetDeclaringClass()->IsVisiblyInitialized()); // Actually ClassStatus::Idx. + + if (!method->IsInvokable()) { + EnsureThrowsInvocationError(this, method); + occi->SkipAbstract(class_def_method_index); + return; + } + + const void* quick_code = occi->GetAndAdvance(class_def_method_index); + if (method->IsNative() && quick_code == nullptr) { + const void* boot_jni_stub = FindBootJniStub(method); + if (boot_jni_stub != nullptr) { + // Use boot JNI stub if found. + quick_code = boot_jni_stub; + } + } + runtime->GetInstrumentation()->InitializeMethodsCode(method, quick_code); + + if (method->IsNative()) { + // Set up the dlsym lookup stub. Do not go through `UnregisterNative()` + // as the extra processing for @CriticalNative is not needed yet. + method->SetEntryPointFromJni( + method->IsCriticalNative() ? GetJniDlsymLookupCriticalStub() : GetJniDlsymLookupStub()); + } +} + void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file, const dex::ClassDef& dex_class_def, @@ -4090,115 +4199,6 @@ void ClassLinker::LoadClass(Thread* self, self->AllowThreadSuspension(); } -void ClassLinker::LoadField(const ClassAccessor::Field& field, - Handle<mirror::Class> klass, - ArtField* dst) { - const uint32_t field_idx = field.GetIndex(); - dst->SetDexFieldIndex(field_idx); - dst->SetDeclaringClass(klass.Get()); - - // Get access flags from the DexFile and set hiddenapi runtime access flags. - dst->SetAccessFlags(field.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(field)); -} - -void ClassLinker::LoadMethod(const DexFile& dex_file, - const ClassAccessor::Method& method, - ObjPtr<mirror::Class> klass, - /*inout*/ MethodAnnotationsIterator* mai, - /*out*/ ArtMethod* dst) { - ScopedAssertNoThreadSuspension sants(__FUNCTION__); - - const uint32_t dex_method_idx = method.GetIndex(); - const dex::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); - uint32_t name_utf16_length; - const char* method_name = dex_file.GetStringDataAndUtf16Length(method_id.name_idx_, - &name_utf16_length); - std::string_view shorty = dex_file.GetShortyView(dex_file.GetProtoId(method_id.proto_idx_)); - - dst->SetDexMethodIndex(dex_method_idx); - dst->SetDeclaringClass(klass); - - // Get access flags from the DexFile and set hiddenapi runtime access flags. - uint32_t access_flags = method.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(method); - - auto has_ascii_name = [method_name, name_utf16_length](const char* ascii_name, - size_t length) ALWAYS_INLINE { - DCHECK_EQ(strlen(ascii_name), length); - return length == name_utf16_length && - method_name[length] == 0 && // Is `method_name` an ASCII string? - memcmp(ascii_name, method_name, length) == 0; - }; - if (UNLIKELY(has_ascii_name("finalize", sizeof("finalize") - 1u))) { - // Set finalizable flag on declaring class if the method has the right signature. - // When initializing without a boot image, `Object` and `Enum` shall have the finalizable - // flag cleared immediately after loading these classes, see `InitWithoutImage()`. - if (shorty == "V") { - klass->SetFinalizable(); - } - } else if (method_name[0] == '<') { - // Fix broken access flags for initializers. Bug 11157540. - // `DexFileVerifier` rejects method names starting with '<' other than constructors. - DCHECK(has_ascii_name("<init>", sizeof("<init>") - 1u) || - has_ascii_name("<clinit>", sizeof("<clinit>") - 1u)) << method_name; - if (UNLIKELY((access_flags & kAccConstructor) == 0)) { - LOG(WARNING) << method_name << " didn't have expected constructor access flag in class " - << klass->PrettyDescriptor() << " in dex file " << dex_file.GetLocation(); - access_flags |= kAccConstructor; - } - } - - access_flags |= GetNterpFastPathFlags(shorty, access_flags, kRuntimeQuickCodeISA); - - if (UNLIKELY((access_flags & kAccNative) != 0u)) { - // Check if the native method is annotated with @FastNative or @CriticalNative. - const dex::MethodAnnotationsItem* method_annotations = mai->AdvanceTo(dex_method_idx); - if (method_annotations != nullptr) { - access_flags |= - annotations::GetNativeMethodAnnotationAccessFlags(dex_file, *method_annotations); - } - dst->SetAccessFlags(access_flags); - DCHECK(!dst->IsAbstract()); - DCHECK(!dst->HasCodeItem()); - DCHECK_EQ(method.GetCodeItemOffset(), 0u); - dst->SetDataPtrSize(nullptr, image_pointer_size_); // JNI stub/trampoline not linked yet. - } else if ((access_flags & kAccAbstract) != 0u) { - dst->SetAccessFlags(access_flags); - // Must be done after SetAccessFlags since IsAbstract depends on it. - DCHECK(dst->IsAbstract()); - if (klass->IsInterface()) { - dst->CalculateAndSetImtIndex(); - } - DCHECK(!dst->HasCodeItem()); - DCHECK_EQ(method.GetCodeItemOffset(), 0u); - dst->SetDataPtrSize(nullptr, image_pointer_size_); // Single implementation not set yet. - } else { - const dex::MethodAnnotationsItem* method_annotations = mai->AdvanceTo(dex_method_idx); - if (method_annotations != nullptr && - annotations::MethodIsNeverCompile(dex_file, *method_annotations)) { - access_flags |= kAccCompileDontBother; - } - dst->SetAccessFlags(access_flags); - DCHECK(!dst->IsAbstract()); - DCHECK(dst->HasCodeItem()); - uint32_t code_item_offset = method.GetCodeItemOffset(); - DCHECK_NE(code_item_offset, 0u); - if (Runtime::Current()->IsAotCompiler()) { - dst->SetDataPtrSize(reinterpret_cast32<void*>(code_item_offset), image_pointer_size_); - } else { - dst->SetCodeItem(dex_file.GetCodeItem(code_item_offset), dex_file.IsCompactDexFile()); - } - } - - if ((access_flags & kAccAbstract) == 0u && - Runtime::Current()->IsZygote() && - !Runtime::Current()->GetJITOptions()->GetProfileSaverOptions().GetProfileBootClassPath()) { - DCHECK(!ArtMethod::IsAbstract(access_flags)); - DCHECK(!ArtMethod::IsIntrinsic(access_flags)); - dst->SetMemorySharedMethod(); - dst->SetHotCounter(); - } -} - void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile* dex_file) { ObjPtr<mirror::DexCache> dex_cache = AllocAndInitializeDexCache(self, *dex_file, /* class_loader= */ nullptr); |