1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//! Instruction-cache coherence for freshly written code.
//!
//! Writing machine code into memory and then executing it is only correct once the
//! processor's instruction fetch sees the bytes the write left in the data cache. On
//! x86 and x86-64 the instruction and data caches are unified, so that happens for
//! free. On architectures with split caches — AArch64 — the data cache must be cleaned
//! and the instruction cache invalidated over the new code first, or the fetcher may
//! read stale bytes and run garbage.
//!
//! [`synchronize`] does this at the point the code is made executable: a no-op where
//! the caches are already coherent, and the platform's correct primitive where they
//! are not. The supported hosts are x86-64 and AArch64; on any other architecture no
//! `sync` is defined, so the crate fails to compile rather than run code with unproven
//! cache behavior.
/// Makes `len` bytes of freshly written machine code at `code` safe to execute by
/// synchronizing the instruction cache over that range.
///
/// Called after the code has been written and the region made readable and executable.
/// On a platform with coherent caches this does nothing; on one with split caches it
/// issues the clean-and-invalidate the architecture requires.
pub
/// x86 and x86-64 keep the instruction and data caches coherent, so code written into
/// a region is visible to the fetcher with no further action.
/// AArch64 has split caches, so the instruction cache must be synchronized over the
/// new code. macOS exposes the correct user-space primitive for this — the raw
/// cache-maintenance instructions (`ic ivau` and friends) fault from user space on
/// Apple silicon — while other systems provide the compiler runtime's `__clear_cache`,
/// which the kernel emulates where those instructions are trapped.