js_wasm_runtime_layer/
memory.rs1use js_sys::{ArrayBuffer, Object, Reflect, Uint8Array, WebAssembly};
2use wasm_bindgen::{JsCast as _, JsValue};
3use wasm_runtime_layer::{
4 backend::{AsContext, AsContextMut, WasmMemory},
5 MemoryType,
6};
7
8use crate::{conversion::ToStoredJs, Engine, JsErrorMsg, StoreInner};
9
10#[derive(Debug, Clone)]
11pub struct Memory {
13 pub id: usize,
15}
16
17#[derive(Debug)]
18pub(crate) struct MemoryInner {
20 pub value: WebAssembly::Memory,
22 pub ty: MemoryType,
24}
25
26impl MemoryInner {
27 pub(crate) fn as_uint8array(&self, offset: u32, len: u32) -> Uint8Array {
29 let buffer = self.value.buffer();
30 let buffer = buffer.dyn_ref::<ArrayBuffer>().unwrap();
31
32 Uint8Array::new_with_byte_offset_and_length(buffer, offset, len)
33 }
34}
35
36impl ToStoredJs for Memory {
37 type Repr = WebAssembly::Memory;
38 fn to_stored_js<T>(&self, store: &StoreInner<T>) -> WebAssembly::Memory {
39 let memory = &store.memories[self.id];
40
41 memory.value.clone()
42 }
43}
44
45impl Memory {
46 pub(crate) fn from_exported_memory<T>(
48 store: &mut StoreInner<T>,
49 value: JsValue,
50 ty: MemoryType,
51 ) -> Option<Self> {
52 let memory: &WebAssembly::Memory = value.dyn_ref()?;
53
54 Some(store.insert_memory(MemoryInner {
55 value: memory.clone(),
56 ty,
57 }))
58 }
59}
60
61impl WasmMemory<Engine> for Memory {
62 fn new(mut ctx: impl AsContextMut<Engine>, ty: MemoryType) -> anyhow::Result<Self> {
63 let desc = Object::new();
64 Reflect::set(&desc, &"initial".into(), &ty.initial_pages().into()).unwrap();
65 if let Some(maximum) = ty.maximum_pages() {
66 Reflect::set(&desc, &"maximum".into(), &maximum.into()).unwrap();
67 }
68
69 let memory = WebAssembly::Memory::new(&desc).map_err(JsErrorMsg::from)?;
70
71 let ctx: &mut StoreInner<_> = &mut *ctx.as_context_mut();
72
73 Ok(ctx.insert_memory(MemoryInner { value: memory, ty }))
74 }
75
76 fn ty(&self, ctx: impl AsContext<Engine>) -> MemoryType {
77 ctx.as_context().memories[self.id].ty
78 }
79
80 fn grow(&self, mut ctx: impl AsContextMut<Engine>, additional: u32) -> anyhow::Result<u32> {
81 let ctx: &mut StoreInner<_> = &mut *ctx.as_context_mut();
82
83 let inner = &mut ctx.memories[self.id];
84 Ok(inner.value.grow(additional))
85 }
86
87 fn current_pages(&self, _: impl AsContext<Engine>) -> u32 {
88 todo!("Memory::current_pages is not yet supported in the js_wasm_runtime_layer backend")
89 }
90
91 fn read(
92 &self,
93 ctx: impl AsContext<Engine>,
94 offset: usize,
95 buffer: &mut [u8],
96 ) -> anyhow::Result<()> {
97 let ctx: &StoreInner<_> = &*ctx.as_context();
98 let memory = &ctx.memories[self.id];
99
100 memory
101 .as_uint8array(offset as _, buffer.len() as _)
102 .copy_to(buffer);
103
104 Ok(())
105 }
106
107 fn write(
108 &self,
109 mut ctx: impl AsContextMut<Engine>,
110 offset: usize,
111 buffer: &[u8],
112 ) -> anyhow::Result<()> {
113 let ctx: &mut StoreInner<_> = &mut *ctx.as_context_mut();
114
115 let inner = &mut ctx.memories[self.id];
116 let dst = inner.as_uint8array(offset as _, buffer.len() as _);
117
118 #[cfg(feature = "tracing")]
119 tracing::debug!("writing {buffer:?} into guest");
120 dst.copy_from(buffer);
121
122 Ok(())
123 }
124}