Change flush order in JIT code cache
Flush the data cache before flushing the instruction when dual mapped.
Bug: 62356545
Test: art/test.py -j4 --jit --64 -r --verbose -t test-art-target-run-test-debug-prebuild-jit-no-relocate-ntrace-gcstress-checkjni-picimage-npictest-ndebuggable-no-jvmti-916-obsolete-jit64
Test: Using an Android N image and testing on device from master-art
Change-Id: Ia73da7449cc3a40be0128825233086924eca90a5
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 8295f46..eb9199a 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -90,7 +90,6 @@
return new_map;
}
-
JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
size_t max_capacity,
bool generate_debug_info,
@@ -802,12 +801,27 @@
//
// For reference, this behavior is caused by this commit:
// https://android.googlesource.com/kernel/msm/+/3fbe6bc28a6b9939d0650f2f17eb5216c719950c
- FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
- reinterpret_cast<char*>(code_ptr + code_size));
if (writable_ptr != code_ptr) {
+ // When there are two mappings of the JIT code cache, RX and
+ // RW, flush the RW version first as we've just dirtied the
+ // cache lines with new code. Flushing the RX version first
+ // can cause a permission fault as the those addresses are not
+ // writable, but can appear dirty in the cache. There is a lot
+ // of potential subtlety here depending on how the cache is
+ // indexed and tagged.
+ //
+ // Flushing the RX version after the RW version is just
+ // invalidating cachelines in the instruction cache. This is
+ // necessary as the instruction cache will often have a
+ // different set of cache lines present and because the JIT
+ // code cache can start a new function at any boundary within
+ // a cache-line.
FlushDataCache(reinterpret_cast<char*>(writable_ptr),
reinterpret_cast<char*>(writable_ptr + code_size));
}
+ FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
+ reinterpret_cast<char*>(code_ptr + code_size));
+
DCHECK(!Runtime::Current()->IsAotCompiler());
if (has_should_deoptimize_flag) {
writable_method_header->SetHasShouldDeoptimizeFlag();