wasm_gc/
lib.rs

1extern crate parity_wasm;
2#[macro_use]
3extern crate log;
4extern crate rustc_demangle;
5
6mod gc;
7mod error;
8mod bitvec;
9
10use std::any::Any;
11use std::mem;
12use std::path::Path;
13
14use parity_wasm::elements::{
15    Module,
16    Serialize,
17    Deserialize
18};
19
20pub use error::Error;
21
22pub struct Config {
23    demangle: bool,
24    keep_debug: bool,
25}
26
27pub struct GcResult(Box<Module>);
28
29impl 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<Vec<u8>, Error> {
55        self.run(3, |_| bytecode.to_vec())?.into_bytes()
56    }
57
58    pub fn run<T: Any>(
59        &mut self,
60        mut module: T,
61        into_bytes: impl FnOnce(T) -> Vec<u8>,
62    ) -> Result<GcResult, Error> {
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
83impl 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<T: Any>(self) -> Result<T, Self> {
91        let module = self.0 as Box<Any>;
92        match module.downcast() {
93            Ok(t) => Ok(*t),
94            Err(box_any) => {
95                match box_any.downcast::<Module>() {
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<Vec<u8>, 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`.
115pub fn garbage_collect_file<I, O>(input_path: I, output_path: O) -> Result<(), Error>
116where
117    I: AsRef<Path>,
118    O: AsRef<Path>,
119{
120    _gc_file(input_path.as_ref(), output_path.as_ref())
121}
122
123fn _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.
136pub fn garbage_collect_slice(bytecode: &[u8]) -> Result<Vec<u8>, Error> {
137    Config::new().gc(bytecode)
138}