use crate::{ElementSegmentIdx, RwasmExecutor, TableEntity, TableIdx, TrapCode};
impl<'a, T> RwasmExecutor<'a, T> {
#[inline(always)]
pub(crate) fn resolve_table(&mut self, table_idx: TableIdx) -> &mut TableEntity {
self.store.tables.entry(table_idx).or_default()
}
#[inline(always)]
pub(crate) fn visit_table_size(&mut self, table_idx: TableIdx) {
let table_size = self.resolve_table(table_idx).size();
self.sp.push_as(table_size);
self.ip.add(1);
}
#[inline(always)]
pub(crate) fn visit_table_grow(&mut self, table_idx: TableIdx) -> Result<(), TrapCode> {
let (init, delta) = self.sp.pop2();
let delta: u32 = delta.into();
let table = self.resolve_table(table_idx);
let result = table.grow_untyped(delta, init);
self.sp.push_as(result);
#[cfg(feature = "tracing")]
self.store
.tracer
.table_size_change(table_idx as u32, init.into(), delta);
self.ip.add(1);
Ok(())
}
#[inline(always)]
pub(crate) fn visit_table_fill(&mut self, table_idx: TableIdx) -> Result<(), TrapCode> {
let (i, val, n) = self.sp.pop3();
self.resolve_table(table_idx)
.fill_untyped(i.into(), val, n.into())?;
self.ip.add(1);
Ok(())
}
#[inline(always)]
pub(crate) fn visit_table_get(&mut self, table_idx: TableIdx) -> Result<(), TrapCode> {
let index = self.sp.pop();
let value = self
.resolve_table(table_idx)
.get_untyped(index.into())
.ok_or(TrapCode::TableOutOfBounds)?;
self.sp.push(value);
self.ip.add(1);
Ok(())
}
#[inline(always)]
pub(crate) fn visit_table_set(&mut self, table_idx: TableIdx) -> Result<(), TrapCode> {
let (index, value) = self.sp.pop2();
self.resolve_table(table_idx)
.set_untyped(index.into(), value)
.map_err(|_| TrapCode::TableOutOfBounds)?;
#[cfg(feature = "tracing")]
self.store
.tracer
.table_change(table_idx as u32, index.into(), value);
self.ip.add(1);
Ok(())
}
#[inline(always)]
pub(crate) fn visit_table_copy(
&mut self,
dst_table_idx: TableIdx,
src_table_idx: TableIdx,
) -> Result<(), TrapCode> {
let (d, s, n) = self.sp.pop3();
let len = u32::from(n);
let src_index = u32::from(s);
let dst_index = u32::from(d);
if src_table_idx != dst_table_idx {
self.resolve_table(src_table_idx);
self.resolve_table(dst_table_idx);
let [Some(src), Some(dst)] = self
.store
.tables
.get_disjoint_mut([&src_table_idx, &dst_table_idx])
else {
return Err(TrapCode::TableOutOfBounds);
};
TableEntity::copy(dst, dst_index, src, src_index, len)?;
} else {
let src = self.resolve_table(src_table_idx);
src.copy_within(dst_index, src_index, len)?;
}
self.ip.add(1);
Ok(())
}
#[inline(always)]
pub(crate) fn visit_table_init(
&mut self,
element_segment_idx: ElementSegmentIdx,
) -> Result<(), TrapCode> {
let table_idx = self.fetch_table_index(1);
let (d, s, n) = self.sp.pop3();
let len = u32::from(n);
let src_index = u32::from(s);
let dst_index = u32::from(d);
let is_empty_segment = self
.store
.empty_elem_segments
.get(element_segment_idx as usize)
.as_deref()
.copied()
.unwrap_or(false);
let mut module_elements_section = &self.module.elem_section[..];
if is_empty_segment {
module_elements_section = &[];
}
let table = self.resolve_table(table_idx);
table.init_untyped(dst_index, module_elements_section, src_index, len)?;
self.ip.add(2);
Ok(())
}
#[inline(always)]
pub(crate) fn visit_element_drop(&mut self, element_segment_idx: ElementSegmentIdx) {
let empty_elem_segments = &mut self.store.empty_elem_segments;
let idx = element_segment_idx as usize;
if idx >= empty_elem_segments.len() {
empty_elem_segments.resize(idx + 1, false);
}
empty_elem_segments.set(idx, true);
self.ip.add(1);
}
}