makepad/libs/relax/compiler/tests/cabi_narrow.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

113 lines
4.4 KiB
Rust

// Narrow integer results (i8, i16, i32, u8, u16, bool) of C functions, called directly
// and through `extern "C" fn` pointers (from the libc symbol and from Relax's own
// `extern "C"` bodies): C leaves the upper register bits undefined, so the caller must
// re-extend them. Output matches rustc.
extern "C" {
fn abs(x: i32) -> i32;
fn atoi(s: *const u8) -> i32;
fn strtol(s: *const u8, end: *mut *const u8, base: i32) -> i64;
// libc functions as pointers, the way std's sys layer gets optional APIs
#[link_name = "dlsym"]
fn dlsym_atoi(h: *mut u8, name: *const u8) -> unsafe extern "C" fn(*const u8) -> i32;
#[link_name = "dlsym"]
fn dlsym_abs(h: *mut u8, name: *const u8) -> unsafe extern "C" fn(i32) -> i32;
// syscall wrappers typically return -1 in a 32-bit register (upper bits zero)
#[link_name = "dlsym"]
fn dlsym_close(h: *mut u8, name: *const u8) -> unsafe extern "C" fn(i32) -> i32;
#[link_name = "dlsym"]
fn dlsym_dup(h: *mut u8, name: *const u8) -> unsafe extern "C" fn(i32) -> i32;
fn close(fd: i32) -> i32;
fn dlsym(h: *mut u8, name: *const u8) -> *mut u8;
}
type IntFn = unsafe extern "C" fn(i32) -> i32;
type WakeFn = unsafe extern "C" fn(*mut u8, usize, u32) -> i32;
static mut WORD: u32 = 0;
/// os_sync_wake_by_address_any with no waiter returns -1 in w0 (x0's upper half zero).
#[cfg(target_os = "macos")]
fn os_sync_line() {
let raw = unsafe { dlsym(RTLD_DEFAULT as *mut u8, cstr("os_sync_wake_by_address_any\0")) } as usize;
if raw == 0 {
println!("os_sync -1 true");
return;
}
let wake: WakeFn = unsafe { core::mem::transmute(raw) };
let r = unsafe { wake(&mut WORD as *mut u32 as *mut u8, 4, 0) };
println!("os_sync {} {}", r, r < 0);
}
#[cfg(not(target_os = "macos"))]
fn os_sync_line() {
println!("os_sync -1 true");
}
#[cfg(target_os = "macos")]
const RTLD_DEFAULT: isize = -2;
#[cfg(not(target_os = "macos"))]
const RTLD_DEFAULT: isize = 0;
// C bodies whose results have garbage-prone upper bits after their own arithmetic
extern "C" fn neg_i8(x: i32) -> i8 {
(0 - x) as i8
}
extern "C" fn neg_i16(x: i32) -> i16 {
(0 - x) as i16
}
extern "C" fn neg_i32(x: i64) -> i32 {
(0 - x) as i32
}
extern "C" fn trunc_u8(x: i32) -> u8 {
x as u8
}
extern "C" fn trunc_u16(x: i32) -> u16 {
x as u16
}
extern "C" fn is_neg(x: i32) -> bool {
x < 0
}
fn via_ptr_i32(f: extern "C" fn(i64) -> i32, x: i64) -> i64 {
f(x) as i64
}
fn cstr(s: &str) -> *const u8 {
s as *const str as *const u8
}
#[test]
fn direct_and_pointer_narrow_returns() {
let a = unsafe { atoi(cstr("-1\0")) };
let b = unsafe { abs(-7) };
println!("direct {} {} {}", a, b, unsafe { strtol(cstr("-42\0"), 0 as *mut *const u8, 10) });
let p_atoi = unsafe { dlsym_atoi(RTLD_DEFAULT as *mut u8, cstr("atoi\0")) };
let p_abs = unsafe { dlsym_abs(RTLD_DEFAULT as *mut u8, cstr("abs\0")) };
let c = unsafe { p_atoi(cstr("-1\0")) };
let d = unsafe { p_atoi(cstr("-2147483648\0")) };
println!("ptr libc {} {} {} {}", c, d, unsafe { p_abs(-5) }, c < 0);
let p_close = unsafe { dlsym_close(RTLD_DEFAULT as *mut u8, cstr("close\0")) };
let p_dup = unsafe { dlsym_dup(RTLD_DEFAULT as *mut u8, cstr("dup\0")) };
let e1 = unsafe { p_close(-1) };
let e2 = unsafe { p_dup(-5) };
let e3 = unsafe { close(-1) };
println!("ptr syscall {} {} direct {} {} {}", e1, e2, e3, e1 < 0, e1 == -1);
// an untyped dlsym result transmuted to a fn pointer type (std's sys-layer pattern)
let raw = unsafe { dlsym(RTLD_DEFAULT as *mut u8, cstr("close\0")) } as usize;
let t_close: IntFn = unsafe { core::mem::transmute(raw) };
let e4 = unsafe { t_close(-1) };
println!("transmuted {} {} {}", e4, e4 < 0, e4 == -1);
os_sync_line();
let f8: extern "C" fn(i32) -> i8 = neg_i8;
let f16: extern "C" fn(i32) -> i16 = neg_i16;
let f32_: extern "C" fn(i64) -> i32 = neg_i32;
let fu8: extern "C" fn(i32) -> u8 = trunc_u8;
let fu16: extern "C" fn(i32) -> u16 = trunc_u16;
let fb: extern "C" fn(i32) -> bool = is_neg;
println!("ptr i8 {} {} i16 {} {}", f8(1), f8(-200), f16(1), f16(40000));
println!("ptr i32 {} {} {}", f32_(1), f32_(-2147483648), via_ptr_i32(neg_i32, 5));
println!("ptr u8 {} {} u16 {} {}", fu8(-1), fu8(300), fu16(-1), fu16(70000));
println!("ptr bool {} {} {}", fb(-3), fb(3), fb(-3) as i32 + fb(3) as i32);
println!("direct bodies {} {} {}", neg_i8(1), neg_i32(7), is_neg(-1));
}