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
21pub(crate) unsafe fn run_const<'wasm, T: Config>(
35 wasm: &mut WasmReader<'wasm>,
36 stack: &mut Stack,
37 module: ModuleAddr,
38 store: &Store<'wasm, 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(feature = "log")]
45 crate::core::utils::print_beautiful_instruction_name_1_byte(first_instr_byte, wasm.pc);
46
47 let instruction_fn = match first_instr_byte {
48 END => end::<T>,
49 GLOBAL_GET => global_get::<T>,
50 I32_CONST => i32_const::<T>,
51 F32_CONST => f32_const::<T>,
52 F64_CONST => f64_const::<T>,
53 I64_CONST => i64_const::<T>,
54 REF_NULL => ref_null::<T>,
55 REF_FUNC => ref_func::<T>,
56 FD_EXTENSIONS => fd_extensions::<T>,
57
58 0x00..=0x0A
59 | 0x0C..=0x22
60 | 0x24..=0x40
61 | 0x45..=0xBF
62 | 0xC0..=0xCF
63 | 0xD1
64 | 0xD3..=0xFC
65 | 0xFE..=0xFF => {
66 unreachable_validated!();
67 }
68 };
69
70 let args = Args {
71 wasm,
72 stack,
73 module,
74 store,
75 };
76
77 let should_break = unsafe { instruction_fn(args) }?;
81 if should_break {
82 break;
83 }
84 }
85 Ok(())
86}
87
88pub(crate) unsafe fn run_const_span<T: Config>(
93 wasm: &[u8],
94 span: &Span,
95 module: ModuleAddr,
96 store: &Store<T>,
97) -> Result<Option<Value>, RuntimeError> {
98 let mut wasm = WasmReader::new(wasm);
99
100 wasm.move_start_to(*span).unwrap_validated();
101
102 let mut stack = Stack::new::<T>(
103 Vec::new(),
104 &FuncType {
105 params: ResultType {
106 valtypes: Vec::new(),
107 },
108 returns: ResultType {
109 valtypes: Vec::new(),
110 },
111 },
112 &[],
113 )?;
114
115 unsafe { run_const(&mut wasm, &mut stack, module, store)? };
117
118 Ok(stack.peek_value())
119}
120
121struct Args<'reader, 'resumable, 'store, 'wasm, T: Config> {
122 wasm: &'reader mut WasmReader<'wasm>,
123 stack: &'resumable mut Stack,
124 module: ModuleAddr,
125 store: &'store Store<'wasm, T>,
126}
127
128macro_rules! define_instruction {
129 ($name:ident, $opcode:expr, $contents:expr) => {
130 unsafe fn $name<T: Config>(args: Args<T>) -> Result<bool, RuntimeError> {
137 $contents(args)
138 }
139 };
140}
141
142define_instruction!(end, opcode::END, |Args { .. }| {
143 trace!("Constant instruction: END");
144 Ok(true)
145});
146
147define_instruction!(
148 global_get,
149 opcode::GLOBAL_GET,
150 |Args {
151 wasm,
152 module,
153 store,
154 stack,
155 }| {
156 let global_idx = unsafe { GlobalIdx::read_unchecked(wasm) };
159
160 let module_instance = unsafe { store.modules.get(module) };
163
164 let global_addr = *unsafe { module_instance.global_addrs.get(global_idx) };
167
168 let global = unsafe { store.inner.globals.get(global_addr) };
171
172 trace!(
173 "Constant instruction: global.get [{global_idx}] -> [{:?}]",
174 global
175 );
176 stack.push_value(global.value)?;
177 Ok(false)
178 }
179);
180
181define_instruction!(
182 i32_const,
183 opcode::I32_CONST,
184 |Args { wasm, stack, .. }| {
185 let constant = wasm.read_var_i32().unwrap_validated();
186 trace!("Constant instruction: i32.const [] -> [{constant}]");
187 stack.push_value(constant.into())?;
188 Ok(false)
189 }
190);
191
192define_instruction!(
193 f32_const,
194 opcode::F32_CONST,
195 |Args { wasm, stack, .. }| {
196 let constant = value::F32::from_bits(wasm.read_f32().unwrap_validated());
197 trace!("Constanting instruction: f32.const [] -> [{constant}]");
198 stack.push_value(constant.into())?;
199 Ok(false)
200 }
201);
202
203define_instruction!(
204 f64_const,
205 opcode::F64_CONST,
206 |Args { wasm, stack, .. }| {
207 let constant = value::F64::from_bits(wasm.read_f64().unwrap_validated());
208 trace!("Constanting instruction: f64.const [] -> [{constant}]");
209 stack.push_value(constant.into())?;
210 Ok(false)
211 }
212);
213
214define_instruction!(
215 i64_const,
216 opcode::I64_CONST,
217 |Args { wasm, stack, .. }| {
218 let constant = wasm.read_var_i64().unwrap_validated();
219 trace!("Constant instruction: i64.const [] -> [{constant}]");
220 stack.push_value(constant.into())?;
221 Ok(false)
222 }
223);
224
225define_instruction!(
226 ref_null,
227 opcode::REF_NULL,
228 |Args { wasm, stack, .. }| {
229 let reftype = RefType::read(wasm).unwrap_validated();
230
231 stack.push_value(Value::Ref(Ref::Null(reftype)))?;
232 trace!("Instruction: ref.null '{:?}' -> [{:?}]", reftype, reftype);
233 Ok(false)
234 }
235);
236
237define_instruction!(
238 ref_func,
239 opcode::REF_FUNC,
240 |Args {
241 wasm,
242 module,
243 store,
244 stack,
245 }| {
246 let func_idx = unsafe { FuncIdx::read_unchecked(wasm) };
249 let func_addr = unsafe { store.modules.get(module).func_addrs.get(func_idx) };
252 stack.push_value(Value::Ref(Ref::Func(*func_addr)))?;
253 Ok(false)
254 }
255);
256
257define_instruction!(
258 fd_extensions,
259 opcode::FD_EXTENSIONS,
260 |Args { wasm, stack, .. }| {
261 use crate::core::reader::types::opcode::fd_extensions::*;
262
263 match wasm.read_var_u32().unwrap_validated() {
264 V128_CONST => {
265 let mut data = [0; 16];
266 for byte_ref in &mut data {
267 *byte_ref = wasm.read_u8().unwrap_validated();
268 }
269
270 stack.push_value(Value::V128(data))?;
271 }
272 0x00..=0x0B | 0x0D.. => unreachable_validated!(),
273 }
274
275 Ok(false)
276 }
277);