summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/jit/jit_code_cache.cc15
-rw-r--r--runtime/jit/jit_code_cache.h5
-rw-r--r--runtime/quick_exception_handler.cc43
3 files changed, 60 insertions, 3 deletions
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 845f6eb8fb..30703e3eb5 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -1316,6 +1316,21 @@ ProfilingInfo* JitCodeCache::GetProfilingInfo(ArtMethod* method, Thread* self) {
return it->second;
}
+void JitCodeCache::MaybeUpdateInlineCache(ArtMethod* method,
+ uint32_t dex_pc,
+ ObjPtr<mirror::Class> cls,
+ Thread* self) {
+ ScopedDebugDisallowReadBarriers sddrb(self);
+ MutexLock mu(self, *Locks::jit_lock_);
+ auto it = profiling_infos_.find(method);
+ if (it == profiling_infos_.end()) {
+ return;
+ }
+ ProfilingInfo* info = it->second;
+ ScopedAssertNoThreadSuspension sants("ProfilingInfo");
+ info->AddInvokeInfo(dex_pc, cls.Ptr());
+}
+
void JitCodeCache::ResetHotnessCounter(ArtMethod* method, Thread* self) {
ScopedDebugDisallowReadBarriers sddrb(self);
MutexLock mu(self, *Locks::jit_lock_);
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 034ee9f6c5..86efb91d0e 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -407,6 +407,11 @@ class JitCodeCache {
ProfilingInfo* GetProfilingInfo(ArtMethod* method, Thread* self);
void ResetHotnessCounter(ArtMethod* method, Thread* self);
+ void MaybeUpdateInlineCache(ArtMethod* method,
+ uint32_t dex_pc,
+ ObjPtr<mirror::Class> cls,
+ Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_);
void VisitRoots(RootVisitor* visitor);
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();
}