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