Skip to content

Commit

Permalink
Use ModuleConfig to configure; remove optional fields.
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik committed May 7, 2019
1 parent 111fd79 commit f681aea
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 23 deletions.
4 changes: 2 additions & 2 deletions crates/fuzz/src/lib.rs
Expand Up @@ -74,9 +74,9 @@ impl Config {
fn round_trip_through_walrus(&self, wasm: &[u8]) -> Vec<u8> {
walrus::Module::from_buffer(&wasm)
.unwrap()
.emit_wasm(false)
.emit_wasm()
.unwrap()
.0
.into()
}

fn run_one(&self, wat: &str) -> Option<FailingTestCase> {
Expand Down
2 changes: 1 addition & 1 deletion examples/round-trip.rs
Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/emit.rs
Expand Up @@ -15,7 +15,7 @@ pub struct EmitContext<'a> {
pub indices: &'a mut IdsToIndices,
pub encoder: Encoder<'a>,
pub locals: IdHashMap<Function, IdHashSet<Local>>,
pub offsets_map: Option<Vec<(usize, usize)>>,
pub code_transform: Vec<(usize, usize)>,
}

pub struct SubContext<'a, 'cx> {
Expand Down
3 changes: 2 additions & 1 deletion 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};
Expand Down Expand Up @@ -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)
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/module/config.rs
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<Module> {
Expand Down
11 changes: 6 additions & 5 deletions src/module/functions/local_function/mod.rs
Expand Up @@ -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<IdHashMap<Expr, usize>>,
pub offsets: IdHashMap<Expr, usize>,
}

impl LocalFunction {
Expand All @@ -48,7 +48,7 @@ impl LocalFunction {
args: Vec<LocalId>,
exprs: FunctionBuilder,
entry: BlockId,
offsets: Option<IdHashMap<Expr, usize>>,
offsets: IdHashMap<Expr, usize>,
) -> LocalFunction {
LocalFunction {
ty,
Expand All @@ -69,14 +69,15 @@ impl LocalFunction {
id: FunctionId,
ty: TypeId,
args: Vec<LocalId>,
preserve_code_transform: bool,
mut body: wasmparser::OperatorsReader,
) -> Result<LocalFunction> {
let mut func = LocalFunction {
ty,
exprs: FunctionBuilder::new(),
args,
entry: None,
offsets: Some(IdHashMap::default()),
offsets: IdHashMap::default(),
};

let result: Vec<_> = module.types.get(ty).results().iter().cloned().collect();
Expand All @@ -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 => (),
}
Expand Down
29 changes: 21 additions & 8 deletions src/module/functions/mod.rs
Expand Up @@ -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::<Vec<_>>();

Expand Down Expand Up @@ -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));
}
}

Expand All @@ -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
Expand All @@ -461,15 +474,15 @@ 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
};

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::<Vec<_>>();
Expand All @@ -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);
Expand Down
30 changes: 25 additions & 5 deletions src/module/mod.rs
Expand Up @@ -74,6 +74,23 @@ pub struct CustomSection {
pub value: Vec<u8>,
}

/// Emitted module information.
#[derive(Debug)]
pub struct EmitResult {
/// The wasm file bytecode.
pub wasm: Vec<u8>,

/// Optional code transform (if module generated from
/// the existing wasm file).
pub code_transform: Vec<(usize, usize)>,
}

impl Into<Vec<u8>> for EmitResult {
fn into(self) -> Vec<u8> {
self.wasm
}
}

impl Module {
/// Construct a new module from the given path with the default
/// configuration.
Expand Down Expand Up @@ -227,13 +244,13 @@ impl Module {
where
P: AsRef<Path>,
{
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<u8>, Option<Vec<(usize, usize)>>)> {
pub fn emit_wasm(&self) -> Result<EmitResult> {
log::debug!("start emit");

let indices = &mut IdsToIndices::default();
Expand All @@ -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);
Expand Down Expand Up @@ -281,10 +298,13 @@ impl Module {
cx.custom_section(&section.name).encoder.raw(&section.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
Expand Down

0 comments on commit f681aea

Please sign in to comment.