wasm/execution/
const_interpreter_loop.rs

1use alloc::vec::Vec;
2
3use crate::{
4    addrs::ModuleAddr,
5    assert_validated::UnwrapValidatedExt,
6    config::Config,
7    core::{
8        indices::{FuncIdx, GlobalIdx},
9        reader::{
10            span::Span,
11            types::{FuncType, ResultType},
12            WasmReader,
13        },
14    },
15    unreachable_validated,
16    value::{self, Ref},
17    value_stack::Stack,
18    RefType, RuntimeError, Store, Value,
19};
20
21// TODO update this documentation
22/// Execute a previosly-validated constant expression. These type of expressions are used for initializing global
23/// variables, data and element segments.
24///
25/// # Arguments
26/// TODO
27///
28/// # Safety
29/// This function assumes that the expression has been validated. Passing unvalidated code will likely result in a
30/// panic, or undefined behaviour.
31// TODO this signature might change to support hooks or match the spec better
32pub(crate) fn run_const<T: Config>(
33    wasm: &mut WasmReader,
34    stack: &mut Stack,
35    module: ModuleAddr,
36    store: &Store<T>,
37) -> Result<(), RuntimeError> {
38    use crate::core::reader::types::opcode::*;
39    loop {
40        let first_instr_byte = wasm.read_u8().unwrap_validated();
41
42        #[cfg(debug_assertions)]
43        crate::core::utils::print_beautiful_instruction_name_1_byte(first_instr_byte, wasm.pc);
44
45        #[cfg(not(debug_assertions))]
46        trace!("Read instruction byte {first_instr_byte:#04X?} ({first_instr_byte}) at wasm_binary[{}]", wasm.pc);
47
48        match first_instr_byte {
49            END => {
50                trace!("Constant instruction: END");
51                break;
52            }
53            GLOBAL_GET => {
54                // SAFETY: Validation guarantees there to be a valid global
55                // index next.
56                let global_idx = unsafe { GlobalIdx::read_unchecked(wasm) };
57
58                let module_instance = store.modules.get(module);
59
60                // SAFETY: Validation guarantees the global index to be valid in
61                // the current module.
62                let global_addr = *unsafe { module_instance.global_addrs.get(global_idx) };
63
64                let global = store.globals.get(global_addr);
65
66                trace!(
67                    "Constant instruction: global.get [{global_idx}] -> [{:?}]",
68                    global
69                );
70                stack.push_value::<T>(global.value)?;
71            }
72            I32_CONST => {
73                let constant = wasm.read_var_i32().unwrap_validated();
74                trace!("Constant instruction: i32.const [] -> [{constant}]");
75                stack.push_value::<T>(constant.into())?;
76            }
77            F32_CONST => {
78                let constant = value::F32::from_bits(wasm.read_f32().unwrap_validated());
79                trace!("Constanting instruction: f32.const [] -> [{constant}]");
80                stack.push_value::<T>(constant.into())?;
81            }
82            F64_CONST => {
83                let constant = value::F64::from_bits(wasm.read_f64().unwrap_validated());
84                trace!("Constanting instruction: f64.const [] -> [{constant}]");
85                stack.push_value::<T>(constant.into())?;
86            }
87            I64_CONST => {
88                let constant = wasm.read_var_i64().unwrap_validated();
89                trace!("Constant instruction: i64.const [] -> [{constant}]");
90                stack.push_value::<T>(constant.into())?;
91            }
92            REF_NULL => {
93                let reftype = RefType::read(wasm).unwrap_validated();
94
95                stack.push_value::<T>(Value::Ref(Ref::Null(reftype)))?;
96                trace!("Instruction: ref.null '{:?}' -> [{:?}]", reftype, reftype);
97            }
98            REF_FUNC => {
99                // SAFETY: Validation guarantees there to be a valid function
100                // index next.
101                let func_idx = unsafe { FuncIdx::read_unchecked(wasm) };
102                // SAFETY: Validation guarantees the function index to be valid
103                // in the current module.
104                let func_addr = unsafe { store.modules.get(module).func_addrs.get(func_idx) };
105                stack.push_value::<T>(Value::Ref(Ref::Func(*func_addr)))?;
106            }
107
108            FD_EXTENSIONS => {
109                use crate::core::reader::types::opcode::fd_extensions::*;
110
111                match wasm.read_var_u32().unwrap_validated() {
112                    V128_CONST => {
113                        let mut data = [0; 16];
114                        for byte_ref in &mut data {
115                            *byte_ref = wasm.read_u8().unwrap_validated();
116                        }
117
118                        stack.push_value::<T>(Value::V128(data))?;
119                    }
120                    0x00..=0x0B | 0x0D.. => unreachable_validated!(),
121                }
122            }
123
124            0x00..=0x0A
125            | 0x0C..=0x22
126            | 0x24..=0x40
127            | 0x45..=0xBF
128            | 0xC0..=0xCF
129            | 0xD1
130            | 0xD3..=0xFC
131            | 0xFE..=0xFF => {
132                unreachable_validated!();
133            }
134        }
135    }
136    Ok(())
137}
138
139pub(crate) fn run_const_span<T: Config>(
140    wasm: &[u8],
141    span: &Span,
142    module: ModuleAddr,
143    store: &Store<T>,
144) -> Result<Option<Value>, RuntimeError> {
145    let mut wasm = WasmReader::new(wasm);
146
147    wasm.move_start_to(*span).unwrap_validated();
148
149    let mut stack = Stack::new::<T>(
150        Vec::new(),
151        &FuncType {
152            params: ResultType {
153                valtypes: Vec::new(),
154            },
155            returns: ResultType {
156                valtypes: Vec::new(),
157            },
158        },
159        &[],
160    )?;
161    run_const(&mut wasm, &mut stack, module, store)?;
162
163    Ok(stack.peek_value())
164}