From f681aeab4738b506f1af5cf61626523c28c3c82d Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Tue, 7 May 2019 16:05:00 -0500 Subject: [PATCH] Use ModuleConfig to configure; remove optional fields. --- crates/fuzz/src/lib.rs | 4 +-- examples/round-trip.rs | 2 +- src/emit.rs | 2 +- src/function_builder.rs | 3 ++- src/module/config.rs | 9 +++++++ src/module/functions/local_function/mod.rs | 11 ++++---- src/module/functions/mod.rs | 29 +++++++++++++++------ src/module/mod.rs | 30 ++++++++++++++++++---- 8 files changed, 67 insertions(+), 23 deletions(-) diff --git a/crates/fuzz/src/lib.rs b/crates/fuzz/src/lib.rs index 56c5749f..2769b3b7 100755 --- a/crates/fuzz/src/lib.rs +++ b/crates/fuzz/src/lib.rs @@ -74,9 +74,9 @@ impl Config { fn round_trip_through_walrus(&self, wasm: &[u8]) -> Vec { walrus::Module::from_buffer(&wasm) .unwrap() - .emit_wasm(false) + .emit_wasm() .unwrap() - .0 + .into() } fn run_one(&self, wat: &str) -> Option { diff --git a/examples/round-trip.rs b/examples/round-trip.rs index 4a4a503b..8808d615 100644 --- a/examples/round-trip.rs +++ b/examples/round-trip.rs @@ -4,7 +4,7 @@ fn main() { env_logger::init(); let a = std::env::args().nth(1).unwrap(); let m = walrus::Module::from_file(&a).unwrap(); - let (wasm, _) = m.emit_wasm(false).unwrap(); + let walrus::EmitResult { wasm, .. } = m.emit_wasm().unwrap(); if let Some(destination) = std::env::args().nth(2) { std::fs::write(destination, wasm).unwrap(); } diff --git a/src/emit.rs b/src/emit.rs index 8a8fca67..9585942f 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -15,7 +15,7 @@ pub struct EmitContext<'a> { pub indices: &'a mut IdsToIndices, pub encoder: Encoder<'a>, pub locals: IdHashMap>, - pub offsets_map: Option>, + pub code_transform: Vec<(usize, usize)>, } pub struct SubContext<'a, 'cx> { diff --git a/src/function_builder.rs b/src/function_builder.rs index c4ace95c..6f7c6026 100644 --- a/src/function_builder.rs +++ b/src/function_builder.rs @@ -1,4 +1,5 @@ use crate::ir::*; +use crate::map::IdHashMap; use crate::tombstone_arena::TombstoneArena; use crate::{FunctionId, LocalFunction, Module, TypeId, ValType}; use crate::{ModuleFunctions, ModuleTypes}; @@ -141,7 +142,7 @@ impl FunctionBuilder { results: ty.results().to_vec().into_boxed_slice(), exprs, }); - let func = LocalFunction::new(ty_id, args, self, entry, None); + let func = LocalFunction::new(ty_id, args, self, entry, IdHashMap::default()); funcs.add_local(func) } } diff --git a/src/module/config.rs b/src/module/config.rs index a0dd30e8..c4240ff5 100644 --- a/src/module/config.rs +++ b/src/module/config.rs @@ -11,6 +11,7 @@ pub struct ModuleConfig { pub(crate) skip_strict_validate: bool, pub(crate) skip_producers_section: bool, pub(crate) skip_name_section: bool, + pub(crate) preserve_code_transform: bool, } impl ModuleConfig { @@ -97,6 +98,14 @@ impl ModuleConfig { self } + /// Sets a flag to whether code transform is preverved during parsing. + /// + /// By default this flag is `false`. + pub fn preserve_code_transform(&mut self, preserve: bool) -> &mut ModuleConfig { + self.preserve_code_transform = preserve; + self + } + /// Parses an in-memory WebAssembly file into a `Module` using this /// configuration. pub fn parse(&self, wasm: &[u8]) -> Result { diff --git a/src/module/functions/local_function/mod.rs b/src/module/functions/local_function/mod.rs index d277be10..378c7802 100644 --- a/src/module/functions/local_function/mod.rs +++ b/src/module/functions/local_function/mod.rs @@ -38,7 +38,7 @@ pub struct LocalFunction { /// Stores the ExprId -> offset map in code section of the original /// instruction. This will be necessary for preserving debug info. - pub offsets: Option>, + pub offsets: IdHashMap, } impl LocalFunction { @@ -48,7 +48,7 @@ impl LocalFunction { args: Vec, exprs: FunctionBuilder, entry: BlockId, - offsets: Option>, + offsets: IdHashMap, ) -> LocalFunction { LocalFunction { ty, @@ -69,6 +69,7 @@ impl LocalFunction { id: FunctionId, ty: TypeId, args: Vec, + preserve_code_transform: bool, mut body: wasmparser::OperatorsReader, ) -> Result { let mut func = LocalFunction { @@ -76,7 +77,7 @@ impl LocalFunction { exprs: FunctionBuilder::new(), args, entry: None, - offsets: Some(IdHashMap::default()), + offsets: IdHashMap::default(), }; let result: Vec<_> = module.types.get(ty).results().iter().cloned().collect(); @@ -93,10 +94,10 @@ impl LocalFunction { while !body.eof() { let (inst, pos) = body.read_with_offset()?; let expr_id = validate_instruction(&mut ctx, inst)?; - if ctx.func.offsets.is_some() { + if preserve_code_transform { match expr_id { Some(id) => { - ctx.func.offsets.as_mut().unwrap().insert(id, pos); + ctx.func.offsets.insert(id, pos); } None => (), } diff --git a/src/module/functions/mod.rs b/src/module/functions/mod.rs index 310bd6d9..0bf9dc50 100644 --- a/src/module/functions/mod.rs +++ b/src/module/functions/mod.rs @@ -371,12 +371,25 @@ impl Module { bodies.push((id, body, args, ty)); } + let preserve_code_transform = self.config.preserve_code_transform; + // Wasm modules can often have a lot of functions and this operation can // take some time, so parse all function bodies in parallel. let results = bodies .into_par_iter() .map(|(id, body, args, ty)| { - (id, LocalFunction::parse(self, indices, id, ty, args, body)) + ( + id, + LocalFunction::parse( + self, + indices, + id, + ty, + args, + preserve_code_transform, + body, + ), + ) }) .collect::>(); @@ -429,13 +442,13 @@ fn remap_offsets( } fn append_code_offsets( - offsets_map: &mut Vec<(usize, usize)>, + code_transform: &mut Vec<(usize, usize)>, code_offset: usize, map: Vec<(usize, usize)>, ) { for (src, dst) in map { let dst = dst + code_offset; - offsets_map.push((src, dst)); + code_transform.push((src, dst)); } } @@ -450,7 +463,7 @@ impl Emit for ModuleFunctions { let mut cx = cx.start_section(Section::Code); cx.encoder.usize(functions.len()); - let generate_map = cx.offsets_map.is_some(); + let generate_map = cx.module.config.preserve_code_transform; // Functions can typically take awhile to serialize, so serialize // everything in parallel. Afterwards we'll actually place all the @@ -461,7 +474,7 @@ impl Emit for ModuleFunctions { log::debug!("emit function {:?} {:?}", id, cx.module.funcs.get(id).name); let mut wasm = Vec::new(); let mut encoder = Encoder::new(&mut wasm); - let mut map = if generate_map && func.offsets.is_some() { + let mut map = if generate_map { Some(IdHashMap::default()) } else { None @@ -469,7 +482,7 @@ impl Emit for ModuleFunctions { let (used_locals, local_indices) = func.emit_locals(cx.module, &mut encoder); func.emit_instructions(cx.indices, &local_indices, &mut encoder, map.as_mut()); - let map = map.map(|m| remap_offsets(func.offsets.as_ref().unwrap(), &m)); + let map = map.map(|m| remap_offsets(&func.offsets, &m)); (wasm, id, used_locals, local_indices, map) }) .collect::>(); @@ -478,8 +491,8 @@ impl Emit for ModuleFunctions { for (wasm, id, used_locals, local_indices, map) in bytes { let code_offset = cx.encoder.pos(); cx.encoder.bytes(&wasm); - if let (Some(mut offsets_map), Some(map)) = (cx.offsets_map.as_mut(), map) { - append_code_offsets(&mut offsets_map, code_offset, map); + if let Some(map) = map { + append_code_offsets(&mut cx.code_transform, code_offset, map); } cx.indices.locals.insert(id, local_indices); cx.locals.insert(id, used_locals); diff --git a/src/module/mod.rs b/src/module/mod.rs index 9332ff90..f003a91c 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -74,6 +74,23 @@ pub struct CustomSection { pub value: Vec, } +/// Emitted module information. +#[derive(Debug)] +pub struct EmitResult { + /// The wasm file bytecode. + pub wasm: Vec, + + /// Optional code transform (if module generated from + /// the existing wasm file). + pub code_transform: Vec<(usize, usize)>, +} + +impl Into> for EmitResult { + fn into(self) -> Vec { + self.wasm + } +} + impl Module { /// Construct a new module from the given path with the default /// configuration. @@ -227,13 +244,13 @@ impl Module { where P: AsRef, { - let (buffer, _) = self.emit_wasm(true)?; + let EmitResult { wasm: buffer, .. } = self.emit_wasm()?; fs::write(path, buffer).context("failed to write wasm module")?; Ok(()) } /// Emit this module into an in-memory wasm buffer. - pub fn emit_wasm(&self, with_map: bool) -> Result<(Vec, Option>)> { + pub fn emit_wasm(&self) -> Result { log::debug!("start emit"); let indices = &mut IdsToIndices::default(); @@ -246,7 +263,7 @@ impl Module { indices, encoder: Encoder::new(&mut wasm), locals: Default::default(), - offsets_map: if with_map { Some(Vec::new()) } else { None }, + code_transform: Vec::new(), }; self.types.emit(&mut cx); self.imports.emit(&mut cx); @@ -281,10 +298,13 @@ impl Module { cx.custom_section(§ion.name).encoder.raw(§ion.value); } - let offsets_map = cx.offsets_map.take(); + let code_transform = cx.code_transform; log::debug!("emission finished"); - Ok((wasm, offsets_map)) + Ok(EmitResult { + wasm, + code_transform, + }) } /// Returns an iterator over all functions in this module