diff --git a/src/builder/mod.rs b/src/builder/mod.rs index 48fb4d2..bffd245 100644 --- a/src/builder/mod.rs +++ b/src/builder/mod.rs @@ -6,6 +6,7 @@ mod code; mod misc; mod import; mod memory; +mod table; pub use self::module::{module, from_module, ModuleBuilder}; pub use self::code::{signatures, signature, function}; diff --git a/src/builder/module.rs b/src/builder/module.rs index 3d5db5c..8775329 100644 --- a/src/builder/module.rs +++ b/src/builder/module.rs @@ -1,6 +1,7 @@ use super::invoke::{Invoke, Identity}; use super::code::{self, SignaturesBuilder, FunctionBuilder}; use super::memory::{self, MemoryBuilder}; +use super::table::{self, TableBuilder}; use super::import; use elements; @@ -208,6 +209,18 @@ impl ModuleBuilder where F: Invoke { (entries.len() - 1) as u32 } + /// Push table + pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 { + let entries = self.module.table.entries_mut(); + entries.push(elements::TableType::new(table.min, Some(table.min))); + let table_index = (entries.len() - 1) as u32; + for entry in table.elements.drain(..) { + self.module.element.entries_mut() + .push(elements::ElementSegment::new(table_index, entry.offset, entry.values)) + } + table_index + } + fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 { match signature { code::Signature::Inline(func_type) => { @@ -254,6 +267,11 @@ impl ModuleBuilder where F: Invoke { MemoryBuilder::with_callback(self) } + /// Add new table using dedicated builder + pub fn table(self) -> TableBuilder { + TableBuilder::with_callback(self) + } + /// Define functions section pub fn functions(self) -> SignaturesBuilder { SignaturesBuilder::with_callback(self) @@ -321,6 +339,18 @@ impl Invoke for ModuleBuilder } } +impl Invoke for ModuleBuilder + where F: Invoke +{ + type Result = Self; + + fn invoke(self, def: table::TableDefinition) -> Self { + let mut b = self; + b.push_table(def); + b + } +} + impl Invoke for ModuleBuilder where F: Invoke { diff --git a/src/builder/table.rs b/src/builder/table.rs new file mode 100644 index 0000000..13f1a2e --- /dev/null +++ b/src/builder/table.rs @@ -0,0 +1,58 @@ +use elements; +use super::invoke::{Invoke, Identity}; + +pub struct TableDefinition { + pub min: u32, + pub elements: Vec, +} + +pub struct TableEntryDefinition { + pub offset: elements::InitExpr, + pub values: Vec, +} + +pub struct TableBuilder { + callback: F, + table: TableDefinition, +} + +impl TableBuilder { + pub fn new() -> Self { + TableBuilder::with_callback(Identity) + } +} + +impl TableBuilder where F: Invoke { + pub fn with_callback(callback: F) -> Self { + TableBuilder { + callback: callback, + table: Default::default(), + } + } + + pub fn with_min(mut self, min: u32) -> Self { + self.table.min = min; + self + } + + pub fn with_element(mut self, index: u32, values: Vec) -> Self { + self.table.elements.push(TableEntryDefinition { + offset: elements::InitExpr::new(vec![elements::Opcode::I32Const(index as i32)]), + values: values, + }); + self + } + + pub fn build(self) -> F::Result { + self.callback.invoke(self.table) + } +} + +impl Default for TableDefinition { + fn default() -> Self { + TableDefinition { + min: 0, + elements: Vec::new(), + } + } +} diff --git a/src/elements/section.rs b/src/elements/section.rs index dc77a64..3c4b1d5 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -323,6 +323,11 @@ impl TableSection { pub fn entries(&self) -> &[TableType] { &self.0 } + + /// Mutable table entries. + pub fn entries_mut(&mut self) -> &mut Vec { + &mut self.0 + } } impl Deserialize for TableSection { @@ -538,6 +543,11 @@ impl ElementSection { pub fn entries(&self) -> &[ElementSegment] { &self.0 } + + /// Mutable elements entries in the section + pub fn entries_mut(&mut self) -> &mut Vec { + &mut self.0 + } } impl Deserialize for ElementSection { diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index 6dfdc52..6a8d1b8 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -649,3 +649,56 @@ fn call_zero_args() { let module = program.add_module("main", module).unwrap(); assert_eq!(module.execute_main(vec![]).unwrap().unwrap(), RuntimeValue::I32(43)); } + +/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/callimport-zero-args.txt +#[test] +fn callimport_zero_zrgs() { + // TODO: import needed +} + +/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/callindirect.txt#L31 +#[test] +fn callindirect_1() { + let body1 = Opcodes::new(vec![ + Opcode::I32Const(0), + Opcode::End, + ]); + + let body2 = Opcodes::new(vec![ + Opcode::I32Const(1), + Opcode::End, + ]); + + let body3 = Opcodes::new(vec![ + Opcode::GetLocal(0), + Opcode::CallIndirect(0, false), + Opcode::End, + ]); + + let module = module() + .table() + .with_min(2) + .with_element(0, vec![0, 1]) + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(body1).build() + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(body2).build() + .build() + .function().main() + .signature() + .param().i32() + .return_type().i32() + .build() + .body().with_opcodes(body3).build() + .build() + .build(); + + let program = ProgramInstance::new(); + let module = program.add_module("main", module).unwrap(); + assert_eq!(module.execute_main(vec![RuntimeValue::I32(0)]).unwrap().unwrap(), RuntimeValue::I32(0)); + assert_eq!(module.execute_main(vec![RuntimeValue::I32(1)]).unwrap().unwrap(), RuntimeValue::I32(1)); +}