diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/spirv-cross-internal/src/emscripten.rs | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/spirv-cross-internal/src/emscripten.rs')
-rw-r--r-- | third_party/rust/spirv-cross-internal/src/emscripten.rs | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/third_party/rust/spirv-cross-internal/src/emscripten.rs b/third_party/rust/spirv-cross-internal/src/emscripten.rs new file mode 100644 index 0000000000..f134fbd88c --- /dev/null +++ b/third_party/rust/spirv-cross-internal/src/emscripten.rs @@ -0,0 +1,162 @@ +//! Utilities for interacting with the generated Emscripten module. +//! Most functionality is generalized, but some functionality is specific to SPIRV-Cross. + +use crate::{bindings, ErrorCode}; +use js_sys::{global, Object, Reflect, Uint32Array, Uint8Array}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern "C" { + // Raw Emscripten bindings + #[wasm_bindgen(js_namespace = sc_internal)] + fn _malloc(size: u32) -> u32; + + #[wasm_bindgen(js_namespace = sc_internal)] + fn _free(offset: u32); +} + +pub fn get_module() -> Module { + const MODULE_NAME: &'static str = "sc_internal"; + let module = Reflect::get(&global(), &JsValue::from_str(MODULE_NAME)) + .unwrap() + .into(); + Module { module } +} + +const U32_SIZE: u32 = std::mem::size_of::<u32>() as u32; + +fn get_value<T>(object: &Object, key: &str) -> T +where + T: std::convert::From<wasm_bindgen::JsValue>, +{ + Reflect::get(object, &JsValue::from_str(key)) + .unwrap() + .into() +} + +/// An Emscripten pointer. +/// Internally stores an offset to a location on the Emscripten `u8` heap. +#[derive(Clone, Copy)] +pub struct Pointer { + offset: u32, +} + +impl Pointer { + pub fn from_offset(offset: u32) -> Self { + Pointer { offset } + } + + pub fn as_offset(&self) -> u32 { + self.offset + } +} + +pub struct Module { + module: Object, +} + +impl Module { + /// Allocate memory on the heap. + pub unsafe fn allocate(&self, byte_len: u32) -> Pointer { + Pointer { + offset: _malloc(byte_len), + } + } + + pub unsafe fn free(&self, pointer: Pointer) { + _free(pointer.as_offset()) + } + + // Read a `u32` value from the heap. + pub unsafe fn get_u32(&self, pointer: Pointer) -> u32 { + let offset = &JsValue::from_f64((pointer.offset / U32_SIZE) as f64); + // TODO: Remove Reflect + Reflect::get(&self.heap_u32(), offset) + .unwrap() + .as_f64() + .unwrap() as u32 + } + + /// Set memory on the heap to `bytes`. + pub unsafe fn set_from_u8_typed_array(&self, pointer: Pointer, bytes: Uint8Array) { + let buffer: JsValue = self.heap_u8().buffer().into(); + let memory = + Uint8Array::new_with_byte_offset_and_length(&buffer, pointer.offset, bytes.length()); + memory.set(&bytes, 0); + } + + /// Set memory on the heap to `bytes`. + pub unsafe fn set_from_u8_slice(&self, pointer: Pointer, bytes: &[u8]) { + self.set_from_u8_typed_array(pointer, Uint8Array::view(bytes)); + } + + fn heap_u8(&self) -> Uint8Array { + const HEAP_U8: &'static str = "HEAPU8"; + get_value(&self.module, HEAP_U8) + } + + fn heap_u32(&self) -> Uint32Array { + const HEAP_U32: &'static str = "HEAPU32"; + get_value(&self.module, HEAP_U32) + } + + /// Clones all bytes from the heap into a `Vec<u8>` while `should_continue` returns `true`. + /// Optionally include the last byte (i.e. to support peeking the final byte for nul-terminated strings). + pub unsafe fn read_bytes_into_vec_while<F>( + &self, + pointer: Pointer, + should_continue: F, + include_last_byte: bool, + ) -> Vec<u8> + where + F: Fn(u8, usize) -> bool, + { + let mut bytes = Vec::new(); + let heap = &self.heap_u8(); + let start_offset = pointer.offset as usize; + loop { + let bytes_read = bytes.len(); + let offset = &JsValue::from_f64((start_offset + bytes_read) as f64); + let byte = Reflect::get(heap, offset).unwrap().as_f64().unwrap() as u8; + if should_continue(byte, bytes_read) { + bytes.push(byte); + continue; + } + if include_last_byte { + bytes.push(byte); + } + break; + } + bytes + } + + /// Clones all bytes from the heap into the pointer provided while `should_continue` returns `true`. + /// Optionally include the last byte (i.e. to support peeking the final byte for nul-terminated strings). + /// Assumes the memory at the pointer is large enough to hold all bytes read (based on when `should_continue` terminates). + pub unsafe fn read_bytes_into_pointer_while<F>( + &self, + pointer: Pointer, + should_continue: F, + include_last_byte: bool, + into_pointer: *mut u8, + ) where + F: Fn(u8, usize) -> bool, + { + let heap = &self.heap_u8(); + let start_offset = pointer.offset as usize; + let mut bytes_read = 0; + loop { + let offset = &JsValue::from_f64((start_offset + bytes_read) as f64); + let byte = Reflect::get(heap, offset).unwrap().as_f64().unwrap() as u8; + if should_continue(byte, bytes_read) { + *into_pointer.offset(bytes_read as isize) = byte; + bytes_read += 1; + continue; + } + if include_last_byte { + *into_pointer.offset(bytes_read as isize) = byte; + } + break; + } + } +} |