nowasm/
execute.rs

1use crate::{
2    components::{Blocktype, Funcidx, Functype, Importdesc, Localidx},
3    instance::FuncInst,
4    instructions::Instr,
5    Env, GlobalVal, HostFunc, Module, Val, Vector, VectorFactory, PAGE_SIZE,
6};
7use core::fmt::{Debug, Display, Formatter};
8
9#[derive(Debug, Clone, Copy)]
10pub enum ExecuteError {
11    NotExportedFunction,
12    UnresolvedImport { index: usize },
13    InvalidImportedMem,
14    InvalidImportedTable,
15    InvalidData { index: usize },
16    InvalidElem { index: usize },
17    InvalidGlobal { index: usize },
18    InvalidMemidx,
19    InvalidFuncidx,
20    InvalidTypeidx,
21    InvalidFuncArgs,
22    Trapped, // TODO: Trap
23}
24
25impl Display for ExecuteError {
26    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
27        match self {
28            Self::NotExportedFunction => write!(f, "Not exported function"),
29            Self::UnresolvedImport { index } => write!(f, "Unresolved import: {}", index),
30            Self::InvalidImportedMem => write!(f, "Invalid imported memory"),
31            Self::InvalidImportedTable => write!(f, "Invalid imported table"),
32            Self::InvalidData { index } => write!(f, "Invalid data: {}", index),
33            Self::InvalidElem { index } => write!(f, "Invalid elem: {}", index),
34            Self::InvalidGlobal { index } => write!(f, "Invalid global: {}", index),
35            Self::InvalidMemidx => write!(f, "Invalid memidx"),
36            Self::InvalidFuncidx => write!(f, "Invalid funcidx"),
37            Self::InvalidTypeidx => write!(f, "Invalid typeidx"),
38            Self::InvalidFuncArgs => write!(f, "Invalid function arguments"),
39            Self::Trapped => write!(f, "Trapped"),
40        }
41    }
42}
43
44#[cfg(feature = "std")]
45impl std::error::Error for ExecuteError {}
46
47pub struct Executor<V: VectorFactory> {
48    pub mem: V::Vector<u8>,
49    pub table: V::Vector<Option<Funcidx>>,
50    pub globals: V::Vector<GlobalVal>,
51    pub locals: V::Vector<Val>,
52    pub values: V::Vector<Val>,
53    pub current_frame: Frame,
54    pub current_block: Block,
55}
56
57impl<V: VectorFactory> Executor<V> {
58    pub fn new(
59        mem: V::Vector<u8>,
60        table: V::Vector<Option<Funcidx>>,
61        globals: V::Vector<GlobalVal>,
62    ) -> Self {
63        Self {
64            mem,
65            table,
66            globals,
67            locals: V::create_vector(None),
68            values: V::create_vector(None),
69            current_frame: Frame::default(),
70            current_block: Block::default(),
71        }
72    }
73
74    pub fn enter_frame(&mut self, ty: &Functype<V>) -> Frame {
75        let locals_start = self.locals.len();
76        for _ in 0..ty.params.len() {
77            let v = self.pop_value();
78            self.locals.push(v);
79        }
80        self.locals[locals_start..].reverse();
81        let values_start = self.values.len();
82
83        let prev = self.current_frame;
84        self.current_frame = Frame {
85            arity: ty.result.len(),
86            locals_start,
87            values_start,
88        };
89        prev
90    }
91
92    // TODO: delete unused parameter
93    pub fn exit_frame(&mut self, _ty: &Functype<V>, prev: Frame) {
94        let frame = self.current_frame;
95
96        assert!(frame.locals_start <= self.locals.len());
97        self.locals.truncate(frame.locals_start);
98
99        self.values
100            .remove_range(frame.values_start..self.values.len() - frame.arity);
101
102        self.current_frame = prev;
103    }
104
105    pub fn enter_block(&mut self, ty: Blocktype) -> Block {
106        assert!(matches!(ty, Blocktype::Empty)); // TODO
107
108        let prev = self.current_block;
109        self.current_block = Block {
110            arity: ty.arity(),
111            values_start: self.values.len(),
112        };
113        prev
114    }
115
116    // TODO: rename skipped
117    pub fn exit_block(&mut self, ty: Blocktype, skipped: bool, prev: Block) {
118        assert!(matches!(ty, Blocktype::Empty)); // TODO
119
120        let block = self.current_block;
121
122        if !skipped {
123            self.values
124                .remove_range(block.values_start..self.values.len() - block.arity);
125        }
126
127        self.current_block = prev;
128    }
129
130    pub fn set_local(&mut self, i: Localidx, v: Val) {
131        let i = self.current_frame.locals_start + i.get();
132        self.locals[i] = v;
133    }
134
135    pub fn get_local(&self, i: Localidx) -> Val {
136        let i = self.current_frame.locals_start + i.get();
137        self.locals[i]
138    }
139
140    pub fn push_value(&mut self, v: Val) {
141        self.values.push(v);
142    }
143
144    pub fn pop_value(&mut self) -> Val {
145        self.values.pop().expect("unreachable")
146    }
147
148    pub fn pop_value_i32(&mut self) -> i32 {
149        let Some(Val::I32(v)) = self.values.pop() else {
150            unreachable!();
151        };
152        v
153    }
154
155    pub fn pop_value_i64(&mut self) -> i64 {
156        let Some(Val::I64(v)) = self.values.pop() else {
157            unreachable!();
158        };
159        v
160    }
161
162    pub fn pop_value_u64(&mut self) -> u64 {
163        let Some(Val::I64(v)) = self.values.pop() else {
164            unreachable!();
165        };
166        v as u64
167    }
168
169    pub fn pop_value_u32(&mut self) -> u32 {
170        let Some(Val::I32(v)) = self.values.pop() else {
171            unreachable!();
172        };
173        v as u32
174    }
175
176    pub fn pop_value_f32(&mut self) -> f32 {
177        let Some(Val::F32(v)) = self.values.pop() else {
178            unreachable!();
179        };
180        v
181    }
182
183    pub fn pop_value_f64(&mut self) -> f64 {
184        let Some(Val::F64(v)) = self.values.pop() else {
185            unreachable!();
186        };
187        v
188    }
189
190    pub fn call_function<H: HostFunc>(
191        &mut self,
192        func_idx: Funcidx,
193        funcs: &mut [FuncInst<H>],
194        module: &Module<V>,
195    ) -> Result<(), ExecuteError> {
196        // TODO: Add validation phase
197        let func = funcs
198            .get_mut(func_idx.get())
199            .ok_or(ExecuteError::InvalidFuncidx)?;
200        let func_type = func.get_type(module).ok_or(ExecuteError::InvalidFuncidx)?; // TODO: change reason
201
202        let prev_frame = self.enter_frame(func_type);
203        match func {
204            FuncInst::Imported {
205                imports_index,
206                host_func,
207            } => {
208                let Importdesc::Func(typeidx) = module.imports()[*imports_index].desc else {
209                    unreachable!()
210                };
211                let func_type = &module.types()[typeidx.get()];
212                let args_end = self.locals.len();
213                let args_start = args_end - func_type.params.len();
214                let args = &self.locals[args_start..args_end];
215
216                let mut env = Env {
217                    mem: &mut self.mem,
218                    globals: &mut self.globals,
219                };
220                let value = host_func.invoke(args, &mut env);
221
222                // TODO: check return value type
223                if let Some(v) = value {
224                    self.values.push(v);
225                }
226            }
227            FuncInst::Module { funcs_index } => {
228                let func = module
229                    .funcs()
230                    .get(*funcs_index)
231                    .ok_or(ExecuteError::InvalidFuncidx)?;
232                for v in func.locals.iter().copied().map(Val::zero) {
233                    self.locals.push(v);
234                }
235                self.execute_instrs(func.body.instrs(), 0, funcs, module)?;
236            }
237        };
238        self.exit_frame(func_type, prev_frame);
239        Ok(())
240    }
241
242    pub fn execute_instrs<H: HostFunc>(
243        &mut self,
244        instrs: &[Instr<V>],
245        level: usize, // TODO: label
246        funcs: &mut [FuncInst<H>],
247        module: &Module<V>,
248    ) -> Result<Option<usize>, ExecuteError> {
249        for instr in instrs {
250            match instr {
251                // Control Instructions
252                Instr::Unreachable => return Err(ExecuteError::Trapped),
253                Instr::Nop => {}
254                Instr::Block(block) => {
255                    let prev_block = self.enter_block(block.blocktype);
256                    let return_level =
257                        self.execute_instrs(&block.instrs, level + 1, funcs, module)?;
258                    let skipped = return_level.map_or(false, |return_level| return_level <= level);
259                    self.exit_block(block.blocktype, skipped, prev_block);
260                    if skipped {
261                        return Ok(return_level);
262                    }
263                }
264                Instr::Loop(block) => {
265                    let current_level = level + 1;
266                    let blocktype = Blocktype::Empty;
267                    let prev_block = self.enter_block(blocktype);
268                    loop {
269                        let return_level =
270                            self.execute_instrs(&block.instrs, current_level, funcs, module)?;
271                        if return_level == Some(current_level) {
272                            continue;
273                        }
274                        let skipped =
275                            return_level.map_or(false, |return_level| return_level <= level);
276                        self.exit_block(blocktype, skipped, prev_block);
277                        if skipped {
278                            return Ok(return_level);
279                        }
280                        break;
281                    }
282                }
283                Instr::If(block) => {
284                    let c = self.pop_value_i32();
285                    let prev_block = self.enter_block(block.blocktype);
286                    let return_level = if c != 0 {
287                        self.execute_instrs(&block.then_instrs, level + 1, funcs, module)?
288                    } else {
289                        self.execute_instrs(&block.else_instrs, level + 1, funcs, module)?
290                    };
291                    let skipped = return_level.map_or(false, |return_level| return_level <= level);
292                    self.exit_block(block.blocktype, skipped, prev_block);
293                    if skipped {
294                        return Ok(return_level);
295                    }
296                }
297                Instr::Br(label) => {
298                    return Ok(Some(level - label.get()));
299                }
300                Instr::BrIf(label) => {
301                    let c = self.pop_value_i32();
302                    if c != 0 {
303                        return Ok(Some(level - label.get()));
304                    }
305                }
306                Instr::BrTable(table) => {
307                    let i = self.pop_value_i32() as usize;
308                    let label = table
309                        .labels
310                        .get(i)
311                        .unwrap_or_else(|| table.labels.last().expect("unreachable"));
312                    return Ok(Some(level - label.get()));
313                }
314                Instr::Return => {
315                    return Ok(Some(0));
316                }
317                Instr::Call(funcidx) => {
318                    self.call_function(*funcidx, funcs, module)?;
319                }
320                Instr::CallIndirect(typeidx) => {
321                    let expect_type = module
322                        .types()
323                        .get(typeidx.get())
324                        .ok_or(ExecuteError::InvalidTypeidx)?;
325
326                    let i = self.pop_value_i32() as usize;
327                    let funcidx = self
328                        .table
329                        .get(i)
330                        .ok_or(ExecuteError::Trapped)?
331                        .ok_or(ExecuteError::Trapped)?;
332                    let func = funcs
333                        .get(funcidx.get())
334                        .ok_or(ExecuteError::InvalidFuncidx)?;
335                    let actual_type = func.get_type(module).ok_or(ExecuteError::InvalidFuncidx)?; // TODO
336                    if expect_type != actual_type {
337                        return Err(ExecuteError::Trapped);
338                    }
339                    self.call_function(funcidx, funcs, module)?;
340                }
341
342                // Parametric Instructions
343                Instr::Drop => {
344                    self.pop_value();
345                }
346                Instr::Select => {
347                    let c = self.pop_value_i32();
348                    let v2 = self.pop_value();
349                    let v1 = self.pop_value();
350                    self.push_value(if c != 0 { v1 } else { v2 });
351                }
352
353                // Variable Instructions
354                Instr::LocalTee(idx) => {
355                    let v = self.pop_value();
356                    self.set_local(*idx, v);
357                    self.push_value(v);
358                }
359                Instr::LocalGet(idx) => {
360                    let v = self.get_local(*idx);
361                    self.push_value(v);
362                }
363                Instr::LocalSet(idx) => {
364                    let v = self.pop_value();
365                    self.set_local(*idx, v);
366                }
367                Instr::GlobalGet(idx) => {
368                    let v = self.globals[idx.get()].get();
369                    self.push_value(v);
370                }
371                Instr::GlobalSet(idx) => {
372                    let v = self.pop_value();
373                    self.globals[idx.get()].set(v);
374                }
375
376                // Memory Instructions
377                Instr::I32Load(arg) => {
378                    // TODO: handle alignment
379                    let i = self.pop_value_i32();
380                    let start = (i + arg.offset as i32) as usize;
381                    let end = start + 4;
382                    if self.mem.len() < end {
383                        return Err(ExecuteError::Trapped);
384                    }
385                    let v = i32::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
386                    self.values.push(Val::I32(v));
387                }
388                Instr::I64Load(arg) => {
389                    // TODO: handle alignment
390                    let i = self.pop_value_i32();
391                    let start = (i + arg.offset as i32) as usize;
392                    let end = start + 8;
393                    if self.mem.len() < end {
394                        return Err(ExecuteError::Trapped);
395                    }
396                    let v = i64::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
397                    self.values.push(Val::I64(v));
398                }
399                Instr::F32Load(arg) => {
400                    // TODO: handle alignment
401                    let i = self.pop_value_i32();
402                    let start = (i + arg.offset as i32) as usize;
403                    let end = start + 4;
404                    if self.mem.len() < end {
405                        return Err(ExecuteError::Trapped);
406                    }
407                    let v = f32::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
408                    self.values.push(Val::F32(v));
409                }
410                Instr::F64Load(arg) => {
411                    // TODO: handle alignment
412                    let i = self.pop_value_i32();
413                    let start = (i + arg.offset as i32) as usize;
414                    let end = start + 8;
415                    if self.mem.len() < end {
416                        return Err(ExecuteError::Trapped);
417                    }
418                    let v = f64::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
419                    self.values.push(Val::F64(v));
420                }
421                Instr::I32Load8S(arg) => {
422                    // TODO: handle alignment
423                    let i = self.pop_value_i32();
424                    let i = (i + arg.offset as i32) as usize;
425                    if self.mem.len() < i {
426                        return Err(ExecuteError::Trapped);
427                    }
428                    let v = self.mem[i] as i8 as i32;
429                    self.values.push(Val::I32(v));
430                }
431                Instr::I32Load8U(arg) => {
432                    // TODO: handle alignment
433                    let i = self.pop_value_i32();
434                    let i = (i + arg.offset as i32) as usize;
435                    if self.mem.len() < i {
436                        return Err(ExecuteError::Trapped);
437                    }
438                    let v = self.mem[i] as i32;
439                    self.values.push(Val::I32(v));
440                }
441                Instr::I32Load16S(arg) => {
442                    // TODO: handle alignment
443                    let i = self.pop_value_i32();
444                    let start = (i + arg.offset as i32) as usize;
445                    let end = start + 2;
446                    if self.mem.len() < end {
447                        return Err(ExecuteError::Trapped);
448                    }
449                    let v = i16::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
450                    self.values.push(Val::I32(v as i32));
451                }
452                Instr::I32Load16U(arg) => {
453                    // TODO: handle alignment
454                    let i = self.pop_value_i32();
455                    let start = (i + arg.offset as i32) as usize;
456                    let end = start + 2;
457                    if self.mem.len() < end {
458                        return Err(ExecuteError::Trapped);
459                    }
460                    let v = u16::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
461                    self.values.push(Val::I32(v as i32));
462                }
463                Instr::I64Load8S(arg) => {
464                    // TODO: handle alignment
465                    let i = self.pop_value_i32();
466                    let i = (i + arg.offset as i32) as usize;
467                    if self.mem.len() < i {
468                        return Err(ExecuteError::Trapped);
469                    }
470                    let v = self.mem[i] as i8 as i64;
471                    self.values.push(Val::I64(v));
472                }
473                Instr::I64Load8U(arg) => {
474                    // TODO: handle alignment
475                    let i = self.pop_value_i32();
476                    let i = (i + arg.offset as i32) as usize;
477                    if self.mem.len() < i {
478                        return Err(ExecuteError::Trapped);
479                    }
480                    let v = self.mem[i] as i64;
481                    self.values.push(Val::I64(v));
482                }
483                Instr::I64Load16S(arg) => {
484                    // TODO: handle alignment
485                    let i = self.pop_value_i32();
486                    let start = (i + arg.offset as i32) as usize;
487                    let end = start + 2;
488                    if self.mem.len() < end {
489                        return Err(ExecuteError::Trapped);
490                    }
491                    let v = i16::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
492                    self.values.push(Val::I64(v as i64));
493                }
494                Instr::I64Load16U(arg) => {
495                    // TODO: handle alignment
496                    let i = self.pop_value_i32();
497                    let start = (i + arg.offset as i32) as usize;
498                    let end = start + 2;
499                    if self.mem.len() < end {
500                        return Err(ExecuteError::Trapped);
501                    }
502                    let v = u16::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
503                    self.values.push(Val::I64(v as i64));
504                }
505                Instr::I64Load32S(arg) => {
506                    // TODO: handle alignment
507                    let i = self.pop_value_i32();
508                    let start = (i + arg.offset as i32) as usize;
509                    let end = start + 4;
510                    if self.mem.len() < end {
511                        return Err(ExecuteError::Trapped);
512                    }
513                    let v = i32::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
514                    self.values.push(Val::I64(v as i64));
515                }
516                Instr::I64Load32U(arg) => {
517                    // TODO: handle alignment
518                    let i = self.pop_value_i32();
519                    let start = (i + arg.offset as i32) as usize;
520                    let end = start + 4;
521                    if self.mem.len() < end {
522                        return Err(ExecuteError::Trapped);
523                    }
524                    let v = u32::from_le_bytes(self.mem[start..end].try_into().unwrap()); // TODO
525                    self.values.push(Val::I64(v as i64));
526                }
527                Instr::I32Store(arg) => {
528                    // TODO: handle alignment
529                    let v = self.pop_value();
530                    let i = self.pop_value_i32();
531                    let start = (i + arg.offset as i32) as usize;
532                    let end = start + v.byte_size();
533                    if self.mem.len() < end {
534                        return Err(ExecuteError::Trapped);
535                    }
536                    v.copy_to(&mut self.mem[start..end]);
537                }
538                Instr::I64Store(arg) => {
539                    // TODO: handle alignment
540                    let v = self.pop_value();
541                    let i = self.pop_value_i32();
542                    let start = (i + arg.offset as i32) as usize;
543                    let end = start + v.byte_size();
544                    if self.mem.len() < end {
545                        return Err(ExecuteError::Trapped);
546                    }
547                    v.copy_to(&mut self.mem[start..end]);
548                }
549                Instr::F32Store(arg) => {
550                    // TODO: handle alignment
551                    let v = self.pop_value();
552                    let i = self.pop_value_i32();
553                    let start = (i + arg.offset as i32) as usize;
554                    let end = start + v.byte_size();
555                    if self.mem.len() < end {
556                        return Err(ExecuteError::Trapped);
557                    }
558                    v.copy_to(&mut self.mem[start..end]);
559                }
560                Instr::F64Store(arg) => {
561                    // TODO: handle alignment
562                    let v = self.pop_value();
563                    let i = self.pop_value_i32();
564                    let start = (i + arg.offset as i32) as usize;
565                    let end = start + v.byte_size();
566                    if self.mem.len() < end {
567                        return Err(ExecuteError::Trapped);
568                    }
569                    v.copy_to(&mut self.mem[start..end]);
570                }
571                Instr::I32Store8(arg) => {
572                    // TODO: handle alignment
573                    let v = self.pop_value();
574                    let i = self.pop_value_i32();
575                    let i = (i + arg.offset as i32) as usize;
576                    if self.mem.len() < i {
577                        return Err(ExecuteError::Trapped);
578                    }
579                    let v = v.as_i32().ok_or(ExecuteError::Trapped)? as u8; // TODO:
580                    self.mem[i] = v;
581                }
582                Instr::I32Store16(arg) => {
583                    // TODO: handle alignment
584                    let v = self.pop_value();
585                    let i = self.pop_value_i32();
586                    let start = (i + arg.offset as i32) as usize;
587                    let end = start + 2;
588                    if self.mem.len() < end {
589                        return Err(ExecuteError::Trapped);
590                    }
591
592                    let v = v.as_i32().ok_or(ExecuteError::Trapped)? as i16; // TODO:
593                    self.mem[start..end].copy_from_slice(&v.to_le_bytes());
594                }
595                Instr::I64Store8(arg) => {
596                    // TODO: handle alignment
597                    let v = self.pop_value();
598                    let i = self.pop_value_i32();
599                    let i = (i + arg.offset as i32) as usize;
600                    if self.mem.len() < i {
601                        return Err(ExecuteError::Trapped);
602                    }
603                    let v = v.as_i64().ok_or(ExecuteError::Trapped)? as u8; // TODO:
604                    self.mem[i] = v;
605                }
606                Instr::I64Store16(arg) => {
607                    // TODO: handle alignment
608                    let v = self.pop_value();
609                    let i = self.pop_value_i32();
610                    let start = (i + arg.offset as i32) as usize;
611                    let end = start + 2;
612                    if self.mem.len() < end {
613                        return Err(ExecuteError::Trapped);
614                    }
615
616                    let v = v.as_i64().ok_or(ExecuteError::Trapped)? as i16; // TODO:
617                    self.mem[start..end].copy_from_slice(&v.to_le_bytes());
618                }
619                Instr::I64Store32(arg) => {
620                    // TODO: handle alignment
621                    let v = self.pop_value();
622                    let i = self.pop_value_i32();
623                    let start = (i + arg.offset as i32) as usize;
624                    let end = start + 4;
625                    if self.mem.len() < end {
626                        return Err(ExecuteError::Trapped);
627                    }
628
629                    let v = v.as_i64().ok_or(ExecuteError::Trapped)? as i32; // TODO:
630                    self.mem[start..end].copy_from_slice(&v.to_le_bytes());
631                }
632                Instr::MemorySize => {
633                    let size = self.mem.len() / PAGE_SIZE;
634                    self.push_value(Val::I32(size as i32));
635                }
636                Instr::MemoryGrow => {
637                    let delta = self.pop_value_i32();
638                    let max = module.mem().and_then(|m| m.limits.max).unwrap_or(u32::MAX);
639                    let current = self.mem.len() / PAGE_SIZE;
640                    let new = current + delta as usize;
641                    if new <= max as usize {
642                        // TODO: use resize()
643                        for _ in 0..delta as usize * PAGE_SIZE {
644                            self.mem.push(0);
645                        }
646                        self.push_value(Val::I32(current as i32));
647                    } else {
648                        self.push_value(Val::I32(-1));
649                    };
650                }
651
652                // Numeric Instructions
653                Instr::I32Const(v) => self.push_value(Val::I32(*v)),
654                Instr::I64Const(v) => self.push_value(Val::I64(*v)),
655                Instr::F32Const(v) => self.push_value(Val::F32(*v)),
656                Instr::F64Const(v) => self.push_value(Val::F64(*v)),
657                Instr::I32Eqz => self.apply_unop_cmp_i32(|v| v == 0),
658                Instr::I32Eq => self.apply_binop_cmp_i32(|v0, v1| v0 == v1),
659                Instr::I32Ne => self.apply_binop_cmp_i32(|v0, v1| v0 != v1),
660                Instr::I32LtS => self.apply_binop_cmp_i32(|v0, v1| v0 < v1),
661                Instr::I32LtU => self.apply_binop_cmp_u32(|v0, v1| v0 < v1),
662                Instr::I32GtS => self.apply_binop_cmp_i32(|v0, v1| v0 > v1),
663                Instr::I32GtU => self.apply_binop_cmp_u32(|v0, v1| v0 > v1),
664                Instr::I32LeS => self.apply_binop_cmp_i32(|v0, v1| v0 <= v1),
665                Instr::I32LeU => self.apply_binop_cmp_u32(|v0, v1| v0 <= v1),
666                Instr::I32GeS => self.apply_binop_cmp_i32(|v0, v1| v0 >= v1),
667                Instr::I32GeU => self.apply_binop_cmp_u32(|v0, v1| v0 >= v1),
668                Instr::I64Eqz => self.apply_unop_cmp_i64(|v| v == 0),
669                Instr::I64Eq => self.apply_binop_cmp_i64(|v0, v1| v0 == v1),
670                Instr::I64Ne => self.apply_binop_cmp_i64(|v0, v1| v0 != v1),
671                Instr::I64LtS => self.apply_binop_cmp_i64(|v0, v1| v0 < v1),
672                Instr::I64LtU => self.apply_binop_cmp_u64(|v0, v1| v0 < v1),
673                Instr::I64GtS => self.apply_binop_cmp_i64(|v0, v1| v0 > v1),
674                Instr::I64GtU => self.apply_binop_cmp_u64(|v0, v1| v0 > v1),
675                Instr::I64LeS => self.apply_binop_cmp_i64(|v0, v1| v0 <= v1),
676                Instr::I64LeU => self.apply_binop_cmp_u64(|v0, v1| v0 <= v1),
677                Instr::I64GeS => self.apply_binop_cmp_i64(|v0, v1| v0 >= v1),
678                Instr::I64GeU => self.apply_binop_cmp_u64(|v0, v1| v0 >= v1),
679                Instr::F32Eq => self.apply_binop_cmp_f32(|v0, v1| v0 == v1),
680                Instr::F32Ne => self.apply_binop_cmp_f32(|v0, v1| v0 != v1),
681                Instr::F32Lt => self.apply_binop_cmp_f32(|v0, v1| v0 < v1),
682                Instr::F32Gt => self.apply_binop_cmp_f32(|v0, v1| v0 > v1),
683                Instr::F32Le => self.apply_binop_cmp_f32(|v0, v1| v0 <= v1),
684                Instr::F32Ge => self.apply_binop_cmp_f32(|v0, v1| v0 >= v1),
685                Instr::F64Eq => self.apply_binop_cmp_f64(|v0, v1| v0 == v1),
686                Instr::F64Ne => self.apply_binop_cmp_f64(|v0, v1| v0 != v1),
687                Instr::F64Lt => self.apply_binop_cmp_f64(|v0, v1| v0 < v1),
688                Instr::F64Gt => self.apply_binop_cmp_f64(|v0, v1| v0 > v1),
689                Instr::F64Le => self.apply_binop_cmp_f64(|v0, v1| v0 <= v1),
690                Instr::F64Ge => self.apply_binop_cmp_f64(|v0, v1| v0 >= v1),
691                Instr::I32Clz => self.apply_unop_i32(|v| v.leading_zeros() as i32),
692                Instr::I32Ctz => self.apply_unop_i32(|v| v.trailing_zeros() as i32),
693                Instr::I32Popcnt => self.apply_unop_i32(|v| v.count_ones() as i32),
694                Instr::I32Add => self.apply_binop_i32(|v0, v1| v0 + v1),
695                Instr::I32Sub => self.apply_binop_i32(|v0, v1| v0 - v1),
696                Instr::I32Mul => self.apply_binop_i32(|v0, v1| v0 * v1),
697                Instr::I32DivS => self.apply_binop_i32(|v0, v1| v0.wrapping_div(v1)), // TODO: wrapping?
698                Instr::I32DivU => self.apply_binop_u32(|v0, v1| v0.wrapping_div(v1)), // TODO: wrapping?
699                Instr::I32RemS => self.apply_binop_i32(|v0, v1| v0.wrapping_rem(v1)), // TODO: wrapping?
700                Instr::I32RemU => self.apply_binop_u32(|v0, v1| v0.wrapping_rem(v1)), // TODO: wrapping?
701                Instr::I32And => self.apply_binop_i32(|v0, v1| v0 & v1),
702                Instr::I32Or => self.apply_binop_i32(|v0, v1| v0 | v1),
703                Instr::I32Xor => self.apply_binop_i32(|v0, v1| v0 ^ v1),
704                Instr::I32Shl => self.apply_binop_i32(|v0, v1| v0.wrapping_shl(v1 as u32)), // TODO: wrapping?
705                Instr::I32ShrS => self.apply_binop_i32(|v0, v1| v0.wrapping_shr(v1 as u32)), // TODO: wrapping?
706                Instr::I32ShrU => self.apply_binop_u32(|v0, v1| v0.wrapping_shr(v1)), // TODO: wrapping?
707                Instr::I32Rotl => self.apply_binop_i32(|v0, v1| v0.rotate_left(v1 as u32)),
708                Instr::I32Rotr => self.apply_binop_i32(|v0, v1| v0.rotate_right(v1 as u32)),
709                Instr::I64Clz => self.apply_unop_i64(|v| v.leading_zeros() as i64),
710                Instr::I64Ctz => self.apply_unop_i64(|v| v.trailing_zeros() as i64),
711                Instr::I64Popcnt => self.apply_unop_i64(|v| v.count_ones() as i64),
712                Instr::I64Add => self.apply_binop_i64(|v0, v1| v0 + v1),
713                Instr::I64Sub => self.apply_binop_i64(|v0, v1| v0 - v1),
714                Instr::I64Mul => self.apply_binop_i64(|v0, v1| v0 * v1),
715                Instr::I64DivS => self.apply_binop_i64(|v0, v1| v0.wrapping_div(v1)), // TODO: wrapping?
716                Instr::I64DivU => self.apply_binop_u64(|v0, v1| v0.wrapping_div(v1)), // TODO: wrapping?
717                Instr::I64RemS => self.apply_binop_i64(|v0, v1| v0.wrapping_rem(v1)), // TODO: wrapping?
718                Instr::I64RemU => self.apply_binop_u64(|v0, v1| v0.wrapping_rem(v1)), // TODO: wrapping?
719                Instr::I64And => self.apply_binop_i64(|v0, v1| v0 & v1),
720                Instr::I64Or => self.apply_binop_i64(|v0, v1| v0 | v1),
721                Instr::I64Xor => self.apply_binop_i64(|v0, v1| v0 ^ v1),
722                Instr::I64Shl => self.apply_binop_i64(|v0, v1| v0.wrapping_shl(v1 as u32)), // TODO: wrapping?
723                Instr::I64ShrS => self.apply_binop_i64(|v0, v1| v0.wrapping_shr(v1 as u32)), // TODO: wrapping?
724                Instr::I64ShrU => self.apply_binop_u64(|v0, v1| v0.wrapping_shr(v1 as u32)), // TODO: wrapping?
725                Instr::I64Rotl => self.apply_binop_i64(|v0, v1| v0.rotate_left(v1 as u32)),
726                Instr::I64Rotr => self.apply_binop_i64(|v0, v1| v0.rotate_right(v1 as u32)),
727                Instr::F32Abs => self.apply_unop_f32(|v| v.abs()),
728                Instr::F32Neg => self.apply_unop_f32(|v| -v),
729                Instr::F32Ceil => self.apply_unop_f32(|v| v.ceil()),
730                Instr::F32Floor => self.apply_unop_f32(|v| v.floor()),
731                Instr::F32Trunc => self.apply_unop_f32(|v| v.trunc()),
732                Instr::F32Nearest => self.apply_unop_f32(|v| v.round()), // TODO: round?
733                Instr::F32Sqrt => self.apply_unop_f32(|v| v.sqrt()),
734                Instr::F32Add => self.apply_binop_f32(|v0, v1| v0 + v1),
735                Instr::F32Sub => self.apply_binop_f32(|v0, v1| v0 - v1),
736                Instr::F32Mul => self.apply_binop_f32(|v0, v1| v0 * v1),
737                Instr::F32Div => self.apply_binop_f32(|v0, v1| v0 / v1),
738                Instr::F32Min => self.apply_binop_f32(|v0, v1| v0.min(v1)),
739                Instr::F32Max => self.apply_binop_f32(|v0, v1| v0.max(v1)),
740                Instr::F32Copysign => self.apply_binop_f32(|v0, v1| v0.copysign(v1)),
741                Instr::F64Abs => self.apply_unop_f64(|v| v.abs()),
742                Instr::F64Neg => self.apply_unop_f64(|v| -v),
743                Instr::F64Ceil => self.apply_unop_f64(|v| v.ceil()),
744                Instr::F64Floor => self.apply_unop_f64(|v| v.floor()),
745                Instr::F64Trunc => self.apply_unop_f64(|v| v.trunc()),
746                Instr::F64Nearest => self.apply_unop_f64(|v| v.round()), // TODO: round?
747                Instr::F64Sqrt => self.apply_unop_f64(|v| v.sqrt()),
748                Instr::F64Add => self.apply_binop_f64(|v0, v1| v0 + v1),
749                Instr::F64Sub => self.apply_binop_f64(|v0, v1| v0 - v1),
750                Instr::F64Mul => self.apply_binop_f64(|v0, v1| v0 * v1),
751                Instr::F64Div => self.apply_binop_f64(|v0, v1| v0 / v1),
752                Instr::F64Min => self.apply_binop_f64(|v0, v1| v0.min(v1)),
753                Instr::F64Max => self.apply_binop_f64(|v0, v1| v0.max(v1)),
754                Instr::F64Copysign => self.apply_binop_f64(|v0, v1| v0.copysign(v1)),
755                Instr::I32WrapI64 => self.convert_from_i64(|v| Val::I32(v as i32)),
756                Instr::I32TruncF32S => self.convert_from_f32(|v| Val::I32(v.trunc() as i32)), // TODO: NaN, etc
757                Instr::I32TruncF32U => self.convert_from_f32(|v| Val::I32(v.trunc() as i32)), // TODO: NaN, etc
758                Instr::I32TruncF64S => self.convert_from_f64(|v| Val::I32(v.trunc() as i32)), // TODO: NaN, etc
759                Instr::I32TruncF64U => self.convert_from_f64(|v| Val::I32(v.trunc() as i32)), // TODO: NaN, etc
760                Instr::I64ExtendI32S => self.convert_from_i32(|v| Val::I64(v as i64)),
761                Instr::I64ExtendI32U => self.convert_from_i32(|v| Val::I64(v as u32 as i64)),
762                Instr::I64TruncF32S => self.convert_from_f32(|v| Val::I64(v.trunc() as i64)), // TODO: NaN, etc
763                Instr::I64TruncF32U => self.convert_from_f32(|v| Val::I64(v.trunc() as i64)), // TODO: NaN, etc
764                Instr::I64TruncF64S => self.convert_from_f64(|v| Val::I64(v.trunc() as i64)), // TODO: NaN, etc
765                Instr::I64TruncF64U => self.convert_from_f64(|v| Val::I64(v.trunc() as i64)), // TODO: NaN, etc
766                Instr::F32ConvertI32S => self.convert_from_i32(|v| Val::F32(v as f32)), // TODO
767                Instr::F32ConvertI32U => self.convert_from_i32(|v| Val::F32(v as u32 as f32)), // TODO
768                Instr::F32ConvertI64S => self.convert_from_i64(|v| Val::F32(v as f32)), // TODO
769                Instr::F32ConvertI64U => self.convert_from_i64(|v| Val::F32(v as u64 as f32)), // TODO
770                Instr::F32DemoteF64 => self.convert_from_f64(|v| Val::F32(v as f32)), // TODO
771                Instr::F64ConvertI32S => self.convert_from_i32(|v| Val::F64(v as f64)), // TODO
772                Instr::F64ConvertI32U => self.convert_from_i32(|v| Val::F64(v as u32 as f64)), // TODO
773                Instr::F64ConvertI64S => self.convert_from_i64(|v| Val::F64(v as f64)), // TODO
774                Instr::F64ConvertI64U => self.convert_from_i64(|v| Val::F64(v as u64 as f64)), // TODO
775                Instr::F64PromoteF32 => self.convert_from_f32(|v| Val::F64(v as f64)),
776                Instr::I32ReinterpretF32 => self.convert_from_f32(|v| Val::I32(v.to_bits() as i32)),
777                Instr::I64ReinterpretF64 => self.convert_from_f64(|v| Val::I64(v.to_bits() as i64)),
778                Instr::F32ReinterpretI32 => {
779                    self.convert_from_i32(|v| Val::F32(f32::from_bits(v as u32)))
780                }
781                Instr::F64ReinterpretI64 => {
782                    self.convert_from_i64(|v| Val::F64(f64::from_bits(v as u64)))
783                }
784
785                // Sign Extension
786                #[cfg(feature = "sign_extension")]
787                Instr::SignExtension(instr) => match instr {
788                    crate::sign_extension::SignExtensionInstr::I32Extend8S => {
789                        self.convert_from_i32(|v| Val::I32(v as i8 as i32))
790                    }
791                    crate::sign_extension::SignExtensionInstr::I32Extend16S => {
792                        self.convert_from_i32(|v| Val::I32(v as i16 as i32))
793                    }
794                    crate::sign_extension::SignExtensionInstr::I64Extend8S => {
795                        self.convert_from_i64(|v| Val::I64(v as i8 as i64))
796                    }
797                    crate::sign_extension::SignExtensionInstr::I64Extend16S => {
798                        self.convert_from_i64(|v| Val::I64(v as i16 as i64))
799                    }
800                    crate::sign_extension::SignExtensionInstr::I64Extend32S => {
801                        self.convert_from_i64(|v| Val::I64(v as i32 as i64))
802                    }
803                },
804            }
805        }
806        Ok(None)
807    }
808
809    fn convert_from_i32<F>(&mut self, f: F)
810    where
811        F: FnOnce(i32) -> Val,
812    {
813        let v = self.pop_value_i32();
814        self.push_value(f(v));
815    }
816
817    fn convert_from_i64<F>(&mut self, f: F)
818    where
819        F: FnOnce(i64) -> Val,
820    {
821        let v = self.pop_value_i64();
822        self.push_value(f(v));
823    }
824
825    fn convert_from_f32<F>(&mut self, f: F)
826    where
827        F: FnOnce(f32) -> Val,
828    {
829        let v = self.pop_value_f32();
830        self.push_value(f(v));
831    }
832
833    fn convert_from_f64<F>(&mut self, f: F)
834    where
835        F: FnOnce(f64) -> Val,
836    {
837        let v = self.pop_value_f64();
838        self.push_value(f(v));
839    }
840
841    fn apply_unop_f32<F>(&mut self, f: F)
842    where
843        F: FnOnce(f32) -> f32,
844    {
845        let v = self.pop_value_f32();
846        self.push_value(Val::F32(f(v)));
847    }
848
849    fn apply_binop_f32<F>(&mut self, f: F)
850    where
851        F: FnOnce(f32, f32) -> f32,
852    {
853        let v0 = self.pop_value_f32();
854        let v1 = self.pop_value_f32();
855        self.push_value(Val::F32(f(v1, v0)));
856    }
857
858    fn apply_unop_f64<F>(&mut self, f: F)
859    where
860        F: FnOnce(f64) -> f64,
861    {
862        let v = self.pop_value_f64();
863        self.push_value(Val::F64(f(v)));
864    }
865
866    fn apply_binop_f64<F>(&mut self, f: F)
867    where
868        F: FnOnce(f64, f64) -> f64,
869    {
870        let v0 = self.pop_value_f64();
871        let v1 = self.pop_value_f64();
872        self.push_value(Val::F64(f(v1, v0)));
873    }
874
875    fn apply_unop_i32<F>(&mut self, f: F)
876    where
877        F: FnOnce(i32) -> i32,
878    {
879        let v = self.pop_value_i32();
880        self.push_value(Val::I32(f(v)));
881    }
882
883    fn apply_binop_i32<F>(&mut self, f: F)
884    where
885        F: FnOnce(i32, i32) -> i32,
886    {
887        let v0 = self.pop_value_i32();
888        let v1 = self.pop_value_i32();
889        self.push_value(Val::I32(f(v1, v0)));
890    }
891
892    fn apply_binop_u32<F>(&mut self, f: F)
893    where
894        F: FnOnce(u32, u32) -> u32,
895    {
896        let v0 = self.pop_value_u32();
897        let v1 = self.pop_value_u32();
898        self.push_value(Val::I32(f(v1, v0) as i32));
899    }
900
901    fn apply_unop_i64<F>(&mut self, f: F)
902    where
903        F: FnOnce(i64) -> i64,
904    {
905        let v = self.pop_value_i64();
906        self.push_value(Val::I64(f(v)));
907    }
908
909    fn apply_binop_i64<F>(&mut self, f: F)
910    where
911        F: FnOnce(i64, i64) -> i64,
912    {
913        let v0 = self.pop_value_i64();
914        let v1 = self.pop_value_i64();
915        self.push_value(Val::I64(f(v1, v0)));
916    }
917
918    fn apply_binop_u64<F>(&mut self, f: F)
919    where
920        F: FnOnce(u64, u64) -> u64,
921    {
922        let v0 = self.pop_value_u64();
923        let v1 = self.pop_value_u64();
924        self.push_value(Val::I64(f(v1, v0) as i64));
925    }
926
927    fn apply_unop_cmp_i32<F>(&mut self, f: F)
928    where
929        F: FnOnce(i32) -> bool,
930    {
931        let v = self.pop_value_i32();
932        self.push_value(Val::I32(f(v) as i32));
933    }
934
935    fn apply_binop_cmp_i32<F>(&mut self, f: F)
936    where
937        F: FnOnce(i32, i32) -> bool,
938    {
939        let v0 = self.pop_value_i32();
940        let v1 = self.pop_value_i32();
941        self.push_value(Val::I32(f(v1, v0) as i32));
942    }
943
944    fn apply_binop_cmp_u32<F>(&mut self, f: F)
945    where
946        F: FnOnce(u32, u32) -> bool,
947    {
948        let v0 = self.pop_value_u32();
949        let v1 = self.pop_value_u32();
950        self.push_value(Val::I32(f(v1, v0) as i32));
951    }
952
953    fn apply_unop_cmp_i64<F>(&mut self, f: F)
954    where
955        F: FnOnce(i64) -> bool,
956    {
957        let v = self.pop_value_i64();
958        self.push_value(Val::I32(f(v) as i32));
959    }
960
961    fn apply_binop_cmp_i64<F>(&mut self, f: F)
962    where
963        F: FnOnce(i64, i64) -> bool,
964    {
965        let v0 = self.pop_value_i64();
966        let v1 = self.pop_value_i64();
967        self.push_value(Val::I32(f(v1, v0) as i32));
968    }
969
970    fn apply_binop_cmp_u64<F>(&mut self, f: F)
971    where
972        F: FnOnce(u64, u64) -> bool,
973    {
974        let v0 = self.pop_value_u64();
975        let v1 = self.pop_value_u64();
976        self.push_value(Val::I32(f(v1, v0) as i32));
977    }
978
979    fn apply_binop_cmp_f32<F>(&mut self, f: F)
980    where
981        F: FnOnce(f32, f32) -> bool,
982    {
983        let v0 = self.pop_value_f32();
984        let v1 = self.pop_value_f32();
985        self.push_value(Val::I32(f(v1, v0) as i32));
986    }
987
988    fn apply_binop_cmp_f64<F>(&mut self, f: F)
989    where
990        F: FnOnce(f64, f64) -> bool,
991    {
992        let v0 = self.pop_value_f64();
993        let v1 = self.pop_value_f64();
994        self.push_value(Val::I32(f(v1, v0) as i32));
995    }
996}
997
998impl<V: VectorFactory> Debug for Executor<V> {
999    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
1000        // TODO
1001        f.debug_struct("Executor").finish_non_exhaustive()
1002    }
1003}
1004
1005// TODO: Activation(?)
1006#[derive(Debug, Default, Clone, Copy)]
1007pub struct Frame {
1008    pub arity: usize,
1009    pub locals_start: usize,
1010    pub values_start: usize,
1011}
1012
1013#[derive(Debug, Default, Clone, Copy)]
1014pub struct Block {
1015    pub arity: usize,
1016    pub values_start: usize,
1017}
1018
1019#[cfg(not(feature = "std"))]
1020trait FloatExt: Sized {
1021    fn abs(self) -> Self;
1022    fn ceil(self) -> Self;
1023    fn floor(self) -> Self;
1024    fn round(self) -> Self;
1025    fn trunc(self) -> Self;
1026    fn copysign(self, sign: Self) -> Self;
1027    fn sqrt(self) -> Self;
1028    fn signum(self) -> Self;
1029}
1030
1031#[cfg(not(feature = "std"))]
1032impl FloatExt for f32 {
1033    fn abs(self) -> Self {
1034        if self < 0.0 {
1035            -self
1036        } else {
1037            self
1038        }
1039    }
1040
1041    fn ceil(self) -> Self {
1042        let int = self as i32;
1043        if self - (int as f32) > 0.0 {
1044            int as f32 + 1.0
1045        } else {
1046            int as f32
1047        }
1048    }
1049
1050    fn floor(self) -> Self {
1051        let int = self as i32;
1052        if self - (int as f32) < 0.0 {
1053            int as f32 - 1.0
1054        } else {
1055            int as f32
1056        }
1057    }
1058
1059    fn round(self) -> Self {
1060        let int = self as i32;
1061        if self - (int as f32) >= 0.5 {
1062            int as f32 + 1.0
1063        } else {
1064            int as f32
1065        }
1066    }
1067
1068    fn trunc(self) -> Self {
1069        self as i32 as f32
1070    }
1071
1072    fn copysign(self, sign: Self) -> Self {
1073        if self.is_nan() {
1074            if sign.is_sign_positive() {
1075                f32::NAN
1076            } else {
1077                -f32::NAN
1078            }
1079        } else {
1080            self.abs() * sign.signum()
1081        }
1082    }
1083
1084    fn sqrt(self) -> Self {
1085        if self < 0.0 {
1086            panic!()
1087        }
1088        if self == 0.0 {
1089            return 0.0;
1090        }
1091
1092        let mut guess = self / 2.0;
1093        let mut previous_guess = 0.0;
1094
1095        while (guess - previous_guess).abs() > f32::EPSILON {
1096            previous_guess = guess;
1097            guess = (guess + self / guess) / 2.0;
1098        }
1099
1100        guess
1101    }
1102
1103    fn signum(self) -> Self {
1104        if self.is_nan() {
1105            f32::NAN
1106        } else if self == 0.0 {
1107            0.0
1108        } else if self > 0.0 {
1109            1.0
1110        } else {
1111            -1.0
1112        }
1113    }
1114}
1115
1116#[cfg(not(feature = "std"))]
1117impl FloatExt for f64 {
1118    fn abs(self) -> Self {
1119        if self < 0.0 {
1120            -self
1121        } else {
1122            self
1123        }
1124    }
1125
1126    fn ceil(self) -> Self {
1127        let int = self as i64;
1128        if self - int as f64 > 0.0 {
1129            int as f64 + 1.0
1130        } else {
1131            int as f64
1132        }
1133    }
1134
1135    fn floor(self) -> Self {
1136        let int = self as i64;
1137        if self - (int as f64) < 0.0 {
1138            int as f64 - 1.0
1139        } else {
1140            int as f64
1141        }
1142    }
1143
1144    fn round(self) -> Self {
1145        let int = self as i64;
1146        if self - (int as f64) >= 0.5 {
1147            int as f64 + 1.0
1148        } else {
1149            int as f64
1150        }
1151    }
1152
1153    fn trunc(self) -> Self {
1154        self as i64 as f64
1155    }
1156
1157    fn copysign(self, sign: Self) -> Self {
1158        if self.is_nan() {
1159            if sign.is_sign_positive() {
1160                f64::NAN
1161            } else {
1162                -f64::NAN
1163            }
1164        } else {
1165            self.abs() * sign.signum()
1166        }
1167    }
1168
1169    fn sqrt(self) -> Self {
1170        if self < 0.0 {
1171            panic!()
1172        }
1173        if self == 0.0 {
1174            return 0.0;
1175        }
1176
1177        let mut guess = self / 2.0;
1178        let mut previous_guess = 0.0;
1179
1180        while (guess - previous_guess).abs() > f64::EPSILON {
1181            previous_guess = guess;
1182            guess = (guess + self / guess) / 2.0;
1183        }
1184
1185        guess
1186    }
1187
1188    fn signum(self) -> Self {
1189        if self.is_nan() {
1190            f64::NAN
1191        } else if self == 0.0 {
1192            0.0
1193        } else if self > 0.0 {
1194            1.0
1195        } else {
1196            -1.0
1197        }
1198    }
1199}
1200
1201#[cfg(test)]
1202mod tests {
1203    use crate::{Env, FuncInst, HostFunc, Module, Resolve, StdVectorFactory, Val};
1204
1205    #[test]
1206    fn control_flow_br_test() {
1207        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Control_flow/br
1208        //
1209        // (module
1210        //   ;; import the browser console object, you'll need to pass this in from JavaScript
1211        //   (import "console" "log" (func $log (param i32)))
1212        //
1213        //   ;; create a global variable and initialize it to 0
1214        //   (global $i (mut i32) (i32.const 0))
1215        //
1216        //   (func
1217        //     (loop $my_loop
1218        //
1219        //       ;; add one to $i
1220        //       global.get $i
1221        //       i32.const 1
1222        //       i32.add
1223        //       global.set $i
1224        //
1225        //       ;; log the current value of $i
1226        //       global.get $i
1227        //       call $log
1228        //
1229        //       ;; if $i is less than 10 branch to loop
1230        //       global.get $i
1231        //       i32.const 10
1232        //       i32.lt_s
1233        //       br_if $my_loop
1234        //
1235        //     )
1236        //   )
1237        //
1238        //   (start 1) ;; run the first function automatically
1239        // )
1240        let input = [
1241            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1242            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 6, 6, 1, 127, 1, 65, 0,
1243            11, 8, 1, 1, 10, 25, 1, 23, 0, 3, 64, 35, 0, 65, 1, 106, 36, 0, 35, 0, 16, 0, 35, 0,
1244            65, 10, 72, 13, 0, 11, 11,
1245        ];
1246        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1247        let instance = module.instantiate(Resolver).expect("instantiate");
1248
1249        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1250            panic!()
1251        };
1252        assert_eq!(10, host_func.messages.len());
1253        for (i, m) in host_func.messages.iter().enumerate() {
1254            assert_eq!(Val::I32((i + 1) as i32), *m);
1255        }
1256    }
1257
1258    #[test]
1259    fn control_flow_drop_test() {
1260        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Control_flow/Drop
1261        //
1262        // (module
1263        //   (import "console" "log" (func $log (param i32)))
1264        //   (func $main
1265        //     ;; load two values onto the stack
1266        //     i32.const 10
1267        //     i32.const 20
1268        //
1269        //     ;; drop the top item from the stack (`20`)
1270        //     drop
1271        //
1272        //     call $log ;; log the top value on the stack (`10`)
1273        //   )
1274        //   (start $main)
1275        // )
1276        let input = [
1277            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1278            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 11, 1, 9, 0,
1279            65, 10, 65, 20, 26, 16, 0, 11,
1280        ];
1281        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1282        let instance = module.instantiate(Resolver).expect("instantiate");
1283
1284        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1285            panic!()
1286        };
1287        assert_eq!(&[Val::I32(10)][..], &host_func.messages);
1288    }
1289
1290    #[test]
1291    fn control_flow_select_test() {
1292        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Control_flow/Select
1293        //
1294        // (module
1295        //   (func (export "select_simple") (result i32)
1296        //     ;; load two values onto the stack
1297        //     i32.const 10
1298        //     i32.const 20
1299        //
1300        //     ;; change to `1` (true) to get the first value (`10`)
1301        //     i32.const 0
1302        //     select
1303        //   )
1304        //   ;; (func (export "select_externref") (param $value externref) (param $condition i32) (result externref)
1305        //   ;;  ;; this is "select t", the explicitly typed variant
1306        //   ;;  ref.null extern
1307        //   ;;  local.get $value
1308        //   ;;  local.get $condition
1309        //   ;;  select (result externref)
1310        //   ;; )
1311        // )
1312        let input = [
1313            0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 127, 3, 2, 1, 0, 7, 17, 1, 13, 115,
1314            101, 108, 101, 99, 116, 95, 115, 105, 109, 112, 108, 101, 0, 0, 10, 11, 1, 9, 0, 65,
1315            10, 65, 20, 65, 0, 27, 11,
1316        ];
1317        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1318        let mut instance = module.instantiate(Resolver).expect("instantiate");
1319
1320        let val = instance
1321            .invoke("select_simple", &[])
1322            .expect("invoke")
1323            .expect("result");
1324        assert_eq!(Val::I32(20), val);
1325    }
1326
1327    #[test]
1328    fn control_flow_block_test() {
1329        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Control_flow/block
1330        //
1331        // (module
1332        //   ;; import the browser console object, you'll need to pass this in from JavaScript
1333        //   (import "console" "log" (func $log (param i32)))
1334        //
1335        //   ;; create a function that takes in a number as a param,
1336        //   ;; and logs that number if it's not equal to 100.
1337        //   (func (export "log_if_not_100") (param $num i32)
1338        //     (block $my_block
1339        //
1340        //       ;; $num is equal to 100
1341        //       local.get $num
1342        //       i32.const 100
1343        //       i32.eq
1344        //
1345        //       (if
1346        //         (then
1347        //
1348        //           ;; branch to the end of the block
1349        //           br $my_block
1350        //
1351        //         )
1352        //       )
1353        //
1354        //       ;; not reachable when $num is 100
1355        //       local.get $num
1356        //       call $log
1357        //
1358        //     )
1359        //   )
1360        // )
1361        let input = [
1362            0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 1, 127, 0, 2, 15, 1, 7, 99, 111, 110, 115,
1363            111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 0, 7, 18, 1, 14, 108, 111, 103, 95,
1364            105, 102, 95, 110, 111, 116, 95, 49, 48, 48, 0, 1, 10, 22, 1, 20, 0, 2, 64, 32, 0, 65,
1365            228, 0, 70, 4, 64, 12, 1, 11, 32, 0, 16, 0, 11, 11,
1366        ];
1367        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1368        let mut instance = module.instantiate(Resolver).expect("instantiate");
1369
1370        assert!(instance
1371            .invoke("log_if_not_100", &[Val::I32(99)])
1372            .expect("invoke")
1373            .is_none());
1374
1375        assert!(instance
1376            .invoke("log_if_not_100", &[Val::I32(100)])
1377            .expect("invoke")
1378            .is_none());
1379
1380        assert!(instance
1381            .invoke("log_if_not_100", &[Val::I32(101)])
1382            .expect("invoke")
1383            .is_none());
1384
1385        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1386            panic!()
1387        };
1388        assert_eq!(&[Val::I32(99), Val::I32(101)][..], &host_func.messages);
1389    }
1390
1391    #[test]
1392    fn memory_size_test() {
1393        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Memory/Size
1394        //
1395        // (module
1396        //   (import "console" "log" (func $log (param i32)))
1397        //   (memory 2)
1398        //   (func $main
1399        //
1400        //     memory.size ;; get the memory size
1401        //     call $log ;; log the result
1402        //
1403        //   )
1404        //   (start $main)
1405        // )
1406        let input = [
1407            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1408            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 5, 3, 1, 0, 2, 8, 1, 1,
1409            10, 8, 1, 6, 0, 63, 0, 16, 0, 11,
1410        ];
1411        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1412        let instance = module.instantiate(Resolver).expect("instantiate");
1413
1414        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1415            panic!()
1416        };
1417        assert_eq!(&[Val::I32(2)][..], &host_func.messages);
1418    }
1419
1420    #[test]
1421    fn memory_grow_test() {
1422        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Memory/Grow
1423        //
1424        // (module
1425        //   (import "console" "log" (func $log (param i32)))
1426        //   (memory 1 2) ;; default memory with one page and max of 2 pages
1427        //
1428        //   (func $main
1429        //     ;; grow default memory by 1 page
1430        //     i32.const 1
1431        //     memory.grow
1432        //     call $log ;; log the result (previous no. pages = 1)
1433        //
1434        //     ;; grow default memory, using an S-function
1435        //     (memory.grow (i32.const 1))
1436        //     call $log ;; log the result (-1: max is 2 pages for default memory declared above!)
1437        //   )
1438        //   (start $main) ;; call immediately on loading
1439        // )
1440        let input = [
1441            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1442            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 5, 4, 1, 1, 1, 2, 8, 1, 1,
1443            10, 16, 1, 14, 0, 65, 1, 64, 0, 16, 0, 65, 1, 64, 0, 16, 0, 11,
1444        ];
1445        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1446        let instance = module.instantiate(Resolver).expect("instantiate");
1447
1448        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1449            panic!()
1450        };
1451        assert_eq!(&[Val::I32(1), Val::I32(-1)][..], &host_func.messages);
1452    }
1453
1454    #[test]
1455    fn consts_test() {
1456        // (module
1457        //   (import "console" "log" (func $log (param i32)))
1458        //   (func $main
1459
1460        //     i32.const 10
1461        //     call $log
1462
1463        //     i32.const -3
1464        //     call $log
1465        //   )
1466        //   (start $main)
1467        // )
1468        let input = [
1469            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1470            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 12, 1, 10, 0,
1471            65, 10, 16, 0, 65, 125, 16, 0, 11,
1472        ];
1473
1474        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1475        let instance = module.instantiate(Resolver).expect("instantiate");
1476
1477        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1478            panic!()
1479        };
1480        assert_eq!(&[Val::I32(10), Val::I32(-3)][..], &host_func.messages);
1481    }
1482
1483    #[test]
1484    fn numeric_reinterpret_test() {
1485        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Numeric/Reinterpret
1486        //
1487        // (module
1488        //   (import "console" "log" (func $log (param i32)))
1489        //   (func $main
1490        //     ;; the value `10000000_00000000_00000000_00000000` in binary
1491        //     ;; maps to `-0` as a floating point and to `-2147483648` as an integer.
1492        //
1493        //     f32.const -0 ;; push an f32 onto the stack
1494        //
1495        //     i32.reinterpret_f32 ;; reinterpret the bytes of the f32 as i32
1496        //
1497        //     call $log ;; log the result
1498        //   )
1499        //   (start $main)
1500        // )
1501        let input = [
1502            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1503            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 12, 1, 10, 0,
1504            67, 0, 0, 0, 128, 188, 16, 0, 11,
1505        ];
1506        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1507        let instance = module.instantiate(Resolver).expect("instantiate");
1508
1509        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1510            panic!()
1511        };
1512        assert_eq!(&[Val::I32(-2147483648)][..], &host_func.messages);
1513    }
1514
1515    #[test]
1516    fn numeric_truncate_float_to_int_test() {
1517        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Numeric/Truncate_float_to_int
1518        //
1519        // (module
1520        //   (import "console" "log" (func $log (param i32)))
1521        //   (func $main
1522        //
1523        //     f32.const 10.5 ;; push an f32 onto the stack
1524        //
1525        //     i32.trunc_f32_s ;; convert from f32 to signed i32 rounding towards zero (.5 will be lost)
1526        //
1527        //     call $log ;; log the result
1528        //
1529        //   )
1530        //   (start $main)
1531        // )
1532        let input = [
1533            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1534            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 12, 1, 10, 0,
1535            67, 0, 0, 40, 65, 168, 16, 0, 11,
1536        ];
1537        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1538        let instance = module.instantiate(Resolver).expect("instantiate");
1539
1540        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1541            panic!()
1542        };
1543        assert_eq!(&[Val::I32(10)][..], &host_func.messages);
1544    }
1545
1546    #[test]
1547    fn numeric_convert_test() {
1548        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Numeric/Convert
1549        // (module
1550        //   (import "console" "log" (func $log (param f32)))
1551        //   (func $main
1552        //
1553        //     i32.const 10 ;; push an i32 onto the stack
1554        //
1555        //     f32.convert_i32_s ;; convert from signed i32 to f32
1556        //
1557        //     call $log ;; log the result
1558        //
1559        //   )
1560        //   (start $main)
1561        // )
1562        let input = [
1563            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 125, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1564            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 9, 1, 7, 0,
1565            65, 10, 178, 16, 0, 11,
1566        ];
1567        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1568        let instance = module.instantiate(Resolver).expect("instantiate");
1569
1570        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1571            panic!()
1572        };
1573        assert_eq!(&[Val::F32(10.0)][..], &host_func.messages);
1574    }
1575
1576    #[test]
1577    fn numeric_demote_test() {
1578        // From: https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Numeric/Demote
1579        //
1580        // (module
1581        //   (import "console" "log" (func $log (param f32)))
1582        //   (func $main
1583        //
1584        //     f64.const 10.5 ;; push an f64 onto the stack
1585        //
1586        //     f32.demote_f64 ;; demote from f64 to f32
1587        //
1588        //     call $log ;; log the result
1589        //
1590        //   )
1591        //   (start $main)
1592        // )
1593        let input = [
1594            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 125, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1595            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 16, 1, 14, 0,
1596            68, 0, 0, 0, 0, 0, 0, 37, 64, 182, 16, 0, 11,
1597        ];
1598        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1599        let instance = module.instantiate(Resolver).expect("instantiate");
1600
1601        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1602            panic!()
1603        };
1604        assert_eq!(&[Val::F32(10.5)][..], &host_func.messages);
1605    }
1606
1607    #[test]
1608    fn numeric_promote_test() {
1609        // Based on https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Numeric/Promote
1610        //
1611        // (module
1612        //   (import "console" "log" (func $log (param f64)))
1613        //   (func $main
1614        //
1615        //     f32.const 10.5 ;; push an f32 onto the stack
1616        //
1617        //     f64.promote_f32 ;; promote from f32 to f64
1618        //
1619        //     call $log ;; log the result
1620        //
1621        //   )
1622        //   (start $main)
1623        // )
1624        let input = [
1625            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 124, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1626            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 12, 1, 10, 0,
1627            67, 0, 0, 40, 65, 187, 16, 0, 11,
1628        ];
1629        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1630        let instance = module.instantiate(Resolver).expect("instantiate");
1631
1632        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1633            panic!()
1634        };
1635        assert_eq!(&[Val::F64(10.5)][..], &host_func.messages);
1636    }
1637
1638    #[test]
1639    fn numeric_wrap_test() {
1640        // Based on https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Numeric/Wrap
1641        //
1642        // (module
1643        //   (import "console" "log" (func $log (param i32)))
1644        //   (func $main
1645        //
1646        //     i64.const 10 ;; push an i64 onto the stack
1647        //
1648        //     i32.wrap_i64 ;; wrap from i64 to i32
1649        //
1650        //     call $log ;; log the result
1651        //   )
1652        //   (start $main)
1653        // )
1654        let input = [
1655            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 127, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1656            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 9, 1, 7, 0,
1657            66, 10, 167, 16, 0, 11,
1658        ];
1659        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1660        let instance = module.instantiate(Resolver).expect("instantiate");
1661
1662        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1663            panic!()
1664        };
1665        assert_eq!(&[Val::I32(10)][..], &host_func.messages);
1666    }
1667
1668    #[test]
1669    fn numeric_extend_test() {
1670        // Based on https://developer.mozilla.org/en-US/docs/WebAssembly/Reference/Numeric/Extend
1671        //
1672        // (module
1673        //   (import "console" "log" (func $log (param i64)))
1674        //   (func $main
1675        //
1676        //     i32.const 10 ;; push an i32 onto the stack
1677        //
1678        //     i64.extend_i32_s ;; sign-extend from i32 to i64
1679        //
1680        //     call $log ;; log the result
1681        //
1682        //   )
1683        //   (start $main)
1684        // )
1685        let input = [
1686            0, 97, 115, 109, 1, 0, 0, 0, 1, 8, 2, 96, 1, 126, 0, 96, 0, 0, 2, 15, 1, 7, 99, 111,
1687            110, 115, 111, 108, 101, 3, 108, 111, 103, 0, 0, 3, 2, 1, 1, 8, 1, 1, 10, 9, 1, 7, 0,
1688            65, 10, 172, 16, 0, 11,
1689        ];
1690        let module = Module::<StdVectorFactory>::decode(&input).expect("decode");
1691        let instance = module.instantiate(Resolver).expect("instantiate");
1692
1693        let FuncInst::Imported { host_func, .. } = &instance.funcs()[0] else {
1694            panic!()
1695        };
1696        assert_eq!(&[Val::I64(10)][..], &host_func.messages);
1697    }
1698
1699    #[derive(Debug)]
1700    struct Resolver;
1701
1702    impl Resolve for Resolver {
1703        type HostFunc = Log;
1704
1705        fn resolve_func(&self, module: &str, name: &str) -> Option<Self::HostFunc> {
1706            if module == "console" && name == "log" {
1707                Some(Log::default())
1708            } else {
1709                None
1710            }
1711        }
1712    }
1713
1714    #[derive(Debug, Default)]
1715    struct Log {
1716        messages: Vec<Val>,
1717    }
1718
1719    impl HostFunc for Log {
1720        fn invoke(&mut self, args: &[Val], _env: &mut Env) -> Option<Val> {
1721            self.messages.push(args[0]);
1722            None
1723        }
1724    }
1725}