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