diff --git a/src/builder/memory.rs b/src/builder/memory.rs index af1a16d..748a1e7 100644 --- a/src/builder/memory.rs +++ b/src/builder/memory.rs @@ -1,8 +1,15 @@ +use elements; use super::invoke::{Invoke, Identity}; pub struct MemoryDefinition { pub min: u32, pub max: Option, + pub data: Vec, +} + +pub struct MemoryDataDefinition { + pub offset: elements::InitExpr, + pub values: Vec, } pub struct MemoryBuilder { @@ -34,6 +41,14 @@ impl MemoryBuilder where F: Invoke { self } + pub fn with_data(mut self, index: u32, values: Vec) -> Self { + self.memory.data.push(MemoryDataDefinition { + offset: elements::InitExpr::new(vec![elements::Opcode::I32Const(index as i32)]), + values: values, + }); + self + } + pub fn build(self) -> F::Result { self.callback.invoke(self.memory) } @@ -44,6 +59,7 @@ impl Default for MemoryDefinition { MemoryDefinition { min: 1, max: None, + data: Vec::new(), } } } diff --git a/src/builder/module.rs b/src/builder/module.rs index 8775329..7a74c87 100644 --- a/src/builder/module.rs +++ b/src/builder/module.rs @@ -203,10 +203,15 @@ impl ModuleBuilder where F: Invoke { } /// Push linear memory region - pub fn push_memory(&mut self, memory: memory::MemoryDefinition) -> u32 { + pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 { let entries = self.module.memory.entries_mut(); entries.push(elements::MemoryType::new(memory.min, memory.max)); - (entries.len() - 1) as u32 + let memory_index = (entries.len() - 1) as u32; + for data in memory.data.drain(..) { + self.module.data.entries_mut() + .push(elements::DataSegment::new(memory_index, data.offset, data.values)) + } + memory_index } /// Push table diff --git a/src/builder/table.rs b/src/builder/table.rs index 13f1a2e..a717494 100644 --- a/src/builder/table.rs +++ b/src/builder/table.rs @@ -7,8 +7,8 @@ pub struct TableDefinition { } pub struct TableEntryDefinition { - pub offset: elements::InitExpr, - pub values: Vec, + pub offset: elements::InitExpr, + pub values: Vec, } pub struct TableBuilder { diff --git a/src/elements/section.rs b/src/elements/section.rs index 3c4b1d5..08ff143 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -591,6 +591,11 @@ impl DataSection { pub fn entries(&self) -> &[DataSegment] { &self.0 } + + /// Mutable list of all data entries in the section + pub fn entries_mut(&mut self) -> &mut Vec { + &mut self.0 + } } impl Deserialize for DataSection { diff --git a/src/interpreter/tests/wabt.rs b/src/interpreter/tests/wabt.rs index 8fad826..2011a7c 100644 --- a/src/interpreter/tests/wabt.rs +++ b/src/interpreter/tests/wabt.rs @@ -1,5 +1,7 @@ ///! Tests from https://github.com/WebAssembly/wabt/tree/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp +// TODO: https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/import.txt + use std::sync::Weak; use builder::module; use elements::{Module, ValueType, Opcodes, Opcode, BlockType, FunctionType}; @@ -2550,4 +2552,64 @@ fn convert_f64() { assert_eq!(module.execute(2, vec![]).unwrap().unwrap(), RuntimeValue::F64(12345679.000000)); assert_eq!(module.execute(3, vec![]).unwrap().unwrap(), RuntimeValue::F64(0.000000)); assert_eq!(module.execute(4, vec![]).unwrap().unwrap(), RuntimeValue::F64(0.000000)); +} + +/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/load.txt#L9 +#[test] +fn load_i32() { + let module = module() + .memory() + .with_data(0, vec![0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xce, 0x41, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x8f, 0x40, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]) + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::I32Const(0), + Opcode::I32Load8S(0, 0), + Opcode::End, + ])).build() + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::I32Const(0), + Opcode::I32Load16S(0, 0), + Opcode::End, + ])).build() + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::I32Const(0), + Opcode::I32Load(0, 0), + Opcode::End, + ])).build() + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::I32Const(0), + Opcode::I32Load8U(0, 0), + Opcode::End, + ])).build() + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::I32Const(0), + Opcode::I32Load16U(0, 0), + Opcode::End, + ])).build() + .build() + .build(); + + let program = ProgramInstance::new(); + let module = program.add_module("main", module).unwrap(); + assert_eq!(module.execute(0, vec![]).unwrap().unwrap(), RuntimeValue::I32(-1)); + assert_eq!(module.execute(1, vec![]).unwrap().unwrap(), RuntimeValue::I32(-1)); + assert_eq!(module.execute(2, vec![]).unwrap().unwrap(), RuntimeValue::I32(-1)); + assert_eq!(module.execute(3, vec![]).unwrap().unwrap(), RuntimeValue::I32(255)); + assert_eq!(module.execute(4, vec![]).unwrap().unwrap(), RuntimeValue::I32(65535)); } \ No newline at end of file