ART: Avoid shared cache lines for JIT code allocations
Dual view JIT exhibits some hygiene issues that causes crashes on
devices with 32-bit kernels.
This change makes JIT code allocations cache aligned. This is based on
guidance in the v7_coherent_user_range() that says "it is assumed that
the Icache does not read data from the write buffer".
Bug: 132205399
Test: >2000 boot tests on affected device with no zygote crashes.
Test: No crashes running ART JIT benchmarks on go/lem
Test: No failures with Treehugger
Change-Id: I901e2e5c07b9502876b33f572be63ec1dca19cbe
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 47a8b47..65e6d9d 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -1047,7 +1047,8 @@
}
// FlushInstructionCache() flushes both data and instruction caches lines. The cacheline range
// flushed is for the executable mapping of the code just added.
- FlushInstructionCache(code_ptr, code_ptr + code_size);
+ uint8_t* x_memory = reinterpret_cast<uint8_t*>(method_header);
+ FlushInstructionCache(x_memory, x_memory + total_size);
// Ensure CPU instruction pipelines are flushed for all cores. This is necessary for
// correctness as code may still be in instruction pipelines despite the i-cache flush. It is
@@ -2148,10 +2149,12 @@
}
}
-uint8_t* JitCodeCache::AllocateCode(size_t code_size) {
- size_t alignment = GetInstructionSetAlignment(kRuntimeISA);
+uint8_t* JitCodeCache::AllocateCode(size_t allocation_size) {
+ // Each allocation should be on its own set of cache lines. The allocation must be large enough
+ // for header, code, and any padding.
uint8_t* result = reinterpret_cast<uint8_t*>(
- mspace_memalign(exec_mspace_, alignment, code_size));
+ mspace_memalign(exec_mspace_, kJitCodeAlignment, allocation_size));
+ size_t alignment = GetInstructionSetAlignment(kRuntimeISA);
size_t header_size = RoundUp(sizeof(OatQuickMethodHeader), alignment);
// Ensure the header ends up at expected instruction alignment.
DCHECK_ALIGNED_PARAM(reinterpret_cast<uintptr_t>(result + header_size), alignment);
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index fabb978..a3e10c7 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -74,8 +74,13 @@
class MarkCodeClosure;
class ScopedCodeCacheWrite;
-// Alignment in bits that will suit all architectures.
-static constexpr int kJitCodeAlignment = 16;
+// Alignment in bytes that will suit all architectures for JIT code cache allocations. The
+// allocated block is used for method header followed by generated code. Allocations should be
+// aligned to avoid sharing cache lines between different allocations. The alignment should be
+// determined from the hardware, but this isn't readily exposed in userland plus some hardware
+// misreports.
+static constexpr int kJitCodeAlignment = 64;
+
using CodeCacheBitmap = gc::accounting::MemoryRangeBitmap<kJitCodeAlignment>;
class JitCodeCache {