use core::ffi::c_void;
use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use super::{Alloc, MemConfig, PrimError, TlsDtor, align_up};
const WASM_PAGE: usize = 65536;
const WERR: PrimError = 0xBEEF;
pub(super) fn mem_init() -> MemConfig {
MemConfig {
page_size: WASM_PAGE,
alloc_granularity: WASM_PAGE,
large_page_size: 0,
has_overcommit: false,
has_partial_free: false,
}
}
#[inline]
fn memory_end() -> usize {
core::arch::wasm32::memory_size::<0>() * WASM_PAGE
}
pub(super) unsafe fn alloc(
size: usize,
try_alignment: usize,
_commit: bool,
_allow_large: bool,
) -> Result<Alloc, PrimError> {
let align = try_alignment.max(WASM_PAGE);
let cur = memory_end();
let pad = align_up(cur, align) - cur;
let pages = (pad + size).div_ceil(WASM_PAGE);
let prev = core::arch::wasm32::memory_grow::<0>(pages);
if prev == usize::MAX {
return Err(WERR);
}
let base = prev * WASM_PAGE;
debug_assert_eq!(base, cur, "memory grew under us in a single-threaded build");
Ok(Alloc {
ptr: core::ptr::with_exposed_provenance_mut(base + pad),
is_large: false,
is_zero: true,
})
}
pub(super) unsafe fn free(_ptr: *mut u8, _size: usize) -> Result<(), PrimError> {
Ok(())
}
pub(super) unsafe fn commit(_ptr: *mut u8, _size: usize) -> Result<bool, PrimError> {
Ok(false)
}
pub(super) unsafe fn decommit(_ptr: *mut u8, _size: usize) -> Result<bool, PrimError> {
Ok(false)
}
pub(super) unsafe fn reset(_ptr: *mut u8, _size: usize) -> Result<(), PrimError> {
Ok(())
}
pub(super) unsafe fn protect(_ptr: *mut u8, _size: usize, _on: bool) -> Result<(), PrimError> {
Err(WERR)
}
pub(super) fn numa_node_count() -> usize {
1
}
#[inline]
pub(super) fn thread_id() -> usize {
1
}
pub(super) fn clock_now() -> u64 {
static TICK: AtomicU64 = AtomicU64::new(1);
TICK.fetch_add(1, Ordering::Relaxed)
}
const MAX_TLS: usize = 64;
static TLS_VALUES: [AtomicUsize; MAX_TLS] = [const { AtomicUsize::new(0) }; MAX_TLS];
static NEXT_SLOT: AtomicUsize = AtomicUsize::new(0);
pub(super) struct TlsSlotImpl(usize);
pub(super) fn tls_new(_dtor: Option<TlsDtor>) -> Option<TlsSlotImpl> {
let idx = NEXT_SLOT.fetch_add(1, Ordering::Relaxed);
if idx < MAX_TLS {
Some(TlsSlotImpl(idx))
} else {
None
}
}
pub(super) fn tls_get(slot: &TlsSlotImpl) -> *mut c_void {
core::ptr::with_exposed_provenance_mut(TLS_VALUES[slot.0].load(Ordering::Relaxed))
}
pub(super) fn tls_set(slot: &TlsSlotImpl, value: *mut c_void) {
TLS_VALUES[slot.0].store(value.expose_provenance(), Ordering::Relaxed);
}
pub(super) fn tls_raw(slot: &TlsSlotImpl) -> usize {
slot.0
}
pub(super) fn tls_from_raw(raw: usize) -> TlsSlotImpl {
TlsSlotImpl(raw)
}