Skip to content

Commit e7f9ec1

Browse files
committed
table: Add table.fill and table.init
This commit introduces support for WebAssembly 2.0 (Draft 2025-01-28)[1] bulk table operations, specifically `table.fill` and `table.init`. These methods allow for efficient filling and initialization of table ranges. The implementation includes bounds-checked `fill` and `init` operations in `VMTable` for low-level functionality, with these methods exposed through the `Table` abstraction and system backend for consistent API access. These additions align with WebAssembly 2.0's bulk memory and table instructions (Section 7.6). [1]: https://webassembly.github.io/spec/core/bikeshed/#bulk-memory-and-table-instructions%E2%91%A0 Signed-off-by: Charalampos Mitrodimas <[email protected]>
1 parent 760022a commit e7f9ec1

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

lib/api/src/backend/sys/entities/table.rs

+39
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,45 @@ impl Table {
132132
.ok_or_else(|| RuntimeError::new(format!("failed to grow table by `{delta}`")))
133133
}
134134

135+
pub(crate) fn fill(
136+
&self,
137+
store: &mut impl AsStoreMut,
138+
index: u32,
139+
len: u32,
140+
value: Value,
141+
) -> Result<(), RuntimeError> {
142+
let item = value_to_table_element(store, value)?;
143+
let obj_mut = store.objects_mut().as_sys_mut();
144+
145+
self.handle
146+
.get_mut(obj_mut)
147+
.fill(index, len, item)
148+
.map_err(Into::<RuntimeError>::into)?;
149+
Ok(())
150+
}
151+
152+
pub(crate) fn init(
153+
&self,
154+
store: &mut impl AsStoreMut,
155+
dst_index: u32,
156+
src_index: u32,
157+
len: u32,
158+
values: &[Value],
159+
) -> Result<(), RuntimeError> {
160+
let mut table_elements = Vec::with_capacity(len as usize);
161+
for value in &values[src_index as usize..(src_index + len) as usize] {
162+
table_elements.push(value_to_table_element(store, value.clone())?);
163+
}
164+
let obj_mut = store.objects_mut().as_sys_mut();
165+
166+
self.handle
167+
.get_mut(obj_mut)
168+
.init(dst_index, src_index, len, &table_elements)
169+
.map_err(Into::<RuntimeError>::into)?;
170+
171+
Ok(())
172+
}
173+
135174
pub(crate) fn copy(
136175
store: &mut impl AsStoreMut,
137176
dst_table: &Self,

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

+37
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,43 @@ impl BackendTable {
119119
})
120120
}
121121

122+
/// Fills `len` elements starting at `index` with the provided `value`.
123+
///
124+
/// # Errors
125+
///
126+
/// Returns an error if the range is out of bounds for the table.
127+
#[inline]
128+
pub fn fill(
129+
&self,
130+
store: &mut impl AsStoreMut,
131+
index: u32,
132+
len: u32,
133+
value: Value,
134+
) -> Result<(), RuntimeError> {
135+
match_rt!(on self => s {
136+
s.fill(store, index, len, value)
137+
})
138+
}
139+
140+
/// Initializes `len` elements at `dst_index` with values from `values[src_index..]`.
141+
///
142+
/// # Errors
143+
///
144+
/// Returns an error if the range is out of bounds for the table or values.
145+
#[inline]
146+
pub fn init(
147+
&self,
148+
store: &mut impl AsStoreMut,
149+
dst_index: u32,
150+
src_index: u32,
151+
len: u32,
152+
values: &[Value],
153+
) -> Result<(), RuntimeError> {
154+
match_rt!(on self => s {
155+
s.init(store, dst_index, src_index, len, values)
156+
})
157+
}
158+
122159
/// Copies the `len` elements of `src_table` starting at `src_index`
123160
/// to the destination table `dst_table` at index `dst_index`.
124161
///

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

+31
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,37 @@ impl Table {
9898
BackendTable::copy(store, &dst_table.0, dst_index, &src_table.0, src_index, len)
9999
}
100100

101+
/// Fills `len` elements in the table starting at `index` with `value`.
102+
///
103+
/// # Errors
104+
///
105+
/// Returns an error if the range is out of bounds or `value` mismatches the table type.
106+
pub fn fill(
107+
&self,
108+
store: &mut impl AsStoreMut,
109+
index: u32,
110+
len: u32,
111+
value: Value,
112+
) -> Result<(), RuntimeError> {
113+
self.0.fill(store, index, len, value)
114+
}
115+
116+
/// Initializes `len` elements in the table at `dst_index` from `values[src_index..]`.
117+
///
118+
/// # Errors
119+
///
120+
/// Returns an error if the table or segment range is out of bounds or values mismatch the table type.
121+
pub fn init(
122+
&self,
123+
store: &mut impl AsStoreMut,
124+
dst_index: u32,
125+
src_index: u32,
126+
len: u32,
127+
values: &[Value],
128+
) -> Result<(), RuntimeError> {
129+
self.0.init(store, dst_index, src_index, len, values)
130+
}
131+
101132
pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, ext: VMExternTable) -> Self {
102133
Self(BackendTable::from_vm_extern(store, ext))
103134
}

lib/vm/src/table.rs

+39
Original file line numberDiff line numberDiff line change
@@ -347,4 +347,43 @@ impl VMTable {
347347

348348
Ok(())
349349
}
350+
351+
/// Fill `len` elements starting at `index` with the given `value`.
352+
///
353+
/// # Errors
354+
/// Returns an error if the range is out of bounds.
355+
pub fn fill(&mut self, index: u32, len: u32, value: TableElement) -> Result<(), Trap> {
356+
if index.checked_add(len).map_or(true, |n| n > self.size()) {
357+
return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
358+
}
359+
for i in index..index + len {
360+
self.set(i, value.clone())?;
361+
}
362+
Ok(())
363+
}
364+
365+
/// Initialize a range of the table with elements from an element segment.
366+
///
367+
/// # Errors
368+
/// Returns an error if:
369+
/// - The range is out of bounds of the table.
370+
/// - The segment range is out of bounds of the provided elements.
371+
pub fn init(
372+
&mut self,
373+
dst_index: u32,
374+
src_index: u32,
375+
len: u32,
376+
elements: &[TableElement],
377+
) -> Result<(), Trap> {
378+
if dst_index.checked_add(len).map_or(true, |n| n > self.size()) {
379+
return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
380+
}
381+
if src_index.checked_add(len).map_or(true, |n| n > elements.len() as u32) {
382+
return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
383+
}
384+
for (dst, src) in (dst_index..dst_index + len).zip(src_index..src_index + len) {
385+
self.set(dst, elements[src as usize].clone())?;
386+
}
387+
Ok(())
388+
}
350389
}

0 commit comments

Comments
 (0)