From c125a4181c1a7120cc5f41de840ad58795074d29 Mon Sep 17 00:00:00 2001 From: Zhou Fang <33002388+zhou-w-fang@users.noreply.github.com> Date: Wed, 5 Feb 2025 22:57:33 -0800 Subject: [PATCH 1/6] feat!: implement Verify methods --- crates/interpreter/src/parser.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/interpreter/src/parser.rs b/crates/interpreter/src/parser.rs index bd15b659..f9245219 100644 --- a/crates/interpreter/src/parser.rs +++ b/crates/interpreter/src/parser.rs @@ -98,6 +98,10 @@ impl<'m, M: Mode> Parser<'m, M> { Ok(val) } + pub fn parse_u16(&mut self) -> MResult { + Ok(self.parse_leb128(false, 16)? as u16) + } + pub fn parse_u32(&mut self) -> MResult { Ok(self.parse_leb128(false, 32)? as u32) } From 690010f667f52045dea5a52b737b9139220bab44 Mon Sep 17 00:00:00 2001 From: Zhou Fang <33002388+zhou-w-fang@users.noreply.github.com> Date: Thu, 6 Feb 2025 21:01:26 -0800 Subject: [PATCH 2/6] refactor!: review --- crates/interpreter/src/parser.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/interpreter/src/parser.rs b/crates/interpreter/src/parser.rs index f9245219..bd15b659 100644 --- a/crates/interpreter/src/parser.rs +++ b/crates/interpreter/src/parser.rs @@ -98,10 +98,6 @@ impl<'m, M: Mode> Parser<'m, M> { Ok(val) } - pub fn parse_u16(&mut self) -> MResult { - Ok(self.parse_leb128(false, 16)? as u16) - } - pub fn parse_u32(&mut self) -> MResult { Ok(self.parse_leb128(false, 32)? as u32) } From 2b0d17675b7c1c82e3cabb08b1e4f2158d3410b4 Mon Sep 17 00:00:00 2001 From: Zhou Fang <33002388+zhou-w-fang@users.noreply.github.com> Date: Thu, 6 Feb 2025 21:47:17 -0800 Subject: [PATCH 3/6] docs: design merge --- crates/interpreter/src/lib.rs | 1 + crates/interpreter/src/valid.rs | 9 +++++++++ crates/interpreter/tests/spec.rs | 6 ++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/interpreter/src/lib.rs b/crates/interpreter/src/lib.rs index 5196f999..9676741e 100644 --- a/crates/interpreter/src/lib.rs +++ b/crates/interpreter/src/lib.rs @@ -157,3 +157,4 @@ pub use syntax::{ FuncType, GlobalType, ImportDesc, Limits, Mut, RefType, ResultType, TableType, ValType, }; pub use valid::prepare; +pub use valid::merge; diff --git a/crates/interpreter/src/valid.rs b/crates/interpreter/src/valid.rs index dab87ede..e67ed338 100644 --- a/crates/interpreter/src/valid.rs +++ b/crates/interpreter/src/valid.rs @@ -25,6 +25,15 @@ use crate::syntax::*; use crate::toctou::*; use crate::util::*; use crate::*; +use crate::Error::Invalid; + +pub fn merge(binary: &[u8], side_table: Vec) -> Result, Error> { + // Convert Vec to Vec. + // Create a custom section at the beginning of the binary, + // and put the serialized `side_table` in it. + // Return the new module. + Err(Invalid) +} /// Checks whether a WASM module in binary format is valid, and returns the side table. pub fn prepare(binary: &[u8]) -> Result, Error> { diff --git a/crates/interpreter/tests/spec.rs b/crates/interpreter/tests/spec.rs index de3b9bc2..54199b8b 100644 --- a/crates/interpreter/tests/spec.rs +++ b/crates/interpreter/tests/spec.rs @@ -164,8 +164,10 @@ impl<'m> Env<'m> { } fn maybe_instantiate(&mut self, name: &str, wasm: &[u8]) -> Result { - let module = self.alloc(wasm.len()); - module.copy_from_slice(wasm); + let side_table = prepare(wasm)?; + let wasm_with_side_table = merge(wasm, side_table)?.as_slice(); + let module = self.alloc(wasm_with_side_table.len()); + module.copy_from_slice(wasm_with_side_table); let module = Module::new(module)?; let memory = self.alloc(mem_size(name)); self.store.instantiate(module, memory) From 55ed65c770d5e9d9d38397941cfbe72776821529 Mon Sep 17 00:00:00 2001 From: Zhou Fang <33002388+zhou-w-fang@users.noreply.github.com> Date: Sun, 9 Feb 2025 21:43:10 -0800 Subject: [PATCH 4/6] feat: implement allocate_branch() and next_index() --- crates/interpreter/src/side_table.rs | 15 +++++++++++++-- crates/interpreter/src/valid.rs | 21 ++++++++++++--------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/crates/interpreter/src/side_table.rs b/crates/interpreter/src/side_table.rs index 78fee146..b837f8e3 100644 --- a/crates/interpreter/src/side_table.rs +++ b/crates/interpreter/src/side_table.rs @@ -18,11 +18,18 @@ use core::ops::Range; use crate::error::*; use crate::module::Parser; +#[derive(Default)] +pub struct BranchTableView<'m> { + pub metadata: Metadata<'m>, + pub branch_idx: usize, +} + +// TODO(dev/fast-interp): Change [u16] to [u8] to not rely on alignment. pub struct SideTableView<'m> { pub func_idx: usize, pub indices: &'m [u16], // including 0 and the length of metadata_array pub metadata: &'m [u16], - pub branch_table_view: Metadata<'m>, + pub branch_table_view: BranchTableView<'m>, } impl<'m> SideTableView<'m> { @@ -35,7 +42,11 @@ impl<'m> SideTableView<'m> { }) } - pub fn metadata(&self, func_idx: usize) -> Metadata<'m> { + pub fn branch_table_view(&mut self, func_idx: usize) -> BranchTableView<'m> { + BranchTableView { metadata: self.metadata(func_idx), ..Default::default() } + } + + fn metadata(&self, func_idx: usize) -> Metadata<'m> { Metadata( &self.metadata[self.indices[func_idx] as usize .. self.indices[func_idx + 1] as usize], ) diff --git a/crates/interpreter/src/valid.rs b/crates/interpreter/src/valid.rs index e67ed338..3b27dac3 100644 --- a/crates/interpreter/src/valid.rs +++ b/crates/interpreter/src/valid.rs @@ -19,13 +19,13 @@ use core::cmp::Ordering; use core::marker::PhantomData; use core::ops::Range; +use crate::Error::Invalid; use crate::error::*; use crate::side_table::*; use crate::syntax::*; use crate::toctou::*; use crate::util::*; use crate::*; -use crate::Error::Invalid; pub fn merge(binary: &[u8], side_table: Vec) -> Result, Error> { // Convert Vec to Vec. @@ -147,7 +147,7 @@ impl ValidMode for Verify { /// Contains at most one _target_ branch. Source branches are eagerly patched to /// their target branch using the branch table. type Branches<'m> = Option>; - type BranchTable<'m> = Metadata<'m>; + type BranchTable<'m> = BranchTableView<'m>; type SideTable<'m> = SideTableView<'m>; type Result = (); @@ -161,10 +161,10 @@ impl ValidMode for Verify { fn next_branch_table<'a, 'm>( side_table: &'a mut Self::SideTable<'m>, type_idx: usize, parser_range: Range, ) -> Result<&'a mut Self::BranchTable<'m>, Error> { - side_table.branch_table_view = side_table.metadata(side_table.func_idx); + side_table.branch_table_view = side_table.branch_table_view(side_table.func_idx); side_table.func_idx += 1; - check(side_table.branch_table_view.type_idx() == type_idx)?; - check(side_table.branch_table_view.parser_range() == parser_range)?; + check(side_table.branch_table_view.metadata.type_idx() == type_idx)?; + check(side_table.branch_table_view.metadata.parser_range() == parser_range)?; Ok(&mut side_table.branch_table_view) } @@ -179,7 +179,7 @@ impl<'m> BranchesApi<'m> for Option> { } } -impl<'m> BranchTableApi<'m> for Metadata<'m> { +impl<'m> BranchTableApi<'m> for BranchTableView<'m> { fn stitch_branch( &mut self, source: SideTableBranch<'m>, target: SideTableBranch<'m>, ) -> CheckResult { @@ -187,7 +187,8 @@ impl<'m> BranchTableApi<'m> for Metadata<'m> { } fn patch_branch(&self, mut source: SideTableBranch<'m>) -> Result, Error> { - let entry = self.branch_table()[source.branch_table].view(); + source.branch_table = self.branch_idx; + let entry = self.metadata.branch_table()[source.branch_table].view(); offset_front(source.parser, entry.delta_ip as isize); source.branch_table += entry.delta_stp as usize; source.result = entry.val_cnt as usize; @@ -195,10 +196,12 @@ impl<'m> BranchTableApi<'m> for Metadata<'m> { Ok(source) } - fn allocate_branch(&mut self) {} + fn allocate_branch(&mut self) { + self.branch_idx += 1; + } fn next_index(&self) -> usize { - 0 + self.branch_idx } } From 68542f1e19f6e19947297da5523e0851f1946228 Mon Sep 17 00:00:00 2001 From: Zhou Fang <33002388+zhou-w-fang@users.noreply.github.com> Date: Sun, 9 Feb 2025 22:23:26 -0800 Subject: [PATCH 5/6] fix: parse side table (put funs len in front) --- crates/interpreter/src/side_table.rs | 20 ++++++-------------- crates/interpreter/src/valid.rs | 2 +- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/crates/interpreter/src/side_table.rs b/crates/interpreter/src/side_table.rs index b837f8e3..fc8c5a45 100644 --- a/crates/interpreter/src/side_table.rs +++ b/crates/interpreter/src/side_table.rs @@ -33,11 +33,14 @@ pub struct SideTableView<'m> { } impl<'m> SideTableView<'m> { - pub fn new(parser: &mut crate::valid::Parser<'m>) -> Result { + pub fn new(binary: &'m [u8]) -> Result { + let num_funcs = + bytemuck::pod_read_unaligned::(bytemuck::cast_slice(&binary[0 .. 2])) as usize; + let indices_end = 2 + (num_funcs + 1) * 2; Ok(SideTableView { func_idx: 0, - indices: parse_side_table_field(parser)?, - metadata: parse_side_table_field(parser)?, + indices: bytemuck::cast_slice::<_, u16>(binary.get(2 .. indices_end).unwrap()), + metadata: bytemuck::cast_slice::<_, u16>(binary.get(indices_end ..).unwrap()), branch_table_view: Default::default(), }) } @@ -53,17 +56,6 @@ impl<'m> SideTableView<'m> { } } -fn parse_u16(data: &[u8]) -> u16 { - bytemuck::pod_read_unaligned::(bytemuck::cast_slice(&data[0 .. 2])) -} - -fn parse_side_table_field<'m>(parser: &mut crate::valid::Parser<'m>) -> Result<&'m [u16], Error> { - let len = parse_u16(parser.save()) as usize; - let parser = parser.split_at(len)?; - let bytes = parser.save().get(0 .. len * 2).unwrap(); - Ok(bytemuck::cast_slice::<_, u16>(bytes)) -} - #[derive(Default, Copy, Clone)] pub struct Metadata<'m>(&'m [u16]); diff --git a/crates/interpreter/src/valid.rs b/crates/interpreter/src/valid.rs index 3b27dac3..e0d7c83b 100644 --- a/crates/interpreter/src/valid.rs +++ b/crates/interpreter/src/valid.rs @@ -155,7 +155,7 @@ impl ValidMode for Verify { check(parser.parse_section_id()? == SectionId::Custom)?; let mut section = parser.split_section()?; check(section.parse_name()? == "wasefire-sidetable")?; - SideTableView::new(parser) + SideTableView::new(parser.save()) } fn next_branch_table<'a, 'm>( From 39ebcb791aa3783739035314093b14e2f6df430b Mon Sep 17 00:00:00 2001 From: Zhou Fang <33002388+zhou-w-fang@users.noreply.github.com> Date: Sun, 9 Feb 2025 22:57:15 -0800 Subject: [PATCH 6/6] feat!: implement merge() --- crates/interpreter/src/side_table.rs | 10 +++++++++- crates/interpreter/src/valid.rs | 20 ++++++++++++++------ crates/interpreter/tests/spec.rs | 7 ++++--- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/crates/interpreter/src/side_table.rs b/crates/interpreter/src/side_table.rs index fc8c5a45..217cab8a 100644 --- a/crates/interpreter/src/side_table.rs +++ b/crates/interpreter/src/side_table.rs @@ -15,6 +15,8 @@ use alloc::vec::Vec; use core::ops::Range; +use bytemuck::{Pod, Zeroable}; + use crate::error::*; use crate::module::Parser; @@ -89,10 +91,16 @@ pub struct MetadataEntry { pub branch_table: Vec, } -#[derive(Copy, Clone, Debug, bytemuck::AnyBitPattern)] +#[derive(Copy, Clone, Debug, Pod, Zeroable)] #[repr(transparent)] pub struct BranchTableEntry([u16; 3]); +impl BranchTableEntry { + pub fn as_bytes(&self) -> &[u8; size_of::()] { + bytemuck::cast_ref(self) + } +} + pub struct BranchTableEntryView { /// The amount to adjust the instruction pointer by if the branch is taken. pub delta_ip: i32, diff --git a/crates/interpreter/src/valid.rs b/crates/interpreter/src/valid.rs index e0d7c83b..6d172d41 100644 --- a/crates/interpreter/src/valid.rs +++ b/crates/interpreter/src/valid.rs @@ -19,7 +19,6 @@ use core::cmp::Ordering; use core::marker::PhantomData; use core::ops::Range; -use crate::Error::Invalid; use crate::error::*; use crate::side_table::*; use crate::syntax::*; @@ -28,11 +27,20 @@ use crate::util::*; use crate::*; pub fn merge(binary: &[u8], side_table: Vec) -> Result, Error> { - // Convert Vec to Vec. - // Create a custom section at the beginning of the binary, - // and put the serialized `side_table` in it. - // Return the new module. - Err(Invalid) + let mut wasm = vec![]; + wasm.extend_from_slice(&binary[0 .. 8]); + wasm.push(0); + wasm.extend_from_slice(&side_table.len().to_le_bytes()); + for entry in side_table { + wasm.extend_from_slice(&entry.type_idx.to_le_bytes()); + wasm.extend_from_slice(&entry.parser_range.start.to_le_bytes()); + wasm.extend_from_slice(&entry.parser_range.end.to_le_bytes()); + for branch in entry.branch_table { + wasm.extend_from_slice(branch.as_bytes()); + } + } + wasm.extend_from_slice(&binary[8 ..]); + Ok(wasm) } /// Checks whether a WASM module in binary format is valid, and returns the side table. diff --git a/crates/interpreter/tests/spec.rs b/crates/interpreter/tests/spec.rs index 54199b8b..b5ab57bc 100644 --- a/crates/interpreter/tests/spec.rs +++ b/crates/interpreter/tests/spec.rs @@ -165,9 +165,10 @@ impl<'m> Env<'m> { fn maybe_instantiate(&mut self, name: &str, wasm: &[u8]) -> Result { let side_table = prepare(wasm)?; - let wasm_with_side_table = merge(wasm, side_table)?.as_slice(); - let module = self.alloc(wasm_with_side_table.len()); - module.copy_from_slice(wasm_with_side_table); + let merged = merge(wasm, side_table)?; + let wasm = merged.as_slice(); + let module = self.alloc(wasm.len()); + module.copy_from_slice(wasm); let module = Module::new(module)?; let memory = self.alloc(mem_size(name)); self.store.instantiate(module, memory)