Flush Icache on AArch64 Windows (#4997)
* cranelift: Add FlushInstructionCache for AArch64 on Windows This was previously done on #3426 for linux. * wasmtime: Add FlushInstructionCache for AArch64 on Windows This was previously done on #3426 for linux. * cranelift: Add MemoryUse flag to JIT Memory Manager This allows us to keep the icache flushing code self-contained and not leak implementation details. This also changes the windows icache flushing code to only flush pages that were previously unflushed. * Add jit-icache-coherence crate * cranelift: Use `jit-icache-coherence` * wasmtime: Use `jit-icache-coherence` * jit-icache-coherence: Make rustix feature additive Mutually exclusive features cause issues. * wasmtime: Remove rustix from wasmtime-jit We now use it via jit-icache-coherence * Rename wasmtime-jit-icache-coherency crate * Use cfg-if in wasmtime-jit-icache-coherency crate * Use inline instead of inline(always) * Add unsafe marker to clear_cache * Conditionally compile all rustix operations membarrier does not exist on MacOS * Publish `wasmtime-jit-icache-coherence` * Remove explicit windows check This is implied by the target_os = "windows" above * cranelift: Remove len != 0 check This is redundant as it is done in non_protected_allocations_iter * Comment cleanups Thanks @akirilov-arm! * Make clear_cache safe * Rename pipeline_flush to pipeline_flush_mt * Revert "Make clear_cache safe" This reverts commit 21165d81c9030ed9b291a1021a367214d2942c90. * More docs! * Fix pipeline_flush reference on clear_cache * Update more docs! * Move pipeline flush after `mprotect` calls Technically the `clear_cache` operation is a lie in AArch64, so move the pipeline flush after the `mprotect` calls so that it benefits from the implicit cache cleaning done by it. * wasmtime: Remove rustix backend from icache crate * wasmtime: Use libc for macos * wasmtime: Flush icache on all arch's for windows * wasmtime: Add flags to membarrier call
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
use crate::unwind::UnwindRegistration;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use object::read::{File, Object, ObjectSection};
|
||||
use std::ffi::c_void;
|
||||
use std::mem::ManuallyDrop;
|
||||
use wasmtime_jit_icache_coherence as icache_coherence;
|
||||
use wasmtime_runtime::MmapVec;
|
||||
|
||||
/// Management of executable memory within a `MmapVec`
|
||||
@@ -54,15 +56,6 @@ impl CodeMemory {
|
||||
/// The returned `CodeMemory` manages the internal `MmapVec` and the
|
||||
/// `publish` method is used to actually make the memory executable.
|
||||
pub fn new(mmap: MmapVec) -> Self {
|
||||
#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
|
||||
{
|
||||
// This is a requirement of the `membarrier` call executed by the `publish` method.
|
||||
rustix::process::membarrier(
|
||||
rustix::process::MembarrierCommand::RegisterPrivateExpeditedSyncCore,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Self {
|
||||
mmap: ManuallyDrop::new(mmap),
|
||||
unwind_registration: ManuallyDrop::new(None),
|
||||
@@ -155,6 +148,13 @@ impl CodeMemory {
|
||||
// must be added here, though, if relocations pop up.
|
||||
assert!(text.relocations().count() == 0);
|
||||
|
||||
// Clear the newly allocated code from cache if the processor requires it
|
||||
//
|
||||
// Do this before marking the memory as R+X, technically we should be able to do it after
|
||||
// but there are some CPU's that have had errata about doing this with read only memory.
|
||||
icache_coherence::clear_cache(ret.text.as_ptr() as *const c_void, ret.text.len())
|
||||
.expect("Failed cache clear");
|
||||
|
||||
// Switch the executable portion from read/write to
|
||||
// read/execute, notably not using read/write/execute to prevent
|
||||
// modifications.
|
||||
@@ -162,14 +162,8 @@ impl CodeMemory {
|
||||
.make_executable(text_range.clone(), enable_branch_protection)
|
||||
.expect("unable to make memory executable");
|
||||
|
||||
#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
|
||||
{
|
||||
// Ensure that no processor has fetched a stale instruction stream.
|
||||
rustix::process::membarrier(
|
||||
rustix::process::MembarrierCommand::PrivateExpeditedSyncCore,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
// Flush any in-flight instructions from the pipeline
|
||||
icache_coherence::pipeline_flush_mt().expect("Failed pipeline flush");
|
||||
|
||||
// With all our memory set up use the platform-specific
|
||||
// `UnwindRegistration` implementation to inform the general
|
||||
|
||||
Reference in New Issue
Block a user