diff options
author | 2025-02-12 10:25:46 +0000 | |
---|---|---|
committer | 2025-02-17 04:47:25 -0800 | |
commit | 474e99956e8be96e84404b5be6ad075bb5cb6b79 (patch) | |
tree | 9c0b2b1d686c906912cbe842b18a9100258d0c10 | |
parent | e7776615ea6b005051219845a143231b5bb1e4f8 (diff) |
Refactor `ArtMethod` entrypoint initialization.
Introduce `Instrumentation::ReinitializeMethodsCode()` for
the cases where we want to reset the entrypoint after the
method has already been initialized. Keep the old function
`Instrumentation::InitializeMethodsCode()` exclusively for
the initialization of a newly loaded method's entrypoint,
split out the work that can be done in suspended state and
remove any unnecessary work. For example, we do not use
the Nterp entrypoint until the class has been verified, so
all the Nterp checks can be removed.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 329196666
Change-Id: I1d0c195b0118fe50434d496f56346a9f744fbaf7
-rw-r--r-- | compiler/common_compiler_test.cc | 7 | ||||
-rw-r--r-- | dex2oat/driver/compiler_driver_test.cc | 7 | ||||
-rw-r--r-- | openjdkjvmti/events.cc | 2 | ||||
-rw-r--r-- | openjdkjvmti/ti_redefine.cc | 4 | ||||
-rw-r--r-- | runtime/class_linker.cc | 40 | ||||
-rw-r--r-- | runtime/common_runtime_test.cc | 2 | ||||
-rw-r--r-- | runtime/gc/heap.h | 3 | ||||
-rw-r--r-- | runtime/instrumentation-inl.h | 129 | ||||
-rw-r--r-- | runtime/instrumentation.cc | 39 | ||||
-rw-r--r-- | runtime/instrumentation.h | 21 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 10 | ||||
-rw-r--r-- | runtime/quick_exception_handler.cc | 3 | ||||
-rw-r--r-- | runtime/runtime.cc | 6 | ||||
-rw-r--r-- | runtime/runtime_callbacks_test.cc | 2 | ||||
-rw-r--r-- | test/common/runtime_state.cc | 2 |
15 files changed, 203 insertions, 74 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index f24406e599..26800637fa 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -32,6 +32,7 @@ #include "driver/compiled_code_storage.h" #include "driver/compiler_options.h" #include "jni/java_vm_ext.h" +#include "instrumentation-inl.h" #include "interpreter/interpreter.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" @@ -306,7 +307,11 @@ void CommonCompilerTestImpl::CompileMethod(ArtMethod* method) { storage.GetStackMap(), storage.GetInstructionSet()); LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code; - GetRuntime()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ method_code); + instrumentation::Instrumentation* instr = GetRuntime()->GetInstrumentation(); + const void* entrypoint = instr->GetInitialEntrypoint(method->GetAccessFlags(), method_code); + CHECK(!instr->IsForcedInterpretOnly()); + CHECK(!instr->EntryExitStubsInstalled()); + instr->UpdateMethodsCode(method, entrypoint); } } diff --git a/dex2oat/driver/compiler_driver_test.cc b/dex2oat/driver/compiler_driver_test.cc index 7d4c32b25c..5dc6589d53 100644 --- a/dex2oat/driver/compiler_driver_test.cc +++ b/dex2oat/driver/compiler_driver_test.cc @@ -31,6 +31,7 @@ #include "dex/dex_file_types.h" #include "gc/heap.h" #include "handle_scope-inl.h" +#include "instrumentation-inl.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/dex_cache-inl.h" @@ -93,7 +94,11 @@ class CompilerDriverTest : public CommonCompilerDriverTest { LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code; } } - runtime_->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ method_code); + instrumentation::Instrumentation* instr = runtime_->GetInstrumentation(); + const void* entrypoint = instr->GetInitialEntrypoint(method->GetAccessFlags(), method_code); + CHECK(!instr->IsForcedInterpretOnly()); + CHECK(!instr->EntryExitStubsInstalled()); + instr->UpdateMethodsCode(method, entrypoint); } void MakeDexFileExecutable(jobject class_loader, const DexFile& dex_file) { diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc index 31107d08a5..a1e9a3dcf4 100644 --- a/openjdkjvmti/events.cc +++ b/openjdkjvmti/events.cc @@ -1251,7 +1251,7 @@ void EventHandler::HandleLocalAccessCapabilityAdded() { continue; } else if (!runtime_->GetClassLinker()->IsQuickToInterpreterBridge(code) && !runtime_->IsAsyncDeoptimizeable(&m, reinterpret_cast<uintptr_t>(code))) { - runtime_->GetInstrumentation()->InitializeMethodsCode(&m, /*aot_code=*/ nullptr); + runtime_->GetInstrumentation()->ReinitializeMethodsCode(&m); } } return true; diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index db9ad2417b..8e7885a726 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -2135,7 +2135,7 @@ art::ObjPtr<art::mirror::Class> Redefiner::ClassRedefinition::AllocateNewClassOb } // Finish setting up methods. linked_class->VisitMethods([&](art::ArtMethod* m) REQUIRES_SHARED(art::Locks::mutator_lock_) { - driver_->runtime_->GetInstrumentation()->InitializeMethodsCode(m, /* aot_code= */ nullptr); + driver_->runtime_->GetInstrumentation()->ReinitializeMethodsCode(m); m->SetNotIntrinsic(); DCHECK(m->IsCopied() || m->GetDeclaringClass() == linked_class.Get()) << m->PrettyMethod() @@ -2573,7 +2573,7 @@ void Redefiner::ClassRedefinition::UpdateMethods(art::ObjPtr<art::mirror::Class> CHECK(method_id != nullptr); uint32_t dex_method_idx = dex_file_->GetIndexForMethodId(*method_id); method.SetDexMethodIndex(dex_method_idx); - driver_->runtime_->GetInstrumentation()->InitializeMethodsCode(&method, /*aot_code=*/ nullptr); + driver_->runtime_->GetInstrumentation()->ReinitializeMethodsCode(&method); if (method.HasCodeItem()) { method.SetCodeItem( dex_file_->GetCodeItem(dex_file_->FindCodeItemOffset(class_def, dex_method_idx))); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 078a5c8383..6418c1a885 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -96,6 +96,7 @@ #include "hidden_api.h" #include "imt_conflict_table.h" #include "imtable-inl.h" +#include "instrumentation-inl.h" #include "intern_table-inl.h" #include "interpreter/interpreter.h" #include "interpreter/mterp/nterp.h" @@ -228,7 +229,7 @@ static void UpdateClassAfterVerification(Handle<mirror::Class> klass, if (interpreter::CanRuntimeUseNterp()) { for (ArtMethod& m : klass->GetMethods(pointer_size)) { if (class_linker->IsQuickToInterpreterBridge(m.GetEntryPointFromQuickCompiledCode())) { - runtime->GetInstrumentation()->InitializeMethodsCode(&m, /*aot_code=*/nullptr); + runtime->GetInstrumentation()->ReinitializeMethodsCode(&m); } } } @@ -3958,7 +3959,7 @@ class ClassLinker::LoadClassHelper { PointerSize pointer_size, LengthPrefixedArray<ArtField>* fields, LengthPrefixedArray<ArtMethod>* methods) - REQUIRES_SHARED(Locks::mutator_lock_); + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Roles::uninterruptible_); uint32_t NumFields() const { return dchecked_integral_cast<uint32_t>(fields_.size()); @@ -4003,7 +4004,7 @@ class ClassLinker::LoadClassHelper { template <PointerSize kPointerSize> ALWAYS_INLINE void FillMethods(ObjPtr<mirror::Class> klass, /*out*/ LengthPrefixedArray<ArtMethod>* methods) - REQUIRES_SHARED(Locks::mutator_lock_); + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Roles::uninterruptible_); Runtime* const runtime_; const DexFile& dex_file_; @@ -4135,28 +4136,29 @@ inline void ClassLinker::LoadClassHelper::LinkCode(ArtMethodData* method, // Method shouldn't have already been linked. DCHECK_EQ(method->entrypoint, nullptr); - if (!ArtMethod::IsInvokable(method->access_flags)) { + uint32_t access_flags = method->access_flags; + if (!ArtMethod::IsInvokable(access_flags)) { method->entrypoint = GetQuickToInterpreterBridge(); occi->SkipAbstract(class_def_method_index); return; } const void* quick_code = occi->GetAndAdvance(class_def_method_index); - if (ArtMethod::IsNative(method->access_flags) && quick_code == nullptr) { + if (ArtMethod::IsNative(access_flags) && quick_code == nullptr) { std::string_view shorty = dex_file_.GetMethodShortyView(method->dex_method_index); - const void* boot_jni_stub = - runtime_->GetClassLinker()->FindBootJniStub(method->access_flags, shorty); + const void* boot_jni_stub = runtime_->GetClassLinker()->FindBootJniStub(access_flags, shorty); if (boot_jni_stub != nullptr) { // Use boot JNI stub if found. quick_code = boot_jni_stub; } } - method->entrypoint = quick_code; + method->entrypoint = + runtime_->GetInstrumentation()->GetInitialEntrypoint(access_flags, quick_code); - if (ArtMethod::IsNative(method->access_flags)) { + if (ArtMethod::IsNative(access_flags)) { // Set up the dlsym lookup stub. Do not go through `UnregisterNative()` // as the extra processing for @CriticalNative is not needed yet. - method->data = ArtMethod::IsCriticalNative(method->access_flags) + method->data = ArtMethod::IsCriticalNative(access_flags) ? GetJniDlsymLookupCriticalStub() : GetJniDlsymLookupStub(); } @@ -4278,8 +4280,12 @@ void ClassLinker::LoadClassHelper::FillMethods(ObjPtr<mirror::Class> klass, DCHECK_EQ(methods_.size(), (methods != nullptr) ? methods->size() : 0u); static constexpr size_t kMethodAlignment = ArtMethod::Alignment(kPointerSize); static constexpr size_t kMethodSize = ArtMethod::Size(kPointerSize); - instrumentation::Instrumentation* instr = - is_aot_compiler_ ? nullptr : runtime_->GetInstrumentation(); + instrumentation::Instrumentation* instr = nullptr; + bool use_stubs = false; + if (!is_aot_compiler_) { + instr = runtime_->GetInstrumentation(); + use_stubs = instr->InitialEntrypointNeedsInstrumentationStubs(); + } for (size_t i = 0, size = methods_.size(); i != size; ++i) { const ArtMethodData& src = methods_[i]; ArtMethod* dst = &methods->At(i, kMethodSize, kMethodAlignment); @@ -4305,12 +4311,12 @@ void ClassLinker::LoadClassHelper::FillMethods(ObjPtr<mirror::Class> klass, dst->SetDataPtrSize(src.data, kPointerSize); if (instr != nullptr) { DCHECK_IMPLIES(dst->IsNative(), dst->GetEntryPointFromJniPtrSize(kPointerSize) == src.data); - if (ArtMethod::IsInvokable(access_flags)) { - instr->InitializeMethodsCode(dst, src.entrypoint); - } else { - DCHECK_EQ(src.entrypoint, GetQuickToInterpreterBridge()); - dst->SetEntryPointFromQuickCompiledCodePtrSize(src.entrypoint, kPointerSize); + const void* entrypoint = src.entrypoint; + if (UNLIKELY(use_stubs)) { + bool is_native = ArtMethod::IsNative(access_flags); + entrypoint = is_native ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge(); } + instr->InitializeMethodsCode(dst, entrypoint, kPointerSize); } } } diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index ab7ddbcb25..fba0f1c758 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -412,7 +412,7 @@ void CommonRuntimeTestImpl::SetUpRuntimeOptionsForFillHeap(RuntimeOptions *optio void CommonRuntimeTestImpl::MakeInterpreted(ObjPtr<mirror::Class> klass) { PointerSize pointer_size = class_linker_->GetImagePointerSize(); for (ArtMethod& method : klass->GetMethods(pointer_size)) { - Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(&method, /*aot_code=*/ nullptr); + Runtime::Current()->GetInstrumentation()->ReinitializeMethodsCode(&method); } } diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 5d9fb1b647..7e30c3d14e 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -722,8 +722,7 @@ class Heap { EXPORT bool ObjectIsInBootImageSpace(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_); - bool IsInBootImageOatFile(const void* p) const - REQUIRES_SHARED(Locks::mutator_lock_); + bool IsInBootImageOatFile(const void* p) const; // Get the start address of the boot images if any; otherwise returns 0. uint32_t GetBootImagesStartAddress() const { diff --git a/runtime/instrumentation-inl.h b/runtime/instrumentation-inl.h new file mode 100644 index 0000000000..3b035ea71b --- /dev/null +++ b/runtime/instrumentation-inl.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_INSTRUMENTATION_INL_H_ +#define ART_RUNTIME_INSTRUMENTATION_INL_H_ + +#include "instrumentation.h" + +#include "art_method-inl.h" +#include "entrypoints/runtime_asm_entrypoints.h" +#include "gc/heap.h" +#include "jit/jit.h" +#include "runtime.h" + +namespace art HIDDEN { +namespace instrumentation { + +inline bool Instrumentation::CanUseAotCode(const void* quick_code) { + if (quick_code == nullptr) { + return false; + } + Runtime* runtime = Runtime::Current(); + // For simplicity, we never use AOT code for debuggable. + if (runtime->IsJavaDebuggable()) { + return false; + } + + if (runtime->IsNativeDebuggable()) { + DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse()); + // If we are doing native debugging, ignore application's AOT code, + // since we want to JIT it (at first use) with extra stackmaps for native + // debugging. We keep however all AOT code from the boot image, + // since the JIT-at-first-use is blocking and would result in non-negligible + // startup performance impact. + return runtime->GetHeap()->IsInBootImageOatFile(quick_code); + } + + return true; +} + +inline const void* Instrumentation::GetInitialEntrypoint(uint32_t method_access_flags, + const void* aot_code) { + if (!ArtMethod::IsInvokable(method_access_flags)) { + return GetQuickToInterpreterBridge(); + } + + // Special case if we need an initialization check. + if (ArtMethod::NeedsClinitCheckBeforeCall(method_access_flags)) { + // If we have code but the method needs a class initialization check before calling that code, + // install the resolution stub that will perform the check. It will be replaced by the proper + // entry point by `ClassLinker::FixupStaticTrampolines()` after initializing class. + // Note: This mimics the logic in image_writer.cc that installs the resolution stub only + // if we have compiled code or we can execute nterp, and the method needs a class + // initialization check. + return (aot_code != nullptr || ArtMethod::IsNative(method_access_flags)) + ? GetQuickResolutionStub() + : GetQuickToInterpreterBridge(); + } + + // Use the provided AOT code if possible. + if (CanUseAotCode(aot_code)) { + return aot_code; + } + + // Use default entrypoints. + return ArtMethod::IsNative(method_access_flags) ? GetQuickGenericJniStub() + : GetQuickToInterpreterBridge(); +} + + +inline bool Instrumentation::InitialEntrypointNeedsInstrumentationStubs() { + return IsForcedInterpretOnly() || EntryExitStubsInstalled(); +} + +inline void Instrumentation::InitializeMethodsCode(ArtMethod* method, + const void* entrypoint, + PointerSize pointer_size) { + if (kIsDebugBuild) { + // Entrypoint should be uninitialized. + CHECK(method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size) == nullptr) + << method->PrettyMethod(); + // We initialize the entrypoint while loading the class, well before the class + // is verified and Nterp entrypoint is allowed. We prefer to check for resolved + // because a verified class may lose its "verified" status (by becoming erroneous) + // but the resolved status is always kept (as "resolved erroneous" if needed). + CHECK(!method->GetDeclaringClass()->IsResolved()); + CHECK_NE(entrypoint, interpreter::GetNterpEntryPoint()) << method->PrettyMethod(); + if (InitialEntrypointNeedsInstrumentationStubs()) { + const void* expected = + method->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge(); + CHECK_EQ(entrypoint, expected) << method->PrettyMethod() << " " << method->IsNative(); + } else if (method->NeedsClinitCheckBeforeCall()) { + if (method->IsNative()) { + CHECK_EQ(entrypoint, GetQuickResolutionStub()); + } else { + // We do not have the original `aot_code` to determine which entrypoint to expect. + CHECK(entrypoint == GetQuickResolutionStub() || + entrypoint == GetQuickToInterpreterBridge()); + } + } else { + bool is_stub = (entrypoint == GetQuickToInterpreterBridge()) || + (entrypoint == GetQuickGenericJniStub()) || + (entrypoint == GetQuickResolutionStub()); + const void* aot_code = is_stub ? nullptr : entrypoint; + const void* initial = GetInitialEntrypoint(method->GetAccessFlags(), aot_code); + CHECK_EQ(initial, entrypoint) + << method->PrettyMethod() << " 0x" << std::hex << method->GetAccessFlags(); + } + } + method->SetEntryPointFromQuickCompiledCodePtrSize(entrypoint, pointer_size); +} + +} // namespace instrumentation +} // namespace art + +#endif // ART_RUNTIME_INSTRUMENTATION_INL_H_ diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index ce740da1a8..28c4f35db3 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "instrumentation.h" +#include "instrumentation-inl.h" #include <functional> #include <optional> @@ -315,37 +315,13 @@ bool Instrumentation::InterpretOnly(ArtMethod* method) REQUIRES_SHARED(Locks::mu return InterpretOnly() || IsDeoptimized(method); } -static bool CanUseAotCode(const void* quick_code) - REQUIRES_SHARED(Locks::mutator_lock_) { - if (quick_code == nullptr) { - return false; - } - Runtime* runtime = Runtime::Current(); - // For simplicity, we never use AOT code for debuggable. - if (runtime->IsJavaDebuggable()) { - return false; - } - - if (runtime->IsNativeDebuggable()) { - DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse()); - // If we are doing native debugging, ignore application's AOT code, - // since we want to JIT it (at first use) with extra stackmaps for native - // debugging. We keep however all AOT code from the boot image, - // since the JIT-at-first-use is blocking and would result in non-negligible - // startup performance impact. - return runtime->GetHeap()->IsInBootImageOatFile(quick_code); - } - - return true; -} - static bool CanUseNterp(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { return interpreter::CanRuntimeUseNterp() && CanMethodUseNterp(method) && method->IsDeclaringClassVerifiedMayBeDead(); } -static const void* GetOptimizedCodeFor(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { +const void* Instrumentation::GetOptimizedCodeFor(ArtMethod* method) { DCHECK(!Runtime::Current()->GetInstrumentation()->InterpretOnly(method)); CHECK(method->IsInvokable()) << method->PrettyMethod(); if (method->IsProxyMethod()) { @@ -378,8 +354,7 @@ static const void* GetOptimizedCodeFor(ArtMethod* method) REQUIRES_SHARED(Locks: return method->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge(); } -void Instrumentation::InitializeMethodsCode(ArtMethod* method, const void* aot_code) - REQUIRES_SHARED(Locks::mutator_lock_) { +void Instrumentation::ReinitializeMethodsCode(ArtMethod* method) { if (!method->IsInvokable()) { DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr || Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge( @@ -405,7 +380,7 @@ void Instrumentation::InitializeMethodsCode(ArtMethod* method, const void* aot_c // Note: this mimics the logic in image_writer.cc that installs the resolution // stub only if we have compiled code or we can execute nterp, and the method needs a class // initialization check. - if (aot_code != nullptr || method->IsNative() || CanUseNterp(method)) { + if (method->IsNative() || CanUseNterp(method)) { if (kIsDebugBuild && CanUseNterp(method)) { // Adds some test coverage for the nterp clinit entrypoint. UpdateEntryPoints(method, interpreter::GetNterpWithClinitEntryPoint()); @@ -418,12 +393,6 @@ void Instrumentation::InitializeMethodsCode(ArtMethod* method, const void* aot_c return; } - // Use the provided AOT code if possible. - if (CanUseAotCode(aot_code)) { - UpdateEntryPoints(method, aot_code); - return; - } - // We check if the class is verified as we need the slow interpreter for lock verification. // If the class is not verified, This will be updated in // ClassLinker::UpdateClassAfterVerification. diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index 59e6b29b90..5112f0e789 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -322,8 +322,22 @@ class Instrumentation { // Returns a string representation of the given entry point. static std::string EntryPointString(const void* code); - // Initialize the entrypoint of the method .`aot_code` is the AOT code. - EXPORT void InitializeMethodsCode(ArtMethod* method, const void* aot_code) + // Return the best initial entrypoint of a method, assuming that stubs are not in use. + // This function can be called while the thread is suspended. + const void* GetInitialEntrypoint(uint32_t method_access_flags, const void* aot_code); + + // Check if the best initial entrypoint needs to be overridden with stubs. + bool InitialEntrypointNeedsInstrumentationStubs() + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Roles::uninterruptible_); + + // Initialize the method's entrypoint with aot code or runtime stub. + // The caller must check and apply `InitialEntrypointNeedsInstrumentationStubs()` + // in the same `Roles::uninterruptible_` section of code. + void InitializeMethodsCode(ArtMethod* method, const void* entrypoint, PointerSize pointer_size) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Roles::uninterruptible_); + + // Reinitialize the entrypoint of the method. + EXPORT void ReinitializeMethodsCode(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); // Update the code of a method respecting any installed stubs. @@ -601,6 +615,9 @@ class Instrumentation { REQUIRES_SHARED(Locks::mutator_lock_); private: + static bool CanUseAotCode(const void* quick_code); + static const void* GetOptimizedCodeFor(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); + // Update the current instrumentation_level_. void UpdateInstrumentationLevel(InstrumentationLevel level); diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index a8a03d4fdd..022532a54d 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -871,7 +871,7 @@ bool JitCodeCache::RemoveMethod(ArtMethod* method, bool release_memory) { return false; } - Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr); + Runtime::Current()->GetInstrumentation()->ReinitializeMethodsCode(method); return true; } @@ -1779,7 +1779,7 @@ void JitCodeCache::InvalidateAllCompiledCode() { OatQuickMethodHeader::FromCodePointer(data.GetCode()); for (ArtMethod* method : data.GetMethods()) { if (method->GetEntryPointFromQuickCompiledCode() == method_header->GetEntryPoint()) { - instr->InitializeMethodsCode(method, /*aot_code=*/ nullptr); + instr->ReinitializeMethodsCode(method); } } } @@ -1789,7 +1789,7 @@ void JitCodeCache::InvalidateAllCompiledCode() { if (UNLIKELY(meth->IsObsolete())) { linker->SetEntryPointsForObsoleteMethod(meth); } else { - instr->InitializeMethodsCode(meth, /*aot_code=*/ nullptr); + instr->ReinitializeMethodsCode(meth); } } osr_code_map_.clear(); @@ -1803,7 +1803,7 @@ void JitCodeCache::InvalidateAllCompiledCode() { if (entry.method->IsPreCompiled()) { entry.method->ClearPreCompiled(); } - instr->InitializeMethodsCode(entry.method, /*aot_code=*/nullptr); + instr->ReinitializeMethodsCode(entry.method); } } @@ -1816,7 +1816,7 @@ void JitCodeCache::InvalidateCompiledCodeFor(ArtMethod* method, // the future. if (method_entrypoint == header->GetEntryPoint()) { // The entrypoint is the one to invalidate, so we just update it to the interpreter entry point. - Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr); + Runtime::Current()->GetInstrumentation()->ReinitializeMethodsCode(method); } else { Thread* self = Thread::Current(); ScopedDebugDisallowReadBarriers sddrb(self); diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 09bbb2ab9e..365a63459d 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -745,8 +745,7 @@ void QuickExceptionHandler::DeoptimizeSingleFrame(DeoptimizationKind kind) { runtime->GetJit()->GetCodeCache()->InvalidateCompiledCodeFor( deopt_method, visitor.GetSingleFrameDeoptQuickMethodHeader()); } else { - runtime->GetInstrumentation()->InitializeMethodsCode( - deopt_method, /*aot_code=*/ nullptr); + runtime->GetInstrumentation()->ReinitializeMethodsCode(deopt_method); } // If the deoptimization is due to an inline cache, update it with the type diff --git a/runtime/runtime.cc b/runtime/runtime.cc index e2c30d619c..d4677d5b86 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -3213,21 +3213,21 @@ class DeoptimizeBootImageClassVisitor : public ClassVisitor { if (Runtime::Current()->GetHeap()->IsInBootImageOatFile(code) && (!m.IsNative() || deoptimize_native_methods) && !m.IsProxyMethod()) { - instrumentation_->InitializeMethodsCode(&m, /*aot_code=*/ nullptr); + instrumentation_->ReinitializeMethodsCode(&m); } if (Runtime::Current()->GetJit() != nullptr && Runtime::Current()->GetJit()->GetCodeCache()->IsInZygoteExecSpace(code) && (!m.IsNative() || deoptimize_native_methods)) { DCHECK(!m.IsProxyMethod()); - instrumentation_->InitializeMethodsCode(&m, /*aot_code=*/ nullptr); + instrumentation_->ReinitializeMethodsCode(&m); } if (m.IsPreCompiled()) { // Precompilation is incompatible with debuggable, so clear the flag // and update the entrypoint in case it has been compiled. m.ClearPreCompiled(); - instrumentation_->InitializeMethodsCode(&m, /*aot_code=*/ nullptr); + instrumentation_->ReinitializeMethodsCode(&m); } // Clear MemorySharedAccessFlags so the boot class methods can be JITed better. diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc index 053d4eaaf5..f63b2f4096 100644 --- a/runtime/runtime_callbacks_test.cc +++ b/runtime/runtime_callbacks_test.cc @@ -80,7 +80,7 @@ class RuntimeCallbacksTest : public CommonRuntimeTest { PointerSize pointer_size = class_linker_->GetImagePointerSize(); for (auto& m : klass->GetMethods(pointer_size)) { if (!m.IsAbstract()) { - Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(&m, /*aot_code=*/ nullptr); + Runtime::Current()->GetInstrumentation()->ReinitializeMethodsCode(&m); } } } diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index 6ff27f98f4..465e2f6850 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -457,7 +457,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeNativeMethod(JNIEnv* env, ScopedUtfChars chars(env, method_name); ArtMethod* method = GetMethod(soa, cls, chars); CHECK(method->IsNative()); - Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(method, /*aot_code=*/ nullptr); + Runtime::Current()->GetInstrumentation()->ReinitializeMethodsCode(method); } extern "C" JNIEXPORT jboolean JNICALL Java_Main_isDebuggable(JNIEnv*, jclass) { |