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