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    unreachable_validated,
8    value::{self, FuncAddr, Ref},
9    value_stack::Stack,
10    ModuleInst, RefType, RuntimeError, Store, Value,
11};
12
13// TODO update this documentation
14/// Execute a previosly-validated constant expression. These type of expressions are used for initializing global
15/// variables, data and element segments.
16///
17/// # Arguments
18/// TODO
19///
20/// # Safety
21/// This function assumes that the expression has been validated. Passing unvalidated code will likely result in a
22/// panic, or undefined behaviour.
23// TODO this signature might change to support hooks or match the spec better
24pub(crate) fn run_const<T>(
25    wasm: &mut WasmReader,
26    stack: &mut Stack,
27    module: &ModuleInst,
28    store: &Store<T>,
29) -> Result<(), RuntimeError> {
30    use crate::core::reader::types::opcode::*;
31    loop {
32        let first_instr_byte = wasm.read_u8().unwrap_validated();
33
34        #[cfg(debug_assertions)]
35        crate::core::utils::print_beautiful_instruction_name_1_byte(first_instr_byte, wasm.pc);
36
37        #[cfg(not(debug_assertions))]
38        trace!("Read instruction byte {first_instr_byte:#04X?} ({first_instr_byte}) at wasm_binary[{}]", wasm.pc);
39
40        match first_instr_byte {
41            END => {
42                trace!("Constant instruction: END");
43                break;
44            }
45            GLOBAL_GET => {
46                let global_idx = wasm.read_var_u32().unwrap_validated() as GlobalIdx;
47
48                //TODO replace double indirection
49                let global = &store.globals[module.global_addrs[global_idx]];
50
51                trace!(
52                    "Constant instruction: global.get [{global_idx}] -> [{:?}]",
53                    global
54                );
55                stack.push_value(global.value)?;
56            }
57            I32_CONST => {
58                let constant = wasm.read_var_i32().unwrap_validated();
59                trace!("Constant instruction: i32.const [] -> [{constant}]");
60                stack.push_value(constant.into())?;
61            }
62            F32_CONST => {
63                let constant = value::F32::from_bits(wasm.read_var_f32().unwrap_validated());
64                trace!("Constanting instruction: f32.const [] -> [{constant}]");
65                stack.push_value(constant.into())?;
66            }
67            F64_CONST => {
68                let constant = value::F64::from_bits(wasm.read_var_f64().unwrap_validated());
69                trace!("Constanting instruction: f64.const [] -> [{constant}]");
70                stack.push_value(constant.into())?;
71            }
72            I64_CONST => {
73                let constant = wasm.read_var_i64().unwrap_validated();
74                trace!("Constant instruction: i64.const [] -> [{constant}]");
75                stack.push_value(constant.into())?;
76            }
77            REF_NULL => {
78                let reftype = RefType::read(wasm).unwrap_validated();
79
80                stack.push_value(Value::Ref(Ref::Null(reftype)))?;
81                trace!("Instruction: ref.null '{:?}' -> [{:?}]", reftype, reftype);
82            }
83            REF_FUNC => {
84                // we already checked for the func_idx to be in bounds during validation
85                let func_idx = wasm.read_var_u32().unwrap_validated() as usize;
86                let func_addr = *module.func_addrs.get(func_idx).unwrap_validated();
87                stack.push_value(Value::Ref(Ref::Func(FuncAddr(func_addr))))?;
88            }
89
90            FD_EXTENSIONS => {
91                use crate::core::reader::types::opcode::fd_extensions::*;
92
93                match wasm.read_var_u32().unwrap_validated() {
94                    V128_CONST => {
95                        let mut data = [0; 16];
96                        for byte_ref in &mut data {
97                            *byte_ref = wasm.read_u8().unwrap_validated();
98                        }
99
100                        stack.push_value(Value::V128(data))?;
101                    }
102                    0x00..=0x0B | 0x0D.. => unreachable_validated!(),
103                }
104            }
105
106            0x00..=0x0A
107            | 0x0C..=0x22
108            | 0x24..=0x40
109            | 0x45..=0xBF
110            | 0xC0..=0xCF
111            | 0xD1
112            | 0xD3..=0xFC
113            | 0xFE..=0xFF => {
114                unreachable_validated!();
115            }
116        }
117    }
118    Ok(())
119}
120
121pub(crate) fn run_const_span<T>(
122    wasm: &[u8],
123    span: &Span,
124    module: &ModuleInst,
125    store: &Store<T>,
126) -> Result<Option<Value>, RuntimeError> {
127    let mut wasm = WasmReader::new(wasm);
128
129    wasm.move_start_to(*span).unwrap_validated();
130
131    let mut stack = Stack::new();
132    run_const(&mut wasm, &mut stack, module, store)?;
133
134    Ok(stack.peek_value())
135}