wasm/execution/
const_interpreter_loop.rs

1use crate::{
2    assert_validated::UnwrapValidatedExt,
3    core::{
4        indices::GlobalIdx,
5        reader::{span::Span, WasmReadable, WasmReader},
6    },
7    value::{self, FuncAddr, Ref},
8    value_stack::Stack,
9    ModuleInst, RefType, RuntimeError, Store, Value,
10};
11
12// TODO update this documentation
13/// Execute a previosly-validated constant expression. These type of expressions are used for initializing global
14/// variables, data and element segments.
15///
16/// # Arguments
17/// TODO
18///
19/// # Safety
20/// This function assumes that the expression has been validated. Passing unvalidated code will likely result in a
21/// panic, or undefined behaviour.
22// TODO this signature might change to support hooks or match the spec better
23pub(crate) fn run_const(
24    wasm: &mut WasmReader,
25    stack: &mut Stack,
26    module: &ModuleInst,
27    store: &Store,
28) -> Result<(), RuntimeError> {
29    use crate::core::reader::types::opcode::*;
30    loop {
31        let first_instr_byte = wasm.read_u8().unwrap_validated();
32
33        #[cfg(debug_assertions)]
34        crate::core::utils::print_beautiful_instruction_name_1_byte(first_instr_byte, wasm.pc);
35
36        #[cfg(not(debug_assertions))]
37        trace!("Read instruction byte {first_instr_byte:#04X?} ({first_instr_byte}) at wasm_binary[{}]", wasm.pc);
38
39        match first_instr_byte {
40            END => {
41                trace!("Constant instruction: END");
42                break;
43            }
44            GLOBAL_GET => {
45                let global_idx = wasm.read_var_u32().unwrap_validated() as GlobalIdx;
46
47                //TODO replace double indirection
48                let global = &store.globals[module.global_addrs[global_idx]];
49
50                trace!(
51                    "Constant instruction: global.get [{global_idx}] -> [{:?}]",
52                    global
53                );
54                stack.push_value(global.value)?;
55            }
56            I32_CONST => {
57                let constant = wasm.read_var_i32().unwrap_validated();
58                trace!("Constant instruction: i32.const [] -> [{constant}]");
59                stack.push_value(constant.into())?;
60            }
61            F32_CONST => {
62                let constant = value::F32::from_bits(wasm.read_var_f32().unwrap_validated());
63                trace!("Constanting instruction: f32.const [] -> [{constant}]");
64                stack.push_value(constant.into())?;
65            }
66            F64_CONST => {
67                let constant = value::F64::from_bits(wasm.read_var_f64().unwrap_validated());
68                trace!("Constanting instruction: f64.const [] -> [{constant}]");
69                stack.push_value(constant.into())?;
70            }
71            I64_CONST => {
72                let constant = wasm.read_var_i64().unwrap_validated();
73                trace!("Constant instruction: i64.const [] -> [{constant}]");
74                stack.push_value(constant.into())?;
75            }
76            REF_NULL => {
77                let reftype = RefType::read_unvalidated(wasm);
78
79                stack.push_value(Value::Ref(reftype.to_null_ref()))?;
80                trace!("Instruction: ref.null '{:?}' -> [{:?}]", reftype, reftype);
81            }
82            REF_FUNC => {
83                // we already checked for the func_idx to be in bounds during validation
84                let func_idx = wasm.read_var_u32().unwrap_validated() as usize;
85                // TODO replace double indirection
86                stack.push_value(Value::Ref(Ref::Func(FuncAddr::new(Some(
87                    module.func_addrs[func_idx],
88                )))))?;
89            }
90            other => {
91                unreachable!("Unknown constant instruction {other:#x}, validation allowed an unimplemented instruction.");
92            }
93        }
94    }
95    Ok(())
96}
97
98pub(crate) fn run_const_span(
99    wasm: &[u8],
100    span: &Span,
101    module: &ModuleInst,
102    store: &Store,
103) -> Result<Option<Value>, RuntimeError> {
104    let mut wasm = WasmReader::new(wasm);
105
106    wasm.move_start_to(*span).unwrap_validated();
107
108    let mut stack = Stack::new();
109    run_const(&mut wasm, &mut stack, module, store)?;
110
111    Ok(stack.peek_unknown_value())
112}