From 92d5ca18c0f2beda76c99a58927445ff4992f903 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 19 Nov 2018 11:21:05 -0800 Subject: [PATCH] Add `wasm-bindgen` to the producers section Recently proposed in WebAssembly/tool-conventions#65 each wasm file will now have an optional `producers` section listing the tooling that went into producing it. Let's add `wasm-bindgen` in when it processes a wasm file! --- crates/cli-support/src/js/mod.rs | 103 +++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 12565567dee..c537aa90086 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -4,6 +4,7 @@ use std::mem; use decode; use failure::{Error, ResultExt}; use parity_wasm::elements::*; +use parity_wasm::elements::Error as ParityError; use shared; use gc; @@ -475,6 +476,7 @@ impl<'a> Context<'a> { })?; self.rewrite_imports(module_name); + self.update_producers_section(); let mut js = if self.config.threads.is_some() { // TODO: It's not clear right now how to best use threads with @@ -2013,6 +2015,107 @@ impl<'a> Context<'a> { ImportTarget::Method(format!("{}_target", import.shim)) }) } + + /// Update the wasm file's `producers` section to include information about + /// the wasm-bindgen tool. + /// + /// Specified at: + /// https://github.com/WebAssembly/tool-conventions/blob/master/ProducersSection.md + fn update_producers_section(&mut self) { + for section in self.module.sections_mut() { + let section = match section { + Section::Custom(s) => s, + _ => continue, + }; + if section.name() != "producers" { + return + } + drop(update(section)); + return + } + + // `CustomSection::new` added in paritytech/parity-wasm#244 which isn't + // merged just yet + let data = [ + ("producers".len() + 1) as u8, + b'p', b'r', b'o', b'd', b'u', b'c', b'e', b'r', b's', + 0, + ]; + let mut section = CustomSection::deserialize(&mut &data[..]).unwrap(); + assert_eq!(section.name(), "producers"); + assert_eq!(section.payload(), [0]); + drop(update(&mut section)); + self.module.sections_mut().push(Section::Custom(section)); + + fn update(section: &mut CustomSection) -> Result<(), ParityError> { + struct Field { + name: String, + values: Vec, + } + struct FieldValue { + name: String, + version: String, + } + + let wasm_bindgen = || { + FieldValue { + name: "wasm-bindgen".to_string(), + version: shared::version(), + } + }; + let mut fields = Vec::new(); + + // Deserialize the fields, appending the wasm-bidngen field/value + // where applicable + { + let mut data = section.payload(); + let amt: u32 = VarUint32::deserialize(&mut data)?.into(); + let mut found_processed_by = false; + for _ in 0..amt { + let name = String::deserialize(&mut data)?; + let cnt: u32 = VarUint32::deserialize(&mut data)?.into(); + let mut values = Vec::with_capacity(cnt as usize); + for _ in 0..cnt { + let name = String::deserialize(&mut data)?; + let version = String::deserialize(&mut data)?; + values.push(FieldValue { name, version }); + } + + if name == "processed-by" { + found_processed_by = true; + values.push(wasm_bindgen()); + } + + fields.push(Field { name, values }); + } + if data.len() != 0 { + return Err(ParityError::InconsistentCode) + } + + if !found_processed_by { + fields.push(Field { + name: "processed-by".to_string(), + values: vec![wasm_bindgen()], + }); + } + } + + // re-serialize these fields back into the custom section + let dst = section.payload_mut(); + dst.truncate(0); + VarUint32::from(fields.len() as u32).serialize(dst)?; + for field in fields.iter() { + field.name.clone().serialize(dst)?; + VarUint32::from(field.values.len() as u32).serialize(dst)?; + for value in field.values.iter() { + value.name.clone().serialize(dst)?; + value.version.clone().serialize(dst)?; + } + } + + Ok(()) + } + } } impl<'a, 'b> SubContext<'a, 'b> {