1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use anyhow::Error;
use wasmer::{Module, Store};

/// Creates an instnace of [Store].
///
/// This function exists because we need to disable simd.
#[cfg(not(target_arch = "wasm32"))]
#[allow(unused_mut)]
pub(crate) fn new_store() -> Store {
    // Use empty enumset to disable simd.
    use enumset::EnumSet;
    use wasmer::{BaseTunables, CompilerConfig, EngineBuilder, Target, Triple};
    let mut set = EnumSet::new();

    // [TODO]: Should we use is_x86_feature_detected! macro instead?
    #[cfg(target_arch = "x86_64")]
    set.insert(wasmer::CpuFeature::SSE2);
    let target = Target::new(Triple::host(), set);

    let config = wasmer_compiler_cranelift::Cranelift::default();
    let mut engine = EngineBuilder::new(Box::new(config) as Box<dyn CompilerConfig>)
        .set_target(Some(target))
        .engine();
    let tunables = BaseTunables::for_target(engine.target());
    engine.set_tunables(tunables);

    Store::new(engine)
}

#[cfg(target_arch = "wasm32")]
fn new_store() -> Store {
    Store::default()
}

// A trait abstracts plugin's wasm compilation and instantiation.
// Depends on the caller, this could be a simple clone from existing module, or
// load from file system cache.
pub trait PluginModuleBytes {
    // Returns a name to the module, typically either path to the plugin or its
    // package name.
    fn get_module_name(&self) -> &str;
    // Returns a compiled wasmer::Module for the plugin module.
    fn compile_module(&self) -> Result<(Store, Module), Error>;
}

/// A struct for the plugin contains raw bytes can be compiled into Wasm Module.
#[derive(Clone)]
pub struct RawPluginModuleBytes {
    plugin_name: String,
    bytes: Vec<u8>,
}

impl PluginModuleBytes for RawPluginModuleBytes {
    fn get_module_name(&self) -> &str {
        &self.plugin_name
    }

    fn compile_module(&self) -> Result<(Store, Module), Error> {
        let store = new_store();
        let module = Module::new(&store, &self.bytes)?;
        Ok((store, module))
    }
}

impl RawPluginModuleBytes {
    pub fn new(identifier: String, bytes: Vec<u8>) -> Self {
        Self {
            plugin_name: identifier,
            bytes,
        }
    }
}

/// A struct for the plugin contains pre-compiled binary.
/// This is for the cases would like to reuse the compiled module, or either
/// load from FileSystemCache.
pub struct CompiledPluginModuleBytes {
    plugin_name: String,
    bytes: wasmer::Module,
    store: wasmer::Store,
}

impl Clone for CompiledPluginModuleBytes {
    fn clone(&self) -> Self {
        Self {
            plugin_name: self.plugin_name.clone(),
            bytes: self.bytes.clone(),
            store: Store::new(self.store.engine().clone()),
        }
    }
}

impl CompiledPluginModuleBytes {
    pub fn new(identifier: String, bytes: wasmer::Module, store: wasmer::Store) -> Self {
        Self {
            plugin_name: identifier,
            bytes,
            store,
        }
    }
}

// Allow to `pre` compile wasm module when there is a raw bytes, want to avoid
// to skip the compilation step per each trasform.
impl From<RawPluginModuleBytes> for CompiledPluginModuleBytes {
    fn from(raw: RawPluginModuleBytes) -> Self {
        let (store, module) = raw.compile_module().unwrap();
        Self::new(raw.plugin_name, module, store)
    }
}

impl PluginModuleBytes for CompiledPluginModuleBytes {
    fn get_module_name(&self) -> &str {
        &self.plugin_name
    }

    fn compile_module(&self) -> Result<(Store, Module), Error> {
        Ok((Store::new(self.store.engine().clone()), self.bytes.clone()))
    }
}