Next Generation WASM Microkernel Operating System
at trap_handler 287 lines 9.7 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::func::{HostFunc, IntoFunc, WasmParams, WasmResults}; 9use crate::wasm::indices::VMSharedTypeIndex; 10use crate::wasm::store::StoreOpaque; 11use crate::wasm::translate::EntityType; 12use crate::wasm::types::{GlobalType, MemoryType, TableType, TagType}; 13use crate::wasm::vm::{ConstExprEvaluator, Imports}; 14use crate::wasm::{Engine, Extern, Func, Global, Instance, Memory, Module, Store, Table, Tag}; 15use alloc::sync::Arc; 16use alloc::vec::Vec; 17use anyhow::{Context, bail, format_err}; 18use core::marker::PhantomData; 19use hashbrown::HashMap; 20use hashbrown::hash_map::Entry; 21 22/// A dynamic linker for WebAssembly modules. 23#[derive(Debug)] 24pub struct Linker<T> { 25 engine: Engine, 26 string2idx: HashMap<Arc<str>, usize>, 27 strings: Vec<Arc<str>>, 28 map: HashMap<ImportKey, Definition>, 29 _m: PhantomData<T>, 30} 31 32#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] 33struct ImportKey { 34 name: usize, 35 module: usize, 36} 37 38#[derive(Debug, Clone)] 39pub(super) enum Definition { 40 Func(Func, VMSharedTypeIndex), 41 HostFunc(Arc<HostFunc>, VMSharedTypeIndex), 42 Global(Global, GlobalType), 43 // Note that tables and memories store not only the original type 44 // information but additionally the current size of the table/memory, as 45 // this is used during linking since the min size specified in the type may 46 // no longer be the current size of the table/memory. 47 Table(Table, TableType), 48 Memory(Memory, MemoryType), 49 Tag(Tag, TagType), 50} 51 52impl<T> Linker<T> { 53 /// Create a new `Linker`. 54 /// 55 /// This linker is scoped to the provided engine and cannot be used to link modules from other engines. 56 pub fn new(engine: &Engine) -> Self { 57 Self { 58 engine: engine.clone(), 59 string2idx: HashMap::new(), 60 strings: Vec::new(), 61 map: HashMap::new(), 62 _m: PhantomData, 63 } 64 } 65 66 pub fn engine(&self) -> &Engine { 67 &self.engine 68 } 69 70 pub fn define( 71 &mut self, 72 store: &mut StoreOpaque, 73 module: &str, 74 name: &str, 75 def: impl Into<Extern>, 76 ) -> crate::Result<&mut Self> { 77 let key = self.import_key(module, Some(name)); 78 self.insert(key, Definition::new(store, def.into()))?; 79 Ok(self) 80 } 81 82 /// Attempt to retrieve a definition from this linker. 83 pub fn get(&self, store: &mut StoreOpaque, module: &str, name: &str) -> Option<Extern> { 84 // Safety: TODO 85 Some(unsafe { self._get(module, name)?.to_extern(store) }) 86 } 87 88 fn _get(&self, module: &str, name: &str) -> Option<&Definition> { 89 let key = ImportKey { 90 module: *self.string2idx.get(module)?, 91 name: *self.string2idx.get(name)?, 92 }; 93 self.map.get(&key) 94 } 95 96 /// Alias all exports of `module` under the name `as_module`. 97 /// 98 /// # Errors 99 /// 100 /// TODO 101 pub fn alias_module(&mut self, module: &str, as_module: &str) -> crate::Result<&mut Self> { 102 let module = self.intern_str(module); 103 let as_module = self.intern_str(as_module); 104 let items = self 105 .map 106 .iter() 107 .filter(|(key, _def)| key.module == module) 108 .map(|(key, def)| (key.name, def.clone())) 109 .collect::<Vec<_>>(); 110 for (name, item) in items { 111 self.insert( 112 ImportKey { 113 module: as_module, 114 name, 115 }, 116 item, 117 )?; 118 } 119 Ok(self) 120 } 121 122 /// Define all exports of the provided `instance` under the module name `module_name`. 123 /// 124 /// # Errors 125 /// 126 /// TODO 127 pub fn define_instance( 128 &mut self, 129 store: &mut StoreOpaque, 130 module_name: &str, 131 instance: Instance, 132 ) -> crate::Result<&mut Self> { 133 let exports = instance 134 .exports(store) 135 .map(|e| (self.import_key(module_name, Some(e.name)), e.definition)) 136 .collect::<Vec<_>>(); // TODO can we somehow get rid of this? 137 138 for (key, ext) in exports { 139 self.insert(key, Definition::new(store, ext))?; 140 } 141 142 Ok(self) 143 } 144 145 /// Instantiate the provided `module`. 146 /// 147 /// This step resolve the modules imports using definitions from this linker, then pass them 148 /// on to `Instance::new_unchecked` for instantiation. 149 /// 150 /// Each import of module will be looked up in this Linker and must have previously been defined. 151 /// 152 /// # Errors 153 /// 154 /// TODO 155 /// 156 /// # Panics 157 /// 158 /// TODO 159 pub fn instantiate( 160 &self, 161 store: &mut Store<T>, 162 const_eval: &mut ConstExprEvaluator, 163 module: &Module, 164 ) -> crate::Result<Instance> { 165 let mut imports = Imports::with_capacity_for(module.translated()); 166 167 for import in module.imports() { 168 let def = self._get(&import.module, &import.name).with_context(|| { 169 let type_ = match import.ty { 170 EntityType::Function(_) => "function", 171 EntityType::Table(_) => "table", 172 EntityType::Memory(_) => "memory", 173 EntityType::Global(_) => "global", 174 EntityType::Tag(_) => "tag", 175 }; 176 177 format_err!("Missing {type_} import {}::{}", import.module, import.name) 178 })?; 179 180 match (def, &import.ty) { 181 (Definition::Func(func, _actual), EntityType::Function(_expected)) => { 182 imports 183 .functions 184 .push(func.as_vmfunction_import(store, module)); 185 } 186 (Definition::HostFunc(func, _actual), EntityType::Function(_expected)) => { 187 let func = func.clone().to_func(store); 188 imports 189 .functions 190 .push(func.as_vmfunction_import(store, module)); 191 } 192 (Definition::Table(table, _actual), EntityType::Table(_expected)) => { 193 imports.tables.push(table.as_vmtable_import(store)); 194 } 195 (Definition::Memory(memory, _actual), EntityType::Memory(_expected)) => { 196 imports.memories.push(memory.as_vmmemory_import(store)); 197 } 198 (Definition::Global(global, _actual), EntityType::Global(_expected)) => { 199 imports.globals.push(global.as_vmglobal_import(store)); 200 } 201 (Definition::Tag(tag, _actual), EntityType::Tag(_expected)) => { 202 imports.tags.push(tag.as_vmtag_import(store)); 203 } 204 _ => panic!("mismatched import type"), 205 } 206 } 207 208 // Safety: we have typechecked the imports above. 209 unsafe { Instance::new_unchecked(store, const_eval, module.clone(), imports) } 210 } 211 212 pub fn func_wrap<Params, Results>( 213 &mut self, 214 module: &str, 215 name: &str, 216 func: impl IntoFunc<T, Params, Results>, 217 ) -> crate::Result<&mut Self> 218 where 219 Params: WasmParams, 220 Results: WasmResults, 221 { 222 let (func, ty) = HostFunc::wrap(self.engine(), func); 223 224 let key = self.import_key(module, Some(name)); 225 self.insert(key, Definition::HostFunc(Arc::new(func), ty.type_index()))?; 226 227 Ok(self) 228 } 229 230 fn insert(&mut self, key: ImportKey, item: Definition) -> crate::Result<()> { 231 match self.map.entry(key) { 232 Entry::Occupied(_) => { 233 bail!( 234 "Name {}::{} is already defined", 235 self.strings[key.module], 236 self.strings[key.name] 237 ); 238 } 239 Entry::Vacant(v) => { 240 v.insert(item); 241 } 242 } 243 244 Ok(()) 245 } 246 247 fn import_key(&mut self, module: &str, name: Option<&str>) -> ImportKey { 248 ImportKey { 249 module: self.intern_str(module), 250 name: name.map_or(usize::MAX, |name| self.intern_str(name)), 251 } 252 } 253 254 fn intern_str(&mut self, string: &str) -> usize { 255 if let Some(idx) = self.string2idx.get(string) { 256 return *idx; 257 } 258 let string: Arc<str> = string.into(); 259 let idx = self.strings.len(); 260 self.strings.push(string.clone()); 261 self.string2idx.insert(string, idx); 262 idx 263 } 264} 265 266impl Definition { 267 fn new(store: &StoreOpaque, item: Extern) -> Definition { 268 match item { 269 Extern::Func(f) => Definition::Func(f, f.type_index(store)), 270 Extern::Table(t) => Definition::Table(t, t.ty(store)), 271 Extern::Memory(m) => Definition::Memory(m, m.ty(store)), 272 Extern::Global(g) => Definition::Global(g, g.ty(store)), 273 Extern::Tag(t) => Definition::Tag(t, t.ty(store)), 274 } 275 } 276 277 unsafe fn to_extern(&self, store: &mut StoreOpaque) -> Extern { 278 match self { 279 Definition::Func(f, _) => Extern::Func(*f), 280 Definition::HostFunc(f, _) => Extern::Func(f.clone().to_func(store)), 281 Definition::Global(g, _) => Extern::Global(*g), 282 Definition::Table(t, _) => Extern::Table(*t), 283 Definition::Memory(m, _) => Extern::Memory(*m), 284 Definition::Tag(t, _) => Extern::Tag(*t), 285 } 286 } 287}