Next Generation WASM Microkernel Operating System
at trap_handler 206 lines 7.4 kB view raw
1// Copyright 2025 Jonas Kruckenberg 2// 3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or 4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or 5// http://opensource.org/licenses/MIT>, at your option. This file may not be 6// copied, modified, or distributed except according to those terms. 7 8use crate::wasm::Engine; 9use crate::wasm::code_registry::{register_code, unregister_code}; 10use crate::wasm::compile::{CompileInputs, CompiledFunctionInfo}; 11use crate::wasm::indices::{DefinedFuncIndex, EntityIndex, VMSharedTypeIndex}; 12use crate::wasm::translate::{Import, ModuleTranslator, TranslatedModule}; 13use crate::wasm::type_registry::RuntimeTypeCollection; 14use crate::wasm::utils::u8_size_of; 15use crate::wasm::vm::{CodeObject, MmapVec, VMArrayCallFunction, VMShape, VMWasmCallFunction}; 16use alloc::string::{String, ToString}; 17use alloc::sync::Arc; 18use core::mem; 19use core::ops::DerefMut; 20use core::ptr::NonNull; 21use wasmparser::{Validator, WasmFeatures}; 22 23/// A compiled WebAssembly module, ready to be instantiated. 24/// 25/// It holds all compiled code as well as the module's type information and other metadata (e.g. for 26/// trap handling and backtrace information). 27/// 28/// Currently, no form of dynamic tiering is implemented instead all functions are compiled synchronously 29/// when the module is created. This is expected to change though. 30#[derive(Debug, Clone)] 31pub struct Module(Arc<ModuleInner>); 32 33#[derive(Debug)] 34struct ModuleInner { 35 name: String, 36 engine: Engine, 37 translated_module: TranslatedModule, 38 required_features: WasmFeatures, 39 vmshape: VMShape, 40 code: Arc<CodeObject>, 41 type_collection: RuntimeTypeCollection, 42} 43 44impl Drop for ModuleInner { 45 fn drop(&mut self) { 46 tracing::warn!("Dropping wasm module {}", self.name); 47 unregister_code(&self.code); 48 } 49} 50 51impl Module { 52 pub fn from_bytes( 53 engine: &Engine, 54 validator: &mut Validator, 55 bytes: &[u8], 56 ) -> crate::Result<Self> { 57 let (mut translation, types) = ModuleTranslator::new(validator).translate(bytes)?; 58 59 tracing::debug!("Gathering compile inputs..."); 60 let function_body_data = mem::take(&mut translation.function_bodies); 61 let inputs = CompileInputs::from_module(&translation, &types, function_body_data); 62 63 tracing::debug!("Compiling inputs..."); 64 let unlinked_outputs = inputs.compile(engine.compiler())?; 65 66 let type_collection = engine.type_registry().register_module_types(engine, types); 67 68 let code = crate::mem::with_kernel_aspace(|aspace| -> crate::Result<_> { 69 tracing::debug!("Applying static relocations..."); 70 let mut code = 71 unlinked_outputs.link_and_finish(engine, &translation.module, |code| { 72 tracing::debug!("Allocating new memory map..."); 73 MmapVec::from_slice(aspace.clone(), &code) 74 })?; 75 76 code.publish(aspace.lock().deref_mut())?; 77 Ok(Arc::new(code)) 78 })?; 79 80 // register this code memory with the trap handler, so we can correctly unwind from traps 81 register_code(&code); 82 83 Ok(Self(Arc::new(ModuleInner { 84 name: translation 85 .module 86 .name 87 .clone() 88 .unwrap_or("<unnamed mystery module>".to_string()), 89 engine: engine.clone(), 90 vmshape: VMShape::for_module(u8_size_of::<*mut u8>(), &translation.module), 91 translated_module: translation.module, 92 required_features: translation.required_features, 93 code, 94 type_collection, 95 }))) 96 } 97 98 /// Returns the modules name if present. 99 pub fn name(&self) -> Option<&str> { 100 self.translated().name.as_deref() 101 } 102 103 /// Returns the modules imports. 104 pub fn imports(&self) -> impl ExactSizeIterator<Item = &Import> { 105 self.translated().imports.iter() 106 } 107 108 /// Returns the modules exports. 109 pub fn exports(&self) -> impl ExactSizeIterator<Item = (&str, EntityIndex)> + '_ { 110 self.translated() 111 .exports 112 .iter() 113 .map(|(name, index)| (name.as_str(), *index)) 114 } 115 116 pub(super) fn required_features(&self) -> WasmFeatures { 117 self.0.required_features 118 } 119 pub(super) fn engine(&self) -> &Engine { 120 &self.0.engine 121 } 122 pub(super) fn translated(&self) -> &TranslatedModule { 123 &self.0.translated_module 124 } 125 pub(super) fn vmshape(&self) -> &VMShape { 126 &self.0.vmshape 127 } 128 pub(crate) fn code(&self) -> &Arc<CodeObject> { 129 &self.0.code 130 } 131 pub(crate) fn type_collection(&self) -> &RuntimeTypeCollection { 132 &self.0.type_collection 133 } 134 pub(crate) fn type_ids(&self) -> &[VMSharedTypeIndex] { 135 self.0.type_collection.type_map().values().as_slice() 136 } 137 pub(crate) fn functions( 138 &self, 139 ) -> cranelift_entity::Iter<DefinedFuncIndex, CompiledFunctionInfo> { 140 self.0.code.function_info().iter() 141 } 142 143 pub(super) fn array_to_wasm_trampoline( 144 &self, 145 index: DefinedFuncIndex, 146 ) -> Option<VMArrayCallFunction> { 147 let loc = self.0.code.function_info()[index].array_to_wasm_trampoline?; 148 let raw = self.code().resolve_function_loc(loc); 149 // Safety: TODO 150 Some(unsafe { mem::transmute::<usize, VMArrayCallFunction>(raw) }) 151 } 152 153 /// Return the address, in memory, of the trampoline that allows Wasm to 154 /// call a array function of the given signature. 155 pub(super) fn wasm_to_array_trampoline( 156 &self, 157 signature: VMSharedTypeIndex, 158 ) -> Option<NonNull<VMWasmCallFunction>> { 159 let trampoline_shared_ty = self.0.engine.type_registry().get_trampoline_type(signature); 160 let trampoline_module_ty = self 161 .0 162 .type_collection 163 .trampoline_type(trampoline_shared_ty)?; 164 165 debug_assert!( 166 self.0 167 .engine 168 .type_registry() 169 .borrow( 170 self.0 171 .type_collection 172 .lookup_shared_type(trampoline_module_ty) 173 .unwrap() 174 ) 175 .unwrap() 176 .unwrap_func() 177 .is_trampoline_type() 178 ); 179 180 let ptr = self.code().wasm_to_host_trampoline(trampoline_module_ty); 181 182 Some(ptr) 183 } 184 185 pub(super) fn function(&self, index: DefinedFuncIndex) -> NonNull<VMWasmCallFunction> { 186 let loc = self.0.code.function_info()[index].wasm_func_loc; 187 NonNull::new(self.code().resolve_function_loc(loc) as *mut VMWasmCallFunction).unwrap() 188 } 189 190 pub(super) fn same(&self, other: &Self) -> bool { 191 Arc::ptr_eq(&self.0, &other.0) 192 } 193 194 pub(super) fn new_stub(engine: Engine) -> Self { 195 let translated_module = TranslatedModule::default(); 196 Self(Arc::new(ModuleInner { 197 name: "<Stub>".to_string(), 198 engine: engine.clone(), 199 vmshape: VMShape::for_module(u8_size_of::<usize>(), &translated_module), 200 translated_module, 201 required_features: WasmFeatures::default(), 202 code: Arc::new(CodeObject::empty()), 203 type_collection: RuntimeTypeCollection::empty(engine), 204 })) 205 } 206}