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