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