├── wasm-gc-api ├── README.md ├── LICENSE-MIT ├── LICENSE-APACHE ├── Cargo.toml └── src │ ├── error.rs │ ├── bitvec.rs │ ├── lib.rs │ └── gc.rs ├── .gitignore ├── wasm-gc-capi ├── Cargo.toml └── src │ └── lib.rs ├── Cargo.toml ├── LICENSE-MIT ├── .appveyor.yml ├── README.md ├── .travis.yml ├── src └── main.rs ├── LICENSE-APACHE └── Cargo.lock /wasm-gc-api/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /wasm-gc-api/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | ../LICENSE-MIT -------------------------------------------------------------------------------- /wasm-gc-api/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | ../LICENSE-APACHE -------------------------------------------------------------------------------- /wasm-gc-capi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-gc-capi" 3 | version = "0.1.0" 4 | authors = ["Alex Crichton "] 5 | 6 | [lib] 7 | crate-type = ['cdylib'] 8 | 9 | [dependencies] 10 | wasm-gc-api = { path = '../wasm-gc-api' } 11 | cfg-if = "0.1" 12 | wasm-bindgen = { version = "0.2", optional = true } 13 | -------------------------------------------------------------------------------- /wasm-gc-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-gc-api" 3 | version = "0.1.11" 4 | authors = ["Alex Crichton "] 5 | repository = "https://github.com/alexcrichton/wasm-gc" 6 | homepage = "https://github.com/alexcrichton/wasm-gc" 7 | license = "MIT/Apache-2.0" 8 | readme = "README.md" 9 | description = "A library to garbage collect webassembly modules" 10 | keywords = ["webasm"] 11 | categories = ["development-tools"] 12 | 13 | [lib] 14 | name = "wasm_gc" 15 | 16 | [dependencies] 17 | parity-wasm = "0.32" 18 | log = "0.4" 19 | rustc-demangle = "0.1.9" 20 | -------------------------------------------------------------------------------- /wasm-gc-api/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::error; 2 | use std::fmt; 3 | use parity_wasm::elements::Error as ParityWasmError; 4 | 5 | /// The error type for garbage collecting webassembly bytecode. 6 | #[derive(Debug)] 7 | pub struct Error(ParityWasmError); 8 | 9 | impl error::Error for Error { 10 | fn description(&self) -> &str { 11 | "webassembly garbage collection failed" 12 | } 13 | } 14 | 15 | impl fmt::Display for Error { 16 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 17 | write!(f, "{:?}", self.0) 18 | } 19 | } 20 | 21 | pub fn from(parity: ParityWasmError) -> Error { 22 | Error(parity) 23 | } 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm-gc" 3 | version = "0.1.6" 4 | authors = ["Alex Crichton "] 5 | repository = "https://github.com/alexcrichton/wasm-gc" 6 | homepage = "https://github.com/alexcrichton/wasm-gc" 7 | license = "MIT/Apache-2.0" 8 | readme = "README.md" 9 | description = "A CLI tool to garbage collect webassembly modules" 10 | keywords = ["webasm"] 11 | categories = ["development-tools"] 12 | 13 | [[bin]] 14 | name = "wasm-gc" 15 | path = "src/main.rs" 16 | 17 | [dependencies] 18 | env_logger = { version = "0.5", default-features = false } 19 | getopts = "0.2" 20 | wasm-gc-api = { path = "wasm-gc-api", version = "0.1" } 21 | 22 | [workspace] 23 | members = ['wasm-gc-capi'] 24 | 25 | [profile.release] 26 | panic = 'abort' 27 | lto = true 28 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Alex Crichton 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | global: 3 | RUSTFLAGS: -Ctarget-feature=+crt-static 4 | matrix: 5 | - TARGET: x86_64-pc-windows-msvc 6 | DEPLOY: 1 7 | 8 | install: 9 | # Install rust, x86_64-pc-windows-msvc host 10 | - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 11 | - rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly 12 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 13 | - rustc -V 14 | - cargo -V 15 | 16 | build: false 17 | 18 | test_script: 19 | - cargo test --locked 20 | - cargo build --release 21 | 22 | before_deploy: 23 | - ps: | 24 | $NAME = "wasm-gc-${env:APPVEYOR_REPO_TAG_NAME}-${env:TARGET}" 25 | New-Item -Path $NAME -ItemType directory 26 | Copy-Item target/release/wasm-gc.exe "${NAME}/" 27 | Copy-Item LICENSE-MIT "${NAME}/" 28 | Copy-Item LICENSE-APACHE "${NAME}/" 29 | Copy-Item README.md "${NAME}/" 30 | 7z a -ttar "${NAME}.tar" "${NAME}" 31 | 7z a "${NAME}.tar.gz" "${NAME}.tar" 32 | Push-AppveyorArtifact "${NAME}.tar.gz" 33 | 34 | deploy: 35 | artifact: /.*\.tar.gz/ 36 | auth_token: 37 | secure: fDuN5NCqK7FRNCJknOgFUq3npP31JDY82gZZhVZRGFm18CbW830UIsHmk01eapez 38 | description: '' 39 | on: 40 | appveyor_repo_tag: true 41 | provider: GitHub 42 | -------------------------------------------------------------------------------- /wasm-gc-api/src/bitvec.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | type T = usize; 4 | 5 | const BITS: usize = mem::size_of::() * 8; 6 | 7 | pub struct BitSet { 8 | bits: Vec, 9 | } 10 | 11 | impl BitSet { 12 | pub fn new() -> BitSet { 13 | BitSet { bits: Vec::new() } 14 | } 15 | 16 | pub fn insert(&mut self, i: u32) -> bool { 17 | let i = i as usize; 18 | let idx = i / BITS; 19 | let bit = 1 << (i % BITS); 20 | if self.bits.len() <= idx { 21 | self.bits.resize(idx + 1, 0); 22 | } 23 | let slot = &mut self.bits[idx]; 24 | if *slot & bit != 0 { 25 | false 26 | } else { 27 | *slot |= bit; 28 | true 29 | } 30 | } 31 | 32 | pub fn contains(&self, i: &u32) -> bool { 33 | let i = *i as usize; 34 | let idx = i / BITS; 35 | let bit = 1 << (i % BITS); 36 | self.bits.get(idx) 37 | .map(|x| *x & bit != 0) 38 | .unwrap_or(false) 39 | } 40 | } 41 | 42 | impl Default for BitSet { 43 | fn default() -> BitSet { 44 | BitSet::new() 45 | } 46 | } 47 | 48 | #[cfg(test)] 49 | mod tests { 50 | use super::BitSet; 51 | 52 | #[test] 53 | fn simple() { 54 | let mut x = BitSet::new(); 55 | assert!(!x.contains(&1)); 56 | assert!(!x.contains(&0)); 57 | assert!(!x.contains(&3)); 58 | assert!(x.insert(3)); 59 | assert!(x.contains(&3)); 60 | assert!(!x.insert(3)); 61 | assert!(x.contains(&3)); 62 | assert!(!x.contains(&1)); 63 | assert!(x.insert(2)); 64 | assert!(x.contains(&2)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wasm-gc 2 | 3 | > **Note**: you probably don't need to use this project. This project is no 4 | > longer necessary to run by hand, nor do you need the `wasm-gc` executable 5 | > installed. 6 | > 7 | > For a longer explanation, these two points mean that `wasm-gc` is likely no 8 | > longer a useful command to run for you: 9 | > 10 | > 1. The Rust compiler now natively supports `--gc-sections` when linking wasm 11 | > executables, which means wasm executables already have 90% of their garbage 12 | > removed when coming out of the compiler. 13 | > 2. The `wasm-pack` (and `wasm-bindgen`) project will already run this by 14 | > default for you, so there's no need to run it again. 15 | > 16 | > Don't include this build! If you think you need to feel free to open an issue 17 | > on `wasm-pack` or `wasm-bindgen`, as it may be a bug in one of those projects! 18 | 19 | A small command to gc a wasm module and remove all unneeded exports, imports, 20 | functions, etc. This is effectively `--gc-sections` for arbitrary wasm 21 | executables. Not needed by Rust programs coming out of the Rust compiler, only 22 | provided here nowadays for learning purposes and to be used as a library if 23 | necessary. 24 | 25 | # License 26 | 27 | This project is licensed under either of 28 | 29 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 30 | http://www.apache.org/licenses/LICENSE-2.0) 31 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or 32 | http://opensource.org/licenses/MIT) 33 | 34 | at your option. 35 | 36 | ### Contribution 37 | 38 | Unless you explicitly state otherwise, any contribution intentionally submitted 39 | for inclusion in this project by you, as defined in the Apache-2.0 license, 40 | shall be dual licensed as above, without any additional terms or conditions. 41 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: false 3 | dist: trusty 4 | 5 | matrix: 6 | include: 7 | - rust: stable 8 | - env: TARGET=x86_64-unknown-linux-musl DEPLOY=1 9 | before_script: 10 | - rustup target add $TARGET 11 | script: cargo build --release --target $TARGET --locked 12 | 13 | - os: osx 14 | - os: osx 15 | env: MACOSX_DEPLOYMENT_TARGET=10.7 DEPLOY=1 TARGET=x86_64-apple-darwin 16 | script: cargo build --release --target $TARGET --locked 17 | 18 | addons: 19 | apt: 20 | packages: 21 | - musl-tools 22 | 23 | script: 24 | - cargo test --locked 25 | 26 | notifications: 27 | email: 28 | on_success: never 29 | 30 | before_deploy: 31 | - name="wasm-gc-$TRAVIS_TAG-$TARGET" 32 | - mkdir $name 33 | - cp target/$TARGET/release/wasm-gc $name/ 34 | - cp README.md LICENSE-MIT LICENSE-APACHE $name/ 35 | - tar czvf $name.tar.gz $name 36 | 37 | deploy: 38 | api_key: 39 | secure: "v5eBBx8qMH8e3D1GHBDZsPgbgC83J/Lda4Z42CSrbDqkbidY+ySMQz+oT9m45jBaO5in8UhlMgBjPV4Wv65KEF3CJ1co85KUc88J6aBR0WfuMSgp/sYR6zhGgdgCQUmMCR0sY+OYtlPSlTXf4mPAvb0ecIUMzsKmBrHTdaD+VlasPe8lqzvM/J5VF4gSEjci2isj7agfhjiz52dUybsIX98I5iMlmi0YgZp0Rht4HLuIKTQuYrsKuWqSBGB8FIW4Lpnxnwy/nhzfIvWC8lbzvHvEBwE6zud4KCRdWLWkEhtoTQUAqGxQ9843m0rRTDHxU487Kyg0j1mphV2wJAgVy35QWeHTX7psgXHEF6nlFlIigcOxELb7osi4mqbYFTFThE1buD+0CEzGn1nvcpsxuezNK5PiiV1tW/d4yZk5ZNzVdXVit8rlkdgQg2WPi/VFPWI8sEVcIrTpyiYa0vrhKUuqiob38mmz1LszW5FBh6iCy3itQdNa3V+4Nvlt3wcmu0n5ICrbmCO54b4/YD7ntXZF3W1mJpLa1RWP3n67OE2m/CQPNpXt72Zt8FkiQ4WqnUw9HfMaEGjJqFljNPugX5P6hyAq8X5kqTHpzmka0VJdn5qgyOjIamgHCKzvgBoIrZiJcQfYUJs7zp4goeMUYpkb8GgCM12QacYXemomYr0=" 40 | file_glob: true 41 | file: 42 | - wasm-gc-$TRAVIS_TAG-$TARGET.tar.gz 43 | on: 44 | condition: $DEPLOY = 1 45 | tags: true 46 | provider: releases 47 | skip_cleanup: true 48 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate env_logger; 2 | extern crate wasm_gc; 3 | extern crate getopts; 4 | 5 | use std::env; 6 | use std::fs::File; 7 | use std::io::{Read, Write}; 8 | 9 | use getopts::Options; 10 | 11 | fn main() { 12 | env_logger::init(); 13 | 14 | let mut opts = Options::new(); 15 | opts.optopt("o", "", "set output file name", "NAME"); 16 | opts.optflag("", "no-demangle", "don't demangle symbol names"); 17 | opts.optflag("h", "help", "print this help menu"); 18 | let args: Vec<_> = env::args().collect(); 19 | let program = args[0].clone(); 20 | let matches = match opts.parse(&args[1..]) { 21 | Ok(m) => { m } 22 | Err(f) => { panic!(f.to_string()) } 23 | }; 24 | if matches.opt_present("h") { 25 | return print_usage(&program, opts) 26 | } 27 | let (input, output) = match matches.free.len() { 28 | 0 => return print_usage(&program, opts), 29 | 1 => { 30 | let input = matches.free[0].clone(); 31 | match matches.opt_str("o"){ 32 | None => (input.clone(), input), 33 | Some(s) => (input, s), 34 | } 35 | } 36 | 2 => (matches.free[0].clone(), matches.free[1].clone()), 37 | _ => return print_usage(&program, opts), 38 | }; 39 | 40 | let mut contents = Vec::new(); 41 | File::open(&input).unwrap().read_to_end(&mut contents).unwrap(); 42 | 43 | let mut cfg = wasm_gc::Config::new(); 44 | cfg.demangle(!matches.opt_present("no-demangle")); 45 | let result = cfg.gc(&contents).expect("failed to parse wasm module"); 46 | File::create(&output).unwrap().write_all(&result).unwrap(); 47 | } 48 | 49 | fn print_usage(program: &str, opts: Options) { 50 | let brief = format!("Usage: {} [options] [OUTPUT]", program); 51 | print!("{}", opts.usage(&brief)); 52 | println!(" 53 | A postprocessing command for wasm files to garbage-collect unused 54 | imports, internal functions, types, etc. This is intended to be 55 | similar to the functionality provided by `--gc-sections` by linkers 56 | in that it is not intended to modify the functionality of the wasm 57 | binary, only make it a little smaller. 58 | 59 | Usage of this command typically looks like: 60 | 61 | # Read and write output to one file 62 | wasm-gc foo.wasm 63 | 64 | # Read input from one file and write it to another file 65 | wasm-gc input.wasm output.wasm 66 | 67 | # Passing various options 68 | wasm-gc --no-demangle input.wasm -o output.wasm 69 | 70 | Please reports bugs to https://github.com/alexcrichton/wasm-gc if you find 71 | them! 72 | "); 73 | } 74 | -------------------------------------------------------------------------------- /wasm-gc-capi/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "wasm-bindgen", feature(proc_macro, wasm_custom_section, wasm_import_module))] 2 | #[macro_use] 3 | extern crate cfg_if; 4 | extern crate wasm_gc; 5 | 6 | pub const ERR_INVALID_MODULE: u32 = 1; 7 | pub const ERR_OUTPUT_TOO_SMALL: u32 = 2; 8 | 9 | #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen)] 10 | pub struct WasmGcOptions { 11 | demangle: bool, 12 | } 13 | 14 | #[cfg_attr(feature = "wasm-bindgen", wasm_bindgen)] 15 | impl WasmGcOptions { 16 | pub fn new() -> WasmGcOptions { 17 | WasmGcOptions { demangle: true } 18 | } 19 | 20 | pub fn demangle(&mut self, demangle: bool) { 21 | self.demangle = demangle; 22 | } 23 | 24 | pub fn gc(&self, input: &[u8], output: &mut [u8]) -> u32 { 25 | gc(input, output, self) 26 | } 27 | } 28 | 29 | cfg_if! { 30 | if #[cfg(feature = "wasm-bindgen")] { 31 | extern crate wasm_bindgen; 32 | use wasm_bindgen::prelude::*; 33 | 34 | #[wasm_bindgen] 35 | pub fn wasm_gc(input: &[u8], output: &mut [u8]) -> u32 { 36 | gc(input, output, &WasmGcOptions::new()) 37 | } 38 | } else { 39 | use std::slice; 40 | 41 | #[no_mangle] 42 | pub unsafe extern fn wasm_gc( 43 | input_ptr: *const u8, 44 | input_len: usize, 45 | output_ptr: *mut u8, 46 | output_len: usize, 47 | ) -> u32 { 48 | let opts = WasmGcOptions::new(); 49 | wasm_gc_options(input_ptr, input_len, output_ptr, output_len, &opts) 50 | } 51 | 52 | #[no_mangle] 53 | pub unsafe extern fn wasm_gc_options( 54 | input_ptr: *const u8, 55 | input_len: usize, 56 | output_ptr: *mut u8, 57 | output_len: usize, 58 | options: *const WasmGcOptions, 59 | ) -> u32 { 60 | let input = slice::from_raw_parts(input_ptr, input_len); 61 | let output = slice::from_raw_parts_mut(output_ptr, output_len); 62 | gc(input, output, &*options) 63 | } 64 | 65 | #[no_mangle] 66 | pub extern fn wasm_gc_options_new() -> *mut WasmGcOptions { 67 | Box::into_raw(Box::new(WasmGcOptions::new())) 68 | } 69 | 70 | #[no_mangle] 71 | pub unsafe extern fn wasm_gc_options_demangle( 72 | opts: *mut WasmGcOptions, 73 | demangle: u32, 74 | ) { 75 | (*opts).demangle = demangle != 0; 76 | } 77 | 78 | #[no_mangle] 79 | pub unsafe extern fn wasm_gc_options_free(opts: *mut WasmGcOptions) { 80 | drop(Box::from_raw(opts)); 81 | } 82 | } 83 | } 84 | 85 | fn gc(input: &[u8], output: &mut [u8], opts: &WasmGcOptions) -> u32 { 86 | let result = wasm_gc::Config::new() 87 | .demangle(opts.demangle) 88 | .gc(input); 89 | let result = match result { 90 | Ok(result) => result, 91 | Err(_) => return ERR_INVALID_MODULE, 92 | }; 93 | match output.get_mut(..result.len()) { 94 | Some(buf) => buf.copy_from_slice(&result), 95 | None => return ERR_OUTPUT_TOO_SMALL, 96 | } 97 | return 0 98 | } 99 | -------------------------------------------------------------------------------- /wasm-gc-api/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate parity_wasm; 2 | #[macro_use] 3 | extern crate log; 4 | extern crate rustc_demangle; 5 | 6 | mod gc; 7 | mod error; 8 | mod bitvec; 9 | 10 | use std::any::Any; 11 | use std::mem; 12 | use std::path::Path; 13 | 14 | use parity_wasm::elements::{ 15 | Module, 16 | Serialize, 17 | Deserialize 18 | }; 19 | 20 | pub use error::Error; 21 | 22 | pub struct Config { 23 | demangle: bool, 24 | keep_debug: bool, 25 | } 26 | 27 | pub struct GcResult(Box); 28 | 29 | impl Config { 30 | /// Creates a blank slate of configuration, ready to gc wasm files. 31 | pub fn new() -> Config { 32 | Config { 33 | demangle: true, 34 | keep_debug: false, 35 | } 36 | } 37 | 38 | /// Configures whether or not this will demangle symbols as part of the gc 39 | /// pass. 40 | pub fn demangle(&mut self, demangle: bool) -> &mut Self { 41 | self.demangle = demangle; 42 | self 43 | } 44 | 45 | /// Configures whether or not debug sections will be preserved. 46 | pub fn keep_debug(&mut self, keep_debug: bool) -> &mut Self { 47 | self.keep_debug = keep_debug; 48 | self 49 | } 50 | 51 | /// Runs gc passes over the wasm input module `input`, returning the 52 | /// serialized output. 53 | #[doc(hidden)] // deprecated, use `run` now. 54 | pub fn gc(&mut self, bytecode: &[u8]) -> Result, Error> { 55 | self.run(3, |_| bytecode.to_vec())?.into_bytes() 56 | } 57 | 58 | pub fn run( 59 | &mut self, 60 | mut module: T, 61 | into_bytes: impl FnOnce(T) -> Vec, 62 | ) -> Result { 63 | if let Some(module) = (&mut module as &mut Any).downcast_mut() { 64 | self._gc(module); 65 | let module = mem::replace(module, Module::new(Vec::new())); 66 | return Ok(GcResult(Box::new(module))) 67 | } 68 | let bytecode = into_bytes(module); 69 | let mut module = Module::deserialize(&mut &bytecode[..]) 70 | .map_err(error::from)? 71 | .parse_names() 72 | .map_err(|(mut l, _)| l.remove(0).1) 73 | .map_err(error::from)?; 74 | self._gc(&mut module); 75 | Ok(GcResult(Box::new(module))) 76 | } 77 | 78 | fn _gc(&mut self, module: &mut Module) { 79 | gc::run(self, module); 80 | } 81 | } 82 | 83 | impl GcResult { 84 | /// Attepts to downcast this `GcResult` into an instance of 85 | /// `parity_wasm::Module`. 86 | /// 87 | /// If your crate's `parity_wasm` crate is a different version than this 88 | /// crate then this method will fail and you'll need to use `into_bytes`. 89 | /// Otherwise the module is successfully extracted and returned. 90 | pub fn into_module(self) -> Result { 91 | let module = self.0 as Box; 92 | match module.downcast() { 93 | Ok(t) => Ok(*t), 94 | Err(box_any) => { 95 | match box_any.downcast::() { 96 | Ok(box_module) => Err(GcResult(box_module)), 97 | Err(_) => panic!(), 98 | } 99 | } 100 | } 101 | } 102 | 103 | /// Convert this `GcResult` into a serialized wasm module. 104 | /// 105 | /// Returns any error that happens during serialization, which shouldn't 106 | /// happen for valid modules. 107 | pub fn into_bytes(self) -> Result, Error> { 108 | let mut output = Vec::new(); 109 | self.0.serialize(&mut output).map_err(error::from)?; 110 | Ok(output) 111 | } 112 | } 113 | 114 | /// Garbage collects the webassembly bytecode from `input_path` and saves it to `output_path`. 115 | pub fn garbage_collect_file(input_path: I, output_path: O) -> Result<(), Error> 116 | where 117 | I: AsRef, 118 | O: AsRef, 119 | { 120 | _gc_file(input_path.as_ref(), output_path.as_ref()) 121 | } 122 | 123 | fn _gc_file(input: &Path, output: &Path) -> Result<(), Error> { 124 | let mut module = parity_wasm::deserialize_file(input) 125 | .map_err(error::from)? 126 | .parse_names() 127 | .map_err(|(mut l, _)| l.remove(0).1) 128 | .map_err(error::from)?; 129 | Config::new()._gc(&mut module); 130 | parity_wasm::serialize_to_file(output, module).map_err(error::from)?; 131 | 132 | Ok(()) 133 | } 134 | 135 | /// Garbage collects given webassembly bytecode. 136 | pub fn garbage_collect_slice(bytecode: &[u8]) -> Result, Error> { 137 | Config::new().gc(bytecode) 138 | } 139 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "atty" 3 | version = "0.2.11" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | dependencies = [ 6 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 8 | "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "byteorder" 13 | version = "1.2.6" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | 16 | [[package]] 17 | name = "cfg-if" 18 | version = "0.1.5" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | 21 | [[package]] 22 | name = "env_logger" 23 | version = "0.5.13" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | dependencies = [ 26 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 27 | "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 28 | "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 29 | "termcolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 30 | ] 31 | 32 | [[package]] 33 | name = "getopts" 34 | version = "0.2.18" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | dependencies = [ 37 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 38 | ] 39 | 40 | [[package]] 41 | name = "humantime" 42 | version = "1.1.1" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | dependencies = [ 45 | "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 46 | ] 47 | 48 | [[package]] 49 | name = "itoa" 50 | version = "0.4.2" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | 53 | [[package]] 54 | name = "lazy_static" 55 | version = "1.1.0" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | dependencies = [ 58 | "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 59 | ] 60 | 61 | [[package]] 62 | name = "libc" 63 | version = "0.2.43" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | 66 | [[package]] 67 | name = "log" 68 | version = "0.4.4" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | dependencies = [ 71 | "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 72 | ] 73 | 74 | [[package]] 75 | name = "parity-wasm" 76 | version = "0.32.0" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | dependencies = [ 79 | "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 80 | ] 81 | 82 | [[package]] 83 | name = "proc-macro2" 84 | version = "0.4.13" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | dependencies = [ 87 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 88 | ] 89 | 90 | [[package]] 91 | name = "quick-error" 92 | version = "1.2.2" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | 95 | [[package]] 96 | name = "quote" 97 | version = "0.6.8" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | dependencies = [ 100 | "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 101 | ] 102 | 103 | [[package]] 104 | name = "redox_syscall" 105 | version = "0.1.40" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | 108 | [[package]] 109 | name = "redox_termios" 110 | version = "0.1.1" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | dependencies = [ 113 | "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 114 | ] 115 | 116 | [[package]] 117 | name = "rustc-demangle" 118 | version = "0.1.9" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | 121 | [[package]] 122 | name = "ryu" 123 | version = "0.2.6" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | 126 | [[package]] 127 | name = "serde" 128 | version = "1.0.75" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | 131 | [[package]] 132 | name = "serde_derive" 133 | version = "1.0.75" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | dependencies = [ 136 | "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 137 | "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 138 | "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", 139 | ] 140 | 141 | [[package]] 142 | name = "serde_json" 143 | version = "1.0.26" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | dependencies = [ 146 | "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 147 | "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 148 | "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", 149 | ] 150 | 151 | [[package]] 152 | name = "syn" 153 | version = "0.14.9" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | dependencies = [ 156 | "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 157 | "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 158 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 159 | ] 160 | 161 | [[package]] 162 | name = "syn" 163 | version = "0.15.1" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | dependencies = [ 166 | "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 167 | "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 168 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 169 | ] 170 | 171 | [[package]] 172 | name = "termcolor" 173 | version = "1.0.2" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | dependencies = [ 176 | "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 177 | ] 178 | 179 | [[package]] 180 | name = "termion" 181 | version = "1.5.1" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | dependencies = [ 184 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 185 | "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 186 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 187 | ] 188 | 189 | [[package]] 190 | name = "unicode-width" 191 | version = "0.1.5" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | 194 | [[package]] 195 | name = "unicode-xid" 196 | version = "0.1.0" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | 199 | [[package]] 200 | name = "version_check" 201 | version = "0.1.4" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | 204 | [[package]] 205 | name = "wasm-bindgen" 206 | version = "0.2.21" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | dependencies = [ 209 | "wasm-bindgen-macro 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 210 | ] 211 | 212 | [[package]] 213 | name = "wasm-bindgen-backend" 214 | version = "0.2.21" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | dependencies = [ 217 | "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 218 | "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 219 | "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 220 | "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 221 | "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", 222 | "syn 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 223 | "wasm-bindgen-shared 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 224 | ] 225 | 226 | [[package]] 227 | name = "wasm-bindgen-macro" 228 | version = "0.2.21" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | dependencies = [ 231 | "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 232 | "wasm-bindgen-macro-support 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 233 | ] 234 | 235 | [[package]] 236 | name = "wasm-bindgen-macro-support" 237 | version = "0.2.21" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | dependencies = [ 240 | "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 241 | "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", 242 | "syn 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 243 | "wasm-bindgen-backend 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 244 | "wasm-bindgen-shared 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 245 | ] 246 | 247 | [[package]] 248 | name = "wasm-bindgen-shared" 249 | version = "0.2.21" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | dependencies = [ 252 | "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", 253 | "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", 254 | ] 255 | 256 | [[package]] 257 | name = "wasm-gc" 258 | version = "0.1.6" 259 | dependencies = [ 260 | "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", 261 | "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", 262 | "wasm-gc-api 0.1.11", 263 | ] 264 | 265 | [[package]] 266 | name = "wasm-gc-api" 267 | version = "0.1.11" 268 | dependencies = [ 269 | "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 270 | "parity-wasm 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", 271 | "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 272 | ] 273 | 274 | [[package]] 275 | name = "wasm-gc-capi" 276 | version = "0.1.0" 277 | dependencies = [ 278 | "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 279 | "wasm-bindgen 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 280 | "wasm-gc-api 0.1.11", 281 | ] 282 | 283 | [[package]] 284 | name = "winapi" 285 | version = "0.3.5" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | dependencies = [ 288 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 289 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 290 | ] 291 | 292 | [[package]] 293 | name = "winapi-i686-pc-windows-gnu" 294 | version = "0.4.0" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | 297 | [[package]] 298 | name = "winapi-util" 299 | version = "0.1.1" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | dependencies = [ 302 | "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 303 | ] 304 | 305 | [[package]] 306 | name = "winapi-x86_64-pc-windows-gnu" 307 | version = "0.4.0" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | 310 | [[package]] 311 | name = "wincolor" 312 | version = "1.0.1" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | dependencies = [ 315 | "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 316 | "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 317 | ] 318 | 319 | [metadata] 320 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 321 | "checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" 322 | "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" 323 | "checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38" 324 | "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" 325 | "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" 326 | "checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" 327 | "checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" 328 | "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 329 | "checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2" 330 | "checksum parity-wasm 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16ad52817c4d343339b3bc2e26861bd21478eda0b7509acf83505727000512ac" 331 | "checksum proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5697238f0d893c7f0ecc59c0999f18d2af85e424de441178bcacc9f9e6cf67" 332 | "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 333 | "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" 334 | "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" 335 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 336 | "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" 337 | "checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" 338 | "checksum serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "22d340507cea0b7e6632900a176101fea959c7065d93ba555072da90aaaafc87" 339 | "checksum serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "234fc8b737737b148ccd625175fc6390f5e4dacfdaa543cb93a3430d984a9119" 340 | "checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae" 341 | "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" 342 | "checksum syn 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85fb2f7f9b7a4c8df2c913a852de570efdb40f0d2edd39c8245ad573f5c7fbcc" 343 | "checksum termcolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3390f44f1f706d8870297b6a2c4f92d9ab65a37c265fbbc6ac4ee72bcc2f3698" 344 | "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" 345 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 346 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 347 | "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" 348 | "checksum wasm-bindgen 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d0a3300924764b11a5cbabdb2c7b9e61f20012f4900f8fe970d7f4e9a96de445" 349 | "checksum wasm-bindgen-backend 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "a4cbcffbbd54c7829d90c8588cd84b8cc8fafc804ab14d6ef715200dd9151f87" 350 | "checksum wasm-bindgen-macro 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "08b25b18d70ce1fc354e9865c2a8fa14d40ec838fe3c881081acc7fdad4e8e56" 351 | "checksum wasm-bindgen-macro-support 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "236087d13faa5916c1a0dff94d815b08a430b9e20d50d470f948b5131039e28e" 352 | "checksum wasm-bindgen-shared 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "8e3b2a6251484b92a20bcb3390b69297f51fd45ddce2ed84f329d2688eb401cf" 353 | "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" 354 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 355 | "checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" 356 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 357 | "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" 358 | -------------------------------------------------------------------------------- /wasm-gc-api/src/gc.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | use std::mem; 3 | use std::str; 4 | 5 | use parity_wasm::elements::*; 6 | use rustc_demangle; 7 | 8 | use Config; 9 | use bitvec::BitSet; 10 | 11 | pub fn run(config: &mut Config, module: &mut Module) { 12 | let analysis = { 13 | let mut cx = LiveContext::new(&module); 14 | 15 | cx.blacklist.insert("__ashldi3"); 16 | cx.blacklist.insert("__ashlti3"); 17 | cx.blacklist.insert("__ashrdi3"); 18 | cx.blacklist.insert("__ashrti3"); 19 | cx.blacklist.insert("__lshrdi3"); 20 | cx.blacklist.insert("__lshrti3"); 21 | cx.blacklist.insert("__floatsisf"); 22 | cx.blacklist.insert("__floatsidf"); 23 | cx.blacklist.insert("__floatdidf"); 24 | cx.blacklist.insert("__floattisf"); 25 | cx.blacklist.insert("__floattidf"); 26 | cx.blacklist.insert("__floatunsisf"); 27 | cx.blacklist.insert("__floatunsidf"); 28 | cx.blacklist.insert("__floatundidf"); 29 | cx.blacklist.insert("__floatuntisf"); 30 | cx.blacklist.insert("__floatuntidf"); 31 | cx.blacklist.insert("__fixsfsi"); 32 | cx.blacklist.insert("__fixsfdi"); 33 | cx.blacklist.insert("__fixsfti"); 34 | cx.blacklist.insert("__fixdfsi"); 35 | cx.blacklist.insert("__fixdfdi"); 36 | cx.blacklist.insert("__fixdfti"); 37 | cx.blacklist.insert("__fixunssfsi"); 38 | cx.blacklist.insert("__fixunssfdi"); 39 | cx.blacklist.insert("__fixunssfti"); 40 | cx.blacklist.insert("__fixunsdfsi"); 41 | cx.blacklist.insert("__fixunsdfdi"); 42 | cx.blacklist.insert("__fixunsdfti"); 43 | cx.blacklist.insert("__udivsi3"); 44 | cx.blacklist.insert("__umodsi3"); 45 | cx.blacklist.insert("__udivmodsi4"); 46 | cx.blacklist.insert("__udivdi3"); 47 | cx.blacklist.insert("__udivmoddi4"); 48 | cx.blacklist.insert("__umoddi3"); 49 | cx.blacklist.insert("__udivti3"); 50 | cx.blacklist.insert("__udivmodti4"); 51 | cx.blacklist.insert("__umodti3"); 52 | cx.blacklist.insert("memcpy"); 53 | cx.blacklist.insert("memmove"); 54 | cx.blacklist.insert("memset"); 55 | cx.blacklist.insert("memcmp"); 56 | cx.blacklist.insert("__powisf2"); 57 | cx.blacklist.insert("__powidf2"); 58 | cx.blacklist.insert("__addsf3"); 59 | cx.blacklist.insert("__adddf3"); 60 | cx.blacklist.insert("__subsf3"); 61 | cx.blacklist.insert("__subdf3"); 62 | cx.blacklist.insert("__divsi3"); 63 | cx.blacklist.insert("__divdi3"); 64 | cx.blacklist.insert("__divti3"); 65 | cx.blacklist.insert("__divdf3"); 66 | cx.blacklist.insert("__divsf3"); 67 | cx.blacklist.insert("__modsi3"); 68 | cx.blacklist.insert("__moddi3"); 69 | cx.blacklist.insert("__modti3"); 70 | cx.blacklist.insert("__divmodsi4"); 71 | cx.blacklist.insert("__divmoddi4"); 72 | cx.blacklist.insert("__muldi3"); 73 | cx.blacklist.insert("__multi3"); 74 | cx.blacklist.insert("__muldf3"); 75 | cx.blacklist.insert("__mulsf3"); 76 | cx.blacklist.insert("__mulosi4"); 77 | cx.blacklist.insert("__mulodi4"); 78 | cx.blacklist.insert("__muloti4"); 79 | cx.blacklist.insert("__lesf2"); 80 | cx.blacklist.insert("__gesf2"); 81 | cx.blacklist.insert("__unordsf2"); 82 | cx.blacklist.insert("__eqsf2"); 83 | cx.blacklist.insert("__ltsf2"); 84 | cx.blacklist.insert("__nesf2"); 85 | cx.blacklist.insert("__gtsf2"); 86 | cx.blacklist.insert("__ledf2"); 87 | cx.blacklist.insert("__gedf2"); 88 | cx.blacklist.insert("__unorddf2"); 89 | cx.blacklist.insert("__eqdf2"); 90 | cx.blacklist.insert("__ltdf2"); 91 | cx.blacklist.insert("__nedf2"); 92 | cx.blacklist.insert("__gtdf2"); 93 | cx.blacklist.insert("rust_eh_personality"); 94 | cx.blacklist.insert("__extendsfdf2"); 95 | 96 | if let Some(section) = module.export_section() { 97 | for (i, entry) in section.entries().iter().enumerate() { 98 | cx.add_export_entry(entry, i as u32); 99 | } 100 | } 101 | if let Some(section) = module.import_section() { 102 | for (i, entry) in section.entries().iter().enumerate() { 103 | debug!("import {:?}", entry); 104 | if let External::Memory(_) = *entry.external() { 105 | cx.add_import_entry(entry, i as u32); 106 | } 107 | } 108 | } 109 | if let Some(section) = module.data_section() { 110 | for entry in section.entries() { 111 | cx.add_data_segment(entry); 112 | } 113 | } 114 | if let Some(tables) = module.table_section() { 115 | for i in 0..tables.entries().len() as u32 { 116 | cx.add_table(i); 117 | } 118 | } 119 | if let Some(elements) = module.elements_section() { 120 | for seg in elements.entries() { 121 | cx.add_element_segment(seg); 122 | } 123 | } 124 | if let Some(i) = module.start_section() { 125 | cx.add_function(i); 126 | } 127 | cx.analysis 128 | }; 129 | 130 | let cx = RemapContext::new(&module, &analysis, config); 131 | for i in (0..module.sections().len()).rev() { 132 | let retain = match module.sections_mut()[i] { 133 | Section::Unparsed { .. } => { 134 | info!("unparsed section"); 135 | continue 136 | } 137 | Section::Custom(ref s) => { 138 | if !cx.config.keep_debug && s.name().starts_with(".debug_") { 139 | false 140 | } else { 141 | info!("skipping custom section: {}", s.name()); 142 | continue 143 | } 144 | } 145 | Section::Reloc(..) => { 146 | info!("skipping reloc section"); 147 | continue 148 | } 149 | Section::Type(ref mut s) => cx.remap_type_section(s), 150 | Section::Import(ref mut s) => cx.remap_import_section(s), 151 | Section::Function(ref mut s) => cx.remap_function_section(s), 152 | Section::Table(ref mut s) => cx.remap_table_section(s), 153 | Section::Memory(ref mut s) => cx.remap_memory_section(s), 154 | Section::Global(ref mut s) => cx.remap_global_section(s), 155 | Section::Export(ref mut s) => cx.remap_export_section(s), 156 | Section::Start(ref mut i) => { cx.remap_function_idx(i); true } 157 | Section::Element(ref mut s) => cx.remap_element_section(s), 158 | Section::Code(ref mut s) => cx.remap_code_section(s), 159 | Section::Data(ref mut s) => cx.remap_data_section(s), 160 | Section::Name(ref mut s) => { cx.remap_name_section(s); true } 161 | }; 162 | if !retain { 163 | debug!("remove empty section"); 164 | module.sections_mut().remove(i); 165 | } 166 | } 167 | } 168 | 169 | #[derive(Default)] 170 | struct Analysis { 171 | codes: BitSet, 172 | tables: BitSet, 173 | memories: BitSet, 174 | globals: BitSet, 175 | types: BitSet, 176 | imports: BitSet, 177 | exports: BitSet, 178 | functions: BitSet, 179 | all_globals: BitSet, 180 | } 181 | 182 | enum Memories<'a> { 183 | Exported(&'a MemorySection), 184 | Imported(&'a MemoryType), 185 | } 186 | 187 | impl<'a> Memories<'a> { 188 | fn has_entry(&self, idx: usize) -> bool { 189 | match *self { 190 | Memories::Exported(memory_section) => idx < memory_section.entries().len(), 191 | Memories::Imported(_) => idx == 0, 192 | } 193 | } 194 | } 195 | 196 | struct LiveContext<'a> { 197 | blacklist: HashSet<&'static str>, 198 | function_section: Option<&'a FunctionSection>, 199 | type_section: Option<&'a TypeSection>, 200 | code_section: Option<&'a CodeSection>, 201 | table_section: Option<&'a TableSection>, 202 | memories: Option>, 203 | global_section: Option<&'a GlobalSection>, 204 | import_section: Option<&'a ImportSection>, 205 | imported_functions: u32, 206 | imported_globals: u32, 207 | analysis: Analysis, 208 | } 209 | 210 | impl<'a> LiveContext<'a> { 211 | fn new(module: &'a Module) -> LiveContext<'a> { 212 | let memories = module.memory_section().map(Memories::Exported).or_else(|| { 213 | if let Some(import_section) = module.import_section() { 214 | for entry in import_section.entries() { 215 | if let External::Memory(ref memory_type) = *entry.external() { 216 | return Some(Memories::Imported(memory_type)); 217 | } 218 | } 219 | } 220 | 221 | None 222 | }); 223 | 224 | LiveContext { 225 | blacklist: HashSet::new(), 226 | function_section: module.function_section(), 227 | type_section: module.type_section(), 228 | code_section: module.code_section(), 229 | table_section: module.table_section(), 230 | memories: memories, 231 | global_section: module.global_section(), 232 | import_section: module.import_section(), 233 | imported_functions: module.import_section() 234 | .map(|s| s.functions()) 235 | .unwrap_or(0) as u32, 236 | imported_globals: module.import_section() 237 | .map(|s| s.globals()) 238 | .unwrap_or(0) as u32, 239 | analysis: Analysis::default(), 240 | } 241 | } 242 | 243 | fn add_function(&mut self, idx: u32) { 244 | if !self.analysis.functions.insert(idx) { 245 | return 246 | } 247 | 248 | if idx < self.imported_functions { 249 | let imports = self.import_section.unwrap(); 250 | debug!("adding import: {}", idx); 251 | let (i, import) = imports.entries() 252 | .iter() 253 | .enumerate() 254 | .filter(|&(_, i)| { 255 | match *i.external() { 256 | External::Function(_) => true, 257 | _ => false, 258 | } 259 | }) 260 | .skip(idx as usize) 261 | .next() 262 | .expect("expected an imported function with this index"); 263 | let i = i as u32; 264 | self.analysis.imports.insert(i); 265 | return self.add_import_entry(import, i); 266 | } 267 | let idx = idx - self.imported_functions; 268 | 269 | if !self.analysis.codes.insert(idx) { 270 | return 271 | } 272 | 273 | debug!("adding function: {}", idx); 274 | let functions = self.function_section.expect("no functions section"); 275 | self.add_type(functions.entries()[idx as usize].type_ref()); 276 | let codes = self.code_section.expect("no codes section"); 277 | self.add_func_body(&codes.bodies()[idx as usize]); 278 | } 279 | 280 | fn add_table(&mut self, mut idx: u32) { 281 | if let Some(imports) = self.import_section { 282 | let imported_tables = imports.entries() 283 | .iter() 284 | .filter(|i| { 285 | match *i.external() { 286 | External::Table(_) => true, 287 | _ => false, 288 | } 289 | }) 290 | .count(); 291 | let imported_tables = imported_tables as u32; 292 | if idx < imported_tables { 293 | debug!("adding table import: {}", idx); 294 | let (i, import) = imports.entries() 295 | .iter() 296 | .enumerate() 297 | .filter(|&(_, i)| { 298 | match *i.external() { 299 | External::Table(_) => true, 300 | _ => false, 301 | } 302 | }) 303 | .skip(idx as usize) 304 | .next() 305 | .expect("expected an imported table with this index"); 306 | let i = i as u32; 307 | self.analysis.imports.insert(i); 308 | return self.add_import_entry(import, i); 309 | } 310 | idx -= imported_tables; 311 | } 312 | if !self.analysis.tables.insert(idx) { 313 | return 314 | } 315 | let tables = self.table_section.expect("no table section"); 316 | let table = &tables.entries()[idx as usize]; 317 | drop(table); 318 | } 319 | 320 | fn add_memory(&mut self, idx: u32) { 321 | if !self.analysis.memories.insert(idx) { 322 | return 323 | } 324 | let memories = self.memories.as_ref().expect("no memory section or imported memory"); 325 | assert!(memories.has_entry(idx as usize)); 326 | } 327 | 328 | fn add_global(&mut self, idx: u32) { 329 | if !self.analysis.all_globals.insert(idx) { 330 | return 331 | } 332 | 333 | if idx < self.imported_globals { 334 | let imports = self.import_section.unwrap(); 335 | debug!("adding global import: {}", idx); 336 | let (i, import) = imports.entries() 337 | .iter() 338 | .enumerate() 339 | .filter(|&(_, i)| { 340 | match *i.external() { 341 | External::Global(_) => true, 342 | _ => false, 343 | } 344 | }) 345 | .skip(idx as usize) 346 | .next() 347 | .expect("expected an imported global with this index"); 348 | let i = i as u32; 349 | self.analysis.imports.insert(i); 350 | return self.add_import_entry(import, i); 351 | } 352 | let idx = idx - self.imported_globals; 353 | 354 | if !self.analysis.globals.insert(idx) { 355 | return 356 | } 357 | let globals = self.global_section.expect("no global section"); 358 | let global = &globals.entries()[idx as usize]; 359 | self.add_global_type(global.global_type()); 360 | self.add_init_expr(global.init_expr()); 361 | } 362 | 363 | fn add_global_type(&mut self, t: &GlobalType) { 364 | self.add_value_type(&t.content_type()); 365 | } 366 | 367 | fn add_init_expr(&mut self, t: &InitExpr) { 368 | for opcode in t.code() { 369 | self.add_opcode(opcode); 370 | } 371 | } 372 | 373 | fn add_type(&mut self, idx: u32) { 374 | if !self.analysis.types.insert(idx) { 375 | return 376 | } 377 | let types = self.type_section.expect("no types section"); 378 | match types.types()[idx as usize] { 379 | Type::Function(ref f) => { 380 | for param in f.params() { 381 | self.add_value_type(param); 382 | } 383 | if let Some(ref ret) = f.return_type() { 384 | self.add_value_type(ret); 385 | } 386 | } 387 | } 388 | } 389 | 390 | fn add_value_type(&mut self, value: &ValueType) { 391 | match *value { 392 | ValueType::I32 => {} 393 | ValueType::I64 => {} 394 | ValueType::F32 => {} 395 | ValueType::F64 => {} 396 | } 397 | } 398 | 399 | fn add_func_body(&mut self, body: &FuncBody) { 400 | for local in body.locals() { 401 | self.add_value_type(&local.value_type()); 402 | } 403 | self.add_opcodes(body.code()); 404 | } 405 | 406 | fn add_opcodes(&mut self, code: &Instructions) { 407 | for opcode in code.elements() { 408 | self.add_opcode(opcode); 409 | } 410 | } 411 | 412 | fn add_opcode(&mut self, code: &Instruction) { 413 | match *code { 414 | Instruction::Block(ref b) | 415 | Instruction::Loop(ref b) | 416 | Instruction::If(ref b) => self.add_block_type(b), 417 | Instruction::Call(f) => self.add_function(f), 418 | Instruction::CallIndirect(t, _) => self.add_type(t), 419 | Instruction::GetGlobal(i) | 420 | Instruction::SetGlobal(i) => self.add_global(i), 421 | _ => {} 422 | } 423 | } 424 | 425 | fn add_block_type(&mut self, bt: &BlockType) { 426 | match *bt { 427 | BlockType::Value(ref v) => self.add_value_type(v), 428 | BlockType::NoResult => {} 429 | } 430 | } 431 | 432 | fn add_export_entry(&mut self, entry: &ExportEntry, idx: u32) { 433 | if self.blacklist.contains(entry.field()) { 434 | return 435 | } 436 | self.analysis.exports.insert(idx); 437 | match *entry.internal() { 438 | Internal::Function(i) => self.add_function(i), 439 | Internal::Table(i) => self.add_table(i), 440 | Internal::Memory(i) => self.add_memory(i), 441 | Internal::Global(i) => self.add_global(i), 442 | } 443 | } 444 | 445 | fn add_import_entry(&mut self, entry: &ImportEntry, idx: u32) { 446 | match *entry.external() { 447 | External::Function(i) => self.add_type(i), 448 | External::Table(_) => {}, 449 | External::Memory(_) => { 450 | self.add_memory(0); 451 | self.analysis.imports.insert(idx); 452 | }, 453 | External::Global(_) => {}, 454 | } 455 | } 456 | 457 | fn add_data_segment(&mut self, data: &DataSegment) { 458 | self.add_memory(data.index()); 459 | self.add_init_expr(data.offset()); 460 | } 461 | 462 | fn add_element_segment(&mut self, seg: &ElementSegment) { 463 | for member in seg.members() { 464 | self.add_function(*member); 465 | } 466 | self.add_table(seg.index()); 467 | self.add_init_expr(seg.offset()); 468 | } 469 | } 470 | 471 | struct RemapContext<'a> { 472 | analysis: &'a Analysis, 473 | config: &'a Config, 474 | functions: Vec, 475 | globals: Vec, 476 | types: Vec, 477 | tables: Vec, 478 | memories: Vec, 479 | } 480 | 481 | impl<'a> RemapContext<'a> { 482 | fn new(m: &Module, analysis: &'a Analysis, config: &'a Config) -> RemapContext<'a> { 483 | let mut nfunctions = 0; 484 | let mut functions = Vec::new(); 485 | let mut nglobals = 0; 486 | let mut globals = Vec::new(); 487 | let mut types = Vec::new(); 488 | let mut ntables = 0; 489 | let mut tables = Vec::new(); 490 | let mut nmemories = 0; 491 | let mut memories = Vec::new(); 492 | 493 | if let Some(s) = m.type_section() { 494 | let mut removed = 0; 495 | for i in 0..(s.types().len() as u32) { 496 | if analysis.types.contains(&i) { 497 | types.push(i - removed); 498 | } else { 499 | debug!("gc type {}", i); 500 | types.push(u32::max_value()); 501 | removed += 1; 502 | } 503 | } 504 | } 505 | if let Some(s) = m.import_section() { 506 | for (i, import) in s.entries().iter().enumerate() { 507 | let (dst, ndst) = match *import.external() { 508 | External::Function(_) => (&mut functions, &mut nfunctions), 509 | External::Table(_) => (&mut tables, &mut ntables), 510 | External::Memory(_) => (&mut memories, &mut nmemories), 511 | External::Global(_) => (&mut globals, &mut nglobals), 512 | }; 513 | if analysis.imports.contains(&(i as u32)) { 514 | dst.push(*ndst); 515 | *ndst += 1; 516 | } else { 517 | debug!("gc import {}", i); 518 | dst.push(u32::max_value()); 519 | } 520 | } 521 | } 522 | if let Some(s) = m.function_section() { 523 | for i in 0..(s.entries().len() as u32) { 524 | if analysis.codes.contains(&i) { 525 | functions.push(nfunctions); 526 | nfunctions += 1; 527 | } else { 528 | debug!("gc function {}", i); 529 | functions.push(u32::max_value()); 530 | } 531 | } 532 | } 533 | if let Some(s) = m.global_section() { 534 | for i in 0..(s.entries().len() as u32) { 535 | if analysis.globals.contains(&i) { 536 | globals.push(nglobals); 537 | nglobals += 1; 538 | } else { 539 | debug!("gc global {}", i); 540 | globals.push(u32::max_value()); 541 | } 542 | } 543 | } 544 | if let Some(s) = m.table_section() { 545 | for i in 0..(s.entries().len() as u32) { 546 | if analysis.tables.contains(&i) { 547 | tables.push(ntables); 548 | ntables += 1; 549 | } else { 550 | debug!("gc table {}", i); 551 | tables.push(u32::max_value()); 552 | } 553 | } 554 | } 555 | if let Some(s) = m.memory_section() { 556 | for i in 0..(s.entries().len() as u32) { 557 | if analysis.memories.contains(&i) { 558 | memories.push(nmemories); 559 | nmemories += 1; 560 | } else { 561 | debug!("gc memory {}", i); 562 | memories.push(u32::max_value()); 563 | } 564 | } 565 | } 566 | 567 | RemapContext { 568 | analysis, 569 | functions, 570 | globals, 571 | memories, 572 | tables, 573 | types, 574 | config, 575 | } 576 | } 577 | 578 | fn retain(&self, set: &BitSet, list: &mut Vec, name: &str) { 579 | for i in (0..list.len()).rev().map(|x| x as u32) { 580 | if !set.contains(&i) { 581 | debug!("removing {} {}", name, i); 582 | list.remove(i as usize); 583 | } 584 | } 585 | } 586 | 587 | fn remap_type_section(&self, s: &mut TypeSection) -> bool { 588 | self.retain(&self.analysis.types, s.types_mut(), "type"); 589 | for t in s.types_mut() { 590 | self.remap_type(t); 591 | } 592 | s.types().len() > 0 593 | } 594 | 595 | fn remap_type(&self, t: &mut Type) { 596 | match *t { 597 | Type::Function(ref mut t) => self.remap_function_type(t), 598 | } 599 | } 600 | 601 | fn remap_function_type(&self, t: &mut FunctionType) { 602 | for param in t.params_mut() { 603 | self.remap_value_type(param); 604 | } 605 | if let Some(m) = t.return_type_mut().as_mut() { 606 | self.remap_value_type(m); 607 | } 608 | } 609 | 610 | fn remap_value_type(&self, t: &mut ValueType) { 611 | drop(t); 612 | } 613 | 614 | fn remap_import_section(&self, s: &mut ImportSection) -> bool { 615 | self.retain(&self.analysis.imports, s.entries_mut(), "import"); 616 | for i in s.entries_mut() { 617 | self.remap_import_entry(i); 618 | } 619 | s.entries().len() > 0 620 | } 621 | 622 | fn remap_import_entry(&self, s: &mut ImportEntry) { 623 | debug!("remap import entry {:?}", s); 624 | match *s.external_mut() { 625 | External::Function(ref mut f) => self.remap_type_idx(f), 626 | External::Table(_) => {} 627 | External::Memory(_) => {} 628 | External::Global(_) => {} 629 | } 630 | } 631 | 632 | fn remap_function_section(&self, s: &mut FunctionSection) -> bool { 633 | self.retain(&self.analysis.codes, s.entries_mut(), "function"); 634 | for f in s.entries_mut() { 635 | self.remap_func(f); 636 | } 637 | s.entries().len() > 0 638 | } 639 | 640 | fn remap_func(&self, f: &mut Func) { 641 | self.remap_type_idx(f.type_ref_mut()); 642 | } 643 | 644 | fn remap_table_section(&self, s: &mut TableSection) -> bool { 645 | self.retain(&self.analysis.tables, s.entries_mut(), "table"); 646 | for t in s.entries_mut() { 647 | drop(t); // TODO 648 | } 649 | s.entries().len() > 0 650 | } 651 | 652 | fn remap_memory_section(&self, s: &mut MemorySection) -> bool { 653 | self.retain(&self.analysis.memories, s.entries_mut(), "memory"); 654 | for m in s.entries_mut() { 655 | drop(m); // TODO 656 | } 657 | s.entries().len() > 0 658 | } 659 | 660 | fn remap_global_section(&self, s: &mut GlobalSection) -> bool { 661 | self.retain(&self.analysis.globals, s.entries_mut(), "global"); 662 | for g in s.entries_mut() { 663 | self.remap_global_entry(g); 664 | } 665 | s.entries().len() > 0 666 | } 667 | 668 | fn remap_global_entry(&self, s: &mut GlobalEntry) { 669 | self.remap_global_type(s.global_type_mut()); 670 | self.remap_init_expr(s.init_expr_mut()); 671 | } 672 | 673 | fn remap_global_type(&self, s: &mut GlobalType) { 674 | drop(s); 675 | } 676 | 677 | fn remap_init_expr(&self, s: &mut InitExpr) { 678 | for code in s.code_mut() { 679 | self.remap_instruction(code); 680 | } 681 | } 682 | 683 | fn remap_export_section(&self, s: &mut ExportSection) -> bool { 684 | self.retain(&self.analysis.exports, s.entries_mut(), "export"); 685 | for s in s.entries_mut() { 686 | self.remap_export_entry(s); 687 | } 688 | s.entries().len() > 0 689 | } 690 | 691 | fn remap_export_entry(&self, s: &mut ExportEntry) { 692 | match *s.internal_mut() { 693 | Internal::Function(ref mut i) => self.remap_function_idx(i), 694 | Internal::Table(ref mut i) => self.remap_table_idx(i), 695 | Internal::Memory(ref mut i) => self.remap_memory_idx(i), 696 | Internal::Global(ref mut i) => self.remap_global_idx(i), 697 | } 698 | } 699 | 700 | fn remap_element_section(&self, s: &mut ElementSection) -> bool { 701 | for s in s.entries_mut() { 702 | self.remap_element_segment(s); 703 | } 704 | true 705 | } 706 | 707 | fn remap_element_segment(&self, s: &mut ElementSegment) { 708 | let mut i = s.index(); 709 | self.remap_table_idx(&mut i); 710 | assert_eq!(s.index(), i); 711 | for m in s.members_mut() { 712 | self.remap_function_idx(m); 713 | } 714 | self.remap_init_expr(s.offset_mut()); 715 | } 716 | 717 | fn remap_code_section(&self, s: &mut CodeSection) -> bool { 718 | self.retain(&self.analysis.codes, s.bodies_mut(), "code"); 719 | for s in s.bodies_mut() { 720 | self.remap_func_body(s); 721 | } 722 | s.bodies().len() > 0 723 | } 724 | 725 | fn remap_func_body(&self, b: &mut FuncBody) { 726 | self.remap_code(b.code_mut()); 727 | } 728 | 729 | fn remap_code(&self, c: &mut Instructions) { 730 | for i in c.elements_mut() { 731 | self.remap_instruction(i); 732 | } 733 | } 734 | 735 | fn remap_instruction(&self, i: &mut Instruction) { 736 | match *i { 737 | Instruction::Block(ref mut b) | 738 | Instruction::Loop(ref mut b) | 739 | Instruction::If(ref mut b) => self.remap_block_type(b), 740 | Instruction::Call(ref mut f) => self.remap_function_idx(f), 741 | Instruction::CallIndirect(ref mut t, _) => self.remap_type_idx(t), 742 | Instruction::GetGlobal(ref mut i) | 743 | Instruction::SetGlobal(ref mut i) => self.remap_global_idx(i), 744 | _ => {} 745 | } 746 | } 747 | 748 | fn remap_block_type(&self, bt: &mut BlockType) { 749 | match *bt { 750 | BlockType::Value(ref mut v) => self.remap_value_type(v), 751 | BlockType::NoResult => {} 752 | } 753 | } 754 | 755 | fn remap_data_section(&self, s: &mut DataSection) -> bool { 756 | for data in s.entries_mut() { 757 | self.remap_data_segment(data); 758 | } 759 | true 760 | } 761 | 762 | fn remap_data_segment(&self, segment: &mut DataSegment) { 763 | let mut i = segment.index(); 764 | self.remap_memory_idx(&mut i); 765 | assert_eq!(segment.index(), i); 766 | self.remap_init_expr(segment.offset_mut()); 767 | } 768 | 769 | fn remap_type_idx(&self, i: &mut u32) { 770 | *i = self.types[*i as usize]; 771 | assert!(*i != u32::max_value()); 772 | } 773 | 774 | fn remap_function_idx(&self, i: &mut u32) { 775 | *i = self.functions[*i as usize]; 776 | assert!(*i != u32::max_value()); 777 | } 778 | 779 | fn remap_global_idx(&self, i: &mut u32) { 780 | trace!("global {} => {}", *i, self.globals[*i as usize]); 781 | *i = self.globals[*i as usize]; 782 | assert!(*i != u32::max_value()); 783 | } 784 | 785 | fn remap_table_idx(&self, i: &mut u32) { 786 | *i = self.tables[*i as usize]; 787 | assert!(*i != u32::max_value()); 788 | } 789 | 790 | fn remap_memory_idx(&self, i: &mut u32) { 791 | *i = self.memories[*i as usize]; 792 | assert!(*i != u32::max_value()); 793 | } 794 | 795 | fn remap_name_section(&self, s: &mut NameSection) { 796 | match *s { 797 | NameSection::Module(_) => {} 798 | NameSection::Function(ref mut f) => { 799 | let map = f.names_mut(); 800 | let new = IndexMap::with_capacity(map.len()); 801 | for (idx, name) in mem::replace(map, new) { 802 | let new_idx = self.functions[idx as usize]; 803 | let name = if self.config.demangle { 804 | rustc_demangle::demangle(&name).to_string() 805 | } else { 806 | name 807 | }; 808 | if new_idx != u32::max_value() { 809 | map.insert(new_idx, name); 810 | } 811 | } 812 | } 813 | NameSection::Local(ref mut l) => { 814 | let map = l.local_names_mut(); 815 | let new = IndexMap::with_capacity(map.len()); 816 | for (idx, value) in mem::replace(map, new) { 817 | let new_idx = self.functions[idx as usize]; 818 | if new_idx != u32::max_value() { 819 | map.insert(new_idx, value); 820 | } 821 | } 822 | } 823 | NameSection::Unparsed { .. } => {} 824 | } 825 | } 826 | } 827 | --------------------------------------------------------------------------------