diff options
author | 2022-05-11 11:50:26 +0000 | |
---|---|---|
committer | 2022-05-12 14:53:31 +0000 | |
commit | 6898d018f6a48bbc2a8e471850e84e4611c7815c (patch) | |
tree | 8b73a5ce6ae7db737684bccf99e715e4d82263ac | |
parent | 59831b5fe40249aab697915980caf2347be1199e (diff) |
Use instrumentation stub if required when undeoptimizing a method
When undeoptimizing a method we have to check if we need entry / exit
stubs for any other reason before installing a resolution trampoline.
Also add a DCHECK that we always update entrypoints that can handle
method entry / exit hooks when instrumentation is enabled.
Bug: 231923130
Test: art/test.py
Change-Id: I8d5e22d85bbd47ebedebe766caa7026b2b82cffb
-rw-r--r-- | runtime/instrumentation.cc | 65 | ||||
-rw-r--r-- | runtime/instrumentation.h | 5 |
2 files changed, 38 insertions, 32 deletions
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 80e35ac0ae..b4dc9f6872 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -230,32 +230,9 @@ static bool IsProxyInit(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) method->GetDeclaringClass()->DescriptorEquals("Ljava/lang/reflect/Proxy;"); } -static void UpdateEntryPoints(ArtMethod* method, const void* quick_code) - REQUIRES_SHARED(Locks::mutator_lock_) { - if (kIsDebugBuild) { - if (NeedsClinitCheckBeforeCall(method) && - !method->GetDeclaringClass()->IsVisiblyInitialized()) { - CHECK(CanHandleInitializationCheck(quick_code)); - } - jit::Jit* jit = Runtime::Current()->GetJit(); - if (jit != nullptr && jit->GetCodeCache()->ContainsPc(quick_code)) { - // Ensure we always have the thumb entrypoint for JIT on arm32. - if (kRuntimeISA == InstructionSet::kArm) { - CHECK_EQ(reinterpret_cast<uintptr_t>(quick_code) & 1, 1u); - } - } - if (IsProxyInit(method)) { - CHECK_NE(quick_code, GetQuickInstrumentationEntryPoint()); - } - } - // If the method is from a boot image, don't dirty it if the entrypoint - // doesn't change. - if (method->GetEntryPointFromQuickCompiledCode() != quick_code) { - method->SetEntryPointFromQuickCompiledCode(quick_code); - } -} - -bool Instrumentation::CodeNeedsEntryExitStub(const void* code, ArtMethod* method) +// Returns true if we need entry exit stub to call entry hooks. JITed code +// directly call entry / exit hooks and don't need the stub. +static bool CodeNeedsEntryExitStub(const void* code, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { // Proxy.init should never have entry/exit stubs. if (IsProxyInit(method)) { @@ -294,6 +271,36 @@ bool Instrumentation::CodeNeedsEntryExitStub(const void* code, ArtMethod* method return true; } +static void UpdateEntryPoints(ArtMethod* method, const void* quick_code) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (kIsDebugBuild) { + if (NeedsClinitCheckBeforeCall(method) && + !method->GetDeclaringClass()->IsVisiblyInitialized()) { + CHECK(CanHandleInitializationCheck(quick_code)); + } + jit::Jit* jit = Runtime::Current()->GetJit(); + if (jit != nullptr && jit->GetCodeCache()->ContainsPc(quick_code)) { + // Ensure we always have the thumb entrypoint for JIT on arm32. + if (kRuntimeISA == InstructionSet::kArm) { + CHECK_EQ(reinterpret_cast<uintptr_t>(quick_code) & 1, 1u); + } + } + if (IsProxyInit(method)) { + CHECK_NE(quick_code, GetQuickInstrumentationEntryPoint()); + } + const Instrumentation* instr = Runtime::Current()->GetInstrumentation(); + if (instr->EntryExitStubsInstalled()) { + DCHECK(quick_code == GetQuickInstrumentationEntryPoint() || + !CodeNeedsEntryExitStub(quick_code, method)); + } + } + // If the method is from a boot image, don't dirty it if the entrypoint + // doesn't change. + if (method->GetEntryPointFromQuickCompiledCode() != quick_code) { + method->SetEntryPointFromQuickCompiledCode(quick_code); + } +} + bool Instrumentation::InterpretOnly(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { if (method->IsNative()) { return false; @@ -1199,7 +1206,11 @@ void Instrumentation::Undeoptimize(ArtMethod* method) { UpdateEntryPoints(method, GetQuickToInterpreterBridge()); } else if (NeedsClinitCheckBeforeCall(method) && !method->GetDeclaringClass()->IsVisiblyInitialized()) { - UpdateEntryPoints(method, GetQuickResolutionStub()); + if (EntryExitStubsInstalled()) { + UpdateEntryPoints(method, GetQuickInstrumentationEntryPoint()); + } else { + UpdateEntryPoints(method, GetQuickResolutionStub()); + } } else { UpdateEntryPoints(method, GetMaybeInstrumentedCodeForInvoke(method)); } diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index c63e73eeea..33ff8ffa9e 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -580,11 +580,6 @@ class Instrumentation { // False otherwise. bool RequiresInstrumentationInstallation(InstrumentationLevel new_level) const; - // Returns true if we need entry exit stub to call entry hooks. JITed code - // directly call entry / exit hooks and don't need the stub. - static bool CodeNeedsEntryExitStub(const void* code, ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_); - // Update the current instrumentation_level_. void UpdateInstrumentationLevel(InstrumentationLevel level); |