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