Skip to main content

waffle/
interp.rs

1//! Waffle IR interpreter.
2
3use crate::entity::{EntityRef, PerEntity};
4use crate::ir::*;
5use crate::ops::Operator;
6use smallvec::{smallvec, SmallVec};
7
8use std::collections::HashMap;
9
10/// How large do we allow a Wasm memory to be when interpreting? Limit
11/// the size somewhat (apply an implementation limit) so we do not
12/// have unreasonably large state.
13const MAX_PAGES: usize = 2048; // 2048 * 64KiB = 128MiB
14
15/// Context for the IR interpreter. Corresponds roughly to Wasm module
16/// state.
17pub struct InterpContext {
18    /// Contents of memories.
19    pub memories: PerEntity<Memory, InterpMemory>,
20    /// Contents of tables.
21    pub tables: PerEntity<Table, InterpTable>,
22    /// Values of globals.
23    pub globals: PerEntity<Global, ConstVal>,
24    /// Fuel remaining: allows deterministic stopping of execution.
25    pub fuel: u64,
26}
27
28/// The state of one interpreter memory.
29#[derive(Debug, Clone, Default, PartialEq, Eq)]
30pub struct InterpMemory {
31    pub data: Vec<u8>,
32    pub max_pages: usize,
33}
34
35/// The state of one interpreter table.
36#[derive(Debug, Clone, Default, PartialEq, Eq)]
37pub struct InterpTable {
38    pub elements: Vec<Func>,
39}
40
41/// One stack frame in the interpreted execution context.
42#[derive(Debug, Clone, Default)]
43pub struct InterpStackFrame {
44    func: Func,
45    cur_block: Block,
46    values: HashMap<Value, SmallVec<[ConstVal; 2]>>,
47}
48
49/// The result of an interpreter session.
50#[derive(Clone, Debug)]
51pub enum InterpResult {
52    /// The function returned with the given value(s).
53    Ok(MultiVal),
54    /// The module trapped.
55    Trap(Func, Block, u32),
56    /// The module ran out of fuel.
57    OutOfFuel,
58}
59
60/// A constant concrete value during interpretation.
61#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
62pub enum ConstVal {
63    I32(u32),
64    I64(u64),
65    F32(u32),
66    F64(u64),
67    #[default]
68    None,
69}
70
71/// Representation of multiple result values.
72type MultiVal = SmallVec<[ConstVal; 2]>;
73
74impl InterpResult {
75    /// Extract the return value(s), if normal return, otherwise
76    /// produce an error.
77    pub fn ok(self) -> anyhow::Result<MultiVal> {
78        match self {
79            InterpResult::Ok(vals) => Ok(vals),
80            other => anyhow::bail!("Bad InterpResult: {:?}", other),
81        }
82    }
83}
84
85impl InterpContext {
86    /// Construct a new interpreter context for the given module.
87    pub fn new(module: &Module<'_>) -> anyhow::Result<Self> {
88        let mut memories = PerEntity::default();
89        for (memory, data) in module.memories.entries() {
90            let mut interp_mem = InterpMemory {
91                data: vec![0; data.initial_pages * WASM_PAGE],
92                max_pages: data.maximum_pages.unwrap_or(MAX_PAGES),
93            };
94            for segment in &data.segments {
95                let end = match segment.offset.checked_add(segment.data.len()) {
96                    Some(end) => end,
97                    None => anyhow::bail!("Data segment offset + length overflows"),
98                };
99                if end > interp_mem.data.len() {
100                    anyhow::bail!("Data segment out of bounds");
101                }
102                interp_mem.data[segment.offset..end].copy_from_slice(&segment.data[..]);
103            }
104            memories[memory] = interp_mem;
105        }
106
107        let mut tables = PerEntity::default();
108        for (table, data) in module.tables.entries() {
109            let interp_table = InterpTable {
110                elements: data.func_elements.clone().unwrap_or(vec![]),
111            };
112            tables[table] = interp_table;
113        }
114
115        let mut globals = PerEntity::default();
116        for (global, data) in module.globals.entries() {
117            globals[global] = match data.ty {
118                Type::I32 => ConstVal::I32(data.value.unwrap_or(0) as u32),
119                Type::I64 => ConstVal::I64(data.value.unwrap_or(0)),
120                Type::F32 => ConstVal::F32(data.value.unwrap_or(0) as u32),
121                Type::F64 => ConstVal::F64(data.value.unwrap_or(0)),
122                _ => unimplemented!(),
123            };
124        }
125
126        Ok(InterpContext {
127            memories,
128            tables,
129            globals,
130            fuel: u64::MAX,
131        })
132    }
133
134    /// Call the given function with the given args, running the
135    /// interpreter until fuel is exhausted or the function returns.
136    pub fn call(&mut self, module: &Module<'_>, func: Func, args: &[ConstVal]) -> InterpResult {
137        let body = match &module.funcs[func] {
138            FuncDecl::Lazy(..) => panic!("Un-expanded function"),
139            FuncDecl::Compiled(..) => panic!("Already-compiled function"),
140            FuncDecl::Import(..) => {
141                let import = &module.imports[func.index()];
142                assert_eq!(import.kind, ImportKind::Func(func));
143                return self.call_import(&import.name[..], args);
144            }
145            FuncDecl::Body(_, _, body) => body,
146            FuncDecl::None => panic!("FuncDecl::None in call()"),
147        };
148
149        log::trace!(
150            "Interp: entering func {}:\n{}\n",
151            func,
152            body.display_verbose("| ", Some(module))
153        );
154        log::trace!("args: {:?}", args);
155
156        let mut frame = InterpStackFrame {
157            func,
158            cur_block: body.entry,
159            values: HashMap::new(),
160        };
161
162        for (&arg, &(_, blockparam)) in args.iter().zip(body.blocks[body.entry].params.iter()) {
163            log::trace!("Entry block param {} gets arg value {:?}", blockparam, arg);
164            frame.values.insert(blockparam, smallvec![arg]);
165        }
166
167        loop {
168            self.fuel -= 1;
169            if self.fuel == 0 {
170                return InterpResult::OutOfFuel;
171            }
172
173            log::trace!("Interpreting block {}", frame.cur_block);
174            for (inst_idx, &inst) in body.blocks[frame.cur_block].insts.iter().enumerate() {
175                log::trace!("Evaluating inst {}", inst);
176                let result = match &body.values[inst] {
177                    &ValueDef::Alias(_) => smallvec![],
178                    &ValueDef::PickOutput(val, idx, _) => {
179                        let val = body.resolve_alias(val);
180                        smallvec![frame.values.get(&val).unwrap()[idx as usize]]
181                    }
182                    &ValueDef::Operator(Operator::Call { function_index }, args, _) => {
183                        let args = body.arg_pool[args]
184                            .iter()
185                            .map(|&arg| {
186                                let arg = body.resolve_alias(arg);
187                                let multivalue = frame.values.get(&arg).unwrap();
188                                assert_eq!(multivalue.len(), 1);
189                                multivalue[0]
190                            })
191                            .collect::<Vec<_>>();
192                        let result = self.call(module, function_index, &args[..]);
193                        match result {
194                            InterpResult::Ok(vals) => vals,
195                            _ => return result,
196                        }
197                    }
198                    &ValueDef::Operator(Operator::CallIndirect { table_index, .. }, args, _) => {
199                        let args = body.arg_pool[args]
200                            .iter()
201                            .map(|&arg| {
202                                let arg = body.resolve_alias(arg);
203                                let multivalue = frame.values.get(&arg).unwrap();
204                                assert_eq!(multivalue.len(), 1);
205                                multivalue[0]
206                            })
207                            .collect::<Vec<_>>();
208                        let idx = args.last().unwrap().as_u32().unwrap() as usize;
209                        let func = self.tables[table_index].elements[idx];
210                        let result = self.call(module, func, &args[..args.len() - 1]);
211                        match result {
212                            InterpResult::Ok(vals) => vals,
213                            _ => return result,
214                        }
215                    }
216                    &ValueDef::Operator(ref op, args, _) => {
217                        let args = body.arg_pool[args]
218                            .iter()
219                            .map(|&arg| {
220                                let arg = body.resolve_alias(arg);
221                                let multivalue = frame
222                                    .values
223                                    .get(&arg)
224                                    .ok_or_else(|| format!("Unset SSA value: {}", arg))
225                                    .unwrap();
226                                assert_eq!(multivalue.len(), 1);
227                                multivalue[0]
228                            })
229                            .collect::<Vec<_>>();
230                        let result = match const_eval(op, &args[..], Some(self)) {
231                            Some(result) => result,
232                            None => {
233                                log::trace!("const_eval failed on {:?} args {:?}", op, args);
234                                return InterpResult::Trap(
235                                    frame.func,
236                                    frame.cur_block,
237                                    inst_idx as u32,
238                                );
239                            }
240                        };
241                        smallvec![result]
242                    }
243                    &ValueDef::None | &ValueDef::Placeholder(..) | &ValueDef::BlockParam(..) => {
244                        unreachable!();
245                    }
246                };
247
248                log::trace!("Inst {} gets result {:?}", inst, result);
249                frame.values.insert(inst, result);
250            }
251
252            match &body.blocks[frame.cur_block].terminator {
253                &Terminator::None => {
254                    return InterpResult::Trap(frame.func, frame.cur_block, u32::MAX)
255                }
256                &Terminator::Unreachable => {
257                    return InterpResult::Trap(frame.func, frame.cur_block, u32::MAX)
258                }
259                &Terminator::Br { ref target } => {
260                    frame.apply_target(body, target);
261                }
262                &Terminator::CondBr {
263                    cond,
264                    ref if_true,
265                    ref if_false,
266                } => {
267                    let cond = body.resolve_alias(cond);
268                    let cond = frame.values.get(&cond).unwrap();
269                    let cond = cond[0].as_u32().unwrap() != 0;
270                    if cond {
271                        frame.apply_target(body, if_true);
272                    } else {
273                        frame.apply_target(body, if_false);
274                    }
275                }
276                &Terminator::Select {
277                    value,
278                    ref targets,
279                    ref default,
280                } => {
281                    let value = body.resolve_alias(value);
282                    let value = frame.values.get(&value).unwrap();
283                    let value = value[0].as_u32().unwrap() as usize;
284                    if value < targets.len() {
285                        frame.apply_target(body, &targets[value]);
286                    } else {
287                        frame.apply_target(body, default);
288                    }
289                }
290                &Terminator::Return { ref values } => {
291                    let values = values
292                        .iter()
293                        .map(|&value| {
294                            let value = body.resolve_alias(value);
295                            frame.values.get(&value).unwrap()[0]
296                        })
297                        .collect();
298                    log::trace!("returning from {}: {:?}", func, values);
299                    return InterpResult::Ok(values);
300                }
301            }
302        }
303    }
304
305    fn call_import(&mut self, name: &str, args: &[ConstVal]) -> InterpResult {
306        panic!("Unknown import: {} with args: {:?}", name, args);
307    }
308}
309
310impl InterpStackFrame {
311    fn apply_target(&mut self, body: &FunctionBody, target: &BlockTarget) {
312        // Collect blockparam args.
313        let args = target
314            .args
315            .iter()
316            .map(|&arg| {
317                let arg = body.resolve_alias(arg);
318                self.values.get(&arg).unwrap().clone()
319            })
320            .collect::<Vec<_>>();
321        log::trace!("taking target {:?} with args {:?}", target, args);
322        // Set blockparams.
323        for (arg, &(_, param)) in args
324            .into_iter()
325            .zip(body.blocks[target.block].params.iter())
326        {
327            log::trace!("setting blockparam {} to {:?}", param, arg);
328            self.values.insert(param, arg);
329        }
330        // Set current block.
331        self.cur_block = target.block;
332    }
333}
334
335impl ConstVal {
336    pub fn as_u32(self) -> Option<u32> {
337        match self {
338            Self::I32(x) => Some(x),
339            _ => None,
340        }
341    }
342
343    pub fn meet(a: Option<ConstVal>, b: Option<ConstVal>) -> Option<ConstVal> {
344        match (a, b) {
345            (None, None) => None,
346            (Some(a), None) | (None, Some(a)) => Some(a),
347            (Some(a), Some(b)) if a == b => Some(a),
348            _ => Some(ConstVal::None),
349        }
350    }
351}
352
353/// Constant-evaluate the given operator with the given arguments,
354/// returning a constant result if possible to know.
355pub fn const_eval(
356    op: &Operator,
357    vals: &[ConstVal],
358    ctx: Option<&mut InterpContext>,
359) -> Option<ConstVal> {
360    match (op, vals) {
361        (Operator::I32Const { value }, []) => Some(ConstVal::I32(*value)),
362        (Operator::I64Const { value }, []) => Some(ConstVal::I64(*value)),
363        (Operator::F32Const { value }, []) => Some(ConstVal::F32(*value)),
364        (Operator::F64Const { value }, []) => Some(ConstVal::F64(*value)),
365        (Operator::I32Eqz, [ConstVal::I32(a)]) => Some(ConstVal::I32(if *a == 0 { 1 } else { 0 })),
366        (Operator::I32Eq, [ConstVal::I32(a), ConstVal::I32(b)]) => {
367            Some(ConstVal::I32(if a == b { 1 } else { 0 }))
368        }
369        (Operator::I32Ne, [ConstVal::I32(a), ConstVal::I32(b)]) => {
370            Some(ConstVal::I32(if a != b { 1 } else { 0 }))
371        }
372        (Operator::I32LtS, [ConstVal::I32(a), ConstVal::I32(b)]) => {
373            Some(ConstVal::I32(if (*a as i32) < (*b as i32) { 1 } else { 0 }))
374        }
375        (Operator::I32LtU, [ConstVal::I32(a), ConstVal::I32(b)]) => {
376            Some(ConstVal::I32(if a < b { 1 } else { 0 }))
377        }
378        (Operator::I32GtS, [ConstVal::I32(a), ConstVal::I32(b)]) => {
379            Some(ConstVal::I32(if (*a as i32) > (*b as i32) { 1 } else { 0 }))
380        }
381        (Operator::I32GtU, [ConstVal::I32(a), ConstVal::I32(b)]) => {
382            Some(ConstVal::I32(if a > b { 1 } else { 0 }))
383        }
384        (Operator::I32LeS, [ConstVal::I32(a), ConstVal::I32(b)]) => {
385            Some(ConstVal::I32(if (*a as i32) <= (*b as i32) {
386                1
387            } else {
388                0
389            }))
390        }
391        (Operator::I32LeU, [ConstVal::I32(a), ConstVal::I32(b)]) => {
392            Some(ConstVal::I32(if a <= b { 1 } else { 0 }))
393        }
394        (Operator::I32GeS, [ConstVal::I32(a), ConstVal::I32(b)]) => {
395            Some(ConstVal::I32(if (*a as i32) >= (*b as i32) {
396                1
397            } else {
398                0
399            }))
400        }
401        (Operator::I32GeU, [ConstVal::I32(a), ConstVal::I32(b)]) => {
402            Some(ConstVal::I32(if a >= b { 1 } else { 0 }))
403        }
404        (Operator::I64Eqz, [ConstVal::I64(a)]) => Some(ConstVal::I32(if *a == 0 { 1 } else { 0 })),
405        (Operator::I64Eq, [ConstVal::I64(a), ConstVal::I64(b)]) => {
406            Some(ConstVal::I32(if a == b { 1 } else { 0 }))
407        }
408        (Operator::I64Ne, [ConstVal::I64(a), ConstVal::I64(b)]) => {
409            Some(ConstVal::I32(if a != b { 1 } else { 0 }))
410        }
411        (Operator::I64LtS, [ConstVal::I64(a), ConstVal::I64(b)]) => {
412            Some(ConstVal::I32(if (*a as i64) < (*b as i64) { 1 } else { 0 }))
413        }
414        (Operator::I64LtU, [ConstVal::I64(a), ConstVal::I64(b)]) => {
415            Some(ConstVal::I32(if a < b { 1 } else { 0 }))
416        }
417        (Operator::I64GtS, [ConstVal::I64(a), ConstVal::I64(b)]) => {
418            Some(ConstVal::I32(if (*a as i64) > (*b as i64) { 1 } else { 0 }))
419        }
420        (Operator::I64GtU, [ConstVal::I64(a), ConstVal::I64(b)]) => {
421            Some(ConstVal::I32(if a > b { 1 } else { 0 }))
422        }
423        (Operator::I64LeS, [ConstVal::I64(a), ConstVal::I64(b)]) => {
424            Some(ConstVal::I32(if (*a as i64) <= (*b as i64) {
425                1
426            } else {
427                0
428            }))
429        }
430        (Operator::I64LeU, [ConstVal::I64(a), ConstVal::I64(b)]) => {
431            Some(ConstVal::I32(if a <= b { 1 } else { 0 }))
432        }
433        (Operator::I64GeS, [ConstVal::I64(a), ConstVal::I64(b)]) => {
434            Some(ConstVal::I32(if (*a as i64) >= (*b as i64) {
435                1
436            } else {
437                0
438            }))
439        }
440        (Operator::I64GeU, [ConstVal::I64(a), ConstVal::I64(b)]) => {
441            Some(ConstVal::I32(if a >= b { 1 } else { 0 }))
442        }
443
444        (Operator::F32Eq, [ConstVal::F32(a), ConstVal::F32(b)]) => {
445            Some(ConstVal::I32(if f32::from_bits(*a) == f32::from_bits(*b) {
446                1
447            } else {
448                0
449            }))
450        }
451        (Operator::F32Ne, [ConstVal::F32(a), ConstVal::F32(b)]) => {
452            Some(ConstVal::I32(if f32::from_bits(*a) != f32::from_bits(*b) {
453                1
454            } else {
455                0
456            }))
457        }
458        (Operator::F32Lt, [ConstVal::F32(a), ConstVal::F32(b)]) => {
459            Some(ConstVal::I32(if f32::from_bits(*a) < f32::from_bits(*b) {
460                1
461            } else {
462                0
463            }))
464        }
465        (Operator::F32Gt, [ConstVal::F32(a), ConstVal::F32(b)]) => {
466            Some(ConstVal::I32(if f32::from_bits(*a) > f32::from_bits(*b) {
467                1
468            } else {
469                0
470            }))
471        }
472        (Operator::F32Le, [ConstVal::F32(a), ConstVal::F32(b)]) => {
473            Some(ConstVal::I32(if f32::from_bits(*a) <= f32::from_bits(*b) {
474                1
475            } else {
476                0
477            }))
478        }
479        (Operator::F32Ge, [ConstVal::F32(a), ConstVal::F32(b)]) => {
480            Some(ConstVal::I32(if f32::from_bits(*a) >= f32::from_bits(*b) {
481                1
482            } else {
483                0
484            }))
485        }
486
487        (Operator::F64Eq, [ConstVal::F64(a), ConstVal::F64(b)]) => {
488            Some(ConstVal::I32(if f64::from_bits(*a) == f64::from_bits(*b) {
489                1
490            } else {
491                0
492            }))
493        }
494        (Operator::F64Ne, [ConstVal::F64(a), ConstVal::F64(b)]) => {
495            Some(ConstVal::I32(if f64::from_bits(*a) != f64::from_bits(*b) {
496                1
497            } else {
498                0
499            }))
500        }
501        (Operator::F64Lt, [ConstVal::F64(a), ConstVal::F64(b)]) => {
502            Some(ConstVal::I32(if f64::from_bits(*a) < f64::from_bits(*b) {
503                1
504            } else {
505                0
506            }))
507        }
508        (Operator::F64Gt, [ConstVal::F64(a), ConstVal::F64(b)]) => {
509            Some(ConstVal::I32(if f64::from_bits(*a) > f64::from_bits(*b) {
510                1
511            } else {
512                0
513            }))
514        }
515        (Operator::F64Le, [ConstVal::F64(a), ConstVal::F64(b)]) => {
516            Some(ConstVal::I32(if f64::from_bits(*a) <= f64::from_bits(*b) {
517                1
518            } else {
519                0
520            }))
521        }
522        (Operator::F64Ge, [ConstVal::F64(a), ConstVal::F64(b)]) => {
523            Some(ConstVal::I32(if f64::from_bits(*a) >= f64::from_bits(*b) {
524                1
525            } else {
526                0
527            }))
528        }
529
530        (Operator::I32Clz, [ConstVal::I32(x)]) => Some(ConstVal::I32(x.leading_zeros())),
531        (Operator::I32Ctz, [ConstVal::I32(x)]) => Some(ConstVal::I32(x.trailing_zeros())),
532        (Operator::I32Popcnt, [ConstVal::I32(x)]) => Some(ConstVal::I32(x.count_ones())),
533
534        (Operator::I32Add, [ConstVal::I32(a), ConstVal::I32(b)]) => {
535            Some(ConstVal::I32(a.wrapping_add(*b)))
536        }
537        (Operator::I32Sub, [ConstVal::I32(a), ConstVal::I32(b)]) => {
538            Some(ConstVal::I32(a.wrapping_sub(*b)))
539        }
540        (Operator::I32Mul, [ConstVal::I32(a), ConstVal::I32(b)]) => {
541            Some(ConstVal::I32(a.wrapping_mul(*b)))
542        }
543        (Operator::I32DivU, [ConstVal::I32(a), ConstVal::I32(b)]) => {
544            Some(ConstVal::I32(a.checked_div(*b)?))
545        }
546        (Operator::I32DivS, [ConstVal::I32(a), ConstVal::I32(b)]) => {
547            Some(ConstVal::I32((*a as i32).checked_div(*b as i32)? as u32))
548        }
549        (Operator::I32RemU, [ConstVal::I32(a), ConstVal::I32(b)]) => {
550            Some(ConstVal::I32(a.checked_rem(*b)?))
551        }
552        (Operator::I32RemS, [ConstVal::I32(a), ConstVal::I32(b)]) => {
553            Some(ConstVal::I32((*a as i32).checked_rem(*b as i32)? as u32))
554        }
555        (Operator::I32And, [ConstVal::I32(a), ConstVal::I32(b)]) => Some(ConstVal::I32(a & b)),
556        (Operator::I32Or, [ConstVal::I32(a), ConstVal::I32(b)]) => Some(ConstVal::I32(a | b)),
557        (Operator::I32Xor, [ConstVal::I32(a), ConstVal::I32(b)]) => Some(ConstVal::I32(a ^ b)),
558        (Operator::I32Shl, [ConstVal::I32(a), ConstVal::I32(b)]) => {
559            Some(ConstVal::I32(a.wrapping_shl(*b)))
560        }
561        (Operator::I32ShrS, [ConstVal::I32(a), ConstVal::I32(b)]) => {
562            Some(ConstVal::I32((*a as i32).wrapping_shr(*b) as u32))
563        }
564        (Operator::I32ShrU, [ConstVal::I32(a), ConstVal::I32(b)]) => {
565            Some(ConstVal::I32(a.wrapping_shr(*b)))
566        }
567        (Operator::I32Rotl, [ConstVal::I32(a), ConstVal::I32(b)]) => {
568            Some(ConstVal::I32(a.rotate_left(*b & 0x1f)))
569        }
570        (Operator::I32Rotr, [ConstVal::I32(a), ConstVal::I32(b)]) => {
571            Some(ConstVal::I32(a.rotate_right(*b & 0x1f)))
572        }
573
574        (Operator::I64Clz, [ConstVal::I64(x)]) => Some(ConstVal::I64(x.leading_zeros() as u64)),
575        (Operator::I64Ctz, [ConstVal::I64(x)]) => Some(ConstVal::I64(x.trailing_zeros() as u64)),
576        (Operator::I64Popcnt, [ConstVal::I64(x)]) => Some(ConstVal::I64(x.count_ones() as u64)),
577
578        (Operator::I64Add, [ConstVal::I64(a), ConstVal::I64(b)]) => {
579            Some(ConstVal::I64(a.wrapping_add(*b)))
580        }
581        (Operator::I64Sub, [ConstVal::I64(a), ConstVal::I64(b)]) => {
582            Some(ConstVal::I64(a.wrapping_sub(*b)))
583        }
584        (Operator::I64Mul, [ConstVal::I64(a), ConstVal::I64(b)]) => {
585            Some(ConstVal::I64(a.wrapping_mul(*b)))
586        }
587        (Operator::I64DivU, [ConstVal::I64(a), ConstVal::I64(b)]) => {
588            Some(ConstVal::I64(a.checked_div(*b)?))
589        }
590        (Operator::I64DivS, [ConstVal::I64(a), ConstVal::I64(b)]) => {
591            Some(ConstVal::I64((*a as i64).checked_div(*b as i64)? as u64))
592        }
593        (Operator::I64RemU, [ConstVal::I64(a), ConstVal::I64(b)]) => {
594            Some(ConstVal::I64(a.checked_rem(*b)?))
595        }
596        (Operator::I64RemS, [ConstVal::I64(a), ConstVal::I64(b)]) => {
597            Some(ConstVal::I64((*a as i64).checked_rem(*b as i64)? as u64))
598        }
599        (Operator::I64And, [ConstVal::I64(a), ConstVal::I64(b)]) => Some(ConstVal::I64(a & b)),
600        (Operator::I64Or, [ConstVal::I64(a), ConstVal::I64(b)]) => Some(ConstVal::I64(a | b)),
601        (Operator::I64Xor, [ConstVal::I64(a), ConstVal::I64(b)]) => Some(ConstVal::I64(a ^ b)),
602        (Operator::I64Shl, [ConstVal::I64(a), ConstVal::I64(b)]) => {
603            Some(ConstVal::I64(a.wrapping_shl(*b as u32)))
604        }
605        (Operator::I64ShrS, [ConstVal::I64(a), ConstVal::I64(b)]) => {
606            Some(ConstVal::I64((*a as i64).wrapping_shr(*b as u32) as u64))
607        }
608        (Operator::I64ShrU, [ConstVal::I64(a), ConstVal::I64(b)]) => {
609            Some(ConstVal::I64(a.wrapping_shr(*b as u32)))
610        }
611        (Operator::I64Rotl, [ConstVal::I64(a), ConstVal::I64(b)]) => {
612            Some(ConstVal::I64(a.rotate_left((*b as u32) & 0x3f)))
613        }
614        (Operator::I64Rotr, [ConstVal::I64(a), ConstVal::I64(b)]) => {
615            Some(ConstVal::I64(a.rotate_right((*b as u32) & 0x3f)))
616        }
617
618        (Operator::F32Abs, [ConstVal::F32(a)]) => {
619            Some(ConstVal::F32(f32::from_bits(*a).abs().to_bits()))
620        }
621        (Operator::F32Neg, [ConstVal::F32(a)]) => {
622            Some(ConstVal::F32((-f32::from_bits(*a)).to_bits()))
623        }
624        (Operator::F32Ceil, [ConstVal::F32(a)]) => {
625            Some(ConstVal::F32(f32::from_bits(*a).ceil().to_bits()))
626        }
627        (Operator::F32Floor, [ConstVal::F32(a)]) => {
628            Some(ConstVal::F32(f32::from_bits(*a).floor().to_bits()))
629        }
630        (Operator::F32Trunc, [ConstVal::F32(a)]) => {
631            Some(ConstVal::F32(f32::from_bits(*a).trunc().to_bits()))
632        }
633        (Operator::F32Nearest, [ConstVal::F32(a)]) => Some(ConstVal::F32(
634            f32::from_bits(*a).round_ties_even().to_bits(),
635        )),
636        (Operator::F32Sqrt, [ConstVal::F32(a)]) => {
637            Some(ConstVal::F32(f32::from_bits(*a).sqrt().to_bits()))
638        }
639        (Operator::F32Add, [ConstVal::F32(a), ConstVal::F32(b)]) => Some(ConstVal::F32(
640            (f32::from_bits(*a) + f32::from_bits(*b)).to_bits(),
641        )),
642        (Operator::F32Sub, [ConstVal::F32(a), ConstVal::F32(b)]) => Some(ConstVal::F32(
643            (f32::from_bits(*a) - f32::from_bits(*b)).to_bits(),
644        )),
645        (Operator::F32Mul, [ConstVal::F32(a), ConstVal::F32(b)]) => Some(ConstVal::F32(
646            (f32::from_bits(*a) * f32::from_bits(*b)).to_bits(),
647        )),
648        (Operator::F32Div, [ConstVal::F32(a), ConstVal::F32(b)]) => Some(ConstVal::F32(
649            (f32::from_bits(*a) / f32::from_bits(*b)).to_bits(),
650        )),
651        (Operator::F32Min, [ConstVal::F32(a), ConstVal::F32(b)]) => Some(ConstVal::F32(
652            f32_min(f32::from_bits(*a), f32::from_bits(*b)).to_bits(),
653        )),
654        (Operator::F32Max, [ConstVal::F32(a), ConstVal::F32(b)]) => Some(ConstVal::F32(
655            f32_max(f32::from_bits(*a), f32::from_bits(*b)).to_bits(),
656        )),
657        (Operator::F32Copysign, [ConstVal::F32(a), ConstVal::F32(b)]) => Some(ConstVal::F32(
658            f32::copysign(f32::from_bits(*a), f32::from_bits(*b)).to_bits(),
659        )),
660
661        (Operator::F64Abs, [ConstVal::F64(a)]) => {
662            Some(ConstVal::F64(f64::from_bits(*a).abs().to_bits()))
663        }
664        (Operator::F64Neg, [ConstVal::F64(a)]) => {
665            Some(ConstVal::F64((-f64::from_bits(*a)).to_bits()))
666        }
667        (Operator::F64Ceil, [ConstVal::F64(a)]) => {
668            Some(ConstVal::F64(f64::from_bits(*a).ceil().to_bits()))
669        }
670        (Operator::F64Floor, [ConstVal::F64(a)]) => {
671            Some(ConstVal::F64(f64::from_bits(*a).floor().to_bits()))
672        }
673        (Operator::F64Trunc, [ConstVal::F64(a)]) => {
674            Some(ConstVal::F64(f64::from_bits(*a).trunc().to_bits()))
675        }
676        (Operator::F64Nearest, [ConstVal::F64(a)]) => Some(ConstVal::F64(
677            f64::from_bits(*a).round_ties_even().to_bits(),
678        )),
679        (Operator::F64Sqrt, [ConstVal::F64(a)]) => {
680            Some(ConstVal::F64(f64::from_bits(*a).sqrt().to_bits()))
681        }
682        (Operator::F64Add, [ConstVal::F64(a), ConstVal::F64(b)]) => Some(ConstVal::F64(
683            (f64::from_bits(*a) + f64::from_bits(*b)).to_bits(),
684        )),
685        (Operator::F64Sub, [ConstVal::F64(a), ConstVal::F64(b)]) => Some(ConstVal::F64(
686            (f64::from_bits(*a) - f64::from_bits(*b)).to_bits(),
687        )),
688        (Operator::F64Mul, [ConstVal::F64(a), ConstVal::F64(b)]) => Some(ConstVal::F64(
689            (f64::from_bits(*a) * f64::from_bits(*b)).to_bits(),
690        )),
691        (Operator::F64Div, [ConstVal::F64(a), ConstVal::F64(b)]) => Some(ConstVal::F64(
692            (f64::from_bits(*a) / f64::from_bits(*b)).to_bits(),
693        )),
694        (Operator::F64Min, [ConstVal::F64(a), ConstVal::F64(b)]) => Some(ConstVal::F64(
695            f64_min(f64::from_bits(*a), f64::from_bits(*b)).to_bits(),
696        )),
697        (Operator::F64Max, [ConstVal::F64(a), ConstVal::F64(b)]) => Some(ConstVal::F64(
698            f64_max(f64::from_bits(*a), f64::from_bits(*b)).to_bits(),
699        )),
700        (Operator::F64Copysign, [ConstVal::F64(a), ConstVal::F64(b)]) => Some(ConstVal::F64(
701            f64::copysign(f64::from_bits(*a), f64::from_bits(*b)).to_bits(),
702        )),
703
704        (Operator::I32WrapI64, [ConstVal::I64(a)]) => Some(ConstVal::I32(*a as u32)),
705
706        (Operator::I32TruncF32S, [ConstVal::F32(a)]) => {
707            let a = f32::from_bits(*a);
708            if a >= (i32::MIN as f32) && a <= (i32::MAX as f32) {
709                Some(ConstVal::I32(a as i32 as u32))
710            } else {
711                None
712            }
713        }
714        (Operator::I32TruncF32U, [ConstVal::F32(a)]) => {
715            let a = f32::from_bits(*a);
716            if a >= 0.0 && a <= (u32::MAX as f32) {
717                Some(ConstVal::I32(a as u32))
718            } else {
719                None
720            }
721        }
722        (Operator::I32TruncF64S, [ConstVal::F64(a)]) => {
723            let a = f64::from_bits(*a);
724            if a >= (i32::MIN as f64) && a <= (i32::MAX as f64) {
725                Some(ConstVal::I32(a as i32 as u32))
726            } else {
727                None
728            }
729        }
730        (Operator::I32TruncF64U, [ConstVal::F64(a)]) => {
731            let a = f64::from_bits(*a);
732            if a >= 0.0 && a <= (u32::MAX as f64) {
733                Some(ConstVal::I32(a as u32))
734            } else {
735                None
736            }
737        }
738
739        (Operator::I64TruncF32S, [ConstVal::F32(a)]) => {
740            let a = f32::from_bits(*a);
741            if a >= (i64::MIN as f32) && a <= (i64::MAX as f32) {
742                Some(ConstVal::I64(a as i64 as u64))
743            } else {
744                None
745            }
746        }
747        (Operator::I64TruncF32U, [ConstVal::F32(a)]) => {
748            let a = f32::from_bits(*a);
749            if a >= 0.0 && a <= (u64::MAX as f32) {
750                Some(ConstVal::I64(a as u64))
751            } else {
752                None
753            }
754        }
755        (Operator::I64TruncF64S, [ConstVal::F64(a)]) => {
756            let a = f64::from_bits(*a);
757            if a >= (i64::MIN as f64) && a <= (i64::MAX as f64) {
758                Some(ConstVal::I64(a as i64 as u64))
759            } else {
760                None
761            }
762        }
763        (Operator::I64TruncF64U, [ConstVal::F64(a)]) => {
764            let a = f64::from_bits(*a);
765            if a >= 0.0 && a <= (u64::MAX as f64) {
766                Some(ConstVal::I64(a as u64))
767            } else {
768                None
769            }
770        }
771
772        (Operator::I32TruncSatF32S, [ConstVal::F32(a)]) => {
773            let a = f32::from_bits(*a);
774            Some(ConstVal::I32(if a.is_nan() {
775                0
776            } else {
777                a.min(i32::MAX as f32).max(i32::MIN as f32) as i32 as u32
778            }))
779        }
780        (Operator::I32TruncSatF32U, [ConstVal::F32(a)]) => {
781            let a = f32::from_bits(*a);
782            Some(ConstVal::I32(if a.is_nan() {
783                0
784            } else {
785                a.min(u32::MAX as f32).max(0.0) as u32
786            }))
787        }
788        (Operator::I32TruncSatF64S, [ConstVal::F64(a)]) => {
789            let a = f64::from_bits(*a);
790            Some(ConstVal::I32(if a.is_nan() {
791                0
792            } else {
793                a.min(i32::MAX as f64).max(i32::MIN as f64) as i32 as u32
794            }))
795        }
796        (Operator::I32TruncSatF64U, [ConstVal::F64(a)]) => {
797            let a = f64::from_bits(*a);
798            Some(ConstVal::I32(if a.is_nan() {
799                0
800            } else {
801                a.min(u32::MAX as f64).max(0.0) as u32
802            }))
803        }
804
805        (Operator::I64TruncSatF32S, [ConstVal::F32(a)]) => {
806            let a = f32::from_bits(*a);
807            Some(ConstVal::I64(if a.is_nan() {
808                0
809            } else {
810                a.min(i64::MAX as f32).max(i64::MIN as f32) as i64 as u64
811            }))
812        }
813        (Operator::I64TruncSatF32U, [ConstVal::F32(a)]) => {
814            let a = f32::from_bits(*a);
815            Some(ConstVal::I64(if a.is_nan() {
816                0
817            } else {
818                a.min(u64::MAX as f32).max(0.0) as u64
819            }))
820        }
821        (Operator::I64TruncSatF64S, [ConstVal::F64(a)]) => {
822            let a = f64::from_bits(*a);
823            Some(ConstVal::I64(if a.is_nan() {
824                0
825            } else {
826                a.min(i64::MAX as f64).max(i64::MIN as f64) as i64 as u64
827            }))
828        }
829        (Operator::I64TruncSatF64U, [ConstVal::F64(a)]) => {
830            let a = f64::from_bits(*a);
831            Some(ConstVal::I64(if a.is_nan() {
832                0
833            } else {
834                a.min(u64::MAX as f64).max(0.0) as u64
835            }))
836        }
837
838        (Operator::F32ConvertI32S, [ConstVal::I32(a)]) => {
839            Some(ConstVal::F32((*a as i32 as f32).to_bits()))
840        }
841        (Operator::F32ConvertI32U, [ConstVal::I32(a)]) => {
842            Some(ConstVal::F32((*a as f32).to_bits()))
843        }
844        (Operator::F32ConvertI64S, [ConstVal::I64(a)]) => {
845            Some(ConstVal::F32((*a as i64 as f32).to_bits()))
846        }
847        (Operator::F32ConvertI64U, [ConstVal::I64(a)]) => {
848            Some(ConstVal::F32((*a as f32).to_bits()))
849        }
850
851        (Operator::F64ConvertI32S, [ConstVal::I32(a)]) => {
852            Some(ConstVal::F64((*a as i32 as f64).to_bits()))
853        }
854        (Operator::F64ConvertI32U, [ConstVal::I32(a)]) => {
855            Some(ConstVal::F64((*a as f64).to_bits()))
856        }
857        (Operator::F64ConvertI64S, [ConstVal::I64(a)]) => {
858            Some(ConstVal::F64((*a as i64 as f64).to_bits()))
859        }
860        (Operator::F64ConvertI64U, [ConstVal::I64(a)]) => {
861            Some(ConstVal::F64((*a as f64).to_bits()))
862        }
863
864        (Operator::F32DemoteF64, [ConstVal::F64(a)]) => {
865            Some(ConstVal::F32((f64::from_bits(*a) as f32).to_bits()))
866        }
867        (Operator::F64PromoteF32, [ConstVal::F32(a)]) => {
868            Some(ConstVal::F64((f32::from_bits(*a) as f64).to_bits()))
869        }
870
871        (Operator::F32ReinterpretI32, [ConstVal::I32(a)]) => Some(ConstVal::F32(*a)),
872        (Operator::F64ReinterpretI64, [ConstVal::I64(a)]) => Some(ConstVal::F64(*a)),
873        (Operator::I32ReinterpretF32, [ConstVal::F32(a)]) => Some(ConstVal::I32(*a)),
874        (Operator::I64ReinterpretF64, [ConstVal::F64(a)]) => Some(ConstVal::I64(*a)),
875
876        (Operator::I32Extend8S, [ConstVal::I32(a)]) => Some(ConstVal::I32(*a as i8 as i32 as u32)),
877        (Operator::I32Extend16S, [ConstVal::I32(a)]) => {
878            Some(ConstVal::I32(*a as i16 as i32 as u32))
879        }
880        (Operator::I64Extend8S, [ConstVal::I64(a)]) => Some(ConstVal::I64(*a as i8 as i64 as u64)),
881        (Operator::I64Extend16S, [ConstVal::I64(a)]) => {
882            Some(ConstVal::I64(*a as i16 as i64 as u64))
883        }
884        (Operator::I64Extend32S, [ConstVal::I64(a)]) => {
885            Some(ConstVal::I64(*a as i32 as i64 as u64))
886        }
887        (Operator::I64ExtendI32S, [ConstVal::I32(a)]) => {
888            Some(ConstVal::I64(*a as i32 as i64 as u64))
889        }
890        (Operator::I64ExtendI32U, [ConstVal::I32(a)]) => Some(ConstVal::I64(*a as u64)),
891
892        (Operator::Select, [x, y, ConstVal::I32(k)]) => Some(if *k != 0 { *x } else { *y }),
893        (Operator::TypedSelect { .. }, [x, y, ConstVal::I32(k)]) => {
894            Some(if *k != 0 { *x } else { *y })
895        }
896
897        (Operator::GlobalGet { global_index }, []) => {
898            ctx.map(|global| global.globals[*global_index])
899        }
900        (Operator::GlobalSet { global_index }, [x]) => ctx.map(|global| {
901            global.globals[*global_index] = *x;
902            ConstVal::None
903        }),
904
905        (Operator::TableGet { .. }, _)
906        | (Operator::TableSet { .. }, _)
907        | (Operator::TableGrow { .. }, _) => None,
908
909        (Operator::TableSize { table_index }, []) => {
910            ctx.map(|global| ConstVal::I32(global.tables[*table_index].elements.len() as u32))
911        }
912
913        (Operator::MemorySize { mem }, []) => {
914            ctx.map(|global| ConstVal::I32((global.memories[*mem].data.len() / WASM_PAGE) as u32))
915        }
916
917        (Operator::MemoryGrow { mem }, [ConstVal::I32(amount)]) => ctx.and_then(|global| {
918            let cur_pages = global.memories[*mem].data.len() / WASM_PAGE;
919            let new_pages = cur_pages + (*amount as usize);
920            if new_pages > global.memories[*mem].max_pages || new_pages > MAX_PAGES {
921                None
922            } else {
923                global.memories[*mem].data.resize(new_pages * WASM_PAGE, 0);
924                Some(ConstVal::I32(cur_pages as u32))
925            }
926        }),
927
928        (Operator::Nop, []) => Some(ConstVal::None),
929        (Operator::Unreachable, []) => None,
930
931        (Operator::I32Load { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
932            let addr = addr.checked_add(memory.offset)?;
933            if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
934                return None;
935            }
936            Some(ConstVal::I32(read_u32(
937                &global.memories[memory.memory],
938                addr,
939            )))
940        }),
941        (Operator::I64Load { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
942            let addr = addr.checked_add(memory.offset)?;
943            if addr.checked_add(8)? > global.memories[memory.memory].data.len() as u32 {
944                return None;
945            }
946            Some(ConstVal::I64(read_u64(
947                &global.memories[memory.memory],
948                addr,
949            )))
950        }),
951        (Operator::F32Load { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
952            let addr = addr.checked_add(memory.offset)?;
953            if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
954                return None;
955            }
956            Some(ConstVal::F32(read_u32(
957                &global.memories[memory.memory],
958                addr,
959            )))
960        }),
961        (Operator::F64Load { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
962            let addr = addr.checked_add(memory.offset)?;
963            if addr.checked_add(8)? > global.memories[memory.memory].data.len() as u32 {
964                return None;
965            }
966            Some(ConstVal::F64(read_u64(
967                &global.memories[memory.memory],
968                addr,
969            )))
970        }),
971        (Operator::I32Load8S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
972            let addr = addr.checked_add(memory.offset)?;
973            if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
974                return None;
975            }
976            Some(ConstVal::I32(
977                read_u8(&global.memories[memory.memory], addr) as i8 as i32 as u32,
978            ))
979        }),
980        (Operator::I32Load8U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
981            let addr = addr.checked_add(memory.offset)?;
982            if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
983                return None;
984            }
985            Some(ConstVal::I32(
986                read_u8(&global.memories[memory.memory], addr) as u32,
987            ))
988        }),
989        (Operator::I32Load16S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
990            let addr = addr.checked_add(memory.offset)?;
991            if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
992                return None;
993            }
994            Some(ConstVal::I32(
995                read_u16(&global.memories[memory.memory], addr) as i16 as i32 as u32,
996            ))
997        }),
998        (Operator::I32Load16U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
999            let addr = addr.checked_add(memory.offset)?;
1000            if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
1001                return None;
1002            }
1003            Some(ConstVal::I32(
1004                read_u16(&global.memories[memory.memory], addr) as u32,
1005            ))
1006        }),
1007        (Operator::I64Load8S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
1008            let addr = addr.checked_add(memory.offset)?;
1009            if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
1010                return None;
1011            }
1012            Some(ConstVal::I64(
1013                read_u8(&global.memories[memory.memory], addr) as i8 as i64 as u64,
1014            ))
1015        }),
1016        (Operator::I64Load8U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
1017            let addr = addr.checked_add(memory.offset)?;
1018            if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
1019                return None;
1020            }
1021            Some(ConstVal::I64(
1022                read_u8(&global.memories[memory.memory], addr) as u64,
1023            ))
1024        }),
1025        (Operator::I64Load16S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
1026            let addr = addr.checked_add(memory.offset)?;
1027            if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
1028                return None;
1029            }
1030            Some(ConstVal::I64(
1031                read_u16(&global.memories[memory.memory], addr) as i16 as i64 as u64,
1032            ))
1033        }),
1034        (Operator::I64Load16U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
1035            let addr = addr.checked_add(memory.offset)?;
1036            if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
1037                return None;
1038            }
1039            Some(ConstVal::I64(
1040                read_u16(&global.memories[memory.memory], addr) as u64,
1041            ))
1042        }),
1043        (Operator::I64Load32S { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
1044            let addr = addr.checked_add(memory.offset)?;
1045            if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
1046                return None;
1047            }
1048            Some(ConstVal::I64(
1049                read_u32(&global.memories[memory.memory], addr) as i32 as i64 as u64,
1050            ))
1051        }),
1052        (Operator::I64Load32U { memory }, [ConstVal::I32(addr)]) => ctx.and_then(|global| {
1053            let addr = addr.checked_add(memory.offset)?;
1054            if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
1055                return None;
1056            }
1057            Some(ConstVal::I64(
1058                read_u32(&global.memories[memory.memory], addr) as u64,
1059            ))
1060        }),
1061        (Operator::I32Store { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => ctx
1062            .and_then(|global| {
1063                let addr = addr.checked_add(memory.offset)?;
1064                if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
1065                    return None;
1066                }
1067                write_u32(&mut global.memories[memory.memory], addr, *data);
1068                Some(ConstVal::None)
1069            }),
1070        (Operator::I64Store { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => ctx
1071            .and_then(|global| {
1072                let addr = addr.checked_add(memory.offset)?;
1073                if addr.checked_add(8)? > global.memories[memory.memory].data.len() as u32 {
1074                    return None;
1075                }
1076                write_u64(&mut global.memories[memory.memory], addr, *data);
1077                Some(ConstVal::None)
1078            }),
1079        (Operator::I32Store8 { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => ctx
1080            .and_then(|global| {
1081                let addr = addr.checked_add(memory.offset)?;
1082                if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
1083                    return None;
1084                }
1085                write_u8(&mut global.memories[memory.memory], addr, *data as u8);
1086                Some(ConstVal::None)
1087            }),
1088        (Operator::I32Store16 { memory }, [ConstVal::I32(addr), ConstVal::I32(data)]) => ctx
1089            .and_then(|global| {
1090                let addr = addr.checked_add(memory.offset)?;
1091                if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
1092                    return None;
1093                }
1094                write_u16(&mut global.memories[memory.memory], addr, *data as u16);
1095                Some(ConstVal::None)
1096            }),
1097        (Operator::I64Store8 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => ctx
1098            .and_then(|global| {
1099                let addr = addr.checked_add(memory.offset)?;
1100                if addr.checked_add(1)? > global.memories[memory.memory].data.len() as u32 {
1101                    return None;
1102                }
1103                write_u8(&mut global.memories[memory.memory], addr, *data as u8);
1104                Some(ConstVal::None)
1105            }),
1106        (Operator::I64Store16 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => ctx
1107            .and_then(|global| {
1108                let addr = addr.checked_add(memory.offset)?;
1109                if addr.checked_add(2)? > global.memories[memory.memory].data.len() as u32 {
1110                    return None;
1111                }
1112                write_u16(&mut global.memories[memory.memory], addr, *data as u16);
1113                Some(ConstVal::None)
1114            }),
1115        (Operator::I64Store32 { memory }, [ConstVal::I32(addr), ConstVal::I64(data)]) => ctx
1116            .and_then(|global| {
1117                let addr = addr.checked_add(memory.offset)?;
1118                if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
1119                    return None;
1120                }
1121                write_u32(&mut global.memories[memory.memory], addr, *data as u32);
1122                Some(ConstVal::None)
1123            }),
1124        (Operator::F32Store { memory }, [ConstVal::I32(addr), ConstVal::F32(data)]) => ctx
1125            .and_then(|global| {
1126                let addr = addr.checked_add(memory.offset)?;
1127                if addr.checked_add(4)? > global.memories[memory.memory].data.len() as u32 {
1128                    return None;
1129                }
1130                write_u32(&mut global.memories[memory.memory], addr, *data);
1131                Some(ConstVal::None)
1132            }),
1133        (Operator::F64Store { memory }, [ConstVal::I32(addr), ConstVal::F64(data)]) => ctx
1134            .and_then(|global| {
1135                let addr = addr.checked_add(memory.offset)?;
1136                if addr.checked_add(8)? > global.memories[memory.memory].data.len() as u32 {
1137                    return None;
1138                }
1139                write_u64(&mut global.memories[memory.memory], addr, *data);
1140                Some(ConstVal::None)
1141            }),
1142        (_, args) if args.iter().any(|&arg| arg == ConstVal::None) => None,
1143        _ => None,
1144    }
1145}
1146
1147pub(crate) fn read_u8(mem: &InterpMemory, addr: u32) -> u8 {
1148    let addr = addr as usize;
1149    mem.data[addr]
1150}
1151
1152pub(crate) fn read_u16(mem: &InterpMemory, addr: u32) -> u16 {
1153    use std::convert::TryInto;
1154    let addr = addr as usize;
1155    u16::from_le_bytes(mem.data[addr..(addr + 2)].try_into().unwrap())
1156}
1157
1158pub(crate) fn read_u32(mem: &InterpMemory, addr: u32) -> u32 {
1159    use std::convert::TryInto;
1160    let addr = addr as usize;
1161    u32::from_le_bytes(mem.data[addr..(addr + 4)].try_into().unwrap())
1162}
1163
1164pub(crate) fn read_u64(mem: &InterpMemory, addr: u32) -> u64 {
1165    use std::convert::TryInto;
1166    let addr = addr as usize;
1167    u64::from_le_bytes(mem.data[addr..(addr + 8)].try_into().unwrap())
1168}
1169
1170pub(crate) fn write_u8(mem: &mut InterpMemory, addr: u32, data: u8) {
1171    let addr = addr as usize;
1172    mem.data[addr] = data;
1173}
1174
1175pub(crate) fn write_u16(mem: &mut InterpMemory, addr: u32, data: u16) {
1176    let addr = addr as usize;
1177    mem.data[addr..(addr + 2)].copy_from_slice(&data.to_le_bytes()[..]);
1178}
1179
1180pub(crate) fn write_u32(mem: &mut InterpMemory, addr: u32, data: u32) {
1181    let addr = addr as usize;
1182    mem.data[addr..(addr + 4)].copy_from_slice(&data.to_le_bytes()[..]);
1183}
1184
1185pub(crate) fn write_u64(mem: &mut InterpMemory, addr: u32, data: u64) {
1186    let addr = addr as usize;
1187    mem.data[addr..(addr + 8)].copy_from_slice(&data.to_le_bytes()[..]);
1188}
1189
1190// Min/max implementations with proper handling for negative-zero (as
1191// distinct from positive-zero): see
1192// https://github.com/wasmi-labs/wasmi/blob/6d3729c17e6d8bcabb8cd7fed0f6278f17f94e06/crates/core/src/value.rs#L575.
1193
1194fn f32_min(a: f32, b: f32) -> f32 {
1195    if a < b {
1196        a
1197    } else if a > b {
1198        b
1199    } else if a == b {
1200        if a.is_sign_negative() && b.is_sign_positive() {
1201            a
1202        } else {
1203            b
1204        }
1205    } else {
1206        f32::NAN
1207    }
1208}
1209fn f32_max(a: f32, b: f32) -> f32 {
1210    if a < b {
1211        b
1212    } else if a > b {
1213        a
1214    } else if a == b {
1215        if a.is_sign_positive() && b.is_sign_negative() {
1216            a
1217        } else {
1218            b
1219        }
1220    } else {
1221        f32::NAN
1222    }
1223}
1224fn f64_min(a: f64, b: f64) -> f64 {
1225    if a < b {
1226        a
1227    } else if a > b {
1228        b
1229    } else if a == b {
1230        if a.is_sign_negative() && b.is_sign_positive() {
1231            a
1232        } else {
1233            b
1234        }
1235    } else {
1236        f64::NAN
1237    }
1238}
1239fn f64_max(a: f64, b: f64) -> f64 {
1240    if a < b {
1241        b
1242    } else if a > b {
1243        a
1244    } else if a == b {
1245        if a.is_sign_positive() && b.is_sign_negative() {
1246            a
1247        } else {
1248            b
1249        }
1250    } else {
1251        f64::NAN
1252    }
1253}