virtual_machine/
environment.rs

1use core::{
2    ffi::{CStr, c_void},
3    marker::PhantomData,
4};
5
6use alloc::{
7    boxed::Box,
8    string::{String, ToString},
9    vec::Vec,
10};
11use wamr_rust_sdk::{
12    sys::{
13        wasm_exec_env_t, wasm_module_inst_t, wasm_runtime_addr_app_to_native,
14        wasm_runtime_addr_native_to_app, wasm_runtime_call_indirect, wasm_runtime_create_exec_env,
15        wasm_runtime_get_custom_data, wasm_runtime_get_exception,
16        wasm_runtime_get_exec_env_singleton, wasm_runtime_get_module_inst,
17        wasm_runtime_set_custom_data, wasm_runtime_set_instruction_count_limit,
18        wasm_runtime_validate_app_addr, wasm_runtime_validate_native_addr,
19    },
20    value::WasmValue,
21};
22
23use crate::{CustomData, Error, Instance, Result, WasmPointer, WasmUsize};
24
25pub type EnvironmentPointer = wasm_exec_env_t;
26
27#[derive(Debug, Clone, Copy)]
28pub struct Environment<'a>(EnvironmentPointer, PhantomData<&'a ()>);
29
30unsafe impl Send for Environment<'_> {}
31
32unsafe impl Sync for Environment<'_> {}
33
34impl Environment<'_> {
35    pub fn from_raw_pointer(raw_pointer: EnvironmentPointer) -> Result<Self> {
36        if raw_pointer.is_null() {
37            return Err(Error::InvalidPointer);
38        }
39
40        Ok(Self(raw_pointer as EnvironmentPointer, PhantomData))
41    }
42
43    pub fn from_instance(instance: &Instance) -> Result<Self> {
44        let instance_pointer = instance.get_inner_reference().get_inner_instance();
45
46        if instance_pointer.is_null() {
47            return Err(Error::InvalidPointer);
48        }
49        Ok(Self(
50            unsafe { wasm_runtime_get_exec_env_singleton(instance_pointer) },
51            PhantomData,
52        ))
53    }
54
55    pub fn get_or_initialize_custom_data(&self) -> Result<&CustomData> {
56        unsafe {
57            let custom_data =
58                wasm_runtime_get_custom_data(self.get_instance_pointer()) as *const CustomData;
59
60            let custom_data = if custom_data.is_null() {
61                let task = abi::get_instance().get_current_task_identifier();
62
63                let custom_data = Box::new(CustomData::new(task));
64
65                wasm_runtime_set_custom_data(
66                    self.get_instance_pointer(),
67                    Box::into_raw(custom_data) as *mut c_void,
68                );
69
70                wasm_runtime_get_custom_data(self.get_instance_pointer()) as *const CustomData
71            } else {
72                custom_data
73            };
74
75            Ok(&*custom_data)
76        }
77    }
78
79    /// # Safety
80    ///
81    /// This function is unsafe because it is not checked that the address is valid.
82    /// Please use `Validate_WASM_pointer` to check the address.
83    pub unsafe fn convert_to_native_pointer<T>(&self, address: WasmPointer) -> Option<*mut T> {
84        unsafe {
85            let pointer =
86                wasm_runtime_addr_app_to_native(self.get_instance_pointer(), address as u64);
87
88            if pointer.is_null() {
89                return None;
90            }
91
92            Some(pointer as *mut T)
93        }
94    }
95
96    /// # Safety
97    ///
98    /// This function is unsafe because it is not checked that the address is valid.
99    /// Please use `Validate_WASM_pointer` to check the address.
100    pub unsafe fn convert_to_wasm_pointer<T>(&self, pointer: *const T) -> WasmPointer {
101        unsafe {
102            wasm_runtime_addr_native_to_app(self.get_instance_pointer(), pointer as *mut c_void)
103                as WasmPointer
104        }
105    }
106
107    pub fn validate_wasm_pointer(&self, address: WasmPointer, size: WasmUsize) -> bool {
108        unsafe {
109            wasm_runtime_validate_app_addr(self.get_instance_pointer(), address as u64, size as u64)
110        }
111    }
112
113    pub fn validate_native_pointer<T>(&self, pointer: *const T, size: u64) -> bool {
114        unsafe {
115            wasm_runtime_validate_native_addr(
116                self.get_instance_pointer(),
117                pointer as *mut c_void,
118                size,
119            )
120        }
121    }
122
123    /// Make an indirect function call (call a function by its index which is not exported).
124    /// For exported functions use `Call_export_function`.
125    pub fn call_indirect_function(
126        &self,
127        function_index: u32,
128        parameters: &Vec<WasmValue>,
129    ) -> Result<()> {
130        let mut arguments = Vec::new();
131
132        for parameter in parameters {
133            arguments.append(&mut parameter.encode());
134        }
135
136        if arguments.is_empty() {
137            arguments.append(&mut WasmValue::I32(0).encode());
138        }
139
140        if !unsafe {
141            wasm_runtime_call_indirect(
142                self.0,
143                function_index,
144                arguments.len() as u32,
145                arguments.as_mut_ptr(),
146            )
147        } {
148            let exception_message =
149                unsafe { wasm_runtime_get_exception(self.get_instance_pointer()) };
150            let exception_message = unsafe { CStr::from_ptr(exception_message) };
151            let exception_message =
152                String::from_utf8_lossy(exception_message.to_bytes()).to_string();
153
154            return Err(Error::ExecutionError(exception_message));
155        }
156
157        Ok(())
158    }
159
160    /// Create a new execution environment.
161    /// This environment should be initialized with `Initialize_thread_environment` and deinitialized with `Deinitialize_thread_environment`.
162    pub fn create_environment(&self, stack_size: usize) -> Result<Self> {
163        let execution_environment =
164            unsafe { wasm_runtime_create_exec_env(self.get_instance_pointer(), stack_size as u32) };
165
166        if execution_environment.is_null() {
167            return Err(Error::ExecutionError(
168                "Execution environment creation failed".to_string(),
169            ));
170        }
171
172        Ok(Self(execution_environment, PhantomData))
173    }
174
175    //    pub fn set_instruction_count_limit(&self, limit: Option<u64>) {
176    //        unsafe {
177    //            wasm_runtime_set_instruction_count_limit(
178    //                self.get_inner_reference(),
179    //                limit.map(|limit| limit as i32).unwrap_or(-1),
180    //            );
181    //        }
182    //    }
183
184    fn get_instance_pointer(&self) -> wasm_module_inst_t {
185        unsafe { wasm_runtime_get_module_inst(self.0) }
186    }
187
188    #[allow(dead_code)]
189    pub(crate) fn get_inner_reference(&self) -> EnvironmentPointer {
190        self.0
191    }
192}