wamr_rust_sdk/
runtime.rs

1/*
2 * Copyright (C) 2019 Intel Corporation. All rights reserved.
3 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4 */
5
6//! This is the main entry point for executing WebAssembly modules.
7//! Every process should have only one instance of this runtime by call
8//! `Runtime::new()` or `Runtime::builder().build()` once.
9
10use std::ffi::c_void;
11
12use wamr_sys::{
13    mem_alloc_type_t_Alloc_With_Pool, mem_alloc_type_t_Alloc_With_System_Allocator,
14    wasm_runtime_destroy, wasm_runtime_full_init, wasm_runtime_init, NativeSymbol,
15    RunningMode_Mode_Interp, RunningMode_Mode_LLVM_JIT, RuntimeInitArgs,
16};
17
18use crate::{host_function::HostFunctionList, RuntimeError};
19
20#[allow(dead_code)]
21#[derive(Debug)]
22pub struct Runtime {
23    host_functions: HostFunctionList,
24}
25
26impl Runtime {
27    /// return a `RuntimeBuilder` instance
28    ///
29    /// has to
30    /// - select a allocation mode
31    /// - select a running mode
32    pub fn builder() -> RuntimeBuilder {
33        RuntimeBuilder::default()
34    }
35
36    /// create a new `Runtime` instance with the default configuration which includes:
37    /// - system allocator mode
38    /// - the default running mode
39    ///
40    /// # Errors
41    ///
42    /// if the runtime initialization failed, it will return `RuntimeError::InitializationFailure`
43    pub fn new() -> Result<Self, RuntimeError> {
44        match unsafe { wasm_runtime_init() } {
45            true => Ok(Runtime {
46                host_functions: HostFunctionList::new("empty"),
47            }),
48            false => Err(RuntimeError::InitializationFailure),
49        }
50    }
51}
52
53impl Drop for Runtime {
54    fn drop(&mut self) {
55        unsafe {
56            wasm_runtime_destroy();
57        }
58    }
59}
60
61/// The builder of `Runtime`. It is used to configure the runtime.
62/// Get one via `Runtime::builder()`
63pub struct RuntimeBuilder {
64    args: RuntimeInitArgs,
65    host_functions: HostFunctionList,
66}
67
68/// Can't build() until config allocator mode
69impl Default for RuntimeBuilder {
70    fn default() -> Self {
71        let args = RuntimeInitArgs::default();
72        RuntimeBuilder {
73            args,
74            host_functions: HostFunctionList::new("host"),
75        }
76    }
77}
78
79impl RuntimeBuilder {
80    /// system allocator mode
81    /// allocate memory from system allocator for runtime consumed memory
82    pub fn use_system_allocator(mut self) -> RuntimeBuilder {
83        self.args.mem_alloc_type = mem_alloc_type_t_Alloc_With_System_Allocator;
84        self
85    }
86
87    /// system allocator mode
88    /// allocate memory from pool, as a pre-allocated buffer, for runtime consumed memory
89    pub fn use_memory_pool(mut self, mut pool: Vec<u8>) -> RuntimeBuilder {
90        self.args.mem_alloc_type = mem_alloc_type_t_Alloc_With_Pool;
91        self.args.mem_alloc_option.pool.heap_buf = pool.as_mut_ptr() as *mut c_void;
92        self.args.mem_alloc_option.pool.heap_size = pool.len() as u32;
93        self
94    }
95
96    /// use interpreter mode
97    pub fn run_as_interpreter(mut self) -> RuntimeBuilder {
98        self.args.running_mode = RunningMode_Mode_Interp;
99        self
100    }
101
102    /// use llvm-jit mode
103    pub fn run_as_llvm_jit(mut self, opt_level: u32, size_level: u32) -> RuntimeBuilder {
104        self.args.running_mode = RunningMode_Mode_LLVM_JIT;
105        self.args.llvm_jit_opt_level = opt_level;
106        self.args.llvm_jit_size_level = size_level;
107        self
108    }
109
110    /// register a host function
111    pub fn register_host_function(
112        mut self,
113        function_name: &str,
114        function_ptr: *mut c_void,
115    ) -> RuntimeBuilder {
116        self.host_functions
117            .register_host_function(function_name, function_ptr);
118        self
119    }
120
121    /// create a `Runtime` instance with the configuration
122    ///
123    /// # Errors
124    ///
125    /// if the runtime initialization failed, it will return `RuntimeError::InitializationFailure`
126    pub fn build(mut self) -> Result<Runtime, RuntimeError> {
127        match unsafe {
128            let module_name = &(self.host_functions).get_module_name();
129            self.args.native_module_name = module_name.as_ptr();
130
131            let native_symbols = &(self.host_functions).get_native_symbols();
132            self.args.n_native_symbols = native_symbols.len() as u32;
133            self.args.native_symbols = native_symbols.as_ptr() as *mut NativeSymbol;
134
135            wasm_runtime_full_init(&mut self.args)
136        } {
137            true => Ok(Runtime {
138                host_functions: self.host_functions,
139            }),
140            false => Err(RuntimeError::InitializationFailure),
141        }
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148    use wamr_sys::{wasm_runtime_free, wasm_runtime_malloc};
149
150    #[test]
151    #[ignore]
152    fn test_runtime_new() {
153        let runtime = Runtime::new();
154        assert!(runtime.is_ok());
155
156        /* use malloc to confirm */
157        let small_buf = unsafe { wasm_runtime_malloc(16) };
158        assert!(!small_buf.is_null());
159        unsafe { wasm_runtime_free(small_buf) };
160
161        drop(runtime);
162
163        /* runtime has been destroyed. malloc should be failed */
164        let small_buf = unsafe { wasm_runtime_malloc(16) };
165        assert!(small_buf.is_null());
166
167        {
168            let runtime = Runtime::new();
169            assert!(runtime.is_ok());
170
171            let runtime = Runtime::new();
172            assert!(runtime.is_ok());
173
174            let runtime = Runtime::new();
175            assert!(runtime.is_ok());
176        }
177
178        /* runtime has been destroyed. malloc should be failed */
179        let small_buf = unsafe { wasm_runtime_malloc(16) };
180        assert!(small_buf.is_null());
181    }
182
183    #[test]
184    fn test_runtime_builder_default() {
185        // use Mode_Default
186        let runtime = Runtime::builder().use_system_allocator().build();
187        assert!(runtime.is_ok());
188
189        let small_buf = unsafe { wasm_runtime_malloc(16) };
190        assert!(!small_buf.is_null());
191        unsafe { wasm_runtime_free(small_buf) };
192    }
193
194    #[test]
195    fn test_runtime_builder_interpreter() {
196        let runtime = Runtime::builder()
197            .run_as_interpreter()
198            .use_system_allocator()
199            .build();
200        assert!(runtime.is_ok());
201
202        let small_buf = unsafe { wasm_runtime_malloc(16) };
203        assert!(!small_buf.is_null());
204        unsafe { wasm_runtime_free(small_buf) };
205    }
206
207    #[test]
208    #[cfg(feature = "llvmjit")]
209    #[ignore]
210    fn test_runtime_builder_llvm_jit() {
211        let runtime = Runtime::builder()
212            .run_as_llvm_jit(3, 3)
213            .use_system_allocator()
214            .build();
215        assert!(runtime.is_ok());
216
217        let small_buf = unsafe { wasm_runtime_malloc(16) };
218        assert!(!small_buf.is_null());
219        unsafe { wasm_runtime_free(small_buf) };
220    }
221}