1use alloc::vec;
14use alloc::vec::Vec;
15
16use crate::{
17 assert_validated::UnwrapValidatedExt,
18 core::{
19 indices::{DataIdx, FuncIdx, GlobalIdx, LabelIdx, LocalIdx, MemIdx, TableIdx, TypeIdx},
20 reader::{
21 types::{memarg::MemArg, BlockType},
22 WasmReadable, WasmReader,
23 },
24 sidetable::Sidetable,
25 },
26 locals::Locals,
27 store::DataInst,
28 value::{self, FuncAddr, Ref},
29 value_stack::Stack,
30 ElemInst, MemInst, ModuleInst, NumType, RefType, RuntimeError, TableInst, ValType, Value,
31};
32
33#[cfg(feature = "hooks")]
34use crate::execution::hooks::HookSet;
35
36use super::store::Store;
37
38pub(super) fn run<H: HookSet>(
40 current_module_idx: &mut usize,
41 stack: &mut Stack,
42 mut hooks: H,
43 store: &mut Store,
44) -> Result<(), RuntimeError> {
45 let global_func_idx =
46 store.modules[*current_module_idx].func_addrs[stack.current_stackframe().func_idx];
47
48 let func_inst = store.functions.get(global_func_idx).unwrap_validated();
49
50 let wasm = &mut WasmReader::new(store.modules[*current_module_idx].wasm_bytecode);
52
53 let mut current_sidetable: &Sidetable = &store.modules[*current_module_idx].sidetable;
54 let mut stp = func_inst.stp;
55
56 wasm.move_start_to(func_inst.code_expr).unwrap();
58
59 use crate::core::reader::types::opcode::*;
60 loop {
61 #[cfg(feature = "hooks")]
63 hooks.instruction_hook(store.modules[*current_module_idx].wasm_bytecode, wasm.pc);
64
65 let first_instr_byte = wasm.read_u8().unwrap_validated();
66
67 #[cfg(debug_assertions)]
68 trace!(
69 "Executing instruction {}",
70 opcode_byte_to_str(first_instr_byte)
71 );
72
73 match first_instr_byte {
74 NOP => {
75 trace!("Instruction: NOP");
76 }
77 END => {
78 let current_func_global_idx = store.modules[*current_module_idx].func_addrs
79 [stack.current_stackframe().func_idx];
80 let current_func_span = store
85 .functions
86 .get(current_func_global_idx)
87 .unwrap_validated()
88 .code_expr;
89
90 if wasm.pc != current_func_span.from() + current_func_span.len() {
93 continue;
94 }
95
96 let (return_module, maybe_return_address, maybe_return_stp) =
97 stack.pop_stackframe();
98
99 if stack.callframe_count() == 0 {
103 break;
104 }
105
106 trace!("end of function reached, returning to previous stack frame");
107 *current_module_idx = return_module;
108 wasm.full_wasm_binary = store.modules[*current_module_idx].wasm_bytecode;
109 wasm.pc = maybe_return_address;
110 stp = maybe_return_stp;
111
112 current_sidetable = &store.modules[*current_module_idx].sidetable;
113
114 trace!("Instruction: END");
115 }
116 IF => {
117 wasm.read_var_u32().unwrap_validated();
118
119 let test_val: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
120
121 if test_val != 0 {
122 stp += 1;
123 } else {
124 do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
125 }
126 trace!("Instruction: IF");
127 }
128 ELSE => {
129 do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
130 }
131 BR_IF => {
132 wasm.read_var_u32().unwrap_validated();
133
134 let test_val: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
135
136 if test_val != 0 {
137 do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
138 } else {
139 stp += 1;
140 }
141 trace!("Instruction: BR_IF");
142 }
143 BR_TABLE => {
144 let label_vec = wasm
145 .read_vec(|wasm| wasm.read_var_u32().map(|v| v as LabelIdx))
146 .unwrap_validated();
147 wasm.read_var_u32().unwrap_validated();
148
149 let case_val_i32: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
151 let case_val = case_val_i32 as usize;
152
153 if case_val >= label_vec.len() {
154 stp += label_vec.len();
155 } else {
156 stp += case_val;
157 }
158
159 do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
160 }
161 BR => {
162 wasm.read_var_u32().unwrap_validated();
164 do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
165 }
166 BLOCK | LOOP => {
167 BlockType::read_unvalidated(wasm);
168 }
169 RETURN => {
170 do_sidetable_control_transfer(wasm, stack, &mut stp, current_sidetable)?;
172 }
173 CALL => {
174 let local_func_idx = wasm.read_var_u32().unwrap_validated() as FuncIdx;
175
176 let func_to_call_addr =
177 store.modules[*current_module_idx].func_addrs[local_func_idx];
178
179 let func_to_call_inst = store.functions.get(func_to_call_addr).unwrap_validated();
180 let func_to_call_ty = func_to_call_inst.ty();
181
182 let (func_to_call_idx, _) = store.modules[func_to_call_inst.module_addr]
184 .func_addrs
185 .iter()
186 .enumerate()
187 .find(|&(_idx, addr)| *addr == func_to_call_addr)
188 .ok_or(RuntimeError::FunctionNotFound)?;
189
190 let params = stack.pop_tail_iter(func_to_call_ty.params.valtypes.len());
191
192 trace!("Instruction: call [{func_to_call_idx:?}]");
193 let func_to_call_module_addr = func_to_call_inst.module_addr;
194 let remaining_locals = func_to_call_inst.locals.iter().cloned();
195 let locals = Locals::new(params, remaining_locals);
196
197 stack.push_stackframe(
198 *current_module_idx,
199 func_to_call_idx,
200 &func_to_call_ty,
201 locals,
202 wasm.pc,
203 stp,
204 )?;
205
206 *current_module_idx = func_to_call_module_addr;
207 wasm.full_wasm_binary = store.modules[*current_module_idx].wasm_bytecode;
208 wasm.move_start_to(func_to_call_inst.code_expr)
209 .unwrap_validated();
210
211 stp = func_to_call_inst.stp;
212 current_sidetable = &store.modules[*current_module_idx].sidetable;
213 trace!("Instruction: CALL");
214 }
215
216 CALL_INDIRECT => {
218 let given_type_idx = wasm.read_var_u32().unwrap_validated() as TypeIdx;
219 let table_idx = wasm.read_var_u32().unwrap_validated() as TableIdx;
220
221 let tab = &store.tables[store.modules[*current_module_idx].table_addrs[table_idx]];
222 let func_ty = store.modules[*current_module_idx]
223 .types
224 .get(given_type_idx)
225 .unwrap_validated();
226
227 let i: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
228
229 let r = tab
230 .elem
231 .get(i as usize)
232 .ok_or(RuntimeError::UndefinedTableIndex)
233 .and_then(|r| {
234 if r.is_null() {
235 trace!("table_idx ({table_idx}) --- element index in table ({i})");
236 Err(RuntimeError::UninitializedElement)
237 } else {
238 Ok(r)
239 }
240 })?;
241
242 let func_to_call_addr = match *r {
243 Ref::Func(func_addr) => func_addr.addr.unwrap_validated(),
244 Ref::Extern(_) => unreachable!(),
245 };
246
247 let func_to_call_inst = &store.functions[func_to_call_addr];
248 let func_to_call_module_addr = func_to_call_inst.module_addr;
249
250 let (func_to_call_idx, _) = store.modules[func_to_call_inst.module_addr]
252 .func_addrs
253 .iter()
254 .enumerate()
255 .find(|&(_idx, addr)| *addr == func_to_call_addr)
256 .ok_or(RuntimeError::FunctionNotFound)?;
257
258 let actual_ty = func_to_call_inst.ty();
259
260 if *func_ty != actual_ty {
261 return Err(RuntimeError::SignatureMismatch);
262 }
263
264 let params = stack.pop_tail_iter(func_ty.params.valtypes.len());
265 let remaining_locals = func_to_call_inst.locals.iter().cloned();
266
267 let locals = Locals::new(params, remaining_locals);
268
269 stack.push_stackframe(
270 *current_module_idx,
271 func_to_call_idx,
272 func_ty,
273 locals,
274 wasm.pc,
275 stp,
276 )?;
277 *current_module_idx = func_to_call_module_addr;
278 wasm.full_wasm_binary = store.modules[*current_module_idx].wasm_bytecode;
279 wasm.move_start_to(func_to_call_inst.code_expr)
280 .unwrap_validated();
281
282 stp = func_to_call_inst.stp;
283 current_sidetable = &store.modules[*current_module_idx].sidetable;
284
285 trace!("Instruction: CALL_INDIRECT");
286 }
287 DROP => {
288 stack.drop_value();
289 trace!("Instruction: DROP");
290 }
291 SELECT => {
292 let test_val: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
293 let val2 = stack.pop_value_with_unknown_type();
294 let val1 = stack.pop_value_with_unknown_type();
295 if test_val != 0 {
296 stack.push_value(val1)?;
297 } else {
298 stack.push_value(val2)?;
299 }
300 trace!("Instruction: SELECT");
301 }
302 SELECT_T => {
303 let type_vec = wasm.read_vec(ValType::read).unwrap_validated();
304 let test_val: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
305 let val2 = stack.pop_value(type_vec[0]);
306 let val1 = stack.pop_value(type_vec[0]);
307 if test_val != 0 {
308 stack.push_value(val1)?;
309 } else {
310 stack.push_value(val2)?;
311 }
312 trace!("Instruction: SELECT_T");
313 }
314 LOCAL_GET => {
315 let local_idx = wasm.read_var_u32().unwrap_validated() as LocalIdx;
316 stack.get_local(local_idx)?;
317 trace!("Instruction: local.get {} [] -> [t]", local_idx);
318 }
319 LOCAL_SET => stack.set_local(wasm.read_var_u32().unwrap_validated() as LocalIdx),
320 LOCAL_TEE => stack.tee_local(wasm.read_var_u32().unwrap_validated() as LocalIdx),
321 GLOBAL_GET => {
322 let global_idx = wasm.read_var_u32().unwrap_validated() as GlobalIdx;
323 let global =
324 &store.globals[store.modules[*current_module_idx].global_addrs[global_idx]];
325
326 stack.push_value(global.value)?;
327
328 trace!(
329 "Instruction: global.get '{}' [<GLOBAL>] -> [{:?}]",
330 global_idx,
331 global.value
332 );
333 }
334 GLOBAL_SET => {
335 let global_idx = wasm.read_var_u32().unwrap_validated() as GlobalIdx;
336 let global =
337 &mut store.globals[store.modules[*current_module_idx].global_addrs[global_idx]];
338 global.value = stack.pop_value(global.ty.ty);
339 trace!("Instruction: GLOBAL_SET");
340 }
341 TABLE_GET => {
342 let table_idx = wasm.read_var_u32().unwrap_validated() as TableIdx;
343 let tab = &store.tables[store.modules[*current_module_idx].table_addrs[table_idx]];
344
345 let i: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
346
347 let val = tab
348 .elem
349 .get(i as usize)
350 .ok_or(RuntimeError::TableAccessOutOfBounds)?;
351
352 stack.push_value((*val).into())?;
353 trace!(
354 "Instruction: table.get '{}' [{}] -> [{}]",
355 table_idx,
356 i,
357 val
358 );
359 }
360 TABLE_SET => {
361 let table_idx = wasm.read_var_u32().unwrap_validated() as TableIdx;
362
363 let tab =
364 &mut store.tables[store.modules[*current_module_idx].table_addrs[table_idx]];
365
366 let val: Ref = stack.pop_value(ValType::RefType(tab.ty.et)).into();
367 let i: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
368
369 tab.elem
370 .get_mut(i as usize)
371 .ok_or(RuntimeError::TableAccessOutOfBounds)
372 .map(|r| *r = val)?;
373 trace!(
374 "Instruction: table.set '{}' [{} {}] -> []",
375 table_idx,
376 i,
377 val
378 )
379 }
380 UNREACHABLE => {
381 return Err(RuntimeError::ReachedUnreachable);
382 }
383 I32_LOAD => {
384 let memarg = MemArg::read_unvalidated(wasm);
385 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
386
387 let mem_inst = &store.memories[store.modules[*current_module_idx].mem_addrs[0]];
388
389 let idx = calculate_mem_address(&memarg, relative_address)?;
390 let data = mem_inst.mem.load(idx)?;
391
392 stack.push_value(Value::I32(data))?;
393 trace!("Instruction: i32.load [{relative_address}] -> [{data}]");
394 }
395 I64_LOAD => {
396 let memarg = MemArg::read_unvalidated(wasm);
397 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
398
399 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
402 let data = mem.mem.load(idx)?;
403
404 stack.push_value(Value::I64(data))?;
405 trace!("Instruction: i64.load [{relative_address}] -> [{data}]");
406 }
407 F32_LOAD => {
408 let memarg = MemArg::read_unvalidated(wasm);
409 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
410
411 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
414 let data = mem.mem.load(idx)?;
415
416 stack.push_value(Value::F32(value::F32(data)))?;
417 trace!("Instruction: f32.load [{relative_address}] -> [{data}]");
418 }
419 F64_LOAD => {
420 let memarg = MemArg::read_unvalidated(wasm);
421 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
422
423 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
426 let data = mem.mem.load(idx)?;
427
428 stack.push_value(Value::F64(value::F64(data)))?;
429 trace!("Instruction: f64.load [{relative_address}] -> [{data}]");
430 }
431 I32_LOAD8_S => {
432 let memarg = MemArg::read_unvalidated(wasm);
433 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
434
435 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
438 let data: i8 = mem.mem.load(idx)?;
439
440 stack.push_value(Value::I32(data as u32))?;
441 trace!("Instruction: i32.load8_s [{relative_address}] -> [{data}]");
442 }
443 I32_LOAD8_U => {
444 let memarg = MemArg::read_unvalidated(wasm);
445 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
446
447 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
450 let data: u8 = mem.mem.load(idx)?;
451
452 stack.push_value(Value::I32(data as u32))?;
453 trace!("Instruction: i32.load8_u [{relative_address}] -> [{data}]");
454 }
455 I32_LOAD16_S => {
456 let memarg = MemArg::read_unvalidated(wasm);
457 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
458
459 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
462 let data: i16 = mem.mem.load(idx)?;
463
464 stack.push_value(Value::I32(data as u32))?;
465 trace!("Instruction: i32.load16_s [{relative_address}] -> [{data}]");
466 }
467 I32_LOAD16_U => {
468 let memarg = MemArg::read_unvalidated(wasm);
469 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
470
471 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
474 let data: u16 = mem.mem.load(idx)?;
475
476 stack.push_value(Value::I32(data as u32))?;
477 trace!("Instruction: i32.load16_u [{relative_address}] -> [{data}]");
478 }
479 I64_LOAD8_S => {
480 let memarg = MemArg::read_unvalidated(wasm);
481 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
482
483 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
486 let data: i8 = mem.mem.load(idx)?;
487
488 stack.push_value(Value::I64(data as u64))?;
489 trace!("Instruction: i64.load8_s [{relative_address}] -> [{data}]");
490 }
491 I64_LOAD8_U => {
492 let memarg = MemArg::read_unvalidated(wasm);
493 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
494
495 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
498 let data: u8 = mem.mem.load(idx)?;
499
500 stack.push_value(Value::I64(data as u64))?;
501 trace!("Instruction: i64.load8_u [{relative_address}] -> [{data}]");
502 }
503 I64_LOAD16_S => {
504 let memarg = MemArg::read_unvalidated(wasm);
505 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
506
507 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
510 let data: i16 = mem.mem.load(idx)?;
511
512 stack.push_value(Value::I64(data as u64))?;
513 trace!("Instruction: i64.load16_s [{relative_address}] -> [{data}]");
514 }
515 I64_LOAD16_U => {
516 let memarg = MemArg::read_unvalidated(wasm);
517 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
518
519 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
522 let data: u16 = mem.mem.load(idx)?;
523
524 stack.push_value(Value::I64(data as u64))?;
525 trace!("Instruction: i64.load16_u [{relative_address}] -> [{data}]");
526 }
527 I64_LOAD32_S => {
528 let memarg = MemArg::read_unvalidated(wasm);
529 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
530
531 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
534 let data: i32 = mem.mem.load(idx)?;
535
536 stack.push_value(Value::I64(data as u64))?;
537 trace!("Instruction: i64.load32_s [{relative_address}] -> [{data}]");
538 }
539 I64_LOAD32_U => {
540 let memarg = MemArg::read_unvalidated(wasm);
541 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
542
543 let mem = &store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
546 let data: u32 = mem.mem.load(idx)?;
547
548 stack.push_value(Value::I64(data as u64))?;
549 trace!("Instruction: i64.load32_u [{relative_address}] -> [{data}]");
550 }
551 I32_STORE => {
552 let memarg = MemArg::read_unvalidated(wasm);
553
554 let data_to_store: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
555 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
556
557 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
560 mem.mem.store(idx, data_to_store)?;
561
562 trace!("Instruction: i32.store [{relative_address} {data_to_store}] -> []");
563 }
564 I64_STORE => {
565 let memarg = MemArg::read_unvalidated(wasm);
566
567 let data_to_store: u64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
568 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
569
570 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
573 mem.mem.store(idx, data_to_store)?;
574
575 trace!("Instruction: i64.store [{relative_address} {data_to_store}] -> []");
576 }
577 F32_STORE => {
578 let memarg = MemArg::read_unvalidated(wasm);
579
580 let data_to_store: f32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
581 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
582
583 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
586 mem.mem.store(idx, data_to_store)?;
587
588 trace!("Instruction: f32.store [{relative_address} {data_to_store}] -> []");
589 }
590 F64_STORE => {
591 let memarg = MemArg::read_unvalidated(wasm);
592
593 let data_to_store: f64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
594 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
595
596 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]]; let idx = calculate_mem_address(&memarg, relative_address)?;
599 mem.mem.store(idx, data_to_store)?;
600
601 trace!("Instruction: f64.store [{relative_address} {data_to_store}] -> []");
602 }
603 I32_STORE8 => {
604 let memarg = MemArg::read_unvalidated(wasm);
605
606 let data_to_store: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
607 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
608
609 let wrapped_data: i8 = i8::from_le_bytes(
610 data_to_store.rem_euclid(2_i32.pow(8)).to_le_bytes()[0..1]
611 .try_into()
612 .expect("array to be of length 1"),
613 );
614
615 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]];
616
617 let idx = calculate_mem_address(&memarg, relative_address)?;
618 mem.mem.store(idx, wrapped_data)?;
619
620 trace!("Instruction: i32.store8 [{relative_address} {wrapped_data}] -> []");
621 }
622 I32_STORE16 => {
623 let memarg = MemArg::read_unvalidated(wasm);
624
625 let data_to_store: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
626 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
627
628 let wrapped_data: i16 = i16::from_le_bytes(
629 data_to_store.rem_euclid(2_i32.pow(16)).to_le_bytes()[0..2]
630 .try_into()
631 .expect("array to be of length 2"),
632 );
633
634 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]];
635
636 let idx = calculate_mem_address(&memarg, relative_address)?;
637 mem.mem.store(idx, wrapped_data)?;
638
639 trace!("Instruction: i32.store16 [{relative_address} {data_to_store}] -> []");
640 }
641 I64_STORE8 => {
642 let memarg = MemArg::read_unvalidated(wasm);
643
644 let data_to_store: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
645 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
646
647 let wrapped_data: i8 = i8::from_le_bytes(
648 data_to_store.rem_euclid(2_i64.pow(8)).to_le_bytes()[0..1]
649 .try_into()
650 .expect("array to be of length 1"),
651 );
652
653 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]];
654
655 let idx = calculate_mem_address(&memarg, relative_address)?;
656 mem.mem.store(idx, wrapped_data)?;
657
658 trace!("Instruction: i64.store8 [{relative_address} {data_to_store}] -> []");
659 }
660 I64_STORE16 => {
661 let memarg = MemArg::read_unvalidated(wasm);
662
663 let data_to_store: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
664 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
665
666 let wrapped_data: i16 = i16::from_le_bytes(
667 data_to_store.rem_euclid(2_i64.pow(16)).to_le_bytes()[0..2]
668 .try_into()
669 .expect("array to be of length 2"),
670 );
671
672 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]];
673
674 let idx = calculate_mem_address(&memarg, relative_address)?;
675 mem.mem.store(idx, wrapped_data)?;
676
677 trace!("Instruction: i64.store16 [{relative_address} {data_to_store}] -> []");
678 }
679 I64_STORE32 => {
680 let memarg = MemArg::read_unvalidated(wasm);
681
682 let data_to_store: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
683 let relative_address: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
684
685 let wrapped_data: i32 = i32::from_le_bytes(
686 data_to_store.rem_euclid(2_i64.pow(32)).to_le_bytes()[0..4]
687 .try_into()
688 .expect("array to be of length 4"),
689 );
690
691 let mem = &mut store.memories[store.modules[*current_module_idx].mem_addrs[0]];
692
693 let idx = calculate_mem_address(&memarg, relative_address)?;
694 mem.mem.store(idx, wrapped_data)?;
695
696 trace!("Instruction: i64.store32 [{relative_address} {data_to_store}] -> []");
697 }
698 MEMORY_SIZE => {
699 let mem_idx = wasm.read_u8().unwrap_validated() as usize;
700 let mem =
701 &mut store.memories[store.modules[*current_module_idx].mem_addrs[mem_idx]];
702 let size = mem.size() as u32;
703 stack.push_value(Value::I32(size))?;
704 trace!("Instruction: memory.size [] -> [{}]", size);
705 }
706 MEMORY_GROW => {
707 let mem_idx = wasm.read_u8().unwrap_validated() as usize;
708 let mem =
709 &mut store.memories[store.modules[*current_module_idx].mem_addrs[mem_idx]];
710 let sz: u32 = mem.size() as u32;
711
712 let n: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
713
714 let pushed_value = match mem.grow(n) {
718 Ok(_) => sz,
719 Err(_) => u32::MAX,
720 };
721 stack.push_value(Value::I32(pushed_value))?;
722 trace!("Instruction: memory.grow [{}] -> [{}]", n, pushed_value);
723 }
724 I32_CONST => {
725 let constant = wasm.read_var_i32().unwrap_validated();
726 trace!("Instruction: i32.const [] -> [{constant}]");
727 stack.push_value(constant.into())?;
728 }
729 F32_CONST => {
730 let constant = f32::from_bits(wasm.read_var_f32().unwrap_validated());
731 trace!("Instruction: f32.const [] -> [{constant:.7}]");
732 stack.push_value(constant.into())?;
733 }
734 I32_EQZ => {
735 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
736
737 let res = if v1 == 0 { 1 } else { 0 };
738
739 trace!("Instruction: i32.eqz [{v1}] -> [{res}]");
740 stack.push_value(res.into())?;
741 }
742 I32_EQ => {
743 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
744 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
745
746 let res = if v1 == v2 { 1 } else { 0 };
747
748 trace!("Instruction: i32.eq [{v1} {v2}] -> [{res}]");
749 stack.push_value(res.into())?;
750 }
751 I32_NE => {
752 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
753 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
754
755 let res = if v1 != v2 { 1 } else { 0 };
756
757 trace!("Instruction: i32.ne [{v1} {v2}] -> [{res}]");
758 stack.push_value(res.into())?;
759 }
760 I32_LT_S => {
761 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
762 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
763
764 let res = if v1 < v2 { 1 } else { 0 };
765
766 trace!("Instruction: i32.lt_s [{v1} {v2}] -> [{res}]");
767 stack.push_value(res.into())?;
768 }
769
770 I32_LT_U => {
771 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
772 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
773
774 let res = if (v1 as u32) < (v2 as u32) { 1 } else { 0 };
775
776 trace!("Instruction: i32.lt_u [{v1} {v2}] -> [{res}]");
777 stack.push_value(res.into())?;
778 }
779 I32_GT_S => {
780 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
781 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
782
783 let res = if v1 > v2 { 1 } else { 0 };
784
785 trace!("Instruction: i32.gt_s [{v1} {v2}] -> [{res}]");
786 stack.push_value(res.into())?;
787 }
788 I32_GT_U => {
789 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
790 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
791
792 let res = if (v1 as u32) > (v2 as u32) { 1 } else { 0 };
793
794 trace!("Instruction: i32.gt_u [{v1} {v2}] -> [{res}]");
795 stack.push_value(res.into())?;
796 }
797 I32_LE_S => {
798 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
799 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
800
801 let res = if v1 <= v2 { 1 } else { 0 };
802
803 trace!("Instruction: i32.le_s [{v1} {v2}] -> [{res}]");
804 stack.push_value(res.into())?;
805 }
806 I32_LE_U => {
807 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
808 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
809
810 let res = if (v1 as u32) <= (v2 as u32) { 1 } else { 0 };
811
812 trace!("Instruction: i32.le_u [{v1} {v2}] -> [{res}]");
813 stack.push_value(res.into())?;
814 }
815 I32_GE_S => {
816 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
817 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
818
819 let res = if v1 >= v2 { 1 } else { 0 };
820
821 trace!("Instruction: i32.ge_s [{v1} {v2}] -> [{res}]");
822 stack.push_value(res.into())?;
823 }
824 I32_GE_U => {
825 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
826 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
827
828 let res = if (v1 as u32) >= (v2 as u32) { 1 } else { 0 };
829
830 trace!("Instruction: i32.ge_u [{v1} {v2}] -> [{res}]");
831 stack.push_value(res.into())?;
832 }
833 I64_EQZ => {
834 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
835
836 let res = if v1 == 0 { 1 } else { 0 };
837
838 trace!("Instruction: i64.eqz [{v1}] -> [{res}]");
839 stack.push_value(res.into())?;
840 }
841 I64_EQ => {
842 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
843 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
844
845 let res = if v1 == v2 { 1 } else { 0 };
846
847 trace!("Instruction: i64.eq [{v1} {v2}] -> [{res}]");
848 stack.push_value(res.into())?;
849 }
850 I64_NE => {
851 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
852 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
853
854 let res = if v1 != v2 { 1 } else { 0 };
855
856 trace!("Instruction: i64.ne [{v1} {v2}] -> [{res}]");
857 stack.push_value(res.into())?;
858 }
859 I64_LT_S => {
860 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
861 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
862
863 let res = if v1 < v2 { 1 } else { 0 };
864
865 trace!("Instruction: i64.lt_s [{v1} {v2}] -> [{res}]");
866 stack.push_value(res.into())?;
867 }
868
869 I64_LT_U => {
870 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
871 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
872
873 let res = if (v1 as u64) < (v2 as u64) { 1 } else { 0 };
874
875 trace!("Instruction: i64.lt_u [{v1} {v2}] -> [{res}]");
876 stack.push_value(res.into())?;
877 }
878 I64_GT_S => {
879 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
880 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
881
882 let res = if v1 > v2 { 1 } else { 0 };
883
884 trace!("Instruction: i64.gt_s [{v1} {v2}] -> [{res}]");
885 stack.push_value(res.into())?;
886 }
887 I64_GT_U => {
888 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
889 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
890
891 let res = if (v1 as u64) > (v2 as u64) { 1 } else { 0 };
892
893 trace!("Instruction: i64.gt_u [{v1} {v2}] -> [{res}]");
894 stack.push_value(res.into())?;
895 }
896 I64_LE_S => {
897 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
898 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
899
900 let res = if v1 <= v2 { 1 } else { 0 };
901
902 trace!("Instruction: i64.le_s [{v1} {v2}] -> [{res}]");
903 stack.push_value(res.into())?;
904 }
905 I64_LE_U => {
906 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
907 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
908
909 let res = if (v1 as u64) <= (v2 as u64) { 1 } else { 0 };
910
911 trace!("Instruction: i64.le_u [{v1} {v2}] -> [{res}]");
912 stack.push_value(res.into())?;
913 }
914 I64_GE_S => {
915 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
916 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
917
918 let res = if v1 >= v2 { 1 } else { 0 };
919
920 trace!("Instruction: i64.ge_s [{v1} {v2}] -> [{res}]");
921 stack.push_value(res.into())?;
922 }
923 I64_GE_U => {
924 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
925 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
926
927 let res = if (v1 as u64) >= (v2 as u64) { 1 } else { 0 };
928
929 trace!("Instruction: i64.ge_u [{v1} {v2}] -> [{res}]");
930 stack.push_value(res.into())?;
931 }
932 F32_EQ => {
933 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
934 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
935
936 let res = if v1 == v2 { 1 } else { 0 };
937
938 trace!("Instruction: f32.eq [{v1} {v2}] -> [{res}]");
939 stack.push_value(res.into())?;
940 }
941 F32_NE => {
942 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
943 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
944
945 let res = if v1 != v2 { 1 } else { 0 };
946
947 trace!("Instruction: f32.ne [{v1} {v2}] -> [{res}]");
948 stack.push_value(res.into())?;
949 }
950 F32_LT => {
951 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
952 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
953
954 let res = if v1 < v2 { 1 } else { 0 };
955
956 trace!("Instruction: f32.lt [{v1} {v2}] -> [{res}]");
957 stack.push_value(res.into())?;
958 }
959 F32_GT => {
960 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
961 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
962
963 let res = if v1 > v2 { 1 } else { 0 };
964
965 trace!("Instruction: f32.gt [{v1} {v2}] -> [{res}]");
966 stack.push_value(res.into())?;
967 }
968 F32_LE => {
969 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
970 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
971
972 let res = if v1 <= v2 { 1 } else { 0 };
973
974 trace!("Instruction: f32.le [{v1} {v2}] -> [{res}]");
975 stack.push_value(res.into())?;
976 }
977 F32_GE => {
978 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
979 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
980
981 let res = if v1 >= v2 { 1 } else { 0 };
982
983 trace!("Instruction: f32.ge [{v1} {v2}] -> [{res}]");
984 stack.push_value(res.into())?;
985 }
986
987 F64_EQ => {
988 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
989 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
990
991 let res = if v1 == v2 { 1 } else { 0 };
992
993 trace!("Instruction: f64.eq [{v1} {v2}] -> [{res}]");
994 stack.push_value(res.into())?;
995 }
996 F64_NE => {
997 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
998 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
999
1000 let res = if v1 != v2 { 1 } else { 0 };
1001
1002 trace!("Instruction: f64.ne [{v1} {v2}] -> [{res}]");
1003 stack.push_value(res.into())?;
1004 }
1005 F64_LT => {
1006 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1007 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1008
1009 let res = if v1 < v2 { 1 } else { 0 };
1010
1011 trace!("Instruction: f64.lt [{v1} {v2}] -> [{res}]");
1012 stack.push_value(res.into())?;
1013 }
1014 F64_GT => {
1015 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1016 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1017
1018 let res = if v1 > v2 { 1 } else { 0 };
1019
1020 trace!("Instruction: f64.gt [{v1} {v2}] -> [{res}]");
1021 stack.push_value(res.into())?;
1022 }
1023 F64_LE => {
1024 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1025 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1026
1027 let res = if v1 <= v2 { 1 } else { 0 };
1028
1029 trace!("Instruction: f64.le [{v1} {v2}] -> [{res}]");
1030 stack.push_value(res.into())?;
1031 }
1032 F64_GE => {
1033 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1034 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1035
1036 let res = if v1 >= v2 { 1 } else { 0 };
1037
1038 trace!("Instruction: f64.ge [{v1} {v2}] -> [{res}]");
1039 stack.push_value(res.into())?;
1040 }
1041
1042 I32_CLZ => {
1043 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1044 let res = v1.leading_zeros() as i32;
1045
1046 trace!("Instruction: i32.clz [{v1}] -> [{res}]");
1047 stack.push_value(res.into())?;
1048 }
1049 I32_CTZ => {
1050 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1051 let res = v1.trailing_zeros() as i32;
1052
1053 trace!("Instruction: i32.ctz [{v1}] -> [{res}]");
1054 stack.push_value(res.into())?;
1055 }
1056 I32_POPCNT => {
1057 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1058 let res = v1.count_ones() as i32;
1059
1060 trace!("Instruction: i32.popcnt [{v1}] -> [{res}]");
1061 stack.push_value(res.into())?;
1062 }
1063 I64_CONST => {
1064 let constant = wasm.read_var_i64().unwrap_validated();
1065 trace!("Instruction: i64.const [] -> [{constant}]");
1066 stack.push_value(constant.into())?;
1067 }
1068 F64_CONST => {
1069 let constant = f64::from_bits(wasm.read_var_f64().unwrap_validated());
1070 trace!("Instruction: f64.const [] -> [{constant}]");
1071 stack.push_value(constant.into())?;
1072 }
1073 I32_ADD => {
1074 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1075 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1076 let res = v1.wrapping_add(v2);
1077
1078 trace!("Instruction: i32.add [{v1} {v2}] -> [{res}]");
1079 stack.push_value(res.into())?;
1080 }
1081 I32_SUB => {
1082 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1083 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1084 let res = v1.wrapping_sub(v2);
1085
1086 trace!("Instruction: i32.sub [{v1} {v2}] -> [{res}]");
1087 stack.push_value(res.into())?;
1088 }
1089 I32_MUL => {
1090 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1091 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1092 let res = v1.wrapping_mul(v2);
1093
1094 trace!("Instruction: i32.mul [{v1} {v2}] -> [{res}]");
1095 stack.push_value(res.into())?;
1096 }
1097 I32_DIV_S => {
1098 let dividend: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1099 let divisor: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1100
1101 if dividend == 0 {
1102 return Err(RuntimeError::DivideBy0);
1103 }
1104 if divisor == i32::MIN && dividend == -1 {
1105 return Err(RuntimeError::UnrepresentableResult);
1106 }
1107
1108 let res = divisor / dividend;
1109
1110 trace!("Instruction: i32.div_s [{divisor} {dividend}] -> [{res}]");
1111 stack.push_value(res.into())?;
1112 }
1113 I32_DIV_U => {
1114 let dividend: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1115 let divisor: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1116
1117 let dividend = dividend as u32;
1118 let divisor = divisor as u32;
1119
1120 if dividend == 0 {
1121 return Err(RuntimeError::DivideBy0);
1122 }
1123
1124 let res = (divisor / dividend) as i32;
1125
1126 trace!("Instruction: i32.div_u [{divisor} {dividend}] -> [{res}]");
1127 stack.push_value(res.into())?;
1128 }
1129 I32_REM_S => {
1130 let dividend: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1131 let divisor: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1132
1133 if dividend == 0 {
1134 return Err(RuntimeError::DivideBy0);
1135 }
1136
1137 let res = divisor.checked_rem(dividend);
1138 let res = res.unwrap_or_default();
1139
1140 trace!("Instruction: i32.rem_s [{divisor} {dividend}] -> [{res}]");
1141 stack.push_value(res.into())?;
1142 }
1143 I64_CLZ => {
1144 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1145 let res = v1.leading_zeros() as i64;
1146
1147 trace!("Instruction: i64.clz [{v1}] -> [{res}]");
1148 stack.push_value(res.into())?;
1149 }
1150 I64_CTZ => {
1151 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1152 let res = v1.trailing_zeros() as i64;
1153
1154 trace!("Instruction: i64.ctz [{v1}] -> [{res}]");
1155 stack.push_value(res.into())?;
1156 }
1157 I64_POPCNT => {
1158 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1159 let res = v1.count_ones() as i64;
1160
1161 trace!("Instruction: i64.popcnt [{v1}] -> [{res}]");
1162 stack.push_value(res.into())?;
1163 }
1164 I64_ADD => {
1165 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1166 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1167 let res = v1.wrapping_add(v2);
1168
1169 trace!("Instruction: i64.add [{v1} {v2}] -> [{res}]");
1170 stack.push_value(res.into())?;
1171 }
1172 I64_SUB => {
1173 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1174 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1175 let res = v1.wrapping_sub(v2);
1176
1177 trace!("Instruction: i64.sub [{v1} {v2}] -> [{res}]");
1178 stack.push_value(res.into())?;
1179 }
1180 I64_MUL => {
1181 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1182 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1183 let res = v1.wrapping_mul(v2);
1184
1185 trace!("Instruction: i64.mul [{v1} {v2}] -> [{res}]");
1186 stack.push_value(res.into())?;
1187 }
1188 I64_DIV_S => {
1189 let dividend: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1190 let divisor: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1191
1192 if dividend == 0 {
1193 return Err(RuntimeError::DivideBy0);
1194 }
1195 if divisor == i64::MIN && dividend == -1 {
1196 return Err(RuntimeError::UnrepresentableResult);
1197 }
1198
1199 let res = divisor / dividend;
1200
1201 trace!("Instruction: i64.div_s [{divisor} {dividend}] -> [{res}]");
1202 stack.push_value(res.into())?;
1203 }
1204 I64_DIV_U => {
1205 let dividend: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1206 let divisor: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1207
1208 let dividend = dividend as u64;
1209 let divisor = divisor as u64;
1210
1211 if dividend == 0 {
1212 return Err(RuntimeError::DivideBy0);
1213 }
1214
1215 let res = (divisor / dividend) as i64;
1216
1217 trace!("Instruction: i64.div_u [{divisor} {dividend}] -> [{res}]");
1218 stack.push_value(res.into())?;
1219 }
1220 I64_REM_S => {
1221 let dividend: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1222 let divisor: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1223
1224 if dividend == 0 {
1225 return Err(RuntimeError::DivideBy0);
1226 }
1227
1228 let res = divisor.checked_rem(dividend);
1229 let res = res.unwrap_or_default();
1230
1231 trace!("Instruction: i64.rem_s [{divisor} {dividend}] -> [{res}]");
1232 stack.push_value(res.into())?;
1233 }
1234 I64_REM_U => {
1235 let dividend: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1236 let divisor: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1237
1238 let dividend = dividend as u64;
1239 let divisor = divisor as u64;
1240
1241 if dividend == 0 {
1242 return Err(RuntimeError::DivideBy0);
1243 }
1244
1245 let res = (divisor % dividend) as i64;
1246
1247 trace!("Instruction: i64.rem_u [{divisor} {dividend}] -> [{res}]");
1248 stack.push_value(res.into())?;
1249 }
1250 I64_AND => {
1251 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1252 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1253
1254 let res = v1 & v2;
1255
1256 trace!("Instruction: i64.and [{v1} {v2}] -> [{res}]");
1257 stack.push_value(res.into())?;
1258 }
1259 I64_OR => {
1260 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1261 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1262
1263 let res = v1 | v2;
1264
1265 trace!("Instruction: i64.or [{v1} {v2}] -> [{res}]");
1266 stack.push_value(res.into())?;
1267 }
1268 I64_XOR => {
1269 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1270 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1271
1272 let res = v1 ^ v2;
1273
1274 trace!("Instruction: i64.xor [{v1} {v2}] -> [{res}]");
1275 stack.push_value(res.into())?;
1276 }
1277 I64_SHL => {
1278 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1279 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1280
1281 let res = v1.wrapping_shl((v2 & 63) as u32);
1282
1283 trace!("Instruction: i64.shl [{v1} {v2}] -> [{res}]");
1284 stack.push_value(res.into())?;
1285 }
1286 I64_SHR_S => {
1287 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1288 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1289
1290 let res = v1.wrapping_shr((v2 & 63) as u32);
1291
1292 trace!("Instruction: i64.shr_s [{v1} {v2}] -> [{res}]");
1293 stack.push_value(res.into())?;
1294 }
1295 I64_SHR_U => {
1296 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1297 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1298
1299 let res = (v1 as u64).wrapping_shr((v2 & 63) as u32);
1300
1301 trace!("Instruction: i64.shr_u [{v1} {v2}] -> [{res}]");
1302 stack.push_value(res.into())?;
1303 }
1304 I64_ROTL => {
1305 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1306 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1307
1308 let res = v1.rotate_left((v2 & 63) as u32);
1309
1310 trace!("Instruction: i64.rotl [{v1} {v2}] -> [{res}]");
1311 stack.push_value(res.into())?;
1312 }
1313 I64_ROTR => {
1314 let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1315 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1316
1317 let res = v1.rotate_right((v2 & 63) as u32);
1318
1319 trace!("Instruction: i64.rotr [{v1} {v2}] -> [{res}]");
1320 stack.push_value(res.into())?;
1321 }
1322 I32_REM_U => {
1323 let dividend: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1324 let divisor: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1325
1326 let dividend = dividend as u32;
1327 let divisor = divisor as u32;
1328
1329 if dividend == 0 {
1330 return Err(RuntimeError::DivideBy0);
1331 }
1332
1333 let res = divisor.checked_rem(dividend);
1334 let res = res.unwrap_or_default() as i32;
1335
1336 trace!("Instruction: i32.rem_u [{divisor} {dividend}] -> [{res}]");
1337 stack.push_value(res.into())?;
1338 }
1339 I32_AND => {
1340 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1341 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1342 let res = v1 & v2;
1343
1344 trace!("Instruction: i32.and [{v1} {v2}] -> [{res}]");
1345 stack.push_value(res.into())?;
1346 }
1347 I32_OR => {
1348 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1349 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1350 let res = v1 | v2;
1351
1352 trace!("Instruction: i32.or [{v1} {v2}] -> [{res}]");
1353 stack.push_value(res.into())?;
1354 }
1355 I32_XOR => {
1356 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1357 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1358 let res = v1 ^ v2;
1359
1360 trace!("Instruction: i32.xor [{v1} {v2}] -> [{res}]");
1361 stack.push_value(res.into())?;
1362 }
1363 I32_SHL => {
1364 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1365 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1366 let res = v2.wrapping_shl(v1 as u32);
1367
1368 trace!("Instruction: i32.shl [{v2} {v1}] -> [{res}]");
1369 stack.push_value(res.into())?;
1370 }
1371 I32_SHR_S => {
1372 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1373 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1374
1375 let res = v2.wrapping_shr(v1 as u32);
1376
1377 trace!("Instruction: i32.shr_s [{v2} {v1}] -> [{res}]");
1378 stack.push_value(res.into())?;
1379 }
1380 I32_SHR_U => {
1381 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1382 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1383
1384 let res = (v2 as u32).wrapping_shr(v1 as u32) as i32;
1385
1386 trace!("Instruction: i32.shr_u [{v2} {v1}] -> [{res}]");
1387 stack.push_value(res.into())?;
1388 }
1389 I32_ROTL => {
1390 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1391 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1392
1393 let res = v2.rotate_left(v1 as u32);
1394
1395 trace!("Instruction: i32.rotl [{v2} {v1}] -> [{res}]");
1396 stack.push_value(res.into())?;
1397 }
1398 I32_ROTR => {
1399 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1400 let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1401
1402 let res = v2.rotate_right(v1 as u32);
1403
1404 trace!("Instruction: i32.rotr [{v2} {v1}] -> [{res}]");
1405 stack.push_value(res.into())?;
1406 }
1407
1408 F32_ABS => {
1409 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1410 let res: value::F32 = v1.abs();
1411
1412 trace!("Instruction: f32.abs [{v1}] -> [{res}]");
1413 stack.push_value(res.into())?;
1414 }
1415 F32_NEG => {
1416 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1417 let res: value::F32 = v1.neg();
1418
1419 trace!("Instruction: f32.neg [{v1}] -> [{res}]");
1420 stack.push_value(res.into())?;
1421 }
1422 F32_CEIL => {
1423 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1424 let res: value::F32 = v1.ceil();
1425
1426 trace!("Instruction: f32.ceil [{v1}] -> [{res}]");
1427 stack.push_value(res.into())?;
1428 }
1429 F32_FLOOR => {
1430 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1431 let res: value::F32 = v1.floor();
1432
1433 trace!("Instruction: f32.floor [{v1}] -> [{res}]");
1434 stack.push_value(res.into())?;
1435 }
1436 F32_TRUNC => {
1437 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1438 let res: value::F32 = v1.trunc();
1439
1440 trace!("Instruction: f32.trunc [{v1}] -> [{res}]");
1441 stack.push_value(res.into())?;
1442 }
1443 F32_NEAREST => {
1444 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1445 let res: value::F32 = v1.nearest();
1446
1447 trace!("Instruction: f32.nearest [{v1}] -> [{res}]");
1448 stack.push_value(res.into())?;
1449 }
1450 F32_SQRT => {
1451 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1452 let res: value::F32 = v1.sqrt();
1453
1454 trace!("Instruction: f32.sqrt [{v1}] -> [{res}]");
1455 stack.push_value(res.into())?;
1456 }
1457 F32_ADD => {
1458 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1459 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1460 let res: value::F32 = v1 + v2;
1461
1462 trace!("Instruction: f32.add [{v1} {v2}] -> [{res}]");
1463 stack.push_value(res.into())?;
1464 }
1465 F32_SUB => {
1466 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1467 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1468 let res: value::F32 = v1 - v2;
1469
1470 trace!("Instruction: f32.sub [{v1} {v2}] -> [{res}]");
1471 stack.push_value(res.into())?;
1472 }
1473 F32_MUL => {
1474 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1475 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1476 let res: value::F32 = v1 * v2;
1477
1478 trace!("Instruction: f32.mul [{v1} {v2}] -> [{res}]");
1479 stack.push_value(res.into())?;
1480 }
1481 F32_DIV => {
1482 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1483 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1484 let res: value::F32 = v1 / v2;
1485
1486 trace!("Instruction: f32.div [{v1} {v2}] -> [{res}]");
1487 stack.push_value(res.into())?;
1488 }
1489 F32_MIN => {
1490 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1491 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1492 let res: value::F32 = v1.min(v2);
1493
1494 trace!("Instruction: f32.min [{v1} {v2}] -> [{res}]");
1495 stack.push_value(res.into())?;
1496 }
1497 F32_MAX => {
1498 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1499 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1500 let res: value::F32 = v1.max(v2);
1501
1502 trace!("Instruction: f32.max [{v1} {v2}] -> [{res}]");
1503 stack.push_value(res.into())?;
1504 }
1505 F32_COPYSIGN => {
1506 let v2: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1507 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1508 let res: value::F32 = v1.copysign(v2);
1509
1510 trace!("Instruction: f32.copysign [{v1} {v2}] -> [{res}]");
1511 stack.push_value(res.into())?;
1512 }
1513
1514 F64_ABS => {
1515 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1516 let res: value::F64 = v1.abs();
1517
1518 trace!("Instruction: f64.abs [{v1}] -> [{res}]");
1519 stack.push_value(res.into())?;
1520 }
1521 F64_NEG => {
1522 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1523 let res: value::F64 = v1.neg();
1524
1525 trace!("Instruction: f64.neg [{v1}] -> [{res}]");
1526 stack.push_value(res.into())?;
1527 }
1528 F64_CEIL => {
1529 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1530 let res: value::F64 = v1.ceil();
1531
1532 trace!("Instruction: f64.ceil [{v1}] -> [{res}]");
1533 stack.push_value(res.into())?;
1534 }
1535 F64_FLOOR => {
1536 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1537 let res: value::F64 = v1.floor();
1538
1539 trace!("Instruction: f64.floor [{v1}] -> [{res}]");
1540 stack.push_value(res.into())?;
1541 }
1542 F64_TRUNC => {
1543 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1544 let res: value::F64 = v1.trunc();
1545
1546 trace!("Instruction: f64.trunc [{v1}] -> [{res}]");
1547 stack.push_value(res.into())?;
1548 }
1549 F64_NEAREST => {
1550 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1551 let res: value::F64 = v1.nearest();
1552
1553 trace!("Instruction: f64.nearest [{v1}] -> [{res}]");
1554 stack.push_value(res.into())?;
1555 }
1556 F64_SQRT => {
1557 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1558 let res: value::F64 = v1.sqrt();
1559
1560 trace!("Instruction: f64.sqrt [{v1}] -> [{res}]");
1561 stack.push_value(res.into())?;
1562 }
1563 F64_ADD => {
1564 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1565 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1566 let res: value::F64 = v1 + v2;
1567
1568 trace!("Instruction: f64.add [{v1} {v2}] -> [{res}]");
1569 stack.push_value(res.into())?;
1570 }
1571 F64_SUB => {
1572 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1573 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1574 let res: value::F64 = v1 - v2;
1575
1576 trace!("Instruction: f64.sub [{v1} {v2}] -> [{res}]");
1577 stack.push_value(res.into())?;
1578 }
1579 F64_MUL => {
1580 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1581 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1582 let res: value::F64 = v1 * v2;
1583
1584 trace!("Instruction: f64.mul [{v1} {v2}] -> [{res}]");
1585 stack.push_value(res.into())?;
1586 }
1587 F64_DIV => {
1588 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1589 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1590 let res: value::F64 = v1 / v2;
1591
1592 trace!("Instruction: f64.div [{v1} {v2}] -> [{res}]");
1593 stack.push_value(res.into())?;
1594 }
1595 F64_MIN => {
1596 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1597 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1598 let res: value::F64 = v1.min(v2);
1599
1600 trace!("Instruction: f64.min [{v1} {v2}] -> [{res}]");
1601 stack.push_value(res.into())?;
1602 }
1603 F64_MAX => {
1604 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1605 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1606 let res: value::F64 = v1.max(v2);
1607
1608 trace!("Instruction: f64.max [{v1} {v2}] -> [{res}]");
1609 stack.push_value(res.into())?;
1610 }
1611 F64_COPYSIGN => {
1612 let v2: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1613 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1614 let res: value::F64 = v1.copysign(v2);
1615
1616 trace!("Instruction: f64.copysign [{v1} {v2}] -> [{res}]");
1617 stack.push_value(res.into())?;
1618 }
1619 I32_WRAP_I64 => {
1620 let v: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1621 let res: i32 = v as i32;
1622
1623 trace!("Instruction: i32.wrap_i64 [{v}] -> [{res}]");
1624 stack.push_value(res.into())?;
1625 }
1626 I32_TRUNC_F32_S => {
1627 let v: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1628 if v.is_infinity() {
1629 return Err(RuntimeError::UnrepresentableResult);
1630 }
1631 if v.is_nan() {
1632 return Err(RuntimeError::BadConversionToInteger);
1633 }
1634 if v >= value::F32(2147483648.0) || v <= value::F32(-2147483904.0) {
1635 return Err(RuntimeError::UnrepresentableResult);
1636 }
1637
1638 let res: i32 = v.as_i32();
1639
1640 trace!("Instruction: i32.trunc_f32_s [{v:.7}] -> [{res}]");
1641 stack.push_value(res.into())?;
1642 }
1643 I32_TRUNC_F32_U => {
1644 let v: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1645 if v.is_infinity() {
1646 return Err(RuntimeError::UnrepresentableResult);
1647 }
1648 if v.is_nan() {
1649 return Err(RuntimeError::BadConversionToInteger);
1650 }
1651 if v >= value::F32(4294967296.0) || v <= value::F32(-1.0) {
1652 return Err(RuntimeError::UnrepresentableResult);
1653 }
1654
1655 let res: i32 = v.as_u32() as i32;
1656
1657 trace!("Instruction: i32.trunc_f32_u [{v:.7}] -> [{res}]");
1658 stack.push_value(res.into())?;
1659 }
1660
1661 I32_TRUNC_F64_S => {
1662 let v: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1663 if v.is_infinity() {
1664 return Err(RuntimeError::UnrepresentableResult);
1665 }
1666 if v.is_nan() {
1667 return Err(RuntimeError::BadConversionToInteger);
1668 }
1669 if v >= value::F64(2147483648.0) || v <= value::F64(-2147483649.0) {
1670 return Err(RuntimeError::UnrepresentableResult);
1671 }
1672
1673 let res: i32 = v.as_i32();
1674
1675 trace!("Instruction: i32.trunc_f64_s [{v:.7}] -> [{res}]");
1676 stack.push_value(res.into())?;
1677 }
1678 I32_TRUNC_F64_U => {
1679 let v: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1680 if v.is_infinity() {
1681 return Err(RuntimeError::UnrepresentableResult);
1682 }
1683 if v.is_nan() {
1684 return Err(RuntimeError::BadConversionToInteger);
1685 }
1686 if v >= value::F64(4294967296.0) || v <= value::F64(-1.0) {
1687 return Err(RuntimeError::UnrepresentableResult);
1688 }
1689
1690 let res: i32 = v.as_u32() as i32;
1691
1692 trace!("Instruction: i32.trunc_f32_u [{v:.7}] -> [{res}]");
1693 stack.push_value(res.into())?;
1694 }
1695
1696 I64_EXTEND_I32_S => {
1697 let v: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1698
1699 let res: i64 = v as i64;
1700
1701 trace!("Instruction: i64.extend_i32_s [{v}] -> [{res}]");
1702 stack.push_value(res.into())?;
1703 }
1704
1705 I64_EXTEND_I32_U => {
1706 let v: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1707
1708 let res: i64 = v as u32 as i64;
1709
1710 trace!("Instruction: i64.extend_i32_u [{v}] -> [{res}]");
1711 stack.push_value(res.into())?;
1712 }
1713
1714 I64_TRUNC_F32_S => {
1715 let v: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1716 if v.is_infinity() {
1717 return Err(RuntimeError::UnrepresentableResult);
1718 }
1719 if v.is_nan() {
1720 return Err(RuntimeError::BadConversionToInteger);
1721 }
1722 if v >= value::F32(9223372036854775808.0) || v <= value::F32(-9223373136366403584.0)
1723 {
1724 return Err(RuntimeError::UnrepresentableResult);
1725 }
1726
1727 let res: i64 = v.as_i64();
1728
1729 trace!("Instruction: i64.trunc_f32_s [{v:.7}] -> [{res}]");
1730 stack.push_value(res.into())?;
1731 }
1732 I64_TRUNC_F32_U => {
1733 let v: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1734 if v.is_infinity() {
1735 return Err(RuntimeError::UnrepresentableResult);
1736 }
1737 if v.is_nan() {
1738 return Err(RuntimeError::BadConversionToInteger);
1739 }
1740 if v >= value::F32(18446744073709551616.0) || v <= value::F32(-1.0) {
1741 return Err(RuntimeError::UnrepresentableResult);
1742 }
1743
1744 let res: i64 = v.as_u64() as i64;
1745
1746 trace!("Instruction: i64.trunc_f32_u [{v:.7}] -> [{res}]");
1747 stack.push_value(res.into())?;
1748 }
1749
1750 I64_TRUNC_F64_S => {
1751 let v: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1752 if v.is_infinity() {
1753 return Err(RuntimeError::UnrepresentableResult);
1754 }
1755 if v.is_nan() {
1756 return Err(RuntimeError::BadConversionToInteger);
1757 }
1758 if v >= value::F64(9223372036854775808.0) || v <= value::F64(-9223372036854777856.0)
1759 {
1760 return Err(RuntimeError::UnrepresentableResult);
1761 }
1762
1763 let res: i64 = v.as_i64();
1764
1765 trace!("Instruction: i64.trunc_f64_s [{v:.17}] -> [{res}]");
1766 stack.push_value(res.into())?;
1767 }
1768 I64_TRUNC_F64_U => {
1769 let v: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1770 if v.is_infinity() {
1771 return Err(RuntimeError::UnrepresentableResult);
1772 }
1773 if v.is_nan() {
1774 return Err(RuntimeError::BadConversionToInteger);
1775 }
1776 if v >= value::F64(18446744073709551616.0) || v <= value::F64(-1.0) {
1777 return Err(RuntimeError::UnrepresentableResult);
1778 }
1779
1780 let res: i64 = v.as_u64() as i64;
1781
1782 trace!("Instruction: i64.trunc_f64_u [{v:.17}] -> [{res}]");
1783 stack.push_value(res.into())?;
1784 }
1785 F32_CONVERT_I32_S => {
1786 let v: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1787 let res: value::F32 = value::F32(v as f32);
1788
1789 trace!("Instruction: f32.convert_i32_s [{v}] -> [{res}]");
1790 stack.push_value(res.into())?;
1791 }
1792 F32_CONVERT_I32_U => {
1793 let v: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1794 let res: value::F32 = value::F32(v as u32 as f32);
1795
1796 trace!("Instruction: f32.convert_i32_u [{v}] -> [{res}]");
1797 stack.push_value(res.into())?;
1798 }
1799 F32_CONVERT_I64_S => {
1800 let v: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1801 let res: value::F32 = value::F32(v as f32);
1802
1803 trace!("Instruction: f32.convert_i64_s [{v}] -> [{res}]");
1804 stack.push_value(res.into())?;
1805 }
1806 F32_CONVERT_I64_U => {
1807 let v: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1808 let res: value::F32 = value::F32(v as u64 as f32);
1809
1810 trace!("Instruction: f32.convert_i64_u [{v}] -> [{res}]");
1811 stack.push_value(res.into())?;
1812 }
1813 F32_DEMOTE_F64 => {
1814 let v: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1815 let res: value::F32 = v.as_f32();
1816
1817 trace!("Instruction: f32.demote_f64 [{v:.17}] -> [{res:.7}]");
1818 stack.push_value(res.into())?;
1819 }
1820 F64_CONVERT_I32_S => {
1821 let v: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1822 let res: value::F64 = value::F64(v as f64);
1823
1824 trace!("Instruction: f64.convert_i32_s [{v}] -> [{res:.17}]");
1825 stack.push_value(res.into())?;
1826 }
1827 F64_CONVERT_I32_U => {
1828 let v: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1829 let res: value::F64 = value::F64(v as u32 as f64);
1830
1831 trace!("Instruction: f64.convert_i32_u [{v}] -> [{res:.17}]");
1832 stack.push_value(res.into())?;
1833 }
1834 F64_CONVERT_I64_S => {
1835 let v: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1836 let res: value::F64 = value::F64(v as f64);
1837
1838 trace!("Instruction: f64.convert_i64_s [{v}] -> [{res:.17}]");
1839 stack.push_value(res.into())?;
1840 }
1841 F64_CONVERT_I64_U => {
1842 let v: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1843 let res: value::F64 = value::F64(v as u64 as f64);
1844
1845 trace!("Instruction: f64.convert_i64_u [{v}] -> [{res:.17}]");
1846 stack.push_value(res.into())?;
1847 }
1848 F64_PROMOTE_F32 => {
1849 let v: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1850 let res: value::F64 = v.as_f32();
1851
1852 trace!("Instruction: f64.promote_f32 [{v:.7}] -> [{res:.17}]");
1853 stack.push_value(res.into())?;
1854 }
1855 I32_REINTERPRET_F32 => {
1856 let v: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1857 let res: i32 = v.reinterpret_as_i32();
1858
1859 trace!("Instruction: i32.reinterpret_f32 [{v:.7}] -> [{res}]");
1860 stack.push_value(res.into())?;
1861 }
1862 I64_REINTERPRET_F64 => {
1863 let v: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1864 let res: i64 = v.reinterpret_as_i64();
1865
1866 trace!("Instruction: i64.reinterpret_f64 [{v:.17}] -> [{res}]");
1867 stack.push_value(res.into())?;
1868 }
1869 F32_REINTERPRET_I32 => {
1870 let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
1871 let res: value::F32 = value::F32::from_bits(v1 as u32);
1872
1873 trace!("Instruction: f32.reinterpret_i32 [{v1}] -> [{res:.7}]");
1874 stack.push_value(res.into())?;
1875 }
1876 F64_REINTERPRET_I64 => {
1877 let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
1878 let res: value::F64 = value::F64::from_bits(v1 as u64);
1879
1880 trace!("Instruction: f64.reinterpret_i64 [{v1}] -> [{res:.17}]");
1881 stack.push_value(res.into())?;
1882 }
1883 REF_NULL => {
1884 let reftype = RefType::read_unvalidated(wasm);
1885
1886 stack.push_value(Value::Ref(reftype.to_null_ref()))?;
1887 trace!("Instruction: ref.null '{:?}' -> [{:?}]", reftype, reftype);
1888 }
1889 REF_IS_NULL => {
1890 let rref = stack.pop_unknown_ref();
1891 let is_null = match rref {
1892 Ref::Extern(rref) => rref.addr.is_none(),
1893 Ref::Func(rref) => rref.addr.is_none(),
1894 };
1895
1896 let res = if is_null { 1 } else { 0 };
1897 trace!("Instruction: ref.is_null [{}] -> [{}]", rref, res);
1898 stack.push_value(Value::I32(res))?;
1899 }
1900 REF_FUNC => {
1902 let func_idx = wasm.read_var_u32().unwrap_validated() as FuncIdx;
1903 stack.push_value(Value::Ref(Ref::Func(FuncAddr::new(Some(
1904 store.modules[*current_module_idx].func_addrs[func_idx],
1905 )))))?;
1906 }
1907 FC_EXTENSIONS => {
1908 let second_instr = wasm.read_var_u32().unwrap_validated();
1910
1911 use crate::core::reader::types::opcode::fc_extensions::*;
1912 match second_instr {
1913 I32_TRUNC_SAT_F32_S => {
1914 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1915 let res = {
1916 if v1.is_nan() {
1917 0
1918 } else if v1.is_negative_infinity() {
1919 i32::MIN
1920 } else if v1.is_infinity() {
1921 i32::MAX
1922 } else {
1923 v1.as_i32()
1924 }
1925 };
1926
1927 trace!("Instruction: i32.trunc_sat_f32_s [{v1}] -> [{res}]");
1928 stack.push_value(res.into())?;
1929 }
1930 I32_TRUNC_SAT_F32_U => {
1931 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1932 let res = {
1933 if v1.is_nan() || v1.is_negative_infinity() {
1934 0
1935 } else if v1.is_infinity() {
1936 u32::MAX as i32
1937 } else {
1938 v1.as_u32() as i32
1939 }
1940 };
1941
1942 trace!("Instruction: i32.trunc_sat_f32_u [{v1}] -> [{res}]");
1943 stack.push_value(res.into())?;
1944 }
1945 I32_TRUNC_SAT_F64_S => {
1946 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1947 let res = {
1948 if v1.is_nan() {
1949 0
1950 } else if v1.is_negative_infinity() {
1951 i32::MIN
1952 } else if v1.is_infinity() {
1953 i32::MAX
1954 } else {
1955 v1.as_i32()
1956 }
1957 };
1958
1959 trace!("Instruction: i32.trunc_sat_f64_s [{v1}] -> [{res}]");
1960 stack.push_value(res.into())?;
1961 }
1962 I32_TRUNC_SAT_F64_U => {
1963 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
1964 let res = {
1965 if v1.is_nan() || v1.is_negative_infinity() {
1966 0
1967 } else if v1.is_infinity() {
1968 u32::MAX as i32
1969 } else {
1970 v1.as_u32() as i32
1971 }
1972 };
1973
1974 trace!("Instruction: i32.trunc_sat_f64_u [{v1}] -> [{res}]");
1975 stack.push_value(res.into())?;
1976 }
1977 I64_TRUNC_SAT_F32_S => {
1978 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1979 let res = {
1980 if v1.is_nan() {
1981 0
1982 } else if v1.is_negative_infinity() {
1983 i64::MIN
1984 } else if v1.is_infinity() {
1985 i64::MAX
1986 } else {
1987 v1.as_i64()
1988 }
1989 };
1990
1991 trace!("Instruction: i64.trunc_sat_f32_s [{v1}] -> [{res}]");
1992 stack.push_value(res.into())?;
1993 }
1994 I64_TRUNC_SAT_F32_U => {
1995 let v1: value::F32 = stack.pop_value(ValType::NumType(NumType::F32)).into();
1996 let res = {
1997 if v1.is_nan() || v1.is_negative_infinity() {
1998 0
1999 } else if v1.is_infinity() {
2000 u64::MAX as i64
2001 } else {
2002 v1.as_u64() as i64
2003 }
2004 };
2005
2006 trace!("Instruction: i64.trunc_sat_f32_u [{v1}] -> [{res}]");
2007 stack.push_value(res.into())?;
2008 }
2009 I64_TRUNC_SAT_F64_S => {
2010 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
2011 let res = {
2012 if v1.is_nan() {
2013 0
2014 } else if v1.is_negative_infinity() {
2015 i64::MIN
2016 } else if v1.is_infinity() {
2017 i64::MAX
2018 } else {
2019 v1.as_i64()
2020 }
2021 };
2022
2023 trace!("Instruction: i64.trunc_sat_f64_s [{v1}] -> [{res}]");
2024 stack.push_value(res.into())?;
2025 }
2026 I64_TRUNC_SAT_F64_U => {
2027 let v1: value::F64 = stack.pop_value(ValType::NumType(NumType::F64)).into();
2028 let res = {
2029 if v1.is_nan() || v1.is_negative_infinity() {
2030 0
2031 } else if v1.is_infinity() {
2032 u64::MAX as i64
2033 } else {
2034 v1.as_u64() as i64
2035 }
2036 };
2037
2038 trace!("Instruction: i64.trunc_sat_f64_u [{v1}] -> [{res}]");
2039 stack.push_value(res.into())?;
2040 }
2041 MEMORY_INIT => {
2044 let data_idx = wasm.read_var_u32().unwrap_validated() as DataIdx;
2049 let mem_idx = wasm.read_u8().unwrap_validated() as usize;
2050
2051 let n: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2052 let s: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2053 let d: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2054
2055 memory_init(
2056 &store.modules,
2057 &mut store.memories,
2058 &store.data,
2059 current_module_idx,
2060 data_idx,
2061 mem_idx,
2062 n,
2063 s,
2064 d,
2065 )?;
2066 }
2067 DATA_DROP => {
2068 let data_idx = wasm.read_var_u32().unwrap_validated() as DataIdx;
2069 data_drop(
2070 &store.modules,
2071 &mut store.data,
2072 current_module_idx,
2073 data_idx,
2074 )?;
2075 }
2076 MEMORY_COPY => {
2078 let (dst_idx, src_idx) = (
2083 wasm.read_u8().unwrap_validated() as usize,
2084 wasm.read_u8().unwrap_validated() as usize,
2085 );
2086 let n: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2087 let s: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2088 let d: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2089
2090 let src_mem =
2091 &store.memories[store.modules[*current_module_idx].mem_addrs[src_idx]];
2092 let dest_mem =
2093 &store.memories[store.modules[*current_module_idx].mem_addrs[dst_idx]];
2094
2095 dest_mem
2096 .mem
2097 .copy(d as MemIdx, &src_mem.mem, s as MemIdx, n as MemIdx)?;
2098 trace!("Instruction: memory.copy");
2099 }
2100 MEMORY_FILL => {
2102 let mem_idx = wasm.read_u8().unwrap_validated() as usize;
2107 let mem = &mut store.memories
2108 [store.modules[*current_module_idx].mem_addrs[mem_idx]];
2109 let n: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2110 let val: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2111
2112 if !(0..=255).contains(&val) {
2113 warn!("Value for memory.fill does not fit in a byte ({val})");
2114 }
2115
2116 let d: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2117
2118 mem.mem.fill(d as usize, val as u8, n as usize)?;
2119
2120 trace!("Instruction: memory.fill");
2121 }
2122 TABLE_INIT => {
2127 let elem_idx = wasm.read_var_u32().unwrap_validated() as usize;
2128 let table_idx = wasm.read_var_u32().unwrap_validated() as usize;
2129
2130 let n: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into(); let s: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into(); let d: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into(); table_init(
2135 &store.modules,
2136 &mut store.tables,
2137 &store.elements,
2138 current_module_idx,
2139 elem_idx,
2140 table_idx,
2141 n,
2142 s,
2143 d,
2144 )?;
2145 }
2146 ELEM_DROP => {
2147 let elem_idx = wasm.read_var_u32().unwrap_validated() as usize;
2148
2149 elem_drop(
2150 &store.modules,
2151 &mut store.elements,
2152 current_module_idx,
2153 elem_idx,
2154 )?;
2155 }
2156 TABLE_COPY => {
2158 let table_x_idx = wasm.read_var_u32().unwrap_validated() as usize;
2159 let table_y_idx = wasm.read_var_u32().unwrap_validated() as usize;
2160
2161 let tab_x_elem_len = store.tables
2162 [store.modules[*current_module_idx].table_addrs[table_x_idx]]
2163 .elem
2164 .len();
2165 let tab_y_elem_len = store.tables
2166 [store.modules[*current_module_idx].table_addrs[table_y_idx]]
2167 .elem
2168 .len();
2169
2170 let n: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into(); let s: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into(); let d: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into(); let src_res = match s.checked_add(n) {
2175 Some(res) => {
2176 if res > tab_y_elem_len as u32 {
2177 return Err(RuntimeError::TableAccessOutOfBounds);
2178 } else {
2179 res as usize
2180 }
2181 }
2182 _ => return Err(RuntimeError::TableAccessOutOfBounds),
2183 };
2184
2185 let dst_res = match d.checked_add(n) {
2186 Some(res) => {
2187 if res > tab_x_elem_len as u32 {
2188 return Err(RuntimeError::TableAccessOutOfBounds);
2189 } else {
2190 res as usize
2191 }
2192 }
2193 _ => return Err(RuntimeError::TableAccessOutOfBounds),
2194 };
2195
2196 let dst = table_x_idx;
2197 let src = table_y_idx;
2198
2199 if table_x_idx == table_y_idx {
2200 store.tables
2201 [store.modules[*current_module_idx].table_addrs[table_x_idx]]
2202 .elem
2203 .copy_within(s as usize..src_res, d as usize); } else {
2205 use core::cmp::Ordering::*;
2206 let src = store.modules[*current_module_idx].table_addrs[src];
2207 let dst = store.modules[*current_module_idx].table_addrs[dst];
2208
2209 let (src_table, dst_table) = match dst.cmp(&src) {
2210 Greater => {
2211 let (left, right) = store.tables.split_at_mut(dst);
2212 (&left[src], &mut right[0])
2213 }
2214 Less => {
2215 let (left, right) = store.tables.split_at_mut(src);
2216 (&right[0], &mut left[dst])
2217 }
2218 Equal => unreachable!(),
2219 };
2220
2221 dst_table.elem[d as usize..dst_res]
2222 .copy_from_slice(&src_table.elem[s as usize..src_res]);
2223 }
2224
2225 trace!(
2226 "Instruction: table.copy '{}' '{}' [{} {} {}] -> []",
2227 table_x_idx,
2228 table_y_idx,
2229 d,
2230 s,
2231 n
2232 );
2233 }
2234 TABLE_GROW => {
2235 let table_idx = wasm.read_var_u32().unwrap_validated() as usize;
2236 let tab = &mut store.tables
2237 [store.modules[*current_module_idx].table_addrs[table_idx]];
2238
2239 let sz = tab.elem.len() as u32;
2240
2241 let n: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2242 let val = stack.pop_unknown_ref();
2243
2244 match tab.grow(n, val) {
2248 Ok(_) => {
2249 stack.push_value(Value::I32(sz))?;
2250 }
2251 Err(_) => {
2252 stack.push_value(Value::I32(u32::MAX))?;
2253 }
2254 }
2255 }
2256 TABLE_SIZE => {
2257 let table_idx = wasm.read_var_u32().unwrap_validated() as usize;
2258 let tab = &mut store.tables
2259 [store.modules[*current_module_idx].table_addrs[table_idx]];
2260
2261 let sz = tab.elem.len() as u32;
2262
2263 stack.push_value(Value::I32(sz))?;
2264
2265 trace!("Instruction: table.size '{}' [] -> [{}]", table_idx, sz);
2266 }
2267 TABLE_FILL => {
2268 let table_idx = wasm.read_var_u32().unwrap_validated() as usize;
2269 let tab = &mut store.tables
2270 [store.modules[*current_module_idx].table_addrs[table_idx]];
2271 let ty = tab.ty.et;
2272
2273 let n: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into(); let val: Ref = stack.pop_value(ValType::RefType(ty)).into();
2275 let i: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into(); let end = (i as usize)
2278 .checked_add(n as usize)
2279 .ok_or(RuntimeError::TableAccessOutOfBounds)?;
2280
2281 tab.elem
2282 .get_mut(i as usize..end)
2283 .ok_or(RuntimeError::TableAccessOutOfBounds)?
2284 .fill(val);
2285
2286 trace!(
2287 "Instruction table.fill '{}' [{} {} {}] -> []",
2288 table_idx,
2289 i,
2290 val,
2291 n
2292 )
2293 }
2294 _ => unreachable!(),
2295 }
2296 }
2297
2298 I32_EXTEND8_S => {
2299 let mut v: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2300
2301 if v | 0xFF != 0xFF {
2302 trace!("Number v ({}) not contained in 8 bits, truncating", v);
2303 v &= 0xFF;
2304 }
2305
2306 let res = if v | 0x7F != 0x7F { v | 0xFFFFFF00 } else { v };
2307
2308 stack.push_value(res.into())?;
2309
2310 trace!("Instruction i32.extend8_s [{}] -> [{}]", v, res);
2311 }
2312 I32_EXTEND16_S => {
2313 let mut v: u32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
2314
2315 if v | 0xFFFF != 0xFFFF {
2316 trace!("Number v ({}) not contained in 16 bits, truncating", v);
2317 v &= 0xFFFF;
2318 }
2319
2320 let res = if v | 0x7FFF != 0x7FFF {
2321 v | 0xFFFF0000
2322 } else {
2323 v
2324 };
2325
2326 stack.push_value(res.into())?;
2327
2328 trace!("Instruction i32.extend16_s [{}] -> [{}]", v, res);
2329 }
2330 I64_EXTEND8_S => {
2331 let mut v: u64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
2332
2333 if v | 0xFF != 0xFF {
2334 trace!("Number v ({}) not contained in 8 bits, truncating", v);
2335 v &= 0xFF;
2336 }
2337
2338 let res = if v | 0x7F != 0x7F {
2339 v | 0xFFFFFFFF_FFFFFF00
2340 } else {
2341 v
2342 };
2343
2344 stack.push_value(res.into())?;
2345
2346 trace!("Instruction i64.extend8_s [{}] -> [{}]", v, res);
2347 }
2348 I64_EXTEND16_S => {
2349 let mut v: u64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
2350
2351 if v | 0xFFFF != 0xFFFF {
2352 trace!("Number v ({}) not contained in 16 bits, truncating", v);
2353 v &= 0xFFFF;
2354 }
2355
2356 let res = if v | 0x7FFF != 0x7FFF {
2357 v | 0xFFFFFFFF_FFFF0000
2358 } else {
2359 v
2360 };
2361
2362 stack.push_value(res.into())?;
2363
2364 trace!("Instruction i64.extend16_s [{}] -> [{}]", v, res);
2365 }
2366 I64_EXTEND32_S => {
2367 let mut v: u64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
2368
2369 if v | 0xFFFF_FFFF != 0xFFFF_FFFF {
2370 trace!("Number v ({}) not contained in 32 bits, truncating", v);
2371 v &= 0xFFFF_FFFF;
2372 }
2373
2374 let res = if v | 0x7FFF_FFFF != 0x7FFF_FFFF {
2375 v | 0xFFFFFFFF_00000000
2376 } else {
2377 v
2378 };
2379
2380 stack.push_value(res.into())?;
2381
2382 trace!("Instruction i64.extend32_s [{}] -> [{}]", v, res);
2383 }
2384
2385 other => {
2386 trace!("Unknown instruction {other:#x}, skipping..");
2387 }
2388 }
2389 }
2390 Ok(())
2391}
2392
2393fn do_sidetable_control_transfer(
2395 wasm: &mut WasmReader,
2396 stack: &mut Stack,
2397 current_stp: &mut usize,
2398 current_sidetable: &Sidetable,
2399) -> Result<(), RuntimeError> {
2400 let sidetable_entry = ¤t_sidetable[*current_stp];
2401
2402 let jump_vals = stack
2404 .pop_tail_iter(sidetable_entry.valcnt)
2405 .collect::<Vec<_>>();
2406 stack.pop_n_values(sidetable_entry.popcnt);
2407
2408 for val in jump_vals {
2409 stack.push_value(val)?;
2410 }
2411
2412 *current_stp = (*current_stp as isize + sidetable_entry.delta_stp) as usize;
2413 wasm.pc = (wasm.pc as isize + sidetable_entry.delta_pc) as usize;
2414
2415 Ok(())
2416}
2417
2418#[inline(always)]
2419fn calculate_mem_address(memarg: &MemArg, relative_address: u32) -> Result<usize, RuntimeError> {
2420 memarg
2421 .offset
2422 .checked_add(relative_address)
2427 .ok_or(RuntimeError::MemoryAccessOutOfBounds)?
2428 .try_into()
2429 .map_err(|_| RuntimeError::MemoryAccessOutOfBounds)
2430}
2431
2432#[inline(always)]
2434#[allow(clippy::too_many_arguments)]
2435pub(super) fn table_init(
2436 store_modules: &[ModuleInst],
2437 store_tables: &mut [TableInst],
2438 store_elements: &[ElemInst],
2439 current_module_idx: &usize,
2440 elem_idx: usize,
2441 table_idx: usize,
2442 n: i32,
2443 s: i32,
2444 d: i32,
2445) -> Result<(), RuntimeError> {
2446 let tab_len = store_tables[store_modules[*current_module_idx].table_addrs[table_idx]].len();
2447
2448 let tab = &mut store_tables[store_modules[*current_module_idx].table_addrs[table_idx]];
2449
2450 let elem_len = store_modules[*current_module_idx]
2452 .elem_addrs
2453 .get(elem_idx)
2454 .map(|elem_addr| store_elements[*elem_addr].len())
2455 .unwrap_or(0);
2456
2457 trace!(
2458 "Instruction: table.init '{}' '{}' [{} {} {}] -> []",
2459 elem_idx,
2460 table_idx,
2461 d,
2462 s,
2463 n
2464 );
2465
2466 let final_src_offset = (s as usize)
2467 .checked_add(n as usize)
2468 .filter(|&res| res <= elem_len)
2469 .ok_or(RuntimeError::TableAccessOutOfBounds)?;
2470
2471 (d as usize)
2472 .checked_add(n as usize)
2473 .filter(|&res| res <= tab_len)
2474 .ok_or(RuntimeError::TableAccessOutOfBounds)?;
2475
2476 let elem = &store_elements[store_modules[*current_module_idx].elem_addrs[elem_idx]];
2477
2478 let dest = &mut tab.elem[d as usize..];
2479 let src = &elem.references[s as usize..final_src_offset];
2480 dest[..src.len()].copy_from_slice(src);
2481 Ok(())
2482}
2483
2484#[inline(always)]
2485pub(super) fn elem_drop(
2486 store_modules: &[ModuleInst],
2487 store_elements: &mut [ElemInst],
2488 current_module_idx: &usize,
2489 elem_idx: usize,
2490) -> Result<(), RuntimeError> {
2491 store_elements[store_modules[*current_module_idx].elem_addrs[elem_idx]].references = vec![];
2493 Ok(())
2494}
2495
2496#[inline(always)]
2497#[allow(clippy::too_many_arguments)]
2498pub(super) fn memory_init(
2499 store_modules: &[ModuleInst],
2500 store_memories: &mut [MemInst],
2501 store_data: &[DataInst],
2502 current_module_idx: &usize,
2503 data_idx: usize,
2504 mem_idx: usize,
2505 n: i32,
2506 s: i32,
2507 d: i32,
2508) -> Result<(), RuntimeError> {
2509 let mem = &store_memories[store_modules[*current_module_idx].mem_addrs[mem_idx]];
2510
2511 mem.mem.init(
2512 d as MemIdx,
2513 &store_data[store_modules[*current_module_idx].data_addrs[data_idx]].data,
2514 s as MemIdx,
2515 n as MemIdx,
2516 )?;
2517
2518 trace!("Instruction: memory.init");
2519 Ok(())
2520}
2521
2522#[inline(always)]
2523pub(super) fn data_drop(
2524 store_modules: &[ModuleInst],
2525 store_data: &mut [DataInst],
2526 current_module_idx: &usize,
2527 data_idx: usize,
2528) -> Result<(), RuntimeError> {
2529 store_data[store_modules[*current_module_idx].data_addrs[data_idx]] =
2537 DataInst { data: Vec::new() };
2538 Ok(())
2539}