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