use crate::emit::{Emit, EmitContext, Section};
use crate::ir::Value;
use crate::parse::IndicesToIds;
use crate::tombstone_arena::{Id, Tombstone, TombstoneArena};
use crate::{GlobalId, ImportId, InitExpr, Module, Result};
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: MemoryData,
}
impl Tombstone for Memory {
fn on_delete(&mut self) {
self.data = MemoryData::default();
}
}
#[derive(Debug, Default)]
pub struct MemoryData {
absolute: Vec<(u32, Vec<u8>)>,
relative: Vec<(GlobalId, Vec<u8>)>,
}
impl Memory {
pub fn id(&self) -> MemoryId {
self.id
}
pub(crate) fn emit_data(&self) -> impl Iterator<Item = (InitExpr, &[u8])> {
let absolute = self
.data
.absolute
.iter()
.map(move |(pos, data)| (InitExpr::Value(Value::I32(*pos as i32)), &data[..]));
let relative = self
.data
.relative
.iter()
.map(move |(id, data)| (InitExpr::Global(*id), &data[..]));
absolute.chain(relative)
}
}
impl Emit for Memory {
fn emit(&self, cx: &mut EmitContext) {
if let Some(max) = self.maximum {
cx.encoder.byte(if self.shared { 0x03 } else { 0x01 });
cx.encoder.u32(self.initial);
cx.encoder.u32(max);
} else {
cx.encoder.byte(0x00);
cx.encoder.u32(self.initial);
}
}
}
#[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: MemoryData::default(),
});
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: MemoryData::default(),
});
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)
}
}
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?;
let id = self
.memories
.add_local(m.shared, m.limits.initial, m.limits.maximum);
ids.push_memory(id);
}
Ok(())
}
}
impl Emit for ModuleMemories {
fn emit(&self, cx: &mut EmitContext) {
log::debug!("emit memory section");
let memories = self.iter().filter(|m| m.import.is_none()).count();
if memories == 0 {
return;
}
let mut cx = cx.start_section(Section::Memory);
cx.encoder.usize(memories);
for memory in self.iter().filter(|m| m.import.is_none()) {
cx.indices.push_memory(memory.id());
memory.emit(&mut cx);
}
}
}
impl MemoryData {
pub fn add_absolute(&mut self, pos: u32, data: Vec<u8>) {
self.absolute.push((pos, data));
}
pub fn add_relative(&mut self, id: GlobalId, data: Vec<u8>) {
self.relative.push((id, data));
}
pub fn globals<'a>(&'a self) -> impl Iterator<Item = GlobalId> + 'a {
self.relative.iter().map(|p| p.0)
}
pub fn is_empty(&self) -> bool {
self.absolute.is_empty() && self.relative.is_empty()
}
pub fn into_iter(self) -> impl Iterator<Item = (InitExpr, Vec<u8>)> {
let absolute = self
.absolute
.into_iter()
.map(move |(pos, data)| (InitExpr::Value(Value::I32(pos as i32)), data));
let relative = self
.relative
.into_iter()
.map(move |(id, data)| (InitExpr::Global(id), data));
absolute.chain(relative)
}
}