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