ART: Add JIT cache race test
Adds a test for the JIT code cache that attempts to trap races between
threads generating code and executing it.
Bug: 38417984
Test: run-test --jit 707
Change-Id: I408b2680b1d266ebe624d6e39113f0261d538e8a
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index fdac24e..e173ffe 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -681,6 +681,57 @@
return CodeCacheSizeLocked();
}
+bool JitCodeCache::RemoveMethod(ArtMethod* method, bool release_memory) {
+ MutexLock mu(Thread::Current(), lock_);
+ if (method->IsNative()) {
+ return false;
+ }
+
+ bool in_cache = false;
+ {
+ ScopedCodeCacheWrite ccw(code_map_.get());
+ for (auto code_iter = method_code_map_.begin(); code_iter != method_code_map_.end();) {
+ if (code_iter->second == method) {
+ if (release_memory) {
+ FreeCode(code_iter->first);
+ }
+ code_iter = method_code_map_.erase(code_iter);
+ in_cache = true;
+ continue;
+ }
+ ++code_iter;
+ }
+ }
+
+ bool osr = false;
+ auto code_map = osr_code_map_.find(method);
+ if (code_map != osr_code_map_.end()) {
+ osr_code_map_.erase(code_map);
+ osr = true;
+ }
+
+ if (!in_cache) {
+ return false;
+ }
+
+ ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
+ if (info != nullptr) {
+ auto profile = std::find(profiling_infos_.begin(), profiling_infos_.end(), info);
+ DCHECK(profile != profiling_infos_.end());
+ profiling_infos_.erase(profile);
+ }
+ method->SetProfilingInfo(nullptr);
+ method->ClearCounter();
+ Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
+ method, GetQuickToInterpreterBridge());
+ VLOG(jit)
+ << "JIT removed (osr=" << std::boolalpha << osr << std::noboolalpha << ") "
+ << ArtMethod::PrettyMethod(method) << "@" << method
+ << " ccache_size=" << PrettySize(CodeCacheSizeLocked()) << ": "
+ << " dcache_size=" << PrettySize(DataCacheSizeLocked());
+ return true;
+}
+
// This notifies the code cache that the given method has been redefined and that it should remove
// any cached information it has on the method. All threads must be suspended before calling this
// method. The compiled code for the method (if there is any) must not be in any threads call stack.
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 612d06b..811b3c7 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -170,6 +170,13 @@
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Removes method from the cache for testing purposes. The caller
+ // must ensure that all threads are suspended and the method should
+ // not be in any thread's stack.
+ bool RemoveMethod(ArtMethod* method, bool release_memory)
+ REQUIRES(!lock_)
+ REQUIRES(Locks::mutator_lock_);
+
// Remove all methods in our cache that were allocated by 'alloc'.
void RemoveMethodsIn(Thread* self, const LinearAlloc& alloc)
REQUIRES(!lock_)