Something went wrong. Try again.
we (web engine): Experimental web browser project to understand the limits of Claude
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198//! Module instance: per-module address-space view into the [`Store`].//!//! An instance carries the parsed module's type section verbatim plus a//! handle for every function, table, memory, global, element segment, and//! data segment the module declared, in declaration order. Indices in the//! original module map 1:1 into these vectors; the store-side addresses//! ([`FuncAddr`] etc.) point at the actual runtime objects.//!//! Imports come first in each vector (so module-local index 0 of a function//! is the first import, if any), matching the binary-format rule. The//! `*_imports` counts make it cheap to ask "is this local index an import?"//! without scanning.
use std::collections::HashMap;
use crate::runtime::store::{DataAddr, ElementAddr, FuncAddr, GlobalAddr, MemoryAddr, TableAddr};use crate::types::FuncType;
/// An externally-visible value an instance can hand to another instance via/// imports or expose via exports.#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum ExternVal { Func(FuncAddr), Table(TableAddr), Memory(MemoryAddr), Global(GlobalAddr),}
/// A live module instance.#[derive(Debug, Default, Clone)]pub struct ModuleInstance { pub types: Vec<FuncType>,
pub func_addrs: Vec<FuncAddr>, pub table_addrs: Vec<TableAddr>, pub memory_addrs: Vec<MemoryAddr>, pub global_addrs: Vec<GlobalAddr>, pub element_addrs: Vec<ElementAddr>, pub data_addrs: Vec<DataAddr>,
/// Number of imported functions sitting at the front of `func_addrs`. pub imported_funcs: u32, pub imported_tables: u32, pub imported_memories: u32, pub imported_globals: u32,
/// Exports keyed by name. pub exports: HashMap<String, ExternVal>,}
impl ModuleInstance { /// A fresh, empty instance — used as the starting point during /// instantiation, which the instantiation pipeline fills in. pub fn new() -> Self { Self::default() }
/// Resolve a module-local function index to a store address. pub fn resolve_func(&self, index: u32) -> Option<FuncAddr> { self.func_addrs.get(index as usize).copied() }
/// Resolve a module-local table index to a store address. pub fn resolve_table(&self, index: u32) -> Option<TableAddr> { self.table_addrs.get(index as usize).copied() }
/// Resolve a module-local memory index to a store address. pub fn resolve_memory(&self, index: u32) -> Option<MemoryAddr> { self.memory_addrs.get(index as usize).copied() }
/// Resolve a module-local global index to a store address. pub fn resolve_global(&self, index: u32) -> Option<GlobalAddr> { self.global_addrs.get(index as usize).copied() }
/// Resolve a module-local element segment index to a store address. pub fn resolve_element(&self, index: u32) -> Option<ElementAddr> { self.element_addrs.get(index as usize).copied() }
/// Resolve a module-local data segment index to a store address. pub fn resolve_data(&self, index: u32) -> Option<DataAddr> { self.data_addrs.get(index as usize).copied() }
/// True if the given module-local function index refers to an imported /// function (vs one defined in this module). pub fn is_func_imported(&self, index: u32) -> bool { index < self.imported_funcs }
/// True if the given module-local table index refers to an imported /// table. pub fn is_table_imported(&self, index: u32) -> bool { index < self.imported_tables }
/// True if the given module-local memory index refers to an imported /// memory. pub fn is_memory_imported(&self, index: u32) -> bool { index < self.imported_memories }
/// True if the given module-local global index refers to an imported /// global. pub fn is_global_imported(&self, index: u32) -> bool { index < self.imported_globals }
/// Look up an export by name. pub fn export(&self, name: &str) -> Option<ExternVal> { self.exports.get(name).copied() }}
#[cfg(test)]mod tests { use super::*;
#[test] fn empty_instance() { let inst = ModuleInstance::new(); assert!(inst.types.is_empty()); assert!(inst.func_addrs.is_empty()); assert_eq!(inst.imported_funcs, 0); assert!(inst.resolve_func(0).is_none()); assert!(inst.export("anything").is_none()); }
#[test] fn resolve_indices() { let mut inst = ModuleInstance::new(); inst.func_addrs.push(FuncAddr::from_raw(10)); inst.func_addrs.push(FuncAddr::from_raw(11)); inst.imported_funcs = 1;
assert_eq!(inst.resolve_func(0), Some(FuncAddr::from_raw(10))); assert_eq!(inst.resolve_func(1), Some(FuncAddr::from_raw(11))); assert_eq!(inst.resolve_func(2), None);
assert!(inst.is_func_imported(0)); assert!(!inst.is_func_imported(1)); }
#[test] fn import_vs_own_partition() { let mut inst = ModuleInstance::new(); inst.table_addrs.push(TableAddr::from_raw(7)); inst.table_addrs.push(TableAddr::from_raw(8)); inst.imported_tables = 2; assert!(inst.is_table_imported(0)); assert!(inst.is_table_imported(1)); assert!(!inst.is_table_imported(2));
inst.memory_addrs.push(MemoryAddr::from_raw(0)); inst.imported_memories = 0; assert!(!inst.is_memory_imported(0));
inst.global_addrs.push(GlobalAddr::from_raw(0)); inst.global_addrs.push(GlobalAddr::from_raw(1)); inst.imported_globals = 1; assert!(inst.is_global_imported(0)); assert!(!inst.is_global_imported(1)); }
#[test] fn exports_lookup() { let mut inst = ModuleInstance::new(); inst.exports .insert("main".to_string(), ExternVal::Func(FuncAddr::from_raw(0))); inst.exports.insert( "mem".to_string(), ExternVal::Memory(MemoryAddr::from_raw(0)), ); assert_eq!( inst.export("main"), Some(ExternVal::Func(FuncAddr::from_raw(0))) ); assert_eq!( inst.export("mem"), Some(ExternVal::Memory(MemoryAddr::from_raw(0))) ); assert_eq!(inst.export("missing"), None); }
#[test] fn resolve_returns_none_for_out_of_range() { let inst = ModuleInstance::new(); assert!(inst.resolve_table(0).is_none()); assert!(inst.resolve_memory(0).is_none()); assert!(inst.resolve_global(0).is_none()); assert!(inst.resolve_element(0).is_none()); assert!(inst.resolve_data(0).is_none()); }}