diff --git a/render-wasm/src/mem.rs b/render-wasm/src/mem.rs index d03cb4fdc1..1c8531e7e9 100644 --- a/render-wasm/src/mem.rs +++ b/render-wasm/src/mem.rs @@ -1,61 +1,73 @@ -use std::sync::Mutex; - -use crate::error::{Error, Result, CRITICAL_ERROR}; +use crate::{error::Result, performance}; pub const LAYOUT_ALIGN: usize = 4; -pub static BUFFERU8: Mutex>> = Mutex::new(None); -pub static BUFFER_ERROR: Mutex = Mutex::new(0x00); +// Please, read about the #[allow(static_mut_refs)] +// +// If we don't put this allow, the compiler shows a warning like this: +// +// shared references to mutable statics are dangerous; it's undefined behavior +// if the static is mutated or if a mutable reference is created for it while +// the shared reference lives +// +// https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html +// +// But this isn't a problem in a single-threaded environment like WebAssembly +// because access/modification is always sequential, not parallel. +pub static mut BUFFERU8: Option> = None; +pub static mut BUFFER_ERROR: u8 = 0x00; pub fn clear_error_code() { - let mut guard = BUFFER_ERROR.lock().unwrap(); - *guard = 0x00; + unsafe { + BUFFER_ERROR = 0x00; + } } /// Sets the error buffer from a byte. Used by #[wasm_error] when E: Into. pub fn set_error_code(code: u8) { - let mut guard = BUFFER_ERROR.lock().unwrap(); - *guard = code; + unsafe { + BUFFER_ERROR = code; + } } #[no_mangle] pub extern "C" fn read_error_code() -> u8 { - if let Ok(guard) = BUFFER_ERROR.lock() { - *guard - } else { - CRITICAL_ERROR - } + unsafe { BUFFER_ERROR } } pub fn write_bytes(mut bytes: Vec) -> *mut u8 { - let mut guard = BUFFERU8.lock().unwrap(); + unsafe { + performance::begin_measure!("write_bytes"); + #[allow(static_mut_refs)] + if BUFFERU8.is_some() { + panic!("Bytes already allocated"); + } - if guard.is_some() { - panic!("Bytes already allocated"); + let ptr = bytes.as_mut_ptr(); + BUFFERU8 = Some(bytes); + performance::end_measure!("write_bytes"); + ptr } - - let ptr = bytes.as_mut_ptr(); - - *guard = Some(bytes); - ptr } pub fn bytes() -> Vec { - let mut guard = BUFFERU8.lock().unwrap(); - guard.take().expect("Buffer is not initialized") + unsafe { + #[allow(static_mut_refs)] + BUFFERU8.take().expect("Buffer is not initialized") + } } pub fn bytes_or_empty() -> Vec { - let mut guard = BUFFERU8.lock().unwrap(); - guard.take().unwrap_or_default() + unsafe { + #[allow(static_mut_refs)] + BUFFERU8.take().unwrap_or_default() + } } pub fn free_bytes() -> Result<()> { - let mut guard = BUFFERU8 - .lock() - .map_err(|_| Error::CriticalError("Failed to lock buffer".to_string()))?; - *guard = None; - std::mem::drop(guard); + unsafe { + BUFFERU8 = None; + } Ok(()) } diff --git a/render-wasm/src/wasm/mem.rs b/render-wasm/src/wasm/mem.rs index 8f6b7508ef..4cff8d0cd2 100644 --- a/render-wasm/src/wasm/mem.rs +++ b/render-wasm/src/wasm/mem.rs @@ -9,15 +9,22 @@ use macros::wasm_error; #[no_mangle] #[wasm_error] pub extern "C" fn alloc_bytes(len: usize) -> Result<*mut u8> { - let mut guard = BUFFERU8 - .lock() - .map_err(|_| Error::CriticalError("Failed to lock buffer".to_string()))?; - - if guard.is_some() { - return Err(Error::CriticalError("Bytes already allocated".to_string())); - } - unsafe { + // If we don't put this allow, the compiler shows a warning like this: + // + // shared references to mutable statics are dangerous; it's undefined behavior + // if the static is mutated or if a mutable reference is created for it while + // the shared reference lives + // + // https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html + // + // But this isn't a problem in a single-threaded environment like WebAssembly + // because access/modification is always sequential, not parallel. + #[allow(static_mut_refs)] + if BUFFERU8.is_some() { + return Err(Error::CriticalError("Bytes already allocated".to_string())); + } + let layout = Layout::from_size_align_unchecked(len, LAYOUT_ALIGN); let ptr = alloc(layout); if ptr.is_null() { @@ -25,7 +32,7 @@ pub extern "C" fn alloc_bytes(len: usize) -> Result<*mut u8> { } // TODO: Maybe this could be removed. ptr::write_bytes(ptr, 0, len); - *guard = Some(Vec::from_raw_parts(ptr, len, len)); + BUFFERU8 = Some(Vec::from_raw_parts(ptr, len, len)); Ok(ptr) } }