Next Generation WASM Microkernel Operating System
at main 169 lines 6.0 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 alloc::vec; 9use alloc::vec::Vec; 10 11use crate::util::zip_eq::IteratorExt; 12use crate::wasm::indices::EntityIndex; 13use crate::wasm::module::Module; 14use crate::wasm::store::{StoreOpaque, Stored}; 15use crate::wasm::vm::{ConstExprEvaluator, Imports, InstanceHandle}; 16use crate::wasm::{Extern, Func, Global, Memory, Table}; 17 18/// An instantiated WebAssembly module. 19/// 20/// This is the main representation of all runtime state associated with a running WebAssembly module. 21/// 22/// # Instance and `VMContext` 23/// 24/// `Instance` and `VMContext` are essentially two halves of the same data structure. `Instance` is 25/// the privileged host-side half responsible for administrating execution, while `VMContext` holds the 26/// actual data that is accessed by compiled WASM code. 27#[derive(Debug, Clone, Copy)] 28#[repr(transparent)] 29pub struct Instance(Stored<InstanceData>); 30#[derive(Debug)] 31pub(super) struct InstanceData { 32 pub handle: InstanceHandle, 33 /// A lazily-populated list of exports of this instance. The order of 34 /// exports here matches the order of the exports in the original 35 /// module. 36 exports: Vec<Option<Extern>>, 37} 38 39#[derive(Clone)] 40pub struct Export<'instance> { 41 /// The name of the export. 42 pub name: &'instance str, 43 /// The definition of the export. 44 pub definition: Extern, 45} 46 47impl Instance { 48 /// Instantiates a new `Instance`. 49 /// 50 /// # Safety 51 /// 52 /// This functions assumes the provided `imports` have already been validated and typechecked for 53 /// compatibility with the `module` being instantiated. 54 pub(crate) unsafe fn new_unchecked( 55 store: &mut StoreOpaque, 56 const_eval: &mut ConstExprEvaluator, 57 module: Module, 58 imports: Imports, 59 ) -> crate::Result<Self> { 60 let mut handle = store.alloc_mut().allocate_module(module.clone())?; 61 62 let is_bulk_memory = module.required_features().bulk_memory(); 63 64 handle.initialize(store, const_eval, &module, imports, is_bulk_memory)?; 65 66 let stored = store.add_instance(InstanceData { 67 handle, 68 exports: vec![None; module.exports().len()], 69 }); 70 71 Ok(Self(stored)) 72 } 73 74 /// Returns the module this instance was instantiated from. 75 pub fn module(self, store: &StoreOpaque) -> &Module { 76 store[self.0].handle.module() 77 } 78 79 /// Returns an iterator over the exports of this instance. 80 pub(crate) fn exports( 81 self, 82 store: &mut StoreOpaque, 83 ) -> impl ExactSizeIterator<Item = Export<'_>> { 84 let exports = &store[self.0].exports; 85 86 if exports.iter().any(Option::is_none) { 87 let module = store[self.0].handle.module().clone(); 88 89 for name in module.translated().exports.keys() { 90 if let Some((export_name_index, _, &entity)) = 91 module.translated().exports.get_full(name) 92 { 93 self.get_export_inner(store, entity, export_name_index); 94 } 95 } 96 } 97 98 let instance = &store[self.0]; 99 let module = instance.handle.module(); 100 module 101 .translated() 102 .exports 103 .iter() 104 .zip_eq(&instance.exports) 105 .map(|((name, _), export)| Export { 106 name, 107 definition: export.clone().unwrap(), 108 }) 109 } 110 111 /// Attempts to get an export from this instance. 112 pub fn get_export(self, store: &mut StoreOpaque, name: &str) -> Option<Extern> { 113 let (export_name_index, _, index) = 114 self.module(store).translated().exports.get_full(name)?; 115 Some(self.get_export_inner(store, *index, export_name_index)) 116 } 117 118 /// Attempts to get an exported `Func` from this instance. 119 pub fn get_func(self, store: &mut StoreOpaque, name: &str) -> Option<Func> { 120 self.get_export(store, name)?.into_func() 121 } 122 123 /// Attempts to get an exported `Table` from this instance. 124 pub fn get_table(self, store: &mut StoreOpaque, name: &str) -> Option<Table> { 125 self.get_export(store, name)?.into_table() 126 } 127 128 /// Attempts to get an exported `Memory` from this instance. 129 pub fn get_memory(self, store: &mut StoreOpaque, name: &str) -> Option<Memory> { 130 self.get_export(store, name)?.into_memory() 131 } 132 133 /// Attempts to get an exported `Global` from this instance. 134 pub fn get_global(self, store: &mut StoreOpaque, name: &str) -> Option<Global> { 135 self.get_export(store, name)?.into_global() 136 } 137 138 fn get_export_inner( 139 self, 140 store: &mut StoreOpaque, 141 entity: EntityIndex, 142 export_name_index: usize, 143 ) -> Extern { 144 // Instantiated instances will lazily fill in exports, so we process 145 // all that lazy logic here. 146 let data = &store[self.0]; 147 148 if let Some(export) = &data.exports[export_name_index] { 149 return export.clone(); 150 } 151 152 let instance = &mut store[self.0]; // Reborrow the &mut InstanceHandle 153 // Safety: we just took `instance` from the store, so all its exports must also belong to the store 154 let item = 155 unsafe { Extern::from_export(instance.handle.get_export_by_index(entity), store) }; 156 let data = &mut store[self.0]; 157 data.exports[export_name_index] = Some(item.clone()); 158 item 159 } 160 161 pub(crate) fn comes_from_same_store(self, store: &StoreOpaque) -> bool { 162 store.has_instance(self.0) 163 } 164 165 /// Print a debug representation of this instances `VMContext` to the logger. 166 pub fn debug_vmctx(self, store: &StoreOpaque) { 167 store[self.0].handle.debug_vmctx(); 168 } 169}