1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
use crate::{
module,
module::{ConstExpr, ElementSegmentItems},
store::Stored,
AsContext,
AsContextMut,
};
use wasmi_arena::ArenaIndex;
use wasmi_core::ValueType;
/// A raw index to a element segment entity.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct ElementSegmentIdx(u32);
impl ArenaIndex for ElementSegmentIdx {
fn into_usize(self) -> usize {
self.0 as usize
}
fn from_usize(value: usize) -> Self {
let value = value.try_into().unwrap_or_else(|error| {
panic!("index {value} is out of bounds as element segment index: {error}")
});
Self(value)
}
}
/// A Wasm data segment reference.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct ElementSegment(Stored<ElementSegmentIdx>);
impl ElementSegment {
/// Creates a new linear memory reference.
pub fn from_inner(stored: Stored<ElementSegmentIdx>) -> Self {
Self(stored)
}
/// Returns the underlying stored representation.
pub fn as_inner(&self) -> &Stored<ElementSegmentIdx> {
&self.0
}
/// Allocates a new [`ElementSegment`] on the store.
///
/// # Errors
///
/// If more than [`u32::MAX`] much linear memory is allocated.
pub fn new(mut ctx: impl AsContextMut, segment: &module::ElementSegment) -> Self {
let entity = ElementSegmentEntity::from(segment);
ctx.as_context_mut()
.store
.inner
.alloc_element_segment(entity)
}
/// Returns the number of items in the [`ElementSegment`].
pub fn size(&self, ctx: impl AsContext) -> u32 {
ctx.as_context()
.store
.inner
.resolve_element_segment(self)
.size()
}
/// Drops the items of the [`ElementSegment`].
pub fn drop_items(&self, mut ctx: impl AsContextMut) {
ctx.as_context_mut()
.store
.inner
.resolve_element_segment_mut(self)
.drop_items()
}
}
/// An instantiated [`ElementSegmentEntity`].
///
/// # Note
///
/// With the `bulk-memory` Wasm proposal it is possible to interact
/// with element segments at runtime. Therefore Wasm instances now have
/// a need to have an instantiated representation of data segments.
#[derive(Debug)]
pub struct ElementSegmentEntity {
/// The [`ValueType`] of elements of this [`ElementSegmentEntity`].
ty: ValueType,
/// The underlying items of the instance element segment.
///
/// # Note
///
/// These items are just readable after instantiation.
/// Using Wasm `elem.drop` simply replaces the instance
/// with an empty one.
items: Option<ElementSegmentItems>,
}
impl From<&'_ module::ElementSegment> for ElementSegmentEntity {
fn from(segment: &'_ module::ElementSegment) -> Self {
let ty = segment.ty();
match segment.kind() {
module::ElementSegmentKind::Passive | module::ElementSegmentKind::Active(_) => Self {
ty,
items: Some(segment.items_cloned()),
},
module::ElementSegmentKind::Declared => Self::empty(ty),
}
}
}
impl ElementSegmentEntity {
/// Create an empty [`ElementSegmentEntity`] representing dropped element segments.
fn empty(ty: ValueType) -> Self {
Self { ty, items: None }
}
/// Returns the [`ValueType`] of elements in the [`ElementSegmentEntity`].
pub fn ty(&self) -> ValueType {
self.ty
}
/// Returns the number of items in the [`ElementSegment`].
pub fn size(&self) -> u32 {
self.items().len() as u32
}
/// Returns the items of the [`ElementSegmentEntity`].
pub fn items(&self) -> &[ConstExpr] {
self.items
.as_ref()
.map(ElementSegmentItems::items)
.unwrap_or(&[])
}
/// Drops the items of the [`ElementSegmentEntity`].
pub fn drop_items(&mut self) {
self.items = None;
}
}