marine_wasmtime_backend/
lib.rs

1/*
2 * Copyright 2023 Fluence Labs Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17mod caller;
18mod store;
19mod utils;
20mod module;
21mod instance;
22mod wasi;
23mod function;
24mod imports;
25mod memory;
26
27use store::*;
28use caller::*;
29use module::*;
30use instance::*;
31use wasi::*;
32use function::*;
33use memory::*;
34use imports::*;
35use utils::*;
36
37use marine_wasm_backend_traits::prelude::*;
38
39use wasmtime_wasi::WasiCtx;
40
41const MB: usize = 1024 * 1024;
42
43/// Default amount of stack space available for executing WebAssembly code.
44pub const DEFAULT_WASM_STACK_SIZE: usize = 2 * MB;
45
46#[derive(Clone)]
47pub struct WasmtimeWasmBackend {
48    engine: wasmtime::Engine,
49}
50
51impl WasmBackend for WasmtimeWasmBackend {
52    type Store = WasmtimeStore;
53    type Module = WasmtimeModule;
54    type Imports = WasmtimeImports;
55    type Instance = WasmtimeInstance;
56    type Context<'c> = WasmtimeContext<'c>;
57    type ContextMut<'c> = WasmtimeContextMut<'c>;
58    type ImportCallContext<'c> = WasmtimeImportCallContext<'c>;
59    type HostFunction = WasmtimeFunction;
60    type ExportFunction = WasmtimeFunction;
61    type Memory = WasmtimeMemory;
62    type MemoryView = WasmtimeMemory;
63    type Wasi = WasmtimeWasi;
64
65    fn new_async() -> WasmBackendResult<Self> {
66        Self::new(WasmtimeConfig::default())
67    }
68}
69
70impl WasmtimeWasmBackend {
71    pub fn increment_epoch(&self) {
72        self.engine.increment_epoch()
73    }
74
75    pub fn new(config: WasmtimeConfig) -> WasmBackendResult<Self> {
76        let engine =
77            wasmtime::Engine::new(&config.config).map_err(WasmBackendError::InitializationError)?;
78
79        Ok(Self { engine })
80    }
81}
82
83#[derive(Default)]
84pub struct StoreState {
85    wasi: Vec<WasiCtx>, // wasmtime store does not release memory until drop, so do we
86    limits: MemoryLimiter,
87}
88
89#[derive(Clone)]
90pub struct WasmtimeConfig {
91    config: wasmtime::Config,
92}
93
94impl Default for WasmtimeConfig {
95    fn default() -> Self {
96        let mut config = wasmtime::Config::default();
97        config
98            .async_support(true)
99            .debug_info(true)
100            .max_wasm_stack(DEFAULT_WASM_STACK_SIZE)
101            .epoch_interruption(true)
102            .wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable);
103
104        Self { config }
105    }
106}
107
108impl WasmtimeConfig {
109    /// Constructs wasmtime config directly from wasmtime config.
110    /// It forcefully enables async support, because the backend does not work with sync configs.
111    pub fn from_raw(mut config: wasmtime::Config) -> Self {
112        config.async_support(true);
113        Self { config }
114    }
115
116    /// Configures whether DWARF debug information will be emitted during
117    /// compilation.
118    ///
119    /// By default this option is `true`.
120    pub fn debug_info(&mut self, enable: bool) -> &mut Self {
121        self.config.debug_info(enable);
122        self
123    }
124
125    /// Enables the epoch interruption mechanism. See Wasmtime docs for detailed explanation.
126    ///
127    /// By default this option is `true`.
128    pub fn epoch_interruption(&mut self, enable: bool) -> &mut Self {
129        self.config.epoch_interruption(enable);
130        self
131    }
132
133    /// Configures the maximum amount of stack space available for
134    /// executing WebAssembly code.
135    ///
136    /// By default this option is 2 MiB.
137    pub fn max_wasm_stack(&mut self, size: usize) -> &mut Self {
138        self.config.max_wasm_stack(size);
139        self
140    }
141
142    /// Configures the size of the stacks used for asynchronous execution.
143    ///
144    /// This setting configures the size of the stacks that are allocated for
145    /// asynchronous execution. The value cannot be less than `max_wasm_stack`.
146    ///
147    /// By default this option is 2 MiB.
148    pub fn async_wasm_stack(&mut self, size: usize) -> &mut Self {
149        self.config.async_stack_size(size);
150        self
151    }
152
153    /// Configures whether the errors from the VM should collect the wasm backtrace and parse debug info.
154    ///
155    /// By default this option is `true`.
156    pub fn wasm_backtrace(&mut self, enable: bool) -> &mut Self {
157        self.config
158            .wasm_backtrace(enable)
159            .wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable);
160        self
161    }
162}