Next Generation WASM Microkernel Operating System
at main 168 lines 5.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 core::ptr::NonNull; 9use core::sync::atomic::Ordering; 10 11use anyhow::Context; 12use cranelift_entity::packed_option::ReservedValue; 13 14use crate::wasm::indices::DefinedTableIndex; 15use crate::wasm::store::{StoreOpaque, Stored}; 16use crate::wasm::types::TableType; 17use crate::wasm::values::Ref; 18use crate::wasm::vm::{ExportedTable, InstanceAndStore, TableElement, VMTableImport, VmPtr}; 19use crate::wasm::{Func, vm}; 20 21#[derive(Clone, Copy, Debug)] 22pub struct Table(Stored<ExportedTable>); 23 24impl Table { 25 pub fn new(store: &mut StoreOpaque, ty: TableType, init: Ref) -> crate::Result<Table> { 26 let wasm_ty = ty.to_wasm_table(); 27 28 // Safety: TODO 29 let mut t = unsafe { 30 store 31 .alloc_mut() 32 .allocate_table(wasm_ty, DefinedTableIndex::reserved_value())? 33 }; 34 35 let init = init.into_table_element(store, ty.element())?; 36 t.fill(0, init, ty.minimum())?; 37 38 let definition = store.add_host_table(t); 39 40 let stored = store.add_table(ExportedTable { 41 definition, 42 vmctx: store.default_caller(), 43 table: wasm_ty.clone(), 44 }); 45 Ok(Self(stored)) 46 } 47 48 pub fn ty(self, store: &StoreOpaque) -> TableType { 49 let export = &store[self.0]; 50 TableType::from_wasm_table(store.engine(), &export.table) 51 } 52 53 pub fn get(self, store: &mut StoreOpaque, index: u64) -> Option<Ref> { 54 // Safety: TODO 55 let table = unsafe { self.vmtable(store).as_mut() }; 56 let element = table.get(index)?; 57 58 match element { 59 TableElement::FuncRef(Some(func_ref)) => { 60 // Safety: TODO 61 let f = unsafe { Func::from_vm_func_ref(store, func_ref) }; 62 Some(Ref::Func(Some(f))) 63 } 64 TableElement::FuncRef(None) => Some(Ref::Func(None)), 65 } 66 } 67 68 pub fn set(self, store: &mut StoreOpaque, index: u64, val: Ref) -> crate::Result<()> { 69 let ty = self.ty(store); 70 let val = val.into_table_element(store, ty.element())?; 71 // Safety: TODO 72 let table = unsafe { self.vmtable(store).as_mut() }; 73 table.set(index, val)?; 74 75 Ok(()) 76 } 77 78 pub fn size(self, store: &StoreOpaque) -> u64 { 79 // Safety: TODO 80 unsafe { 81 u64::try_from( 82 store[self.0] 83 .definition 84 .as_ref() 85 .current_elements 86 .load(Ordering::Relaxed), 87 ) 88 .unwrap() 89 } 90 } 91 92 pub fn grow(self, store: &mut StoreOpaque, delta: u64, init: Ref) -> crate::Result<u64> { 93 let ty = self.ty(store); 94 let init = init.into_table_element(store, ty.element())?; 95 // Safety: TODO 96 let table = unsafe { self.vmtable(store).as_mut() }; 97 let old_size = table.grow(delta, init)?.context("failed to grow table")?; 98 Ok(u64::try_from(old_size).unwrap()) 99 } 100 101 pub fn copy( 102 store: &mut StoreOpaque, 103 dst_table: &Table, 104 dst_index: u64, 105 src_table: &Table, 106 src_index: u64, 107 len: u64, 108 ) -> crate::Result<()> { 109 let dst_ty = dst_table.ty(store); 110 let src_ty = src_table.ty(store); 111 112 src_ty 113 .element() 114 .ensure_matches(store.engine(), dst_ty.element()) 115 .context( 116 "type mismatch: source table's element type does not match \ 117 destination table's element type", 118 )?; 119 120 let dst_table = dst_table.vmtable(store); 121 let src_table = src_table.vmtable(store); 122 123 vm::Table::copy( 124 dst_table.as_ptr(), 125 src_table.as_ptr(), 126 dst_index, 127 src_index, 128 len, 129 )?; 130 131 Ok(()) 132 } 133 134 pub fn fill(self, store: &mut StoreOpaque, dst: u64, val: Ref, len: u64) -> crate::Result<()> { 135 let ty = self.ty(store); 136 let val = val.into_table_element(store, ty.element())?; 137 // Safety: TODO 138 let table = unsafe { self.vmtable(store).as_mut() }; 139 table.fill(dst, val, len)?; 140 141 Ok(()) 142 } 143 144 pub(super) fn from_exported_table(store: &mut StoreOpaque, export: ExportedTable) -> Self { 145 let stored = store.add_table(export); 146 Self(stored) 147 } 148 pub(super) fn vmtable(self, store: &mut StoreOpaque) -> NonNull<vm::Table> { 149 let ExportedTable { 150 definition, vmctx, .. 151 } = store[self.0]; 152 // Safety: TODO 153 unsafe { 154 InstanceAndStore::from_vmctx(vmctx, |pair| { 155 let (instance, _) = pair.unpack_mut(); 156 let def_index = instance.table_index(definition.as_ref()); 157 instance.get_defined_table(def_index) 158 }) 159 } 160 } 161 pub(super) fn as_vmtable_import(self, store: &mut StoreOpaque) -> VMTableImport { 162 let export = &store[self.0]; 163 VMTableImport { 164 from: VmPtr::from(export.definition), 165 vmctx: VmPtr::from(export.vmctx), 166 } 167 } 168}