Interpret a single Cranelift instruction. Note that program traps and interpreter errors are distinct: a program trap results in `Ok(Flow::Trap(...))` whereas an interpretation error (e.g. the types of two values are incompatible) results in `Err(...)`.
(state: &mut dyn State<'a>, inst_context: I)
| 60 | /// distinct: a program trap results in `Ok(Flow::Trap(...))` whereas an interpretation error (e.g. |
| 61 | /// the types of two values are incompatible) results in `Err(...)`. |
| 62 | pub fn step<'a, I>(state: &mut dyn State<'a>, inst_context: I) -> Result<ControlFlow<'a>, StepError> |
| 63 | where |
| 64 | I: InstructionContext, |
| 65 | { |
| 66 | let inst = inst_context.data(); |
| 67 | let ctrl_ty = inst_context.controlling_type().unwrap(); |
| 68 | trace!( |
| 69 | "Step: {}{}", |
| 70 | inst.opcode(), |
| 71 | if ctrl_ty.is_invalid() { |
| 72 | String::new() |
| 73 | } else { |
| 74 | format!(".{ctrl_ty}") |
| 75 | } |
| 76 | ); |
| 77 | |
| 78 | // The following closures make the `step` implementation much easier to express. Note that they |
| 79 | // frequently close over the `state` or `inst_context` for brevity. |
| 80 | |
| 81 | // Retrieve the current value for an instruction argument. |
| 82 | let arg = |index: usize| -> DataValue { |
| 83 | let value_ref = inst_context.args()[index]; |
| 84 | state.current_frame().get(value_ref).clone() |
| 85 | }; |
| 86 | |
| 87 | // Retrieve the current values for all of an instruction's arguments. |
| 88 | let args = || -> SmallVec<[DataValue; 1]> { state.collect_values(inst_context.args()) }; |
| 89 | |
| 90 | // Retrieve the current values for a range of an instruction's arguments. |
| 91 | let args_range = |indexes: RangeFrom<usize>| -> Result<SmallVec<[DataValue; 1]>, StepError> { |
| 92 | Ok(SmallVec::<[DataValue; 1]>::from(&args()[indexes])) |
| 93 | }; |
| 94 | |
| 95 | // Retrieve the immediate value for an instruction, expecting it to exist. |
| 96 | let imm = || -> DataValue { |
| 97 | match inst { |
| 98 | InstructionData::UnaryConst { |
| 99 | constant_handle, |
| 100 | opcode, |
| 101 | } => { |
| 102 | let buffer = state |
| 103 | .get_current_function() |
| 104 | .dfg |
| 105 | .constants |
| 106 | .get(constant_handle); |
| 107 | match (ctrl_ty.bytes(), opcode) { |
| 108 | (_, Opcode::F128const) => { |
| 109 | DataValue::F128(buffer.try_into().expect("a 16-byte data buffer")) |
| 110 | } |
| 111 | (16, Opcode::Vconst) => DataValue::V128( |
| 112 | buffer.as_slice().try_into().expect("a 16-byte data buffer"), |
| 113 | ), |
| 114 | (8, Opcode::Vconst) => { |
| 115 | DataValue::V64(buffer.as_slice().try_into().expect("an 8-byte data buffer")) |
| 116 | } |
| 117 | (4, Opcode::Vconst) => { |
| 118 | DataValue::V32(buffer.as_slice().try_into().expect("a 4-byte data buffer")) |
| 119 | } |
no test coverage detected