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::builtins::BuiltinFunctionIndex;
9use crate::wasm::compile::{FilePos, NS_BUILTIN, NS_WASM_FUNC};
10use crate::wasm::indices::FuncIndex;
11use crate::wasm::trap::TrapKind;
12use cranelift_codegen::ir::{ExternalName, StackSlots, UserExternalName, UserExternalNameRef};
13use cranelift_codegen::{
14 Final, FinalizedMachReloc, FinalizedRelocTarget, MachBufferFinalized, ValueLabelsRanges,
15 binemit,
16};
17use cranelift_entity::PrimaryMap;
18
19#[derive(Debug)]
20pub struct CompiledFunction {
21 /// The machine code buffer for this function.
22 buffer: MachBufferFinalized<Final>,
23 /// What names each name ref corresponds to.
24 name_map: PrimaryMap<UserExternalNameRef, UserExternalName>,
25 /// The alignment for the compiled function.
26 alignment: u32,
27 /// The metadata for the compiled function.
28 metadata: CompiledFunctionMetadata,
29}
30
31impl CompiledFunction {
32 pub fn new(
33 buffer: MachBufferFinalized<Final>,
34 name_map: PrimaryMap<UserExternalNameRef, UserExternalName>,
35 alignment: u32,
36 ) -> Self {
37 Self {
38 buffer,
39 name_map,
40 alignment,
41 metadata: CompiledFunctionMetadata::default(),
42 }
43 }
44
45 pub fn buffer(&self) -> &[u8] {
46 self.buffer.data()
47 }
48
49 pub fn alignment(&self) -> u32 {
50 self.alignment
51 }
52
53 pub fn relocations(&self) -> impl ExactSizeIterator<Item = Relocation> + use<'_> {
54 self.buffer
55 .relocs()
56 .iter()
57 .map(|r| Relocation::from_mach_reloc(r, &self.name_map))
58 }
59
60 /// Returns an iterator to the function's traps.
61 pub fn traps(&self) -> impl ExactSizeIterator<Item = TrapInfo> + use<'_> {
62 self.buffer.traps().iter().map(|trap| TrapInfo {
63 trap: TrapKind::from_trap_code(trap.code).expect("unexpected trap code"),
64 offset: trap.offset,
65 })
66 }
67
68 pub fn metadata(&self) -> &CompiledFunctionMetadata {
69 &self.metadata
70 }
71
72 pub fn metadata_mut(&mut self) -> &mut CompiledFunctionMetadata {
73 &mut self.metadata
74 }
75}
76
77#[derive(Debug, Default)]
78pub struct CompiledFunctionMetadata {
79 /// Mapping of value labels and their locations.
80 pub value_labels_ranges: ValueLabelsRanges,
81 /// Allocated stack slots.
82 pub sized_stack_slots: StackSlots,
83 /// Start source location.
84 pub start_srcloc: FilePos,
85 /// End source location.
86 pub end_srcloc: FilePos,
87 // /// An array of data for the instructions in this function, indicating where
88 // /// each instruction maps back to in the original function.
89 // ///
90 // /// This array is sorted least-to-greatest by the `code_offset` field.
91 // /// Additionally the span of each `InstructionAddressMap` is implicitly the
92 // /// gap between it and the next item in the array.
93 // pub address_map: Box<[InstructionAddressMapping]>,
94}
95
96#[derive(Debug)]
97pub struct Relocation {
98 pub kind: binemit::Reloc,
99 pub target: RelocationTarget,
100 pub addend: binemit::Addend,
101 pub offset: binemit::CodeOffset,
102}
103
104#[derive(Debug, Copy, Clone)]
105pub enum RelocationTarget {
106 Wasm(FuncIndex),
107 Builtin(BuiltinFunctionIndex),
108}
109
110impl Relocation {
111 fn from_mach_reloc(
112 reloc: &FinalizedMachReloc,
113 name_map: &PrimaryMap<UserExternalNameRef, UserExternalName>,
114 ) -> Self {
115 let &FinalizedMachReloc {
116 offset,
117 kind,
118 ref target,
119 addend,
120 } = reloc;
121
122 let target = match *target {
123 FinalizedRelocTarget::ExternalName(ExternalName::User(user_func_ref)) => {
124 let name = &name_map[user_func_ref];
125 match name.namespace {
126 // A reference to another jit'ed WASM function
127 NS_WASM_FUNC => RelocationTarget::Wasm(FuncIndex::from_u32(name.index)),
128 // A reference to a WASM builtin
129 NS_BUILTIN => {
130 RelocationTarget::Builtin(BuiltinFunctionIndex::from_u32(name.index))
131 }
132 _ => panic!("unknown namespace {}", name.namespace),
133 }
134 }
135 FinalizedRelocTarget::ExternalName(ExternalName::LibCall(libcall)) => {
136 // cranelift libcalls are a lot like wasm builtins, they are emitted for instructions
137 // that have no ISA equivalent and would be too complicated to emit as JIT code
138 todo!("libcalls {libcall:?}")
139 }
140 _ => panic!("unsupported relocation target {target:?}"),
141 };
142
143 Self {
144 kind,
145 target,
146 addend,
147 offset,
148 }
149 }
150}
151
152/// Information about a trap in a compiled function.
153pub struct TrapInfo {
154 /// The offset relative to the function start of the trapping address.
155 pub offset: u32,
156 /// The trap code corresponding to the trapping instruction.
157 pub trap: TrapKind,
158}