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 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}