Skip to content

Commit 1487ac4

Browse files
authored
Merge pull request #5617 from wasmerio/feat/memory-size-fn
Implement Memory::size function
2 parents bf72908 + 80d3537 commit 1487ac4

10 files changed

Lines changed: 102 additions & 1 deletion

File tree

lib/api/src/backend/js/entities/memory/js.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ extern "C" {
88
#[derive(Clone, Debug, PartialEq, Eq)]
99
pub type JSMemory;
1010

11+
/// The `buffer` property of the `Memory` object, which is an `ArrayBuffer` or `SharedArrayBuffer`.
12+
///
13+
/// [MDN documentation](https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/JavaScript_interface/Memory/buffer)
14+
#[wasm_bindgen(method, getter, js_name = buffer, js_namespace = WebAssembly)]
15+
pub fn buffer(this: &JSMemory) -> JsValue;
16+
1117
/// The `grow()` protoype method of the `Memory` object increases the
1218
/// size of the memory instance by a specified number of WebAssembly
1319
/// pages.

lib/api/src/backend/js/entities/memory/mod.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub(crate) mod buffer;
88
pub(crate) use buffer::*;
99

1010
use wasm_bindgen::JsCast;
11-
use wasmer_types::{MemoryError, MemoryType, Pages};
11+
use wasmer_types::{MemoryError, MemoryType, Pages, WASM_PAGE_SIZE};
1212

1313
use crate::{
1414
js::vm::memory::VMMemory,
@@ -88,6 +88,24 @@ impl Memory {
8888
MemoryView::new(self, store)
8989
}
9090

91+
pub fn size(&self, store: &impl AsStoreRef) -> Pages {
92+
let js_memory = &self.handle.memory;
93+
let our_js_memory: &JSMemory = JsCast::unchecked_from_js_ref(js_memory);
94+
let buffer = our_js_memory.buffer();
95+
96+
let byte_length = match buffer.dyn_into::<js_sys::ArrayBuffer>() {
97+
Ok(array_buffer) => array_buffer.byte_length(),
98+
Err(buffer) => match buffer.dyn_into::<js_sys::SharedArrayBuffer>() {
99+
Ok(array_buffer) => array_buffer.byte_length(),
100+
Err(_) => {
101+
unreachable!("Memory.buffer should be an array buffer or a shared array buffer")
102+
}
103+
},
104+
};
105+
106+
Pages(byte_length.div_ceil(WASM_PAGE_SIZE as u32))
107+
}
108+
91109
pub fn grow<IntoPages>(
92110
&self,
93111
store: &mut impl AsStoreMut,

lib/api/src/backend/jsc/entities/memory/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,23 @@ impl Memory {
8888
MemoryView::new(self, store)
8989
}
9090

91+
pub fn size(&self, store: &impl AsStoreRef) -> Pages {
92+
let store_ref = store.as_store_ref();
93+
let engine = store_ref.engine();
94+
let context = engine.as_jsc().context();
95+
96+
let js_memory = &self.handle.memory;
97+
let buffer = js_memory
98+
.get_property(context, "buffer")
99+
.to_object(context)
100+
.unwrap();
101+
let byte_length = buffer
102+
.get_property(context, "byteLength")
103+
.to_number(context)
104+
.unwrap() as u32;
105+
Pages(byte_length.div_ceil(wasmer_types::WASM_PAGE_SIZE as u32))
106+
}
107+
91108
pub fn grow<IntoPages>(
92109
&self,
93110
store: &mut impl AsStoreMut,

lib/api/src/backend/sys/entities/memory/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ impl Memory {
5353
.ty()
5454
}
5555

56+
pub(crate) fn size(&self, store: &impl AsStoreRef) -> Pages {
57+
self.handle
58+
.get(store.as_store_ref().objects().as_sys())
59+
.size()
60+
}
61+
5662
pub(crate) fn grow<IntoPages>(
5763
&self,
5864
store: &mut impl AsStoreMut,

lib/api/src/backend/v8/entities/memory/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ impl Memory {
8888
}
8989
}
9090

91+
pub fn size(&self, store: &impl AsStoreRef) -> Pages {
92+
check_isolate(store);
93+
let size = unsafe { wasm_memory_size(self.handle) };
94+
Pages(size)
95+
}
96+
9197
pub fn view<'a>(&self, store: &'a impl AsStoreRef) -> MemoryView<'a> {
9298
check_isolate(store);
9399
let store_ref = store.as_store_ref();

lib/api/src/backend/wamr/entities/memory/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ impl Memory {
7979
}
8080
}
8181

82+
pub fn size(&self, store: &impl AsStoreRef) -> Pages {
83+
let size = unsafe { wasm_memory_size(self.handle) };
84+
Pages(size)
85+
}
86+
8287
pub fn view<'a>(&self, store: &'a impl AsStoreRef) -> MemoryView<'a> {
8388
MemoryView::new(self, store)
8489
}

lib/api/src/backend/wasmi/entities/memory/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ impl Memory {
7878
}
7979
}
8080

81+
pub fn size(&self, store: &impl AsStoreRef) -> Pages {
82+
let size = unsafe { wasm_memory_size(self.handle) };
83+
Pages(size)
84+
}
85+
8186
pub fn view<'a>(&self, store: &'a impl AsStoreRef) -> MemoryView<'a> {
8287
MemoryView::new(self, store)
8388
}

lib/api/src/entities/memory/inner.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ impl BackendMemory {
125125
})
126126
}
127127

128+
/// Retrieve the size of the memory in pages.
129+
pub fn size(&self, store: &impl AsStoreRef) -> Pages {
130+
match_rt!(on self => s {
131+
s.size(store)
132+
})
133+
}
134+
128135
/// Grow memory by the specified amount of WebAssembly [`Pages`] and return
129136
/// the previous memory size.
130137
///

lib/api/src/entities/memory/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ impl Memory {
7979
MemoryView::new(self, store)
8080
}
8181

82+
/// Retrieve the size of the memory in pages.
83+
pub fn size(&self, store: &impl AsStoreRef) -> Pages {
84+
self.0.size(store)
85+
}
86+
8287
/// Grow memory by the specified amount of WebAssembly [`Pages`] and return
8388
/// the previous memory size.
8489
///

lib/api/tests/memory.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,29 @@ fn test_wasm_slice_issue_5444() {
116116
Some(MemoryAccessError::UnalignedPointerRead)
117117
))
118118
}
119+
120+
#[cfg_attr(
121+
feature = "wamr",
122+
ignore = "wamr reports memory size incorrectly in this scenario"
123+
)]
124+
#[test]
125+
fn test_wasm_memory_size() {
126+
let mut store = Store::default();
127+
128+
// Test once with not-shared memory...
129+
{
130+
let memory = Memory::new(&mut store, MemoryType::new(10, Some(65536), false)).unwrap();
131+
assert_eq!(memory.size(&store).0, 10);
132+
memory.grow(&mut store, wasmer::Pages(1)).unwrap();
133+
assert_eq!(memory.size(&store).0, 11);
134+
}
135+
136+
// ... and once with shared memory, since JS and JSC (at least) have different
137+
// representations for it
138+
{
139+
let memory = Memory::new(&mut store, MemoryType::new(10, Some(65536), true)).unwrap();
140+
assert_eq!(memory.size(&store).0, 10);
141+
memory.grow(&mut store, wasmer::Pages(1)).unwrap();
142+
assert_eq!(memory.size(&store).0, 11);
143+
}
144+
}

0 commit comments

Comments
 (0)