1use crate::utils::CowBytes;
2use crate::varint::{read_varint, write_varint, MAX_VARINT_LENGTH};
3use core::ops::Range;
4
5#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
6#[repr(u8)]
7pub enum Reg {
8 RA = 0,
9 SP = 1,
10 T0 = 2,
11 T1 = 3,
12 T2 = 4,
13 S0 = 5,
14 S1 = 6,
15 A0 = 7,
16 A1 = 8,
17 A2 = 9,
18 A3 = 10,
19 A4 = 11,
20 A5 = 12,
21}
22
23impl Reg {
24 #[inline]
25 pub const fn from_u8(value: u8) -> Option<Reg> {
26 match value {
27 0 => Some(Reg::RA),
28 1 => Some(Reg::SP),
29 2 => Some(Reg::T0),
30 3 => Some(Reg::T1),
31 4 => Some(Reg::T2),
32 5 => Some(Reg::S0),
33 6 => Some(Reg::S1),
34 7 => Some(Reg::A0),
35 8 => Some(Reg::A1),
36 9 => Some(Reg::A2),
37 10 => Some(Reg::A3),
38 11 => Some(Reg::A4),
39 12 => Some(Reg::A5),
40 _ => None,
41 }
42 }
43
44 pub const fn name(self) -> &'static str {
45 use Reg::*;
46 match self {
47 RA => "ra",
48 SP => "sp",
49 T0 => "t0",
50 T1 => "t1",
51 T2 => "t2",
52 S0 => "s0",
53 S1 => "s1",
54 A0 => "a0",
55 A1 => "a1",
56 A2 => "a2",
57 A3 => "a3",
58 A4 => "a4",
59 A5 => "a5",
60 }
61 }
62
63 pub const ALL: [Reg; 13] = {
65 use Reg::*;
66 [RA, SP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5]
67 };
68
69 pub const ARG_REGS: [Reg; 9] = [Reg::A0, Reg::A1, Reg::A2, Reg::A3, Reg::A4, Reg::A5, Reg::T0, Reg::T1, Reg::T2];
71
72 pub const MAXIMUM_INPUT_REGS: usize = 9;
73 pub const MAXIMUM_OUTPUT_REGS: usize = 2;
74}
75
76impl core::fmt::Display for Reg {
77 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
78 fmt.write_str(self.name())
79 }
80}
81
82#[allow(clippy::partial_pub_fields)]
83#[doc(hidden)]
84pub struct VisitorHelper<'a, T> {
85 pub visitor: T,
86 reader: Reader<'a>,
87}
88
89impl<'a, T> VisitorHelper<'a, T> {
90 #[inline]
91 pub fn run<E>(
92 blob: &'a ProgramBlob<'a>,
93 visitor: T,
94 decode_table: &[fn(&mut Self) -> <T as InstructionVisitor>::ReturnTy; 256],
95 ) -> (T, <T as InstructionVisitor>::ReturnTy)
96 where
97 T: ParsingVisitor<E>,
98 {
99 let mut state = VisitorHelper {
100 visitor,
101 reader: blob.get_section_reader(blob.code.clone()),
102 };
103
104 let mut result = Ok(());
105 loop {
106 let Ok(opcode) = state.reader.read_byte() else { break };
107 result = state.visitor.on_pre_visit(state.reader.position - 1 - blob.code.start, opcode);
108 if result.is_err() {
109 break;
110 }
111
112 result = decode_table[opcode as usize](&mut state);
113 if result.is_err() {
114 break;
115 }
116
117 result = state.visitor.on_post_visit();
118 if result.is_err() {
119 break;
120 }
121 }
122
123 (state.visitor, result)
124 }
125
126 #[cold]
127 pub fn unknown_opcode<U, E>(&mut self) -> <T as InstructionVisitor>::ReturnTy
128 where
129 T: InstructionVisitor<ReturnTy = Result<U, E>>,
130 E: From<ProgramParseError>,
131 {
132 let error = ProgramParseError::unexpected_instruction(self.reader.position - 1);
133 Err(error.into())
134 }
135
136 #[inline(always)]
137 pub fn read_args_imm(&mut self) -> Result<u32, ProgramParseError> {
138 self.reader.read_varint()
139 }
140
141 #[inline(always)]
142 pub fn read_args_imm2(&mut self) -> Result<(u32, u32), ProgramParseError> {
143 let imm1 = self.reader.read_varint()?;
144 let imm2 = self.reader.read_varint()?;
145 Ok((imm1, imm2))
146 }
147
148 #[inline(always)]
149 pub fn read_args_reg_imm(&mut self) -> Result<(Reg, u32), ProgramParseError> {
150 let reg = self.reader.read_reg()?;
151 let imm = self.reader.read_varint()?;
152 Ok((reg, imm))
153 }
154
155 #[inline(always)]
156 pub fn read_args_reg_imm2(&mut self) -> Result<(Reg, u32, u32), ProgramParseError> {
157 let reg = self.reader.read_reg()?;
158 let imm1 = self.reader.read_varint()?;
159 let imm2 = self.reader.read_varint()?;
160 Ok((reg, imm1, imm2))
161 }
162
163 #[inline(always)]
164 pub fn read_args_regs2_imm(&mut self) -> Result<(Reg, Reg, u32), ProgramParseError> {
165 let (reg1, reg2) = self.reader.read_regs2()?;
166 let imm = self.reader.read_varint()?;
167 Ok((reg1, reg2, imm))
168 }
169
170 #[inline(always)]
171 pub fn read_args_regs3(&mut self) -> Result<(Reg, Reg, Reg), ProgramParseError> {
172 self.reader.read_regs3()
173 }
174
175 #[inline(always)]
176 pub fn read_args_regs2(&mut self) -> Result<(Reg, Reg), ProgramParseError> {
177 self.reader.read_regs2()
178 }
179}
180
181macro_rules! define_opcodes {
182 (@impl_shared $($name:ident = $value:expr,)+) => {
183 #[allow(non_camel_case_types)]
184 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
185 #[repr(u8)]
186 pub enum Opcode {
187 $(
188 $name = $value,
189 )+
190 }
191
192 impl Opcode {
193 #[cfg_attr(feature = "alloc", inline)]
194 pub fn from_u8(byte: u8) -> Option<Opcode> {
195 if !IS_INSTRUCTION_VALID[byte as usize] {
196 return None;
197 }
198
199 #[allow(unsafe_code)]
200 unsafe {
202 Some(core::mem::transmute(byte))
203 }
204 }
205 }
206
207 #[test]
208 fn test_opcode_from_u8() {
209 fn from_u8_naive(byte: u8) -> Option<Opcode> {
210 match byte {
211 $($value => Some(Opcode::$name),)+
212 _ => None
213 }
214 }
215
216 for byte in 0..=255 {
217 assert_eq!(from_u8_naive(byte), Opcode::from_u8(byte));
218 }
219 }
220
221 const IS_INSTRUCTION_VALID_CONST: [bool; 256] = {
222 let mut is_valid = [false; 256];
223 $(
224 is_valid[$value] = true;
225 )+
226 is_valid
227 };
228
229 #[cfg(feature = "alloc")]
230 static IS_INSTRUCTION_VALID: [bool; 256] = IS_INSTRUCTION_VALID_CONST;
231
232 #[cfg(not(feature = "alloc"))]
233 use IS_INSTRUCTION_VALID_CONST as IS_INSTRUCTION_VALID;
234 };
235
236 (
237 $d:tt
238
239 [$($name_argless:ident = $value_argless:expr,)+]
240 [$($name_reg_imm:ident = $value_reg_imm:expr,)+]
241 [$($name_reg_imm_imm:ident = $value_reg_imm_imm:expr,)+]
242 [$($name_reg_reg_imm:ident = $value_reg_reg_imm:expr,)+]
243 [$($name_reg_reg_reg:ident = $value_reg_reg_reg:expr,)+]
244 [$($name_imm:ident = $value_imm:expr,)+]
245 [$($name_imm_imm:ident = $value_imm_imm:expr,)+]
246 [$($name_reg_reg:ident = $value_reg_reg:expr,)+]
247 ) => {
248 pub trait ParsingVisitor<E>: InstructionVisitor<ReturnTy = Result<(), E>> {
249 fn on_pre_visit(&mut self, _offset: usize, _opcode: u8) -> Self::ReturnTy {
250 Ok(())
251 }
252
253 fn on_post_visit(&mut self) -> Self::ReturnTy {
254 Ok(())
255 }
256 }
257
258 pub trait InstructionVisitor {
259 type ReturnTy;
260
261 $(fn $name_argless(&mut self) -> Self::ReturnTy;)+
262 $(fn $name_reg_imm(&mut self, reg: Reg, imm: u32) -> Self::ReturnTy;)+
263 $(fn $name_reg_imm_imm(&mut self, reg: Reg, imm1: u32, imm2: u32) -> Self::ReturnTy;)+
264 $(fn $name_reg_reg_imm(&mut self, reg1: Reg, reg2: Reg, imm: u32) -> Self::ReturnTy;)+
265 $(fn $name_reg_reg_reg(&mut self, reg1: Reg, reg2: Reg, reg3: Reg) -> Self::ReturnTy;)+
266 $(fn $name_imm(&mut self, imm: u32) -> Self::ReturnTy;)+
267 $(fn $name_imm_imm(&mut self, imm1: u32, imm2: u32) -> Self::ReturnTy;)+
268 $(fn $name_reg_reg(&mut self, reg1: Reg, reg2: Reg) -> Self::ReturnTy;)+
269
270 }
271
272 #[macro_export]
273 macro_rules! implement_instruction_visitor {
274 (impl<$d($visitor_ty_params:tt),*> $visitor_ty:ty, $method:ident) => {
275 impl<$d($visitor_ty_params),*> polkavm_common::program::InstructionVisitor for $visitor_ty {
276 type ReturnTy = ();
277
278 $(fn $name_argless(&mut self) -> Self::ReturnTy {
279 self.$method(polkavm_common::program::Instruction::$name_argless);
280 })+
281 $(fn $name_reg_imm(&mut self, reg: Reg, imm: u32) -> Self::ReturnTy {
282 self.$method(polkavm_common::program::Instruction::$name_reg_imm(reg, imm));
283 })+
284 $(fn $name_reg_imm_imm(&mut self, reg: Reg, imm1: u32, imm2: u32) -> Self::ReturnTy {
285 self.$method(polkavm_common::program::Instruction::$name_reg_imm_imm(reg, imm1, imm2));
286 })+
287 $(fn $name_reg_reg_imm(&mut self, reg1: Reg, reg2: Reg, imm: u32) -> Self::ReturnTy {
288 self.$method(polkavm_common::program::Instruction::$name_reg_reg_imm(reg1, reg2, imm));
289 })+
290 $(fn $name_reg_reg_reg(&mut self, reg1: Reg, reg2: Reg, reg3: Reg) -> Self::ReturnTy {
291 self.$method(polkavm_common::program::Instruction::$name_reg_reg_reg(reg1, reg2, reg3));
292 })+
293 $(fn $name_imm(&mut self, imm: u32) -> Self::ReturnTy {
294 self.$method(polkavm_common::program::Instruction::$name_imm(imm));
295 })+
296 $(fn $name_imm_imm(&mut self, imm1: u32, imm2: u32) -> Self::ReturnTy {
297 self.$method(polkavm_common::program::Instruction::$name_imm_imm(imm1, imm2));
298 })+
299 $(fn $name_reg_reg(&mut self, reg1: Reg, reg2: Reg) -> Self::ReturnTy {
300 self.$method(polkavm_common::program::Instruction::$name_reg_reg(reg1, reg2));
301 })+
302 }
303 }
304 }
305
306 pub use implement_instruction_visitor;
307
308 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
309 #[allow(non_camel_case_types)]
310 pub enum Instruction {
311 $($name_argless,)+
312 $($name_reg_imm(Reg, u32),)+
313 $($name_reg_imm_imm(Reg, u32, u32),)+
314 $($name_reg_reg_imm(Reg, Reg, u32),)+
315 $($name_reg_reg_reg(Reg, Reg, Reg),)+
316 $($name_imm(u32),)+
317 $($name_imm_imm(u32, u32),)+
318 $($name_reg_reg(Reg, Reg),)+
319 }
320
321 impl Instruction {
322 pub fn visit<T>(self, visitor: &mut T) -> T::ReturnTy where T: InstructionVisitor {
323 match self {
324 $(Self::$name_argless => visitor.$name_argless(),)+
325 $(Self::$name_reg_imm(reg, imm) => visitor.$name_reg_imm(reg, imm),)+
326 $(Self::$name_reg_imm_imm(reg, imm1, imm2) => visitor.$name_reg_imm_imm(reg, imm1, imm2),)+
327 $(Self::$name_reg_reg_imm(reg1, reg2, imm) => visitor.$name_reg_reg_imm(reg1, reg2, imm),)+
328 $(Self::$name_reg_reg_reg(reg1, reg2, reg3) => visitor.$name_reg_reg_reg(reg1, reg2, reg3),)+
329 $(Self::$name_imm(imm) => visitor.$name_imm(imm),)+
330 $(Self::$name_imm_imm(imm1, imm2) => visitor.$name_imm_imm(imm1, imm2),)+
331 $(Self::$name_reg_reg(reg1, reg2) => visitor.$name_reg_reg(reg1, reg2),)+
332 }
333 }
334
335 pub fn serialize_into(self, buffer: &mut [u8]) -> usize {
336 match self {
337 $(Self::$name_argless => Self::serialize_argless(buffer, Opcode::$name_argless),)+
338 $(Self::$name_reg_imm(reg, imm) => Self::serialize_reg_imm(buffer, Opcode::$name_reg_imm, reg, imm),)+
339 $(Self::$name_reg_imm_imm(reg, imm1, imm2) => Self::serialize_reg_imm_imm(buffer, Opcode::$name_reg_imm_imm, reg, imm1, imm2),)+
340 $(Self::$name_reg_reg_imm(reg1, reg2, imm) => Self::serialize_reg_reg_imm(buffer, Opcode::$name_reg_reg_imm, reg1, reg2, imm),)+
341 $(Self::$name_reg_reg_reg(reg1, reg2, reg3) => Self::serialize_reg_reg_reg(buffer, Opcode::$name_reg_reg_reg, reg1, reg2, reg3),)+
342 $(Self::$name_imm(imm) => Self::serialize_imm(buffer, Opcode::$name_imm, imm),)+
343 $(Self::$name_imm_imm(imm1, imm2) => Self::serialize_imm_imm(buffer, Opcode::$name_imm_imm, imm1, imm2),)+
344 $(Self::$name_reg_reg(reg1, reg2) => Self::serialize_reg_reg(buffer, Opcode::$name_reg_reg, reg1, reg2),)+
345
346 }
347 }
348
349 pub fn opcode(self) -> Opcode {
350 match self {
351 $(Self::$name_argless => Opcode::$name_argless,)+
352 $(Self::$name_reg_imm(..) => Opcode::$name_reg_imm,)+
353 $(Self::$name_reg_imm_imm(..) => Opcode::$name_reg_imm_imm,)+
354 $(Self::$name_reg_reg_imm(..) => Opcode::$name_reg_reg_imm,)+
355 $(Self::$name_reg_reg_reg(..) => Opcode::$name_reg_reg_reg,)+
356 $(Self::$name_imm(..) => Opcode::$name_imm,)+
357 $(Self::$name_imm_imm(..) => Opcode::$name_imm_imm,)+
358 $(Self::$name_reg_reg(..) => Opcode::$name_reg_reg,)+
359 }
360 }
361 }
362
363 impl core::fmt::Display for Instruction {
364 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
365 self.visit(fmt)
366 }
367 }
368
369 fn parse_instruction_impl(opcode: u8, reader: &mut Reader) -> Result<Instruction, ProgramParseError> {
370 Ok(match opcode {
371 $($value_argless => Instruction::$name_argless,)+
372 $($value_reg_imm => {
373 let reg = reader.read_reg()?;
374 let imm = reader.read_varint()?;
375 Instruction::$name_reg_imm(reg, imm)
376 },)+
377 $($value_reg_imm_imm => {
378 let reg = reader.read_reg()?;
379 let imm1 = reader.read_varint()?;
380 let imm2 = reader.read_varint()?;
381 Instruction::$name_reg_imm_imm(reg, imm1, imm2)
382 },)+
383 $($value_reg_reg_imm => {
384 let (reg1, reg2) = reader.read_regs2()?;
385 let imm = reader.read_varint()?;
386 Instruction::$name_reg_reg_imm(reg1, reg2, imm)
387 },)+
388 $($value_reg_reg_reg => {
389 let (reg1, reg2) = reader.read_regs2()?;
390 let reg3 = reader.read_reg()?;
391 Instruction::$name_reg_reg_reg(reg1, reg2, reg3)
392 },)+
393 $($value_imm => {
394 Instruction::$name_imm(reader.read_varint()?)
395 },)+
396 $($value_imm_imm => {
397 let imm1 = reader.read_varint()?;
398 let imm2 = reader.read_varint()?;
399 Instruction::$name_imm_imm(imm1, imm2)
400 },)+
401 $($value_reg_reg => {
402 let (reg1, reg2) = reader.read_regs2()?;
403 Instruction::$name_reg_reg(reg1, reg2)
404 },)+
405 _ => return Err(ProgramParseError::unexpected_instruction(reader.position - 1))
406 })
407 }
408
409 pub mod asm {
410 use super::{Instruction, Reg};
411
412 $(
413 pub fn $name_argless() -> Instruction {
414 Instruction::$name_argless
415 }
416 )+
417
418 $(
419 pub fn $name_reg_imm(reg: Reg, imm: u32) -> Instruction {
420 Instruction::$name_reg_imm(reg, imm)
421 }
422 )+
423
424 $(
425 pub fn $name_reg_imm_imm(reg: Reg, imm1: u32, imm2: u32) -> Instruction {
426 Instruction::$name_reg_imm_imm(reg, imm1, imm2)
427 }
428 )+
429
430 $(
431 pub fn $name_reg_reg_imm(reg1: Reg, reg2: Reg, imm: u32) -> Instruction {
432 Instruction::$name_reg_reg_imm(reg1, reg2, imm)
433 }
434 )+
435
436 $(
437 pub fn $name_reg_reg_reg(reg1: Reg, reg2: Reg, reg3: Reg) -> Instruction {
438 Instruction::$name_reg_reg_reg(reg1, reg2, reg3)
439 }
440 )+
441
442 $(
443 pub fn $name_imm(imm: u32) -> Instruction {
444 Instruction::$name_imm(imm)
445 }
446 )+
447
448 $(
449 pub fn $name_imm_imm(imm1: u32, imm2: u32) -> Instruction {
450 Instruction::$name_imm_imm(imm1, imm2)
451 }
452 )+
453
454 $(
455 pub fn $name_reg_reg(reg1: Reg, reg2: Reg) -> Instruction {
456 Instruction::$name_reg_reg(reg1, reg2)
457 }
458 )+
459
460 pub fn ret() -> Instruction {
461 jump_indirect(Reg::RA, 0)
462 }
463 }
464
465 #[macro_export]
466 macro_rules! prepare_visitor {
467 ($table_name:ident, $visitor_ty:ident<$d($visitor_ty_params:tt),*>) => {{
468 use polkavm_common::program::{
469 InstructionVisitor,
470 VisitorHelper,
471 };
472
473 type ReturnTy<$d($visitor_ty_params),*> = <$visitor_ty<$d($visitor_ty_params),*> as InstructionVisitor>::ReturnTy;
474 type VisitFn<'_code, $d($visitor_ty_params),*> = fn(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>;
475
476 static $table_name: [VisitFn; 256] = {
477 let mut table = [VisitorHelper::unknown_opcode as VisitFn; 256];
478 $({
479 #[cfg_attr(target_os = "linux", link_section = concat!(".text.", stringify!($table_name)))]
484 fn $name_argless<'_code, $d($visitor_ty_params),*>(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>{
485 state.visitor.$name_argless()
486 }
487
488 table[$value_argless] = $name_argless;
489 })*
490
491 $({
492 #[cfg_attr(target_os = "linux", link_section = concat!(".text.", stringify!($table_name)))]
493 fn $name_reg_imm<'_code, $d($visitor_ty_params),*>(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>{
494 let (reg, imm) = state.read_args_reg_imm()?;
495 state.visitor.$name_reg_imm(reg, imm)
496 }
497
498 table[$value_reg_imm] = $name_reg_imm;
499 })*
500
501 $({
502 #[cfg_attr(target_os = "linux", link_section = concat!(".text.", stringify!($table_name)))]
503 fn $name_reg_imm_imm<'_code, $d($visitor_ty_params),*>(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>{
504 let (reg, imm1, imm2) = state.read_args_reg_imm2()?;
505 state.visitor.$name_reg_imm_imm(reg, imm1, imm2)
506 }
507
508 table[$value_reg_imm_imm] = $name_reg_imm_imm;
509 })*
510
511 $({
512 #[cfg_attr(target_os = "linux", link_section = concat!(".text.", stringify!($table_name)))]
513 fn $name_reg_reg_imm<'_code, $d($visitor_ty_params),*>(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>{
514 let (reg1, reg2, imm) = state.read_args_regs2_imm()?;
515 state.visitor.$name_reg_reg_imm(reg1, reg2, imm)
516 }
517
518 table[$value_reg_reg_imm] = $name_reg_reg_imm;
519 })*
520
521 $({
522 #[cfg_attr(target_os = "linux", link_section = concat!(".text.", stringify!($table_name)))]
523 fn $name_reg_reg_reg<'_code, $d($visitor_ty_params),*>(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>{
524 let (reg1, reg2, reg3) = state.read_args_regs3()?;
525 state.visitor.$name_reg_reg_reg(reg1, reg2, reg3)
526 }
527
528 table[$value_reg_reg_reg] = $name_reg_reg_reg;
529 })*
530
531 $({
532 #[cfg_attr(target_os = "linux", link_section = concat!(".text.", stringify!($table_name)))]
533 fn $name_imm<'_code, $d($visitor_ty_params),*>(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>{
534 let imm = state.read_args_imm()?;
535 state.visitor.$name_imm(imm)
536 }
537
538 table[$value_imm] = $name_imm;
539 })*
540
541 $({
542 #[cfg_attr(target_os = "linux", link_section = concat!(".text.", stringify!($table_name)))]
543 fn $name_imm_imm<'_code, $d($visitor_ty_params),*>(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>{
544 let (imm1, imm2) = state.read_args_imm2()?;
545 state.visitor.$name_imm_imm(imm1, imm2)
546 }
547
548 table[$value_imm_imm] = $name_imm_imm;
549 })*
550
551 $({
552 #[cfg_attr(target_os = "linux", link_section = concat!(".text.", stringify!($table_name)))]
553 fn $name_reg_reg<'_code, $d($visitor_ty_params),*>(state: &mut VisitorHelper<'_code, $visitor_ty<$d($visitor_ty_params),*>>) -> ReturnTy<$d($visitor_ty_params),*>{
554 let (reg1, reg2) = state.read_args_regs2()?;
555 state.visitor.$name_reg_reg(reg1, reg2)
556 }
557
558 table[$value_reg_reg] = $name_reg_reg;
559 })*
560
561 table
562 };
563
564 #[inline]
565 fn run<$d($visitor_ty_params),*>(
566 blob: &ProgramBlob,
567 visitor: $visitor_ty<$d($visitor_ty_params),*>,
568 )
569 -> ($visitor_ty<$d($visitor_ty_params),*>, <$visitor_ty<$d($visitor_ty_params),*> as InstructionVisitor>::ReturnTy)
570 {
571 let decode_table: &[VisitFn; 256] = &$table_name;
572 let decode_table: &[VisitFn; 256] = unsafe { core::mem::transmute(decode_table) };
574
575 VisitorHelper::run(blob, visitor, decode_table)
576 }
577
578 run
579 }};
580 }
581
582 pub use prepare_visitor;
583
584 define_opcodes!(
585 @impl_shared
586 $($name_argless = $value_argless,)+
587 $($name_reg_imm = $value_reg_imm,)+
588 $($name_reg_imm_imm = $value_reg_imm_imm,)+
589 $($name_reg_reg_imm = $value_reg_reg_imm,)+
590 $($name_reg_reg_reg = $value_reg_reg_reg,)+
591 $($name_imm = $value_imm,)+
592 $($name_imm_imm = $value_imm_imm,)+
593 $($name_reg_reg = $value_reg_reg,)+
594 );
595 }
596}
597
598define_opcodes! {
601 $
602
603 [
605 trap = 0,
606 fallthrough = 17,
607 ]
608
609 [
611 call = 6,
612 jump_indirect = 19,
613 load_imm = 4,
614 load_u8 = 60,
615 load_i8 = 74,
616 load_u16 = 76,
617 load_i16 = 66,
618 load_u32 = 10,
619 store_u8 = 71,
620 store_u16 = 69,
621 store_u32 = 22,
622 ]
623
624 [
626 branch_eq_imm = 7,
627 branch_not_eq_imm = 15,
628 branch_less_unsigned_imm = 44,
629 branch_less_signed_imm = 32,
630 branch_greater_or_equal_unsigned_imm = 52,
631 branch_greater_or_equal_signed_imm = 45,
632 branch_less_or_equal_signed_imm = 46,
633 branch_less_or_equal_unsigned_imm = 59,
634 branch_greater_signed_imm = 53,
635 branch_greater_unsigned_imm = 50,
636 store_imm_indirect_u8 = 26,
637 store_imm_indirect_u16 = 54,
638 store_imm_indirect_u32 = 13,
639 ]
640
641 [
643 store_indirect_u8 = 16,
644 store_indirect_u16 = 29,
645 store_indirect_u32 = 3,
646 load_indirect_u8 = 11,
647 load_indirect_i8 = 21,
648 load_indirect_u16 = 37,
649 load_indirect_i16 = 33,
650 load_indirect_u32 = 1,
651 call_indirect = 42,
652 add_imm = 2,
653 and_imm = 18,
654 xor_imm = 31,
655 or_imm = 49,
656 mul_imm = 35,
657 mul_upper_signed_signed_imm = 65,
658 mul_upper_unsigned_unsigned_imm = 63,
659 set_less_than_unsigned_imm = 27,
660 set_less_than_signed_imm = 56,
661 shift_logical_left_imm = 9,
662 shift_logical_right_imm = 14,
663 shift_arithmetic_right_imm = 25,
664 negate_and_add_imm = 40,
665 set_greater_than_unsigned_imm = 39,
666 set_greater_than_signed_imm = 61,
667 shift_logical_right_imm_alt = 72,
668 shift_arithmetic_right_imm_alt = 80,
669 shift_logical_left_imm_alt = 75,
670 branch_eq = 24,
671 branch_not_eq = 30,
672 branch_less_unsigned = 47,
673 branch_less_signed = 48,
674 branch_greater_or_equal_unsigned = 41,
675 branch_greater_or_equal_signed = 43,
676
677 cmov_if_zero_imm = 85,
678 cmov_if_not_zero_imm = 86,
679 ]
680
681 [
683 add = 8,
684 sub = 20,
685 and = 23,
686 xor = 28,
687 or = 12,
688 mul = 34,
689 mul_upper_signed_signed = 67,
690 mul_upper_unsigned_unsigned = 57,
691 mul_upper_signed_unsigned = 81,
692 set_less_than_unsigned = 36,
693 set_less_than_signed = 58,
694 shift_logical_left = 55,
695 shift_logical_right = 51,
696 shift_arithmetic_right = 77,
697 div_unsigned = 68,
698 div_signed = 64,
699 rem_unsigned = 73,
700 rem_signed = 70,
701
702 cmov_if_zero = 83,
703 cmov_if_not_zero = 84,
704 ]
705
706 [
708 jump = 5,
709 ecalli = 78,
710 ]
711
712 [
714 store_imm_u8 = 62,
715 store_imm_u16 = 79,
716 store_imm_u32 = 38,
717 ]
718
719 [
721 move_reg = 82,
722 sbrk = 87,
723 ]
724}
725
726impl Opcode {
727 pub fn starts_new_basic_block(self) -> bool {
728 matches!(
729 self,
730 Self::trap
731 | Self::fallthrough
732 | Self::jump
733 | Self::jump_indirect
734 | Self::call
735 | Self::call_indirect
736 | Self::branch_eq
737 | Self::branch_eq_imm
738 | Self::branch_greater_or_equal_signed
739 | Self::branch_greater_or_equal_signed_imm
740 | Self::branch_greater_or_equal_unsigned
741 | Self::branch_greater_or_equal_unsigned_imm
742 | Self::branch_greater_signed_imm
743 | Self::branch_greater_unsigned_imm
744 | Self::branch_less_or_equal_signed_imm
745 | Self::branch_less_or_equal_unsigned_imm
746 | Self::branch_less_signed
747 | Self::branch_less_signed_imm
748 | Self::branch_less_unsigned
749 | Self::branch_less_unsigned_imm
750 | Self::branch_not_eq
751 | Self::branch_not_eq_imm
752 )
753 }
754}
755
756impl Instruction {
757 pub fn deserialize(input: &[u8]) -> Option<(usize, Self)> {
758 let mut reader = Reader { blob: input, position: 0 };
759
760 let opcode = reader.read_byte().ok()?;
761 let instruction = parse_instruction_impl(opcode, &mut reader).ok()?;
762 Some((reader.position, instruction))
763 }
764
765 fn serialize_argless(buffer: &mut [u8], opcode: Opcode) -> usize {
766 buffer[0] = opcode as u8;
767 1
768 }
769
770 fn serialize_reg_imm_imm(buffer: &mut [u8], opcode: Opcode, reg: Reg, imm1: u32, imm2: u32) -> usize {
771 buffer[0] = opcode as u8;
772 buffer[1] = reg as u8;
773 let mut position = 2;
774 position += write_varint(imm1, &mut buffer[position..]);
775 position += write_varint(imm2, &mut buffer[position..]);
776 position
777 }
778
779 fn serialize_reg_reg_reg(buffer: &mut [u8], opcode: Opcode, reg1: Reg, reg2: Reg, reg3: Reg) -> usize {
780 buffer[0] = opcode as u8;
781 buffer[1] = reg1 as u8 | (reg2 as u8) << 4;
782 buffer[2] = reg3 as u8;
783 3
784 }
785
786 fn serialize_reg_reg_imm(buffer: &mut [u8], opcode: Opcode, reg1: Reg, reg2: Reg, imm: u32) -> usize {
787 buffer[0] = opcode as u8;
788 buffer[1] = reg1 as u8 | (reg2 as u8) << 4;
789 write_varint(imm, &mut buffer[2..]) + 2
790 }
791
792 fn serialize_reg_imm(buffer: &mut [u8], opcode: Opcode, reg: Reg, imm: u32) -> usize {
793 buffer[0] = opcode as u8;
794 buffer[1] = reg as u8;
795 write_varint(imm, &mut buffer[2..]) + 2
796 }
797
798 fn serialize_imm(buffer: &mut [u8], opcode: Opcode, imm: u32) -> usize {
799 buffer[0] = opcode as u8;
800 write_varint(imm, &mut buffer[1..]) + 1
801 }
802
803 fn serialize_imm_imm(buffer: &mut [u8], opcode: Opcode, imm1: u32, imm2: u32) -> usize {
804 buffer[0] = opcode as u8;
805 let mut position = 1;
806 position += write_varint(imm1, &mut buffer[position..]);
807 position += write_varint(imm2, &mut buffer[position..]);
808 position
809 }
810
811 fn serialize_reg_reg(buffer: &mut [u8], opcode: Opcode, reg1: Reg, reg2: Reg) -> usize {
812 buffer[0] = opcode as u8;
813 buffer[1] = reg1 as u8 | (reg2 as u8) << 4;
814 2
815 }
816}
817
818pub const MAX_INSTRUCTION_LENGTH: usize = 2 + MAX_VARINT_LENGTH * 2;
819
820impl<'a> InstructionVisitor for core::fmt::Formatter<'a> {
821 type ReturnTy = core::fmt::Result;
822
823 fn trap(&mut self) -> Self::ReturnTy {
824 write!(self, "trap")
825 }
826
827 fn fallthrough(&mut self) -> Self::ReturnTy {
828 write!(self, "@:")
829 }
830
831 fn sbrk(&mut self, d: Reg, s: Reg) -> Self::ReturnTy {
832 write!(self, "{d} = sbrk {s}")
833 }
834
835 fn ecalli(&mut self, nth_import: u32) -> Self::ReturnTy {
836 write!(self, "ecalli {nth_import}")
837 }
838
839 fn set_less_than_unsigned(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
840 write!(self, "{d} = {s1} <u {s2}")
841 }
842
843 fn set_less_than_signed(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
844 write!(self, "{d} = {s1} <s {s2}")
845 }
846
847 fn shift_logical_right(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
848 write!(self, "{d} = {s1} >> {s2}")
849 }
850
851 fn shift_arithmetic_right(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
852 write!(self, "{d} = {s1} >>a {s2}")
853 }
854
855 fn shift_logical_left(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
856 write!(self, "{d} = {s1} << {s2}")
857 }
858
859 fn xor(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
860 write!(self, "{d} = {s1} ^ {s2}")
861 }
862
863 fn and(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
864 write!(self, "{d} = {s1} & {s2}")
865 }
866
867 fn or(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
868 write!(self, "{d} = {s1} | {s2}")
869 }
870
871 fn add(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
872 write!(self, "{d} = {s1} + {s2}")
873 }
874
875 fn sub(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
876 write!(self, "{d} = {s1} - {s2}")
877 }
878
879 fn mul(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
880 write!(self, "{d} = {s1} * {s2}")
881 }
882
883 fn mul_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
884 write!(self, "{d} = {s1} * {s2}")
885 }
886
887 fn mul_upper_signed_signed(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
888 write!(self, "{d} = ({s1} as i64 * {s2} as i64) >> 32")
889 }
890
891 fn mul_upper_signed_signed_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
892 write!(self, "{d} = ({s1} as i64 * {s2} as i64) >> 32", s2 = s2 as i32)
893 }
894
895 fn mul_upper_unsigned_unsigned(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
896 write!(self, "{d} = ({s1} as u64 * {s2} as u64) >> 32")
897 }
898
899 fn mul_upper_unsigned_unsigned_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
900 write!(self, "{d} = ({s1} as u64 * {s2} as u64) >> 32")
901 }
902
903 fn mul_upper_signed_unsigned(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
904 write!(self, "{d} = ({s1} as i64 * {s2} as u64) >> 32")
905 }
906
907 fn div_unsigned(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
908 write!(self, "{d} = {s1} /u {s2}")
909 }
910
911 fn div_signed(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
912 write!(self, "{d} = {s1} /s {s2}")
913 }
914
915 fn rem_unsigned(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
916 write!(self, "{d} = {s1} %u {s2}")
917 }
918
919 fn rem_signed(&mut self, d: Reg, s1: Reg, s2: Reg) -> Self::ReturnTy {
920 write!(self, "{d} = {s1} %s {s2}")
921 }
922
923 fn set_less_than_unsigned_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
924 write!(self, "{d} = {s1} <u 0x{s2:x}")
925 }
926
927 fn set_greater_than_unsigned_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
928 write!(self, "{d} = {s1} >u 0x{s2:x}")
929 }
930
931 fn set_less_than_signed_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
932 write!(self, "{d} = {s1} <s {s2}", s2 = s2 as i32)
933 }
934
935 fn set_greater_than_signed_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
936 write!(self, "{d} = {s1} >s {s2}", s2 = s2 as i32)
937 }
938
939 fn shift_logical_right_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
940 write!(self, "{d} = {s1} >> {s2}")
941 }
942
943 fn shift_logical_right_imm_alt(&mut self, d: Reg, s2: Reg, s1: u32) -> Self::ReturnTy {
944 write!(self, "{d} = {s1} >> {s2}")
945 }
946
947 fn shift_arithmetic_right_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
948 write!(self, "{d} = {s1} >>a {s2}")
949 }
950
951 fn shift_arithmetic_right_imm_alt(&mut self, d: Reg, s2: Reg, s1: u32) -> Self::ReturnTy {
952 write!(self, "{d} = {s1} >>a {s2}")
953 }
954
955 fn shift_logical_left_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
956 write!(self, "{d} = {s1} << {s2}")
957 }
958
959 fn shift_logical_left_imm_alt(&mut self, d: Reg, s2: Reg, s1: u32) -> Self::ReturnTy {
960 write!(self, "{d} = {s1} << {s2}")
961 }
962
963 fn or_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
964 write!(self, "{d} = {s1} | 0x{s2:x}")
965 }
966
967 fn and_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
968 write!(self, "{d} = {s1} & 0x{s2:x}")
969 }
970
971 fn xor_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
972 write!(self, "{d} = {s1} ^ 0x{s2:x}")
973 }
974
975 fn load_imm(&mut self, d: Reg, a: u32) -> Self::ReturnTy {
976 write!(self, "{d} = 0x{a:x}")
977 }
978
979 fn move_reg(&mut self, d: Reg, s: Reg) -> Self::ReturnTy {
980 write!(self, "{d} = {s}")
981 }
982
983 fn cmov_if_zero(&mut self, d: Reg, s: Reg, c: Reg) -> Self::ReturnTy {
984 write!(self, "{d} = {s} if {c} == 0")
985 }
986
987 fn cmov_if_not_zero(&mut self, d: Reg, s: Reg, c: Reg) -> Self::ReturnTy {
988 write!(self, "{d} = {s} if {c} != 0")
989 }
990
991 fn cmov_if_zero_imm(&mut self, d: Reg, c: Reg, s: u32) -> Self::ReturnTy {
992 write!(self, "{d} = {s} if {c} == 0")
993 }
994
995 fn cmov_if_not_zero_imm(&mut self, d: Reg, c: Reg, s: u32) -> Self::ReturnTy {
996 write!(self, "{d} = {s} if {c} != 0")
997 }
998
999 fn add_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
1000 if (s2 as i32) < 0 && (s2 as i32) > -4096 {
1001 write!(self, "{d} = {s1} - {s2}", s2 = -(s2 as i32))
1002 } else {
1003 write!(self, "{d} = {s1} + 0x{s2:x}")
1004 }
1005 }
1006
1007 fn negate_and_add_imm(&mut self, d: Reg, s1: Reg, s2: u32) -> Self::ReturnTy {
1008 if s2 == 0 {
1009 write!(self, "{d} = -{s1}")
1010 } else {
1011 write!(self, "{d} = -{s1} + {s2}")
1012 }
1013 }
1014
1015 fn store_imm_indirect_u8(&mut self, base: Reg, offset: u32, value: u32) -> Self::ReturnTy {
1016 write!(self, "u8 [{base} + {offset}] = {value}")
1017 }
1018
1019 fn store_imm_indirect_u16(&mut self, base: Reg, offset: u32, value: u32) -> Self::ReturnTy {
1020 write!(self, "u16 [{base} + {offset}] = {value}")
1021 }
1022
1023 fn store_imm_indirect_u32(&mut self, base: Reg, offset: u32, value: u32) -> Self::ReturnTy {
1024 write!(self, "u32 [{base} + {offset}] = {value}")
1025 }
1026
1027 fn store_indirect_u8(&mut self, src: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1028 if offset != 0 {
1029 write!(self, "u8 [{base} + {offset}] = {src}")
1030 } else {
1031 write!(self, "u8 [{base}] = {src}")
1032 }
1033 }
1034
1035 fn store_indirect_u16(&mut self, src: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1036 if offset != 0 {
1037 write!(self, "u16 [{base} + {offset}] = {src}")
1038 } else {
1039 write!(self, "u16 [{base}] = {src}")
1040 }
1041 }
1042
1043 fn store_indirect_u32(&mut self, src: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1044 if offset != 0 {
1045 write!(self, "u32 [{base} + {offset}] = {src}")
1046 } else {
1047 write!(self, "u32 [{base}] = {src}")
1048 }
1049 }
1050
1051 fn store_imm_u8(&mut self, value: u32, offset: u32) -> Self::ReturnTy {
1052 write!(self, "u8 [0x{offset:x}] = {value}")
1053 }
1054
1055 fn store_imm_u16(&mut self, value: u32, offset: u32) -> Self::ReturnTy {
1056 write!(self, "u16 [0x{offset:x}] = {value}")
1057 }
1058
1059 fn store_imm_u32(&mut self, value: u32, offset: u32) -> Self::ReturnTy {
1060 write!(self, "u32 [0x{offset:x}] = {value}")
1061 }
1062
1063 fn store_u8(&mut self, src: Reg, offset: u32) -> Self::ReturnTy {
1064 write!(self, "u8 [0x{offset:x}] = {src}")
1065 }
1066
1067 fn store_u16(&mut self, src: Reg, offset: u32) -> Self::ReturnTy {
1068 write!(self, "u16 [0x{offset:x}] = {src}")
1069 }
1070
1071 fn store_u32(&mut self, src: Reg, offset: u32) -> Self::ReturnTy {
1072 write!(self, "u32 [0x{offset:x}] = {src}")
1073 }
1074
1075 fn load_indirect_u8(&mut self, dst: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1076 if offset != 0 {
1077 write!(self, "{} = u8 [{} + {}]", dst, base, offset)
1078 } else {
1079 write!(self, "{} = u8 [{}]", dst, base)
1080 }
1081 }
1082
1083 fn load_indirect_i8(&mut self, dst: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1084 if offset != 0 {
1085 write!(self, "{} = i8 [{} + {}]", dst, base, offset)
1086 } else {
1087 write!(self, "{} = i8 [{}]", dst, base)
1088 }
1089 }
1090
1091 fn load_indirect_u16(&mut self, dst: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1092 if offset != 0 {
1093 write!(self, "{} = u16 [{} + {}]", dst, base, offset)
1094 } else {
1095 write!(self, "{} = u16 [{} ]", dst, base)
1096 }
1097 }
1098
1099 fn load_indirect_i16(&mut self, dst: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1100 if offset != 0 {
1101 write!(self, "{} = i16 [{} + {}]", dst, base, offset)
1102 } else {
1103 write!(self, "{} = i16 [{}]", dst, base)
1104 }
1105 }
1106
1107 fn load_indirect_u32(&mut self, dst: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1108 if offset != 0 {
1109 write!(self, "{} = u32 [{} + {}]", dst, base, offset)
1110 } else {
1111 write!(self, "{} = u32 [{}]", dst, base)
1112 }
1113 }
1114
1115 fn load_u8(&mut self, dst: Reg, offset: u32) -> Self::ReturnTy {
1116 write!(self, "{} = u8 [0x{:x}]", dst, offset)
1117 }
1118
1119 fn load_i8(&mut self, dst: Reg, offset: u32) -> Self::ReturnTy {
1120 write!(self, "{} = i8 [0x{:x}]", dst, offset)
1121 }
1122
1123 fn load_u16(&mut self, dst: Reg, offset: u32) -> Self::ReturnTy {
1124 write!(self, "{} = u16 [0x{:x}]", dst, offset)
1125 }
1126
1127 fn load_i16(&mut self, dst: Reg, offset: u32) -> Self::ReturnTy {
1128 write!(self, "{} = i16 [0x{:x}]", dst, offset)
1129 }
1130
1131 fn load_u32(&mut self, dst: Reg, offset: u32) -> Self::ReturnTy {
1132 write!(self, "{} = u32 [0x{:x}]", dst, offset)
1133 }
1134
1135 fn branch_less_unsigned(&mut self, s1: Reg, s2: Reg, imm: u32) -> Self::ReturnTy {
1136 write!(self, "if {} <u {}: jump @{:x}", s1, s2, imm)
1137 }
1138
1139 fn branch_less_signed(&mut self, s1: Reg, s2: Reg, imm: u32) -> Self::ReturnTy {
1140 write!(self, "if {} <s {}: jump @{:x}", s1, s2, imm)
1141 }
1142
1143 fn branch_less_unsigned_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1144 write!(self, "if {} <u {}: jump @{:x}", s1, s2, imm)
1145 }
1146
1147 fn branch_less_signed_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1148 write!(self, "if {} <s {}: jump @{:x}", s1, s2, imm)
1149 }
1150
1151 fn branch_greater_or_equal_unsigned(&mut self, s1: Reg, s2: Reg, imm: u32) -> Self::ReturnTy {
1152 write!(self, "if {} >=u {}: jump @{:x}", s1, s2, imm)
1153 }
1154
1155 fn branch_greater_or_equal_signed(&mut self, s1: Reg, s2: Reg, imm: u32) -> Self::ReturnTy {
1156 write!(self, "if {} >=s {}: jump @{:x}", s1, s2, imm)
1157 }
1158
1159 fn branch_greater_or_equal_unsigned_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1160 write!(self, "if {} >=u {}: jump @{:x}", s1, s2, imm)
1161 }
1162
1163 fn branch_greater_or_equal_signed_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1164 write!(self, "if {} >=s {}: jump @{:x}", s1, s2, imm)
1165 }
1166
1167 fn branch_eq(&mut self, s1: Reg, s2: Reg, imm: u32) -> Self::ReturnTy {
1168 write!(self, "if {} == {}: jump @{:x}", s1, s2, imm)
1169 }
1170
1171 fn branch_not_eq(&mut self, s1: Reg, s2: Reg, imm: u32) -> Self::ReturnTy {
1172 write!(self, "if {} != {}: jump @{:x}", s1, s2, imm)
1173 }
1174
1175 fn branch_eq_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1176 write!(self, "if {} == {}: jump @{:x}", s1, s2, imm)
1177 }
1178
1179 fn branch_not_eq_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1180 write!(self, "if {} != {}: jump @{:x}", s1, s2, imm)
1181 }
1182
1183 fn branch_less_or_equal_unsigned_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1184 write!(self, "if {} <=u {}: jump @{:x}", s1, s2, imm)
1185 }
1186
1187 fn branch_less_or_equal_signed_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1188 write!(self, "if {} <=s {}: jump @{:x}", s1, s2, imm)
1189 }
1190
1191 fn branch_greater_unsigned_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1192 write!(self, "if {} >u {}: jump @{:x}", s1, s2, imm)
1193 }
1194
1195 fn branch_greater_signed_imm(&mut self, s1: Reg, s2: u32, imm: u32) -> Self::ReturnTy {
1196 write!(self, "if {} >s {}: jump @{:x}", s1, s2, imm)
1197 }
1198
1199 fn jump(&mut self, target: u32) -> Self::ReturnTy {
1200 write!(self, "jump @{:x}", target)
1201 }
1202
1203 fn call(&mut self, ra: Reg, target: u32) -> Self::ReturnTy {
1204 match ra {
1205 Reg::RA => write!(self, "call @{:x}", target),
1206 _ => write!(self, "call @{:x}, {}", target, ra),
1207 }
1208 }
1209
1210 fn jump_indirect(&mut self, base: Reg, offset: u32) -> Self::ReturnTy {
1211 use Reg::*;
1212 match (base, offset) {
1213 (RA, 0) => write!(self, "ret"),
1214 (_, 0) => write!(self, "jump [{}]", base),
1215 (_, _) => write!(self, "jump [{} + {}]", base, offset),
1216 }
1217 }
1218
1219 fn call_indirect(&mut self, ra: Reg, base: Reg, offset: u32) -> Self::ReturnTy {
1220 use Reg::*;
1221 match (ra, base, offset) {
1222 (RA, _, 0) => write!(self, "call [{}]", base),
1223 (RA, _, _) => write!(self, "call [{} + {}]", base, offset),
1224 (_, _, 0) => write!(self, "call [{}], {}", base, ra),
1225 (_, _, _) => write!(self, "call [{} + {}], {}", base, offset, ra),
1226 }
1227 }
1228}
1229
1230#[derive(Debug)]
1231pub struct ProgramParseError(ProgramParseErrorKind);
1232
1233#[derive(Debug)]
1234enum ProgramParseErrorKind {
1235 FailedToReadVarint {
1236 offset: usize,
1237 },
1238 FailedToReadStringNonUtf {
1239 offset: usize,
1240 },
1241 FailedToReadInstructionArguments {
1242 offset: usize,
1243 },
1244 UnexpectedSection {
1245 offset: usize,
1246 section: u8,
1247 },
1248 UnexpectedInstruction {
1249 offset: usize,
1250 },
1251 UnexpectedEnd {
1252 offset: usize,
1253 expected_count: usize,
1254 actual_count: usize,
1255 },
1256 UnsupportedVersion {
1257 version: u8,
1258 },
1259 Other(&'static str),
1260}
1261
1262impl ProgramParseError {
1263 #[cold]
1264 #[inline]
1265 fn unexpected_instruction(offset: usize) -> ProgramParseError {
1266 ProgramParseError(ProgramParseErrorKind::UnexpectedInstruction { offset })
1267 }
1268
1269 #[cold]
1270 #[inline]
1271 fn failed_to_read_instruction_arguments(offset: usize) -> ProgramParseError {
1272 ProgramParseError(ProgramParseErrorKind::FailedToReadInstructionArguments { offset })
1273 }
1274
1275 #[cold]
1276 #[inline]
1277 fn failed_to_read_varint(offset: usize) -> ProgramParseError {
1278 ProgramParseError(ProgramParseErrorKind::FailedToReadVarint { offset })
1279 }
1280
1281 #[cold]
1282 #[inline]
1283 fn unexpected_end_of_file(offset: usize, expected_count: usize, actual_count: usize) -> ProgramParseError {
1284 ProgramParseError(ProgramParseErrorKind::UnexpectedEnd {
1285 offset,
1286 expected_count,
1287 actual_count,
1288 })
1289 }
1290}
1291
1292impl core::fmt::Display for ProgramParseError {
1293 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
1294 match self.0 {
1295 ProgramParseErrorKind::FailedToReadVarint { offset } => {
1296 write!(
1297 fmt,
1298 "failed to parse program blob: failed to parse a varint at offset 0x{:x}",
1299 offset
1300 )
1301 }
1302 ProgramParseErrorKind::FailedToReadStringNonUtf { offset } => {
1303 write!(
1304 fmt,
1305 "failed to parse program blob: failed to parse a string at offset 0x{:x} (not valid UTF-8)",
1306 offset
1307 )
1308 }
1309 ProgramParseErrorKind::FailedToReadInstructionArguments { offset } => {
1310 write!(
1311 fmt,
1312 "failed to parse program blob: failed to parse instruction arguments at offset 0x{:x}",
1313 offset
1314 )
1315 }
1316 ProgramParseErrorKind::UnexpectedSection { offset, section } => {
1317 write!(
1318 fmt,
1319 "failed to parse program blob: found unexpected section as offset 0x{:x}: 0x{:x}",
1320 offset, section
1321 )
1322 }
1323 ProgramParseErrorKind::UnexpectedInstruction { offset } => {
1324 write!(
1325 fmt,
1326 "failed to parse program blob: failed to parse instruction at offset 0x{:x}",
1327 offset
1328 )
1329 }
1330 ProgramParseErrorKind::UnexpectedEnd {
1331 offset,
1332 expected_count,
1333 actual_count,
1334 } => {
1335 write!(fmt, "failed to parse program blob: unexpected end of file at offset 0x{:x}: expected to be able to read at least {} bytes, found {} bytes", offset, expected_count, actual_count)
1336 }
1337 ProgramParseErrorKind::UnsupportedVersion { version } => {
1338 write!(fmt, "failed to parse program blob: unsupported version: {}", version)
1339 }
1340 ProgramParseErrorKind::Other(error) => {
1341 write!(fmt, "failed to parse program blob: {}", error)
1342 }
1343 }
1344 }
1345}
1346
1347#[cfg(feature = "std")]
1348impl std::error::Error for ProgramParseError {}
1349
1350#[derive(Clone, PartialEq, Eq, Debug)]
1351pub struct ProgramExport<'a> {
1352 jump_target: u32,
1353 symbol: ProgramSymbol<'a>,
1354}
1355
1356impl<'a> ProgramExport<'a> {
1357 pub fn new(jump_target: u32, symbol: ProgramSymbol<'a>) -> Self {
1358 Self { jump_target, symbol }
1359 }
1360
1361 pub fn jump_target(&self) -> u32 {
1362 self.jump_target
1363 }
1364
1365 pub fn symbol(&self) -> &ProgramSymbol<'a> {
1366 &self.symbol
1367 }
1368
1369 #[cfg(feature = "alloc")]
1370 pub fn into_owned(self) -> ProgramExport<'static> {
1371 ProgramExport {
1372 jump_target: self.jump_target,
1373 symbol: self.symbol.into_owned(),
1374 }
1375 }
1376}
1377
1378#[derive(Clone, PartialEq, Eq, Debug)]
1379pub struct ProgramImport<'a> {
1380 symbol: ProgramSymbol<'a>,
1381}
1382
1383impl<'a> ProgramImport<'a> {
1384 pub fn new(symbol: ProgramSymbol<'a>) -> Self {
1385 Self { symbol }
1386 }
1387
1388 pub fn symbol(&self) -> &ProgramSymbol<'a> {
1389 &self.symbol
1390 }
1391
1392 #[cfg(feature = "alloc")]
1393 pub fn into_owned(self) -> ProgramImport<'static> {
1394 ProgramImport {
1395 symbol: self.symbol.into_owned(),
1396 }
1397 }
1398}
1399
1400#[derive(Clone, PartialEq, Eq, Debug)]
1401pub struct ProgramSymbol<'a>(CowBytes<'a>);
1402
1403impl<'a> ProgramSymbol<'a> {
1404 pub fn new(bytes: CowBytes<'a>) -> Self {
1405 Self(bytes)
1406 }
1407
1408 pub fn into_inner(self) -> CowBytes<'a> {
1409 self.0
1410 }
1411
1412 #[cfg(feature = "alloc")]
1413 pub fn into_owned(self) -> ProgramSymbol<'static> {
1414 ProgramSymbol(self.0.into_owned())
1415 }
1416}
1417
1418impl<'a> From<&'a [u8]> for ProgramSymbol<'a> {
1419 fn from(symbol: &'a [u8]) -> Self {
1420 ProgramSymbol(symbol.into())
1421 }
1422}
1423
1424impl<'a> From<&'a str> for ProgramSymbol<'a> {
1425 fn from(symbol: &'a str) -> Self {
1426 ProgramSymbol(symbol.into())
1427 }
1428}
1429
1430#[cfg(feature = "alloc")]
1431impl<'a> From<alloc::vec::Vec<u8>> for ProgramSymbol<'a> {
1432 fn from(symbol: alloc::vec::Vec<u8>) -> Self {
1433 ProgramSymbol(symbol.into())
1434 }
1435}
1436
1437impl<'a> core::ops::Deref for ProgramSymbol<'a> {
1438 type Target = CowBytes<'a>;
1439
1440 fn deref(&self) -> &Self::Target {
1441 &self.0
1442 }
1443}
1444
1445impl<'a> core::fmt::Display for ProgramSymbol<'a> {
1446 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
1447 if let Ok(ident) = core::str::from_utf8(&self.0) {
1448 fmt.write_str("'")?;
1449 fmt.write_str(ident)?;
1450 fmt.write_str("'")?;
1451 } else {
1452 fmt.write_str("0x")?;
1453 for &byte in self.0.iter() {
1454 core::write!(fmt, "{:02x}", byte)?;
1455 }
1456 }
1457
1458 Ok(())
1459 }
1460}
1461
1462#[derive(Clone, Default)]
1464pub struct ProgramBlob<'a> {
1465 blob: CowBytes<'a>,
1466
1467 ro_data_size: u32,
1468 rw_data_size: u32,
1469 stack_size: u32,
1470
1471 ro_data: Range<usize>,
1472 rw_data: Range<usize>,
1473 exports: Range<usize>,
1474 imports: Range<usize>,
1475 code: Range<usize>,
1476 jump_table: Range<usize>,
1477
1478 debug_strings: Range<usize>,
1479 debug_line_program_ranges: Range<usize>,
1480 debug_line_programs: Range<usize>,
1481
1482 instruction_count: u32,
1483 basic_block_count: u32,
1484}
1485
1486#[derive(Clone)]
1487struct Reader<'a> {
1488 blob: &'a [u8],
1489 position: usize,
1490}
1491
1492impl<'a> Reader<'a> {
1493 fn skip(&mut self, count: usize) -> Result<(), ProgramParseError> {
1494 self.read_slice_as_range(count).map(|_| ())
1495 }
1496
1497 fn finish(&mut self) {
1498 self.position += self.blob.len();
1499 self.blob = b"";
1500 }
1501
1502 #[inline(always)]
1503 fn read_byte(&mut self) -> Result<u8, ProgramParseError> {
1504 Ok(self.read_slice(1)?[0])
1505 }
1506
1507 #[inline(always)]
1508 fn read_slice(&mut self, length: usize) -> Result<&'a [u8], ProgramParseError> {
1509 let Some(slice) = self.blob.get(..length) else {
1510 return Err(ProgramParseError::unexpected_end_of_file(self.position, length, self.blob.len()));
1511 };
1512
1513 self.position += length;
1514 self.blob = &self.blob[length..];
1515 Ok(slice)
1516 }
1517
1518 #[inline(always)]
1519 fn read_varint(&mut self) -> Result<u32, ProgramParseError> {
1520 let first_byte = self.read_byte()?;
1521 let Some((length, value)) = read_varint(self.blob, first_byte) else {
1522 return Err(ProgramParseError::failed_to_read_varint(self.position - 1));
1523 };
1524
1525 self.position += length;
1526 self.blob = &self.blob[length..];
1527 Ok(value)
1528 }
1529
1530 #[inline(always)]
1531 fn read_regs3(&mut self) -> Result<(Reg, Reg, Reg), ProgramParseError> {
1532 let data = self.read_slice(2)?;
1533 let reg1 = data[0] & 0b1111;
1534 let reg2 = data[0] >> 4;
1535 let reg3 = data[1];
1536 if let Some(reg1) = Reg::from_u8(reg1) {
1537 if let Some(reg2) = Reg::from_u8(reg2) {
1538 if let Some(reg3) = Reg::from_u8(reg3) {
1539 return Ok((reg1, reg2, reg3));
1540 }
1541 }
1542 }
1543
1544 Err(ProgramParseError::failed_to_read_instruction_arguments(self.position - 2))
1545 }
1546
1547 #[inline(always)]
1548 fn read_reg(&mut self) -> Result<Reg, ProgramParseError> {
1549 let reg = self.read_byte()?;
1550 if let Some(reg) = Reg::from_u8(reg) {
1551 return Ok(reg);
1552 }
1553
1554 Err(ProgramParseError::failed_to_read_instruction_arguments(self.position - 1))
1555 }
1556
1557 #[inline(always)]
1558 fn read_regs2(&mut self) -> Result<(Reg, Reg), ProgramParseError> {
1559 let regs = self.read_byte()?;
1560 let reg1 = regs & 0b1111;
1561 let reg2 = regs >> 4;
1562 if let Some(reg1) = Reg::from_u8(reg1) {
1563 if let Some(reg2) = Reg::from_u8(reg2) {
1564 return Ok((reg1, reg2));
1565 }
1566 }
1567
1568 Err(ProgramParseError::failed_to_read_instruction_arguments(self.position - 1))
1569 }
1570
1571 fn read_bytes_with_length(&mut self) -> Result<&'a [u8], ProgramParseError> {
1572 let length = self.read_varint()? as usize;
1573 self.read_slice(length)
1574 }
1575
1576 fn read_string_with_length(&mut self) -> Result<&'a str, ProgramParseError> {
1577 let offset = self.position;
1578 let slice = self.read_bytes_with_length()?;
1579
1580 core::str::from_utf8(slice)
1581 .ok()
1582 .ok_or(ProgramParseError(ProgramParseErrorKind::FailedToReadStringNonUtf { offset }))
1583 }
1584
1585 fn read_slice_as_range(&mut self, count: usize) -> Result<Range<usize>, ProgramParseError> {
1586 if self.blob.len() < count {
1587 return Err(ProgramParseError::unexpected_end_of_file(self.position, count, self.blob.len()));
1588 };
1589
1590 let range = self.position..self.position + count;
1591 self.position += count;
1592 self.blob = &self.blob[count..];
1593 Ok(range)
1594 }
1595
1596 fn is_eof(&self) -> bool {
1597 self.blob.is_empty()
1598 }
1599
1600 fn read_section_range_into(
1601 &mut self,
1602 out_section: &mut u8,
1603 out_range: &mut Range<usize>,
1604 expected_section: u8,
1605 ) -> Result<(), ProgramParseError> {
1606 if *out_section == expected_section {
1607 let section_length = self.read_varint()? as usize;
1608 *out_range = self.read_slice_as_range(section_length)?;
1609 *out_section = self.read_byte()?;
1610 }
1611
1612 Ok(())
1613 }
1614}
1615
1616impl<'a> ProgramBlob<'a> {
1617 pub fn parse(bytes: impl Into<CowBytes<'a>>) -> Result<Self, ProgramParseError> {
1619 Self::parse_impl(bytes.into())
1620 }
1621
1622 pub fn as_bytes(&self) -> &[u8] {
1624 &self.blob
1625 }
1626
1627 #[inline(never)]
1628 fn parse_impl(blob: CowBytes<'a>) -> Result<Self, ProgramParseError> {
1629 if !blob.starts_with(&BLOB_MAGIC) {
1630 return Err(ProgramParseError(ProgramParseErrorKind::Other(
1631 "blob doesn't start with the expected magic bytes",
1632 )));
1633 }
1634
1635 let mut program = ProgramBlob {
1636 blob,
1637 ..ProgramBlob::default()
1638 };
1639
1640 let mut reader = Reader {
1641 blob: &program.blob[BLOB_MAGIC.len()..],
1642 position: BLOB_MAGIC.len(),
1643 };
1644
1645 let blob_version = reader.read_byte()?;
1646 if blob_version != BLOB_VERSION_V1 {
1647 return Err(ProgramParseError(ProgramParseErrorKind::UnsupportedVersion {
1648 version: blob_version,
1649 }));
1650 }
1651
1652 let mut section = reader.read_byte()?;
1653 if section == SECTION_MEMORY_CONFIG {
1654 let section_length = reader.read_varint()?;
1655 let position = reader.position;
1656 program.ro_data_size = reader.read_varint()?;
1657 program.rw_data_size = reader.read_varint()?;
1658 program.stack_size = reader.read_varint()?;
1659 if position + section_length as usize != reader.position {
1660 return Err(ProgramParseError(ProgramParseErrorKind::Other(
1661 "the memory config section contains more data than expected",
1662 )));
1663 }
1664 section = reader.read_byte()?;
1665 }
1666
1667 reader.read_section_range_into(&mut section, &mut program.ro_data, SECTION_RO_DATA)?;
1668 reader.read_section_range_into(&mut section, &mut program.rw_data, SECTION_RW_DATA)?;
1669 reader.read_section_range_into(&mut section, &mut program.imports, SECTION_IMPORTS)?;
1670 reader.read_section_range_into(&mut section, &mut program.exports, SECTION_EXPORTS)?;
1671 reader.read_section_range_into(&mut section, &mut program.jump_table, SECTION_JUMP_TABLE)?;
1672
1673 if program.ro_data.len() > program.ro_data_size as usize {
1674 return Err(ProgramParseError(ProgramParseErrorKind::Other(
1675 "size of the read-only data payload exceeds the declared size of the section",
1676 )));
1677 }
1678
1679 if program.rw_data.len() > program.rw_data_size as usize {
1680 return Err(ProgramParseError(ProgramParseErrorKind::Other(
1681 "size of the read-write data payload exceeds the declared size of the section",
1682 )));
1683 }
1684
1685 if section == SECTION_CODE {
1686 let section_length = reader.read_varint()?;
1687 let initial_position = reader.position;
1688 let instruction_count = reader.read_varint()?;
1689 let basic_block_count = reader.read_varint()?;
1690 let header_size = (reader.position - initial_position) as u32;
1691 if section_length < header_size {
1692 return Err(ProgramParseError(ProgramParseErrorKind::Other("the code section is too short")));
1693 }
1694
1695 let body_length = section_length - header_size;
1696 if instruction_count > body_length {
1697 return Err(ProgramParseError(ProgramParseErrorKind::Other("invalid instruction count")));
1698 }
1699
1700 if basic_block_count > body_length {
1701 return Err(ProgramParseError(ProgramParseErrorKind::Other("invalid basic block count")));
1702 }
1703
1704 program.instruction_count = instruction_count;
1705 program.basic_block_count = basic_block_count;
1706 program.code = reader.read_slice_as_range(body_length as usize)?;
1707 section = reader.read_byte()?;
1708 }
1709
1710 reader.read_section_range_into(&mut section, &mut program.debug_strings, SECTION_OPT_DEBUG_STRINGS)?;
1711 reader.read_section_range_into(&mut section, &mut program.debug_line_programs, SECTION_OPT_DEBUG_LINE_PROGRAMS)?;
1712 reader.read_section_range_into(
1713 &mut section,
1714 &mut program.debug_line_program_ranges,
1715 SECTION_OPT_DEBUG_LINE_PROGRAM_RANGES,
1716 )?;
1717
1718 while (section & 0b10000000) != 0 {
1719 #[cfg(feature = "logging")]
1721 log::debug!("Skipping unsupported optional section: {}", section);
1722 let section_length = reader.read_varint()?;
1723 reader.skip(section_length as usize)?;
1724 section = reader.read_byte()?;
1725 }
1726
1727 if section == SECTION_END_OF_FILE {
1728 return Ok(program);
1729 }
1730
1731 Err(ProgramParseError(ProgramParseErrorKind::UnexpectedSection {
1732 offset: reader.position - 1,
1733 section,
1734 }))
1735 }
1736
1737 pub fn ro_data(&self) -> &[u8] {
1741 &self.blob[self.ro_data.clone()]
1742 }
1743
1744 pub fn ro_data_size(&self) -> u32 {
1748 self.ro_data_size
1749 }
1750
1751 pub fn rw_data(&self) -> &[u8] {
1755 &self.blob[self.rw_data.clone()]
1756 }
1757
1758 pub fn rw_data_size(&self) -> u32 {
1762 self.rw_data_size
1763 }
1764
1765 pub fn stack_size(&self) -> u32 {
1767 self.stack_size
1768 }
1769
1770 pub fn code(&self) -> &[u8] {
1772 &self.blob[self.code.clone()]
1773 }
1774
1775 pub fn instruction_count(&self) -> u32 {
1781 self.instruction_count
1782 }
1783
1784 pub fn basic_block_count(&self) -> u32 {
1790 self.basic_block_count
1791 }
1792
1793 fn get_section_reader(&self, range: Range<usize>) -> Reader {
1794 Reader {
1795 blob: &self.blob[range.start..range.end],
1796 position: range.start,
1797 }
1798 }
1799
1800 pub fn imports(&'_ self) -> impl Iterator<Item = Result<ProgramImport, ProgramParseError>> + Clone + '_ {
1802 #[derive(Clone)]
1803 enum State {
1804 Uninitialized,
1805 Pending(u32),
1806 Finished,
1807 }
1808
1809 #[derive(Clone)]
1810 struct ImportIterator<'a> {
1811 state: State,
1812 reader: Reader<'a>,
1813 }
1814
1815 impl<'a> ImportIterator<'a> {
1816 fn read_next(&mut self) -> Result<Option<ProgramImport<'a>>, ProgramParseError> {
1817 let remaining = match core::mem::replace(&mut self.state, State::Finished) {
1818 State::Uninitialized => self.reader.read_varint()?,
1819 State::Pending(remaining) => remaining,
1820 State::Finished => return Ok(None),
1821 };
1822
1823 if remaining == 0 {
1824 if !self.reader.is_eof() {
1825 return Err(ProgramParseError(ProgramParseErrorKind::Other(
1826 "the import section contains more data than expected",
1827 )));
1828 }
1829
1830 return Ok(None);
1831 }
1832
1833 let symbol = self.reader.read_bytes_with_length()?;
1834 let import = ProgramImport { symbol: symbol.into() };
1835
1836 self.state = State::Pending(remaining - 1);
1837 Ok(Some(import))
1838 }
1839 }
1840
1841 impl<'a> Iterator for ImportIterator<'a> {
1842 type Item = Result<ProgramImport<'a>, ProgramParseError>;
1843 fn next(&mut self) -> Option<Self::Item> {
1844 self.read_next().transpose()
1845 }
1846 }
1847
1848 ImportIterator {
1849 state: if self.imports != (0_usize..0_usize) {
1850 State::Uninitialized
1851 } else {
1852 State::Finished
1853 },
1854 reader: self.get_section_reader(self.imports.clone()),
1855 }
1856 }
1857
1858 pub fn exports(&'_ self) -> impl Iterator<Item = Result<ProgramExport, ProgramParseError>> + Clone + '_ {
1860 #[derive(Clone)]
1861 enum State {
1862 Uninitialized,
1863 Pending(u32),
1864 Finished,
1865 }
1866
1867 #[derive(Clone)]
1868 struct ExportIterator<'a> {
1869 state: State,
1870 reader: Reader<'a>,
1871 }
1872
1873 impl<'a> ExportIterator<'a> {
1874 fn read_next(&mut self) -> Result<Option<ProgramExport<'a>>, ProgramParseError> {
1875 let remaining = match core::mem::replace(&mut self.state, State::Finished) {
1876 State::Uninitialized => self.reader.read_varint()?,
1877 State::Pending(remaining) => remaining,
1878 State::Finished => return Ok(None),
1879 };
1880
1881 if remaining == 0 {
1882 if !self.reader.is_eof() {
1883 return Err(ProgramParseError(ProgramParseErrorKind::Other(
1884 "the export section contains more data than expected",
1885 )));
1886 }
1887
1888 return Ok(None);
1889 }
1890
1891 let jump_target = self.reader.read_varint()?;
1892 let symbol = self.reader.read_bytes_with_length()?;
1893 let export = ProgramExport {
1894 jump_target,
1895 symbol: symbol.into(),
1896 };
1897
1898 self.state = State::Pending(remaining - 1);
1899 Ok(Some(export))
1900 }
1901 }
1902
1903 impl<'a> Iterator for ExportIterator<'a> {
1904 type Item = Result<ProgramExport<'a>, ProgramParseError>;
1905 fn next(&mut self) -> Option<Self::Item> {
1906 self.read_next().transpose()
1907 }
1908 }
1909
1910 ExportIterator {
1911 state: if self.exports != (0_usize..0_usize) {
1912 State::Uninitialized
1913 } else {
1914 State::Finished
1915 },
1916 reader: self.get_section_reader(self.exports.clone()),
1917 }
1918 }
1919
1920 pub fn instructions(&'_ self) -> impl Iterator<Item = Result<Instruction, ProgramParseError>> + Clone + '_ {
1922 #[derive(Clone)]
1923 struct CodeIterator<'a> {
1924 reader: Reader<'a>,
1925 }
1926
1927 impl<'a> Iterator for CodeIterator<'a> {
1928 type Item = Result<Instruction, ProgramParseError>;
1929 fn next(&mut self) -> Option<Self::Item> {
1930 if self.reader.is_eof() {
1931 return None;
1932 }
1933
1934 let result = (|| -> Result<Instruction, ProgramParseError> {
1935 let opcode = self.reader.read_byte()?;
1936 parse_instruction_impl(opcode, &mut self.reader)
1937 })();
1938
1939 if result.is_err() {
1940 self.reader.finish();
1941 }
1942
1943 Some(result)
1944 }
1945 }
1946
1947 CodeIterator {
1948 reader: self.get_section_reader(self.code.clone()),
1949 }
1950 }
1951
1952 pub fn jump_table_upper_bound(&self) -> usize {
1954 self.jump_table.len()
1955 }
1956
1957 pub fn jump_table(&'_ self) -> impl Iterator<Item = Result<u32, ProgramParseError>> + Clone + '_ {
1959 #[derive(Clone)]
1960 struct JumpTableIterator<'a> {
1961 reader: Reader<'a>,
1962 }
1963
1964 impl<'a> Iterator for JumpTableIterator<'a> {
1965 type Item = Result<u32, ProgramParseError>;
1966 fn next(&mut self) -> Option<Self::Item> {
1967 if self.reader.is_eof() {
1968 return None;
1969 }
1970
1971 Some(self.reader.read_varint())
1972 }
1973 }
1974
1975 JumpTableIterator {
1976 reader: self.get_section_reader(self.jump_table.clone()),
1977 }
1978 }
1979
1980 pub fn get_debug_string(&self, offset: u32) -> Result<&str, ProgramParseError> {
1982 let mut reader = self.get_section_reader(self.debug_strings.clone());
1983 reader.skip(offset as usize)?;
1984 reader.read_string_with_length()
1985 }
1986
1987 pub fn get_debug_line_program_at(&self, nth_instruction: u32) -> Result<Option<LineProgram>, ProgramParseError> {
1989 if self.debug_line_program_ranges.is_empty() || self.debug_line_programs.is_empty() {
1990 return Ok(None);
1991 }
1992
1993 if self.blob[self.debug_line_programs.start] != VERSION_DEBUG_LINE_PROGRAM_V1 {
1994 return Err(ProgramParseError(ProgramParseErrorKind::Other(
1995 "the debug line programs section has an unsupported version",
1996 )));
1997 }
1998
1999 const ENTRY_SIZE: usize = 12;
2000
2001 let slice = &self.blob[self.debug_line_program_ranges.clone()];
2002 if slice.len() % ENTRY_SIZE != 0 {
2003 return Err(ProgramParseError(ProgramParseErrorKind::Other(
2004 "the debug function ranges section has an invalid size",
2005 )));
2006 }
2007
2008 let offset = binary_search(slice, ENTRY_SIZE, |xs| {
2009 let begin = u32::from_le_bytes([xs[0], xs[1], xs[2], xs[3]]);
2010 if nth_instruction < begin {
2011 return core::cmp::Ordering::Greater;
2012 }
2013
2014 let end = u32::from_le_bytes([xs[4], xs[5], xs[6], xs[7]]);
2015 if nth_instruction >= end {
2016 return core::cmp::Ordering::Less;
2017 }
2018
2019 core::cmp::Ordering::Equal
2020 });
2021
2022 let Ok(offset) = offset else { return Ok(None) };
2023
2024 let xs = &slice[offset..offset + ENTRY_SIZE];
2025 let index_begin = u32::from_le_bytes([xs[0], xs[1], xs[2], xs[3]]);
2026 let index_end = u32::from_le_bytes([xs[4], xs[5], xs[6], xs[7]]);
2027 let info_offset = u32::from_le_bytes([xs[8], xs[9], xs[10], xs[11]]);
2028
2029 if nth_instruction < index_begin || nth_instruction >= index_end {
2030 return Err(ProgramParseError(ProgramParseErrorKind::Other(
2031 "binary search for function debug info failed",
2032 )));
2033 }
2034
2035 let mut reader = self.get_section_reader(self.debug_line_programs.clone());
2036 reader.skip(info_offset as usize)?;
2037
2038 Ok(Some(LineProgram {
2039 entry_index: offset / ENTRY_SIZE,
2040 region_counter: 0,
2041 blob: self,
2042 reader,
2043 is_finished: false,
2044 program_counter: index_begin,
2045 stack: Default::default(),
2046 stack_depth: 0,
2047 mutation_depth: 0,
2048 }))
2049 }
2050
2051 #[cfg(feature = "alloc")]
2053 pub fn into_owned(self) -> ProgramBlob<'static> {
2054 ProgramBlob {
2055 blob: self.blob.into_owned(),
2056
2057 ro_data_size: self.ro_data_size,
2058 rw_data_size: self.rw_data_size,
2059 stack_size: self.stack_size,
2060
2061 ro_data: self.ro_data,
2062 rw_data: self.rw_data,
2063 exports: self.exports,
2064 imports: self.imports,
2065 code: self.code,
2066 jump_table: self.jump_table,
2067
2068 debug_strings: self.debug_strings,
2069 debug_line_program_ranges: self.debug_line_program_ranges,
2070 debug_line_programs: self.debug_line_programs,
2071
2072 instruction_count: self.instruction_count,
2073 basic_block_count: self.basic_block_count,
2074 }
2075 }
2076}
2077
2078#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2080pub enum SourceLocation<'a> {
2081 Path { path: &'a str },
2082 PathAndLine { path: &'a str, line: u32 },
2083 Full { path: &'a str, line: u32, column: u32 },
2084}
2085
2086impl<'a> SourceLocation<'a> {
2087 pub fn path(&self) -> &'a str {
2089 match *self {
2090 Self::Path { path, .. } => path,
2091 Self::PathAndLine { path, .. } => path,
2092 Self::Full { path, .. } => path,
2093 }
2094 }
2095
2096 pub fn line(&self) -> Option<u32> {
2098 match *self {
2099 Self::Path { .. } => None,
2100 Self::PathAndLine { line, .. } => Some(line),
2101 Self::Full { line, .. } => Some(line),
2102 }
2103 }
2104
2105 pub fn column(&self) -> Option<u32> {
2107 match *self {
2108 Self::Path { .. } => None,
2109 Self::PathAndLine { .. } => None,
2110 Self::Full { column, .. } => Some(column),
2111 }
2112 }
2113}
2114
2115impl<'a> core::fmt::Display for SourceLocation<'a> {
2116 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
2117 match *self {
2118 Self::Path { path } => fmt.write_str(path),
2119 Self::PathAndLine { path, line } => write!(fmt, "{}:{}", path, line),
2120 Self::Full { path, line, column } => write!(fmt, "{}:{}:{}", path, line, column),
2121 }
2122 }
2123}
2124
2125#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
2126pub enum FrameKind {
2127 Enter,
2128 Call,
2129 Line,
2130}
2131
2132pub struct FrameInfo<'a> {
2133 blob: &'a ProgramBlob<'a>,
2134 inner: &'a LineProgramFrame,
2135}
2136
2137impl<'a> FrameInfo<'a> {
2138 pub fn namespace(&self) -> Result<Option<&str>, ProgramParseError> {
2140 let namespace = self.blob.get_debug_string(self.inner.namespace_offset)?;
2141 if namespace.is_empty() {
2142 Ok(None)
2143 } else {
2144 Ok(Some(namespace))
2145 }
2146 }
2147
2148 pub fn function_name_without_namespace(&self) -> Result<Option<&str>, ProgramParseError> {
2150 let function_name = self.blob.get_debug_string(self.inner.function_name_offset)?;
2151 if function_name.is_empty() {
2152 Ok(None)
2153 } else {
2154 Ok(Some(function_name))
2155 }
2156 }
2157
2158 pub fn path_debug_string_offset(&self) -> Option<u32> {
2160 if self.inner.path_offset == 0 {
2161 None
2162 } else {
2163 Some(self.inner.path_offset)
2164 }
2165 }
2166
2167 pub fn path(&self) -> Result<Option<&str>, ProgramParseError> {
2169 let path = self.blob.get_debug_string(self.inner.path_offset)?;
2170 if path.is_empty() {
2171 Ok(None)
2172 } else {
2173 Ok(Some(path))
2174 }
2175 }
2176
2177 pub fn line(&self) -> Option<u32> {
2179 if self.inner.line == 0 {
2180 None
2181 } else {
2182 Some(self.inner.line)
2183 }
2184 }
2185
2186 pub fn column(&self) -> Option<u32> {
2188 if self.inner.column == 0 {
2189 None
2190 } else {
2191 Some(self.inner.column)
2192 }
2193 }
2194
2195 pub fn kind(&self) -> FrameKind {
2196 self.inner.kind.unwrap_or(FrameKind::Line)
2197 }
2198
2199 pub fn full_name(&'_ self) -> Result<impl core::fmt::Display + '_, ProgramParseError> {
2201 Ok(DisplayName {
2202 prefix: self.namespace()?.unwrap_or(""),
2203 suffix: self.function_name_without_namespace()?.unwrap_or(""),
2204 })
2205 }
2206
2207 pub fn location(&self) -> Result<Option<SourceLocation>, ProgramParseError> {
2209 if let Some(path) = self.path()? {
2210 if let Some(line) = self.line() {
2211 if let Some(column) = self.column() {
2212 Ok(Some(SourceLocation::Full { path, line, column }))
2213 } else {
2214 Ok(Some(SourceLocation::PathAndLine { path, line }))
2215 }
2216 } else {
2217 Ok(Some(SourceLocation::Path { path }))
2218 }
2219 } else {
2220 Ok(None)
2221 }
2222 }
2223}
2224
2225pub struct RegionInfo<'a> {
2227 entry_index: usize,
2228 blob: &'a ProgramBlob<'a>,
2229 range: Range<u32>,
2230 frames: &'a [LineProgramFrame],
2231}
2232
2233impl<'a> RegionInfo<'a> {
2234 pub fn entry_index(&self) -> usize {
2236 self.entry_index
2237 }
2238
2239 pub fn instruction_range(&self) -> Range<u32> {
2241 self.range.clone()
2242 }
2243
2244 pub fn frames(&self) -> impl ExactSizeIterator<Item = FrameInfo> {
2246 self.frames.iter().map(|inner| FrameInfo { blob: self.blob, inner })
2247 }
2248}
2249
2250#[derive(Default)]
2251struct LineProgramFrame {
2252 kind: Option<FrameKind>,
2253 namespace_offset: u32,
2254 function_name_offset: u32,
2255 path_offset: u32,
2256 line: u32,
2257 column: u32,
2258}
2259
2260pub struct LineProgram<'a> {
2262 entry_index: usize,
2263 region_counter: usize,
2264 blob: &'a ProgramBlob<'a>,
2265 reader: Reader<'a>,
2266 is_finished: bool,
2267 program_counter: u32,
2268 stack: [LineProgramFrame; 16],
2270 stack_depth: u32,
2271 mutation_depth: u32,
2272}
2273
2274impl<'a> LineProgram<'a> {
2275 pub fn entry_index(&self) -> usize {
2277 self.entry_index
2278 }
2279
2280 pub fn run(&mut self) -> Result<Option<RegionInfo>, ProgramParseError> {
2282 struct SetTrueOnDrop<'a>(&'a mut bool);
2283 impl<'a> Drop for SetTrueOnDrop<'a> {
2284 fn drop(&mut self) {
2285 *self.0 = true;
2286 }
2287 }
2288
2289 if self.is_finished {
2290 return Ok(None);
2291 }
2292
2293 const INSTRUCTION_LIMIT_PER_REGION: usize = 512;
2295
2296 let mark_as_finished_on_drop = SetTrueOnDrop(&mut self.is_finished);
2297 for _ in 0..INSTRUCTION_LIMIT_PER_REGION {
2298 let byte = match self.reader.read_byte() {
2299 Ok(byte) => byte,
2300 Err(error) => {
2301 return Err(error);
2302 }
2303 };
2304
2305 let Some(opcode) = LineProgramOp::from_u8(byte) else {
2306 return Err(ProgramParseError(ProgramParseErrorKind::Other(
2307 "found an unrecognized line program opcode",
2308 )));
2309 };
2310
2311 let (count, stack_depth) = match opcode {
2312 LineProgramOp::FinishProgram => {
2313 return Ok(None);
2314 }
2315 LineProgramOp::SetMutationDepth => {
2316 self.mutation_depth = self.reader.read_varint()?;
2317 continue;
2318 }
2319 LineProgramOp::SetKindEnter => {
2320 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2321 frame.kind = Some(FrameKind::Enter);
2322 }
2323 continue;
2324 }
2325 LineProgramOp::SetKindCall => {
2326 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2327 frame.kind = Some(FrameKind::Call);
2328 }
2329 continue;
2330 }
2331 LineProgramOp::SetKindLine => {
2332 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2333 frame.kind = Some(FrameKind::Line);
2334 }
2335 continue;
2336 }
2337 LineProgramOp::SetNamespace => {
2338 let value = self.reader.read_varint()?;
2339 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2340 frame.namespace_offset = value;
2341 }
2342 continue;
2343 }
2344 LineProgramOp::SetFunctionName => {
2345 let value = self.reader.read_varint()?;
2346 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2347 frame.function_name_offset = value;
2348 }
2349 continue;
2350 }
2351 LineProgramOp::SetPath => {
2352 let value = self.reader.read_varint()?;
2353 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2354 frame.path_offset = value;
2355 }
2356 continue;
2357 }
2358 LineProgramOp::SetLine => {
2359 let value = self.reader.read_varint()?;
2360 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2361 frame.line = value;
2362 }
2363 continue;
2364 }
2365 LineProgramOp::SetColumn => {
2366 let value = self.reader.read_varint()?;
2367 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2368 frame.column = value;
2369 }
2370 continue;
2371 }
2372 LineProgramOp::SetStackDepth => {
2373 self.stack_depth = self.reader.read_varint()?;
2374 continue;
2375 }
2376 LineProgramOp::IncrementLine => {
2377 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2378 frame.line += 1;
2379 }
2380 continue;
2381 }
2382 LineProgramOp::AddLine => {
2383 let value = self.reader.read_varint()?;
2384 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2385 frame.line = frame.line.wrapping_add(value);
2386 }
2387 continue;
2388 }
2389 LineProgramOp::SubLine => {
2390 let value = self.reader.read_varint()?;
2391 if let Some(frame) = self.stack.get_mut(self.mutation_depth as usize) {
2392 frame.line = frame.line.wrapping_sub(value);
2393 }
2394 continue;
2395 }
2396 LineProgramOp::FinishInstruction => (1, self.stack_depth),
2397 LineProgramOp::FinishMultipleInstructions => {
2398 let count = self.reader.read_varint()?;
2399 (count, self.stack_depth)
2400 }
2401 LineProgramOp::FinishInstructionAndIncrementStackDepth => {
2402 let depth = self.stack_depth;
2403 self.stack_depth = self.stack_depth.saturating_add(1);
2404 (1, depth)
2405 }
2406 LineProgramOp::FinishMultipleInstructionsAndIncrementStackDepth => {
2407 let count = self.reader.read_varint()?;
2408 let depth = self.stack_depth;
2409 self.stack_depth = self.stack_depth.saturating_add(1);
2410 (count, depth)
2411 }
2412 LineProgramOp::FinishInstructionAndDecrementStackDepth => {
2413 let depth = self.stack_depth;
2414 self.stack_depth = self.stack_depth.saturating_sub(1);
2415 (1, depth)
2416 }
2417 LineProgramOp::FinishMultipleInstructionsAndDecrementStackDepth => {
2418 let count = self.reader.read_varint()?;
2419 let depth = self.stack_depth;
2420 self.stack_depth = self.stack_depth.saturating_sub(1);
2421 (count, depth)
2422 }
2423 };
2424
2425 let range = self.program_counter..self.program_counter + count;
2426 self.program_counter += count;
2427
2428 let frames = &self.stack[..core::cmp::min(stack_depth as usize, self.stack.len())];
2429 core::mem::forget(mark_as_finished_on_drop);
2430
2431 let entry_index = self.region_counter;
2432 self.region_counter += 1;
2433 return Ok(Some(RegionInfo {
2434 entry_index,
2435 blob: self.blob,
2436 range,
2437 frames,
2438 }));
2439 }
2440
2441 Err(ProgramParseError(ProgramParseErrorKind::Other(
2442 "found a line program with too many instructions",
2443 )))
2444 }
2445}
2446
2447struct DisplayName<'a> {
2448 prefix: &'a str,
2449 suffix: &'a str,
2450}
2451
2452impl<'a> core::fmt::Display for DisplayName<'a> {
2453 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
2454 fmt.write_str(self.prefix)?;
2455 if !self.prefix.is_empty() {
2456 fmt.write_str("::")?;
2457 }
2458 fmt.write_str(self.suffix)
2459 }
2460}
2461
2462fn binary_search(slice: &[u8], chunk_size: usize, compare: impl Fn(&[u8]) -> core::cmp::Ordering) -> Result<usize, usize> {
2465 let mut size = slice.len() / chunk_size;
2466 if size == 0 {
2467 return Err(0);
2468 }
2469
2470 let mut base = 0_usize;
2471 while size > 1 {
2472 let half = size / 2;
2473 let mid = base + half;
2474 let item = &slice[mid * chunk_size..(mid + 1) * chunk_size];
2475 match compare(item) {
2476 core::cmp::Ordering::Greater => {
2477 size -= half;
2479 }
2480 core::cmp::Ordering::Less => {
2481 size -= half;
2483 base = mid;
2484 }
2485 core::cmp::Ordering::Equal => {
2486 let previous_item = &slice[(mid - 1) * chunk_size..mid * chunk_size];
2488 if compare(previous_item) != core::cmp::Ordering::Equal {
2489 return Ok(mid * chunk_size);
2491 }
2492
2493 size -= half;
2499 }
2500 }
2501 }
2502
2503 let item = &slice[base * chunk_size..(base + 1) * chunk_size];
2504 let ord = compare(item);
2505 if ord == core::cmp::Ordering::Equal {
2506 Ok(base * chunk_size)
2507 } else {
2508 Err((base + usize::from(ord == core::cmp::Ordering::Less)) * chunk_size)
2509 }
2510}
2511
2512#[cfg(test)]
2513extern crate std;
2514
2515#[cfg(test)]
2516proptest::proptest! {
2517 #![proptest_config(proptest::prelude::ProptestConfig::with_cases(20000))]
2518 #[allow(clippy::ignored_unit_patterns)]
2519 #[test]
2520 fn test_binary_search(needle: u8, mut xs: std::vec::Vec<u8>) {
2521 xs.sort();
2522 let binary_result = binary_search(&xs, 1, |slice| slice[0].cmp(&needle));
2523 let mut linear_result = Err(0);
2524 for (index, value) in xs.iter().copied().enumerate() {
2525 #[allow(clippy::comparison_chain)]
2526 if value == needle {
2527 linear_result = Ok(index);
2528 break;
2529 } else if value < needle {
2530 linear_result = Err(index + 1);
2531 continue;
2532 } else {
2533 break;
2534 }
2535 }
2536
2537 assert_eq!(binary_result, linear_result, "linear search = {:?}, binary search = {:?}, needle = {}, xs = {:?}", linear_result, binary_result, needle, xs);
2538 }
2539}
2540
2541pub const BLOB_MAGIC: [u8; 4] = [b'P', b'V', b'M', b'\0'];
2543
2544pub const SECTION_MEMORY_CONFIG: u8 = 1;
2545pub const SECTION_RO_DATA: u8 = 2;
2546pub const SECTION_RW_DATA: u8 = 3;
2547pub const SECTION_IMPORTS: u8 = 4;
2548pub const SECTION_EXPORTS: u8 = 5;
2549pub const SECTION_JUMP_TABLE: u8 = 6;
2550pub const SECTION_CODE: u8 = 7;
2551pub const SECTION_OPT_DEBUG_STRINGS: u8 = 128;
2552pub const SECTION_OPT_DEBUG_LINE_PROGRAMS: u8 = 129;
2553pub const SECTION_OPT_DEBUG_LINE_PROGRAM_RANGES: u8 = 130;
2554pub const SECTION_END_OF_FILE: u8 = 0;
2555
2556pub const BLOB_VERSION_V1: u8 = 1;
2557
2558pub const VERSION_DEBUG_LINE_PROGRAM_V1: u8 = 1;
2559
2560#[derive(Copy, Clone, Debug)]
2561pub enum LineProgramOp {
2562 FinishProgram = 0,
2563 SetMutationDepth = 1,
2564 SetKindEnter = 2,
2565 SetKindCall = 3,
2566 SetKindLine = 4,
2567 SetNamespace = 5,
2568 SetFunctionName = 6,
2569 SetPath = 7,
2570 SetLine = 8,
2571 SetColumn = 9,
2572 SetStackDepth = 10,
2573 IncrementLine = 11,
2574 AddLine = 12,
2575 SubLine = 13,
2576 FinishInstruction = 14,
2577 FinishMultipleInstructions = 15,
2578 FinishInstructionAndIncrementStackDepth = 16,
2579 FinishMultipleInstructionsAndIncrementStackDepth = 17,
2580 FinishInstructionAndDecrementStackDepth = 18,
2581 FinishMultipleInstructionsAndDecrementStackDepth = 19,
2582}
2583
2584impl LineProgramOp {
2585 #[inline]
2586 pub const fn from_u8(value: u8) -> Option<Self> {
2587 match value {
2588 0 => Some(Self::FinishProgram),
2589 1 => Some(Self::SetMutationDepth),
2590 2 => Some(Self::SetKindEnter),
2591 3 => Some(Self::SetKindCall),
2592 4 => Some(Self::SetKindLine),
2593 5 => Some(Self::SetNamespace),
2594 6 => Some(Self::SetFunctionName),
2595 7 => Some(Self::SetPath),
2596 8 => Some(Self::SetLine),
2597 9 => Some(Self::SetColumn),
2598 10 => Some(Self::SetStackDepth),
2599 11 => Some(Self::IncrementLine),
2600 12 => Some(Self::AddLine),
2601 13 => Some(Self::SubLine),
2602 14 => Some(Self::FinishInstruction),
2603 15 => Some(Self::FinishMultipleInstructions),
2604 16 => Some(Self::FinishInstructionAndIncrementStackDepth),
2605 17 => Some(Self::FinishMultipleInstructionsAndIncrementStackDepth),
2606 18 => Some(Self::FinishInstructionAndDecrementStackDepth),
2607 19 => Some(Self::FinishMultipleInstructionsAndDecrementStackDepth),
2608 _ => None,
2609 }
2610 }
2611}