diff options
author | 2023-11-06 22:39:52 +0000 | |
---|---|---|
committer | 2023-11-07 10:45:26 +0000 | |
commit | effa0a6222b07f6ee7aad734e6ef72376ed94a2c (patch) | |
tree | 96cd05826194dab0cf23fd971fb46113e5afcd10 /runtime/quick_exception_handler.cc | |
parent | 10f07e0ceb600a84c6805212efaf119d49eaeeb2 (diff) |
Reland "Fix pathological deoptimization case."
This reverts commit 4384e944119846a2bc1d699a8c366baf9ac24c8e.
Reason for revert: use the right bottom shadow frame for the inline
cache.
Change-Id: Ia3208bd0792dd3a615763ef146973e0c84cf31b4
Diffstat (limited to 'runtime/quick_exception_handler.cc')
-rw-r--r-- | runtime/quick_exception_handler.cc | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index fd57b4ae83..590a596c1f 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -29,6 +29,7 @@ #include "base/systrace.h" #include "dex/dex_file_types.h" #include "dex/dex_instruction.h" +#include "dex/dex_instruction-inl.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "entrypoints/runtime_asm_entrypoints.h" @@ -385,6 +386,7 @@ class DeoptimizeStackVisitor final : public StackVisitor { : StackVisitor(self, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames), exception_handler_(exception_handler), prev_shadow_frame_(nullptr), + bottom_shadow_frame_(nullptr), stacked_shadow_frame_pushed_(false), single_frame_deopt_(single_frame), single_frame_done_(false), @@ -401,6 +403,10 @@ class DeoptimizeStackVisitor final : public StackVisitor { return single_frame_deopt_quick_method_header_; } + ShadowFrame* GetBottomShadowFrame() const { + return bottom_shadow_frame_; + } + void FinishStackWalk() REQUIRES_SHARED(Locks::mutator_lock_) { // This is the upcall, or the next full frame in single-frame deopt, or the // code isn't deoptimizeable. We remember the frame and last pc so that we @@ -503,6 +509,7 @@ class DeoptimizeStackVisitor final : public StackVisitor { // Will be popped after the long jump after DeoptimizeStack(), // right before interpreter::EnterInterpreterFromDeoptimize(). stacked_shadow_frame_pushed_ = true; + bottom_shadow_frame_ = new_frame; GetThread()->PushStackedShadowFrame( new_frame, StackedShadowFrameType::kDeoptimizationShadowFrame); } @@ -641,6 +648,7 @@ class DeoptimizeStackVisitor final : public StackVisitor { QuickExceptionHandler* const exception_handler_; ShadowFrame* prev_shadow_frame_; + ShadowFrame* bottom_shadow_frame_; bool stacked_shadow_frame_pushed_; const bool single_frame_deopt_; bool single_frame_done_; @@ -707,14 +715,43 @@ void QuickExceptionHandler::DeoptimizeSingleFrame(DeoptimizationKind kind) { // When deoptimizing for debug support the optimized code is still valid and // can be reused when debugging support (like breakpoints) are no longer // needed fot this method. - if (Runtime::Current()->UseJitCompilation() && (kind != DeoptimizationKind::kDebugging)) { - Runtime::Current()->GetJit()->GetCodeCache()->InvalidateCompiledCodeFor( + Runtime* runtime = Runtime::Current(); + if (runtime->UseJitCompilation() && (kind != DeoptimizationKind::kDebugging)) { + runtime->GetJit()->GetCodeCache()->InvalidateCompiledCodeFor( deopt_method, visitor.GetSingleFrameDeoptQuickMethodHeader()); } else { - Runtime::Current()->GetInstrumentation()->InitializeMethodsCode( + runtime->GetInstrumentation()->InitializeMethodsCode( deopt_method, /*aot_code=*/ nullptr); } + // If the deoptimization is due to an inline cache, update it with the type + // that made us deoptimize. This avoids pathological cases of never seeing + // that type while executing baseline generated code. + if (kind == DeoptimizationKind::kJitInlineCache || kind == DeoptimizationKind::kJitSameTarget) { + DCHECK(runtime->UseJitCompilation()); + ShadowFrame* shadow_frame = visitor.GetBottomShadowFrame(); + uint32_t dex_pc = shadow_frame->GetDexPC(); + CodeItemDataAccessor accessor(shadow_frame->GetMethod()->DexInstructionData()); + const uint16_t* const insns = accessor.Insns(); + const Instruction* inst = Instruction::At(insns + dex_pc); + switch (inst->Opcode()) { + case Instruction::INVOKE_INTERFACE: + case Instruction::INVOKE_VIRTUAL: + case Instruction::INVOKE_INTERFACE_RANGE: + case Instruction::INVOKE_VIRTUAL_RANGE: { + runtime->GetJit()->GetCodeCache()->MaybeUpdateInlineCache( + shadow_frame->GetMethod(), + dex_pc, + shadow_frame->GetVRegReference(inst->VRegC())->GetClass(), + self_); + break; + } + default: { + LOG(FATAL) << "Unexpected instruction for inline cache: " << inst->Name(); + } + } + } + PrepareForLongJumpToInvokeStubOrInterpreterBridge(); } |