Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/jit-icache-coherence/src/lib.rs
1692 views
1
//! This crate provides utilities for instruction cache maintenance for JIT authors.
2
//!
3
//! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime
4
//! > project and is not intended for general use. APIs are not strictly
5
//! > reviewed for safety and usage outside of Wasmtime may have bugs. If
6
//! > you're interested in using this feel free to file an issue on the
7
//! > Wasmtime repository to start a discussion about doing so, but otherwise
8
//! > be aware that your usage of this crate is not supported.
9
//!
10
//! In self modifying codes such as when writing a JIT, special care must be taken when marking the
11
//! code as ready for execution. On fully coherent architectures (X86, S390X) the data cache (D-Cache)
12
//! and the instruction cache (I-Cache) are always in sync. However this is not guaranteed for all
13
//! architectures such as AArch64 where these caches are not coherent with each other.
14
//!
15
//! When writing new code there may be a I-cache entry for that same address which causes the
16
//! processor to execute whatever was in the cache instead of the new code.
17
//!
18
//! See the [ARM Community - Caches and Self-Modifying Code] blog post that contains a great
19
//! explanation of the above. (It references AArch32 but it has a high level overview of this problem).
20
//!
21
//! ## Usage
22
//!
23
//! You should call [clear_cache] on any pages that you write with the new code that you're intending
24
//! to execute. You can do this at any point in the code from the moment that you write the page up to
25
//! the moment where the code is executed.
26
//!
27
//! You also need to call [pipeline_flush_mt] to ensure that there isn't any invalid instruction currently
28
//! in the pipeline if you are running in a multi threaded environment.
29
//!
30
//! For single threaded programs you are free to omit [pipeline_flush_mt], otherwise you need to
31
//! call both [clear_cache] and [pipeline_flush_mt] in that order.
32
//!
33
//! ### Example:
34
//! ```
35
//! # use std::ffi::c_void;
36
//! # use std::io;
37
//! # use wasmtime_internal_jit_icache_coherence::*;
38
//! #
39
//! # struct Page {
40
//! # addr: *const c_void,
41
//! # len: usize,
42
//! # }
43
//! #
44
//! # fn main() -> anyhow::Result<()> {
45
//! #
46
//! # let run_code = || {};
47
//! # let code = vec![0u8; 64];
48
//! # let newly_written_pages = vec![Page {
49
//! # addr: &code[0] as *const u8 as *const c_void,
50
//! # len: code.len(),
51
//! # }];
52
//! # unsafe {
53
//! // Invalidate the cache for all the newly written pages where we wrote our new code.
54
//! for page in newly_written_pages {
55
//! clear_cache(page.addr, page.len)?;
56
//! }
57
//!
58
//! // Once those are invalidated we also need to flush the pipeline
59
//! pipeline_flush_mt()?;
60
//!
61
//! // We can now safely execute our new code.
62
//! run_code();
63
//! # }
64
//! # Ok(())
65
//! # }
66
//! ```
67
//!
68
//! <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
69
//!
70
//! **Warning**: In order to correctly use this interface you should always call [clear_cache].
71
//! A followup call to [pipeline_flush_mt] is required if you are running in a multi-threaded environment.
72
//!
73
//! </pre></div>
74
//!
75
//! [ARM Community - Caches and Self-Modifying Code]: https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/caches-and-self-modifying-code
76
77
use std::ffi::c_void;
78
79
cfg_if::cfg_if! {
80
if #[cfg(target_os = "windows")] {
81
mod win;
82
use win as imp;
83
} else if #[cfg(miri)] {
84
mod miri;
85
use crate::miri as imp;
86
} else {
87
mod libc;
88
use crate::libc as imp;
89
}
90
}
91
92
/// Flushes instructions in the processor pipeline
93
///
94
/// This pipeline flush is broadcast to all processors that are executing threads in the current process.
95
///
96
/// Calling [pipeline_flush_mt] is only required for multi-threaded programs and it *must* be called
97
/// after all calls to [clear_cache].
98
///
99
/// If the architecture does not require a pipeline flush, this function does nothing.
100
pub fn pipeline_flush_mt() -> imp::Result<()> {
101
imp::pipeline_flush_mt()
102
}
103
104
/// Flushes the instruction cache for a region of memory.
105
///
106
/// If the architecture does not require an instruction cache flush, this function does nothing.
107
///
108
/// # Unsafe
109
///
110
/// It is necessary to call [pipeline_flush_mt] after this function if you are running in a multi-threaded
111
/// environment.
112
pub unsafe fn clear_cache(ptr: *const c_void, len: usize) -> imp::Result<()> {
113
imp::clear_cache(ptr, len)
114
}
115
116