summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/jit/jit_code_cache.cc118
-rw-r--r--runtime/jit/jit_code_cache.h11
-rw-r--r--test/667-jit-jni-stub/jit_jni_stub_test.cc17
-rw-r--r--test/667-jit-jni-stub/src/Main.java15
4 files changed, 26 insertions, 135 deletions
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 2474399f59..8ca80131f9 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -261,7 +261,6 @@ JitCodeCache::JitCodeCache()
zygote_map_(&shared_region_),
lock_cond_("Jit code cache condition variable", *Locks::jit_lock_),
collection_in_progress_(false),
- last_collection_increased_code_cache_(false),
garbage_collect_code_(true),
number_of_baseline_compilations_(0),
number_of_optimized_compilations_(0),
@@ -1097,23 +1096,6 @@ bool JitCodeCache::IsAtMaxCapacity() const {
return private_region_.GetCurrentCapacity() == private_region_.GetMaxCapacity();
}
-bool JitCodeCache::ShouldDoFullCollection() {
- if (IsAtMaxCapacity()) {
- // Always do a full collection when the code cache is full.
- return true;
- } else if (private_region_.GetCurrentCapacity() < GetReservedCapacity()) {
- // Always do partial collection when the code cache size is below the reserved
- // capacity.
- return false;
- } else if (last_collection_increased_code_cache_) {
- // This time do a full collection.
- return true;
- } else {
- // This time do a partial collection.
- return false;
- }
-}
-
void JitCodeCache::GarbageCollectCache(Thread* self) {
ScopedTrace trace(__FUNCTION__);
// Wait for an existing collection, or let everyone know we are starting one.
@@ -1140,19 +1122,11 @@ void JitCodeCache::GarbageCollectCache(Thread* self) {
{
TimingLogger::ScopedTiming st("Code cache collection", &logger);
- bool do_full_collection = false;
- {
- MutexLock mu(self, *Locks::jit_lock_);
- do_full_collection = ShouldDoFullCollection();
- }
-
- VLOG(jit) << "Do "
- << (do_full_collection ? "full" : "partial")
- << " code cache collection, code="
+ VLOG(jit) << "Do code cache collection, code="
<< PrettySize(CodeCacheSize())
<< ", data=" << PrettySize(DataCacheSize());
- DoCollection(self, /* collect_profiling_info= */ do_full_collection);
+ DoCollection(self);
VLOG(jit) << "After code cache collection, code="
<< PrettySize(CodeCacheSize())
@@ -1160,43 +1134,7 @@ void JitCodeCache::GarbageCollectCache(Thread* self) {
{
MutexLock mu(self, *Locks::jit_lock_);
-
- // Increase the code cache only when we do partial collections.
- // TODO: base this strategy on how full the code cache is?
- if (do_full_collection) {
- last_collection_increased_code_cache_ = false;
- } else {
- last_collection_increased_code_cache_ = true;
- private_region_.IncreaseCodeCacheCapacity();
- }
-
- bool next_collection_will_be_full = ShouldDoFullCollection();
-
- // Start polling the liveness of compiled code to prepare for the next full collection.
- if (next_collection_will_be_full) {
- ScopedDebugDisallowReadBarriers sddrb(self);
- for (auto it : profiling_infos_) {
- it.second->ResetCounter();
- }
-
- // Change entry points of native methods back to the GenericJNI entrypoint.
- for (const auto& entry : jni_stubs_map_) {
- const JniStubData& data = entry.second;
- if (!data.IsCompiled() || IsInZygoteExecSpace(data.GetCode())) {
- continue;
- }
- const OatQuickMethodHeader* method_header =
- OatQuickMethodHeader::FromCodePointer(data.GetCode());
- for (ArtMethod* method : data.GetMethods()) {
- if (method->GetEntryPointFromQuickCompiledCode() == method_header->GetEntryPoint()) {
- // Don't call Instrumentation::UpdateMethodsCode(), same as for normal methods above.
- // Make sure a single invocation of the GenericJNI trampoline tries to recompile.
- method->SetHotCounter();
- method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
- }
- }
- }
- }
+ private_region_.IncreaseCodeCacheCapacity();
live_bitmap_.reset(nullptr);
NotifyCollectionDone(self);
}
@@ -1340,35 +1278,11 @@ void JitCodeCache::ResetHotnessCounter(ArtMethod* method, Thread* self) {
}
-void JitCodeCache::DoCollection(Thread* self, bool collect_profiling_info) {
+void JitCodeCache::DoCollection(Thread* self) {
ScopedTrace trace(__FUNCTION__);
{
ScopedDebugDisallowReadBarriers sddrb(self);
MutexLock mu(self, *Locks::jit_lock_);
-
- // Update to interpreter the methods that have baseline entrypoints and whose baseline
- // hotness count hasn't changed.
- // Note that these methods may be in thread stack or concurrently revived
- // between. That's OK, as the thread executing it will mark it.
- uint16_t warmup_threshold = Runtime::Current()->GetJITOptions()->GetWarmupThreshold();
- for (auto it : profiling_infos_) {
- ProfilingInfo* info = it.second;
- if (!info->CounterHasChanged()) {
- const void* entry_point = info->GetMethod()->GetEntryPointFromQuickCompiledCode();
- if (ContainsPc(entry_point)) {
- OatQuickMethodHeader* method_header =
- OatQuickMethodHeader::FromEntryPoint(entry_point);
- if (CodeInfo::IsBaseline(method_header->GetOptimizedCodeInfoPtr())) {
- info->GetMethod()->ResetCounter(warmup_threshold);
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(
- info->GetMethod(), /*aot_code=*/ nullptr);
- }
- }
- }
- }
- // TODO: collect profiling info
- // TODO: collect optimized code
-
// Mark compiled code that are entrypoints of ArtMethods. Compiled code that is not
// an entry point is either:
// - an osr compiled code, that will be removed if not in a thread call stack.
@@ -1411,10 +1325,6 @@ void JitCodeCache::DoCollection(Thread* self, bool collect_profiling_info) {
// change. We do know they cannot change to a code cache entry that is not marked,
// therefore we can safely remove those entries.
RemoveUnmarkedCode(self);
-
- if (collect_profiling_info) {
- // TODO: Collect unused profiling infos.
- }
}
OatQuickMethodHeader* JitCodeCache::LookupMethodHeader(uintptr_t pc, ArtMethod* method) {
@@ -1824,7 +1734,22 @@ void JitCodeCache::InvalidateAllCompiledCode() {
Runtime* runtime = Runtime::Current();
ClassLinker* linker = runtime->GetClassLinker();
instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
- // TODO: Clear `jni_stubs_map_`?
+
+ // Change entry points of native methods back to the GenericJNI entrypoint.
+ for (const auto& entry : jni_stubs_map_) {
+ const JniStubData& data = entry.second;
+ if (!data.IsCompiled() || IsInZygoteExecSpace(data.GetCode())) {
+ continue;
+ }
+ const OatQuickMethodHeader* method_header =
+ OatQuickMethodHeader::FromCodePointer(data.GetCode());
+ for (ArtMethod* method : data.GetMethods()) {
+ if (method->GetEntryPointFromQuickCompiledCode() == method_header->GetEntryPoint()) {
+ ClearMethodCounter(method, /*was_warm=*/true);
+ instr->InitializeMethodsCode(method, /*aot_code=*/ nullptr);
+ }
+ }
+ }
for (const auto& entry : method_code_map_) {
ArtMethod* meth = entry.second;
// We were compiled, so we must be warm.
@@ -1843,8 +1768,7 @@ void JitCodeCache::InvalidateAllCompiledCode() {
if (entry.method->IsPreCompiled()) {
entry.method->ClearPreCompiled();
}
- Runtime::Current()->GetInstrumentation()->InitializeMethodsCode(entry.method,
- /*aot_code=*/nullptr);
+ instr->InitializeMethodsCode(entry.method, /*aot_code=*/nullptr);
}
saved_compiled_methods_map_.clear();
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 88b54d5a5b..82510fbe3c 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -496,12 +496,7 @@ class JitCodeCache {
// Return whether the code cache's capacity is at its maximum.
bool IsAtMaxCapacity() const REQUIRES(Locks::jit_lock_);
- // Return whether we should do a full collection given the current state of the cache.
- bool ShouldDoFullCollection()
- REQUIRES(Locks::jit_lock_)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- void DoCollection(Thread* self, bool collect_profiling_info)
+ void DoCollection(Thread* self)
REQUIRES(!Locks::jit_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -594,9 +589,6 @@ class JitCodeCache {
// Bitmap for collecting code and data.
std::unique_ptr<CodeCacheBitmap> live_bitmap_;
- // Whether the last collection round increased the code cache.
- bool last_collection_increased_code_cache_ GUARDED_BY(Locks::jit_lock_);
-
// Whether we can do garbage collection. Not 'const' as tests may override this.
bool garbage_collect_code_ GUARDED_BY(Locks::jit_lock_);
@@ -623,7 +615,6 @@ class JitCodeCache {
// Histograms for keeping track of profiling info statistics.
Histogram<uint64_t> histogram_profiling_info_memory_use_ GUARDED_BY(Locks::jit_lock_);
- friend class art::JitJniStubTestHelper;
friend class ScopedCodeCacheWrite;
friend class MarkCodeClosure;
diff --git a/test/667-jit-jni-stub/jit_jni_stub_test.cc b/test/667-jit-jni-stub/jit_jni_stub_test.cc
index c21971fa8b..2b8e14c03d 100644
--- a/test/667-jit-jni-stub/jit_jni_stub_test.cc
+++ b/test/667-jit-jni-stub/jit_jni_stub_test.cc
@@ -25,17 +25,6 @@
namespace art {
-// Local class declared as a friend of JitCodeCache so that we can access its internals.
-class JitJniStubTestHelper {
- public:
- static bool isNextJitGcFull(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
- CHECK(Runtime::Current()->GetJit() != nullptr);
- jit::JitCodeCache* cache = Runtime::Current()->GetJit()->GetCodeCache();
- MutexLock mu(self, *Locks::jit_lock_);
- return cache->ShouldDoFullCollection();
- }
-};
-
// Calls through to a static method with signature "()V".
extern "C" JNIEXPORT
void Java_Main_callThrough(JNIEnv* env, jclass, jclass klass, jstring methodName) {
@@ -51,13 +40,15 @@ void Java_Main_jitGc(JNIEnv*, jclass) {
CHECK(Runtime::Current()->GetJit() != nullptr);
jit::JitCodeCache* cache = Runtime::Current()->GetJit()->GetCodeCache();
ScopedObjectAccess soa(Thread::Current());
+ cache->InvalidateAllCompiledCode();
cache->GarbageCollectCache(Thread::Current());
}
extern "C" JNIEXPORT
jboolean Java_Main_isNextJitGcFull(JNIEnv*, jclass) {
- ScopedObjectAccess soa(Thread::Current());
- return JitJniStubTestHelper::isNextJitGcFull(soa.Self());
+ // Because we invalidate all compiled code above, we currently always do a
+ // full GC.
+ return true;
}
} // namespace art
diff --git a/test/667-jit-jni-stub/src/Main.java b/test/667-jit-jni-stub/src/Main.java
index 234c5daf4c..179e186f6a 100644
--- a/test/667-jit-jni-stub/src/Main.java
+++ b/test/667-jit-jni-stub/src/Main.java
@@ -43,10 +43,6 @@ public class Main {
// Also tests stack walk over the JIT-compiled stub.
callThrough(Main.class, "testGcWithCallThroughStubOnStack");
- // Test that, when marking used methods before a full JIT GC, a single execution
- // of the GenericJNI trampoline can save the compiled stub from being collected.
- testSingleInvocationTriggersRecompilation();
-
// Test that the JNI compiled stub can actually be collected.
testStubCanBeCollected();
}
@@ -64,17 +60,6 @@ public class Main {
assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
}
- public static void testSingleInvocationTriggersRecompilation() {
- // After scheduling a full JIT GC, single call through the GenericJNI
- // trampoline should ensure that the compiled stub is used again.
- doJitGcsUntilFullJitGcIsScheduled();
- callThrough(Main.class, "doNothing");
- ensureCompiledCallThroughEntrypoint(/* call */ false); // Wait for the compilation task to run.
- assertTrue(hasJitCompiledEntrypoint(Main.class, "callThrough"));
- jitGc(); // This JIT GC should not collect the callThrough() stub.
- assertTrue(hasJitCompiledCode(Main.class, "callThrough"));
- }
-
public static void testMixedFramesOnStack() {
// Starts without a compiled JNI stub for callThrough().
assertFalse(hasJitCompiledEntrypoint(Main.class, "callThrough"));