1 use super::*;
2 use crate::decode::unwrap_uninhabited;
3 use crate::opcode::Opcode;
4 
5 type Handler = fn(Interpreter<'_>) -> Done;
6 
7 /// The extra indirection through a macro is necessary to avoid a compiler error
8 /// when compiling without `#![feature(explicit_tail_calls)]` enabled (via
9 /// `--cfg pulley_tail_calls`).
10 ///
11 /// It seems rustc first parses the function, encounters `become` and emits
12 /// an error about using an unstable keyword on a stable compiler, then applies
13 /// `#[cfg(...)` after parsing to disable the function.
14 ///
15 /// Macro bodies are just bags of tokens; the body is not parsed until after
16 /// they are expanded, and this macro is only expanded when `pulley_tail_calls`
17 /// is enabled.
18 macro_rules! tail_call {
19     ($e:expr) => {
20         become $e
21     };
22 }
23 
24 impl Interpreter<'_> {
25     pub fn run(mut self) -> Done {
26         // Perform a dynamic dispatch through a function pointer indexed by
27         // opcode.
28         let opcode = unwrap_uninhabited(Opcode::decode(self.bytecode()));
29         let handler = OPCODE_HANDLER_TABLE[opcode as usize];
30         tail_call!(handler(self));
31     }
32 }
33 
34 /// Same as `Interpreter::run`, except for extended opcodes.
35 fn run_extended(mut i: Interpreter<'_>) -> Done {
36     let opcode = unwrap_uninhabited(ExtendedOpcode::decode(i.bytecode()));
37     let handler = EXTENDED_OPCODE_HANDLER_TABLE[opcode as usize];
38     tail_call!(handler(i));
39 }
40 
41 static OPCODE_HANDLER_TABLE: [Handler; Opcode::MAX as usize + 1] = {
42     macro_rules! define_opcode_handler_table {
43         ($(
44             $( #[$attr:meta] )*
45             $snake_name:ident = $name:ident $( {
46                 $(
47                     $( #[$field_attr:meta] )*
48                     $field:ident : $field_ty:ty
49                 ),*
50             } )?;
51         )*) => {
52             [
53                 $($snake_name,)* // refers to functions defined down below
54                 run_extended,
55             ]
56         };
57     }
58 
59     for_each_op!(define_opcode_handler_table)
60 };
61 
62 // same as above, but without a +1 for handling of extended ops as this is the
63 // extended ops.
64 static EXTENDED_OPCODE_HANDLER_TABLE: [Handler; ExtendedOpcode::MAX as usize] = {
65     macro_rules! define_extended_opcode_handler_table {
66         ($(
67             $( #[$attr:meta] )*
68             $snake_name:ident = $name:ident $( {
69                 $(
70                     $( #[$field_attr:meta] )*
71                     $field:ident : $field_ty:ty
72                 ),*
73             } )?;
74         )*) => {
75             [
76                 $($snake_name,)* // refers to functions defined down below
77             ]
78         };
79     }
80 
81     for_each_extended_op!(define_extended_opcode_handler_table)
82 };
83 
84 // Define a top-level function for each opcode. Each function here is the
85 // destination of the indirect return-call-indirect of above. Each function is
86 // also specialized to a single opcode and should be thoroughly inlined to
87 // ensure that everything "boils away".
88 macro_rules! define_opcode_handler {
89     ($(
90         $( #[$attr:meta] )*
91         $snake_name:ident = $name:ident $( {
92             $(
93                 $( #[$field_attr:meta] )*
94                 $field:ident : $field_ty:ty
95             ),*
96         } )?;
97     )*) => {$(
98         fn $snake_name(mut i: Interpreter<'_>) -> Done {
99             $(
100                 let ($($field,)*) = unwrap_uninhabited(
101                     crate::decode::operands::$snake_name(i.bytecode())
102                 );
103             )?
104             match OpVisitor::$snake_name(&mut i, $($($field),*)?) {
105                 ControlFlow::Continue(()) => tail_call!(i.run()),
106                 ControlFlow::Break(done) => done,
107             }
108         }
109     )*};
110 }
111 
112 for_each_op!(define_opcode_handler);
113 
114 macro_rules! define_extended_opcode_handler {
115     ($(
116         $( #[$attr:meta] )*
117         $snake_name:ident = $name:ident $( {
118             $(
119                 $( #[$field_attr:meta] )*
120                 $field:ident : $field_ty:ty
121             ),*
122         } )?;
123     )*) => {$(
124         fn $snake_name(mut i: Interpreter<'_>) -> Done {
125             $(
126                 let ($($field,)*) = unwrap_uninhabited(
127                     crate::decode::operands::$snake_name(i.bytecode())
128                 );
129             )?
130             match ExtendedOpVisitor::$snake_name(&mut i, $($($field),*)?) {
131                 ControlFlow::Continue(()) => tail_call!(i.run()),
132                 ControlFlow::Break(done) => done,
133             }
134         }
135     )*};
136 }
137 for_each_extended_op!(define_extended_opcode_handler);
138