makepad/libs/relax/compiler/tests/domain_statics.rs
Admin b22a714840 makepad run: the Rust JIT (libs/relax) and makepad-remote
The JIT that runs makepad apps from source: lexer, front end, type checker,
lazy borrow checker (Gandalf; `--check-first` opts in), codegen, session and
warm/cold caches keyed by compiler stamp, provided crates bound late,
startup images, live patching. User-facing name is `makepad run` (binary
`makepad`, MAKEPAD_RUN_* env, ~/.makepad-run); libs/relax stays the internal
library name. `makepad check` reports rustc-style diagnostics with rustc
error codes and checks a whole workspace (`--workspace`). Runs on macOS,
Linux, Windows and Android. makepad-remote: one tool schema for apps and the
WM (app/1): grabs, captures, traces, frame profiles and tweaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

76 lines
2.5 KiB
Rust

// Statics are domain-local (src/domain.rs): code reaches one through the running thread's domain
// block, a static's image points at other statics (cyclic ones too), and a thread std starts runs in
// its parent's domain. With one domain this must read exactly as absolute addresses did.
use std::sync::atomic::*;
struct Node {
next: &'static Node,
v: u32,
}
static BASE: u64 = 7;
static PBASE: &u64 = &BASE;
static TABLE: [&u64; 2] = [&BASE, &BASE];
static NA: Node = Node { next: &NB, v: 1 };
static NB: Node = Node { next: &NA, v: 2 };
static mut COUNTER: u64 = 5;
static mut CELL: u64 = 1;
static PCELL: *mut u64 = unsafe { &CELL as *const u64 as *mut u64 };
static HITS: AtomicU64 = AtomicU64::new(0);
static PHITS: &AtomicU64 = &HITS;
#[test]
fn images_point_at_statics() {
assert_eq!(*PBASE, 7);
assert!(std::ptr::eq(PBASE, &BASE));
assert!(std::ptr::eq(TABLE[0], &BASE) && std::ptr::eq(TABLE[1], &BASE));
assert_eq!(NA.next.v, 2);
assert_eq!(NB.next.v, 1);
assert!(std::ptr::eq(NA.next.next, &NA));
unsafe {
COUNTER += 1;
assert_eq!(COUNTER, 6);
*PCELL += 10;
assert_eq!(CELL, 11);
assert!(std::ptr::eq(PCELL as *const u64, &CELL as *const u64));
}
PHITS.fetch_add(3, Ordering::SeqCst);
assert_eq!(HITS.load(Ordering::SeqCst), 3);
}
#[test]
fn threads_run_in_the_domain_of_their_parent() {
HITS.store(0, Ordering::SeqCst);
let mut hs = Vec::new();
for i in 0..4u64 {
hs.push(std::thread::spawn(move || {
for _ in 0..1000 {
PHITS.fetch_add(1, Ordering::SeqCst);
}
// the statics this thread names are the process's: the same addresses as in the parent
(&HITS as *const AtomicU64 as usize, NA.next.next.v as u64 + i, *PBASE)
}));
}
let mut seen = Vec::new();
for h in hs {
seen.push(h.join().unwrap());
}
assert_eq!(HITS.load(Ordering::SeqCst), 4000);
for (k, (addr, v, b)) in seen.iter().enumerate() {
assert_eq!(*addr, &HITS as *const AtomicU64 as usize);
assert_eq!(*v, 1 + k as u64);
assert_eq!(*b, 7);
}
// a panic caught inside a thread leaves its statics alone
let r = std::thread::spawn(|| {
let r = std::panic::catch_unwind(|| {
PHITS.fetch_add(1, Ordering::SeqCst);
panic!("domain test");
});
r.is_err() && HITS.load(Ordering::SeqCst) >= 4001
})
.join()
.unwrap();
assert!(r);
}