use crate::emit::{Emit, EmitContext};
use crate::map::IdHashSet;
use crate::parse::IndicesToIds;
use crate::tombstone_arena::{Id, Tombstone, TombstoneArena};
use crate::{Data, ImportId, Module, Result};
use anyhow::bail;
pub type MemoryId = Id<Memory>;
#[derive(Debug)]
pub struct Memory {
id: MemoryId,
pub shared: bool,
pub initial: u32,
pub maximum: Option<u32>,
pub import: Option<ImportId>,
pub data_segments: IdHashSet<Data>,
pub name: Option<String>,
}
impl Tombstone for Memory {
fn on_delete(&mut self) {
self.data_segments = Default::default();
}
}
impl Memory {
pub fn id(&self) -> MemoryId {
self.id
}
}
#[derive(Debug, Default)]
pub struct ModuleMemories {
arena: TombstoneArena<Memory>,
}
impl ModuleMemories {
pub fn add_import(
&mut self,
shared: bool,
initial: u32,
maximum: Option<u32>,
import: ImportId,
) -> MemoryId {
let id = self.arena.next_id();
let id2 = self.arena.alloc(Memory {
id,
shared,
initial,
maximum,
import: Some(import),
data_segments: Default::default(),
name: None,
});
debug_assert_eq!(id, id2);
id
}
pub fn add_local(&mut self, shared: bool, initial: u32, maximum: Option<u32>) -> MemoryId {
let id = self.arena.next_id();
let id2 = self.arena.alloc(Memory {
id,
shared,
initial,
maximum,
import: None,
data_segments: Default::default(),
name: None,
});
debug_assert_eq!(id, id2);
id
}
pub fn get(&self, id: MemoryId) -> &Memory {
&self.arena[id]
}
pub fn get_mut(&mut self, id: MemoryId) -> &mut Memory {
&mut self.arena[id]
}
pub fn delete(&mut self, id: MemoryId) {
self.arena.delete(id);
}
pub fn iter(&self) -> impl Iterator<Item = &Memory> {
self.arena.iter().map(|(_, f)| f)
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Memory> {
self.arena.iter_mut().map(|(_, f)| f)
}
pub fn len(&self) -> usize {
self.arena.len()
}
}
impl Module {
pub(crate) fn parse_memories(
&mut self,
section: wasmparser::MemorySectionReader,
ids: &mut IndicesToIds,
) -> Result<()> {
log::debug!("parse memory section");
for m in section {
let m = m?;
if m.memory64 {
bail!("64-bit memories not supported")
};
let id =
self.memories
.add_local(m.shared, m.initial as u32, m.maximum.map(|m| m as u32));
ids.push_memory(id);
}
Ok(())
}
}
impl Emit for ModuleMemories {
fn emit(&self, cx: &mut EmitContext) {
log::debug!("emit memory section");
let mut wasm_memory_section = wasm_encoder::MemorySection::new();
let memories = self.iter().filter(|m| m.import.is_none()).count();
if memories == 0 {
return;
}
for memory in self.iter().filter(|m| m.import.is_none()) {
cx.indices.push_memory(memory.id());
wasm_memory_section.memory(wasm_encoder::MemoryType {
minimum: memory.initial as u64,
maximum: memory.maximum.map(|v| v as u64),
memory64: false,
shared: memory.shared,
});
}
cx.wasm_module.section(&wasm_memory_section);
}
}
#[cfg(test)]
mod tests {
use crate::Module;
#[test]
fn memories_len() {
let mut module = Module::default();
assert_eq!(module.memories.len(), 0);
module.memories.add_local(false, 0, Some(1024));
assert_eq!(module.memories.len(), 1);
module.memories.add_local(true, 1024, Some(2048));
assert_eq!(module.memories.len(), 2);
}
}