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 alloc::sync::Arc;
9use core::sync::atomic::AtomicU64;
10
11use cranelift_codegen::settings::{Configurable, Flags};
12use k23_spin::{Mutex, MutexGuard};
13use rand::{Rng, SeedableRng};
14use rand_chacha::ChaCha20Rng;
15
16use crate::arch;
17use crate::wasm::compile::Compiler;
18use crate::wasm::cranelift::CraneliftCompiler;
19use crate::wasm::type_registry::TypeRegistry;
20
21/// Global context for the runtime.
22///
23/// An engine can be safely shared across threads and is a cheap cloneable
24/// handle to the actual engine. The engine itself will be deallocated once all
25/// references to it have gone away.
26#[derive(Debug, Clone)]
27pub struct Engine(Arc<EngineInner>);
28
29#[derive(Debug)]
30pub struct EngineInner {
31 compiler: CraneliftCompiler,
32 type_registry: TypeRegistry,
33 rng: Option<Mutex<ChaCha20Rng>>,
34 asid_alloc: Mutex<arch::AsidAllocator>,
35 epoch_counter: AtomicU64,
36}
37
38impl Default for Engine {
39 fn default() -> Self {
40 let isa_builder = cranelift_codegen::isa::lookup(target_lexicon::HOST).unwrap();
41 let mut b = cranelift_codegen::settings::builder();
42 b.set("opt_level", "speed_and_size").unwrap();
43 b.set("libcall_call_conv", "isa_default").unwrap();
44 b.set("preserve_frame_pointers", "true").unwrap();
45 b.set("enable_probestack", "true").unwrap();
46 b.set("probestack_strategy", "inline").unwrap();
47 let target_isa = isa_builder.finish(Flags::new(b)).unwrap();
48
49 Self(Arc::new(EngineInner {
50 compiler: CraneliftCompiler::new(target_isa),
51 type_registry: TypeRegistry::default(),
52 rng: None,
53 asid_alloc: Mutex::new(arch::AsidAllocator::new()),
54 epoch_counter: AtomicU64::new(0),
55 }))
56 }
57}
58
59impl Engine {
60 pub fn new(rng: &mut impl Rng) -> Self {
61 let isa_builder = cranelift_codegen::isa::lookup(target_lexicon::HOST).unwrap();
62 let mut b = cranelift_codegen::settings::builder();
63 b.set("opt_level", "speed_and_size").unwrap();
64 b.set("libcall_call_conv", "isa_default").unwrap();
65 b.set("preserve_frame_pointers", "true").unwrap();
66 b.set("enable_probestack", "true").unwrap();
67 b.set("probestack_strategy", "inline").unwrap();
68 let target_isa = isa_builder.finish(Flags::new(b)).unwrap();
69
70 Self(Arc::new(EngineInner {
71 compiler: CraneliftCompiler::new(target_isa),
72 type_registry: TypeRegistry::default(),
73 rng: Some(Mutex::new(ChaCha20Rng::from_rng(rng))),
74 asid_alloc: Mutex::new(arch::AsidAllocator::new()),
75 epoch_counter: AtomicU64::new(0),
76 }))
77 }
78
79 pub fn same(lhs: &Engine, rhs: &Engine) -> bool {
80 Arc::ptr_eq(&lhs.0, &rhs.0)
81 }
82
83 pub fn compiler(&self) -> &dyn Compiler {
84 &self.0.compiler
85 }
86
87 /// Returns the type registry of this engine, used to canonicalize types.
88 pub fn type_registry(&self) -> &TypeRegistry {
89 &self.0.type_registry
90 }
91
92 pub fn allocate_asid(&self) -> u16 {
93 let mut alloc = self.0.asid_alloc.lock();
94 alloc.alloc().expect("out of address space identifiers")
95 }
96 pub fn rng(&self) -> Option<MutexGuard<'_, ChaCha20Rng>> {
97 Some(self.0.rng.as_ref()?.lock())
98 }
99 pub fn epoch_counter(&self) -> &AtomicU64 {
100 &self.0.epoch_counter
101 }
102}