Be a bit smarter with JIT code triggering deoptimization.
Do not re-use an OSR method that triggered deoptimization.
Also add a stack overflow check before doing OSR.
bug:27094810
Change-Id: I6ff6a7fb9b3df9b7c0ff37e3610595efa70ad067
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 188deb0..8d3da37 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -294,6 +294,14 @@
return false;
}
+ if (UNLIKELY(__builtin_frame_address(0) < thread->GetStackEnd())) {
+ // Don't attempt to do an OSR if we are close to the stack limit. Since
+ // the interpreter frames are still on stack, OSR has the potential
+ // to stack overflow even for a simple loop.
+ // b/27094810.
+ return false;
+ }
+
// Get the actual Java method if this method is from a proxy class. The compiler
// and the JIT code cache do not expect methods from proxy classes.
method = method->GetInterfaceMethodIfProxy(sizeof(void*));
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 9111ddf..9e4dddf 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -782,5 +782,24 @@
return mspace_usable_size(reinterpret_cast<const void*>(FromCodeToAllocation(ptr)));
}
+void JitCodeCache::InvalidateCompiledCodeFor(ArtMethod* method,
+ const OatQuickMethodHeader* header) {
+ if (method->GetEntryPointFromQuickCompiledCode() == header->GetEntryPoint()) {
+ // The entrypoint is the one to invalidate, so we just update
+ // it to the interpreter entry point and clear the counter to get the method
+ // Jitted again.
+ Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
+ method, GetQuickToInterpreterBridge());
+ method->ClearCounter();
+ } else {
+ MutexLock mu(Thread::Current(), lock_);
+ auto it = osr_code_map_.find(method);
+ if (it != osr_code_map_.end() && OatQuickMethodHeader::FromCodePointer(it->second) == header) {
+ // Remove the OSR method, to avoid using it again.
+ osr_code_map_.erase(it);
+ }
+ }
+}
+
} // namespace jit
} // namespace art
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 048f8d0..71f5cda 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -172,6 +172,10 @@
size_t GetMemorySizeOfCodePointer(const void* ptr) REQUIRES(!lock_);
+ void InvalidateCompiledCodeFor(ArtMethod* method, const OatQuickMethodHeader* code)
+ REQUIRES(!lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
private:
// Take ownership of maps.
JitCodeCache(MemMap* code_map,
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 786cf06..dd384c7 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -23,6 +23,8 @@
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "handle_scope-inl.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/throwable.h"
@@ -629,13 +631,17 @@
DeoptimizeStackVisitor visitor(self_, context_, this, true);
visitor.WalkStack(true);
- // Compiled code made an explicit deoptimization. Transfer the code
- // to interpreter and clear the counter to JIT the method again.
+ // Compiled code made an explicit deoptimization.
ArtMethod* deopt_method = visitor.GetSingleFrameDeoptMethod();
DCHECK(deopt_method != nullptr);
- deopt_method->ClearCounter();
- Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
- deopt_method, GetQuickToInterpreterBridge());
+ if (Runtime::Current()->UseJit()) {
+ Runtime::Current()->GetJit()->GetCodeCache()->InvalidateCompiledCodeFor(
+ deopt_method, handler_method_header_);
+ } else {
+ // Transfer the code to interpreter.
+ Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
+ deopt_method, GetQuickToInterpreterBridge());
+ }
// PC needs to be of the quick-to-interpreter bridge.
int32_t offset;