Skip to main content

wasefire_interpreter/
exec.rs

1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// TODO: Some toctou could be used instead of panic.
16use alloc::vec;
17use alloc::vec::Vec;
18
19use wasefire_common::id::UniqueId;
20
21use crate::cursor::*;
22use crate::error::*;
23use crate::module::*;
24use crate::side_table::*;
25use crate::syntax::*;
26use crate::toctou::*;
27use crate::*;
28
29pub const MEMORY_ALIGN: usize = 16;
30
31/// Runtime values.
32// TODO: Introduce untyped values? (to save the tag)
33#[derive(Copy, Clone, PartialEq, Eq)]
34pub enum Val {
35    I32(u32),
36    I64(u64),
37    #[cfg(feature = "float-types")]
38    F32(u32),
39    #[cfg(feature = "float-types")]
40    F64(u64),
41    #[cfg(feature = "vector-types")]
42    V128(u128),
43    Null(RefType),
44    Ref(Ptr),
45    RefExtern(usize),
46}
47
48static STORE_ID: UniqueId = UniqueId::new();
49
50/// Runtime store.
51// We cannot GC by design. Vectors can only grow.
52#[derive(Debug)]
53pub struct Store<'m> {
54    id: usize,
55    insts: Vec<Instance<'m>>,
56    // TODO: This should be an Linker struct that can be shared between stores. The FuncType can be
57    // reconstructed on demand (only counts can be stored).
58    funcs: Vec<(HostName<'m>, FuncType<'m>)>,
59    // When present, contains a module name and a length. In that case, any unresolved imported
60    // function for that module name is appended to funcs (one per type, so the function name is
61    // the name of the first unresolved function of that type). The length of resolvable host
62    // functions in `funcs` is stored to limit normal linking to that part.
63    func_default: Option<(&'m str, usize)>,
64    threads: Vec<Continuation<'m>>,
65}
66
67#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
68struct HostName<'m> {
69    module: &'m str,
70    name: &'m str,
71}
72
73/// Identifies a store.
74#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
75pub struct StoreId(usize);
76
77/// Identifies an instance within a store.
78#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
79pub struct InstId {
80    store_id: usize,
81    inst_id: usize,
82}
83
84impl InstId {
85    /// Returns the identifier of the store of this instance.
86    pub fn store_id(self) -> StoreId {
87        StoreId(self.store_id)
88    }
89}
90
91/// Store wrapper when calling into the host.
92#[derive(Debug)]
93// Invariant that there is at least one thread.
94pub struct Call<'a, 'm> {
95    store: &'a mut Store<'m>,
96}
97
98impl Default for Store<'_> {
99    fn default() -> Self {
100        Self {
101            id: STORE_ID.next() as usize,
102            insts: vec![],
103            funcs: vec![],
104            func_default: None,
105            threads: vec![],
106        }
107    }
108}
109
110impl<'m> Store<'m> {
111    /// Returns the identifier of this store.
112    pub fn id(&self) -> StoreId {
113        StoreId(self.id)
114    }
115
116    /// Instantiates a valid module in this store.
117    ///
118    /// The memory is not dynamically allocated and must thus be provided. It is not necessary for
119    /// the memory length to be a multiple of 64kB. Execution will trap if the module tries to
120    /// access part of the memory that does not exist.
121    pub fn instantiate(
122        &mut self, module: Module<'m>, memory: &'m mut [u8],
123    ) -> Result<InstId, Error> {
124        let inst_id = self.insts.len();
125        self.insts.push(Instance::new(module));
126        for import in self.last_inst().module.imports() {
127            let type_ = import.type_(&self.last_inst().module);
128            let id = self.resolve(&import, type_)?;
129            match import.desc {
130                ImportDesc::Func(_) => self.last_inst().funcs.ext.push(id),
131                ImportDesc::Table(_) => self.last_inst().tables.ext.push(id),
132                ImportDesc::Mem(_) => self.last_inst().mems.ext.push(id),
133                ImportDesc::Global(_) => self.last_inst().globals.ext.push(id),
134            }
135        }
136        if let Some(mut parser) = self.last_inst().module.section(SectionId::Table) {
137            for _ in 0 .. parser.parse_vec().into_ok() {
138                (self.last_inst().tables.int).push(Table::new(parser.parse_tabletype().into_ok()));
139            }
140        }
141        if let Some(mut parser) = self.last_inst().module.section(SectionId::Memory) {
142            match parser.parse_vec().into_ok() {
143                0 => (),
144                1 => {
145                    let limits = parser.parse_memtype().into_ok();
146                    self.last_inst().mems.int.init(memory, limits)?;
147                }
148                _ => unimplemented!(),
149            }
150        }
151        if let Some(mut parser) = self.last_inst().module.section(SectionId::Global) {
152            for _ in 0 .. parser.parse_vec().into_ok() {
153                parser.parse_globaltype().into_ok();
154                let value = Thread::const_expr(self, inst_id, &mut parser);
155                self.last_inst().globals.int.push(Global::new(value));
156            }
157        }
158        if let Some(mut parser) = self.last_inst().module.section(SectionId::Element) {
159            for _ in 0 .. parser.parse_vec().into_ok() {
160                // TODO: This is inefficient because we only need init for active segments.
161                let mut elem = ComputeElem::new(self, inst_id);
162                parser.parse_elem(&mut elem).into_ok();
163                let ComputeElem { mode, init, .. } = elem;
164                let drop = match mode {
165                    ElemMode::Passive => false,
166                    ElemMode::Active { table, offset } => {
167                        let n = init.len();
168                        let table = self.table(inst_id, table);
169                        table_init(offset, 0, n, table, &init)?;
170                        true
171                    }
172                    ElemMode::Declarative => true,
173                };
174                self.last_inst().elems.push(drop);
175            }
176        }
177        if let Some(mut parser) = self.last_inst().module.section(SectionId::Data) {
178            for _ in 0 .. parser.parse_vec().into_ok() {
179                let mut data = ComputeData::new(self, inst_id);
180                parser.parse_data(&mut data).into_ok();
181                let ComputeData { mode, init, .. } = data;
182                let drop = match mode {
183                    DataMode::Passive => false,
184                    DataMode::Active { memory, offset } => {
185                        let n = init.len();
186                        let memory = self.mem(inst_id, memory);
187                        memory_init(offset, 0, n, memory, init)?;
188                        true
189                    }
190                };
191                self.last_inst().datas.push(drop);
192            }
193        }
194        if let Some(mut parser) = self.last_inst().module.section(SectionId::Start) {
195            let x = parser.parse_funcidx().into_ok();
196            let ptr = self.func_ptr(inst_id, x);
197            let inst_id = ptr.instance().unwrap_wasm();
198            let (mut parser, side_table) = self.insts[inst_id].module.func(ptr.index());
199            let mut locals = Vec::new();
200            append_locals(&mut parser, &mut locals);
201            let ret = Parser::default();
202            let thread = Thread::new(parser, Frame::new(inst_id, 0, ret, locals, side_table, 0));
203            let result = thread.run(self)?;
204            assert!(matches!(result, RunResult::Done(x) if x.is_empty()));
205        }
206        Ok(InstId { store_id: self.id, inst_id })
207    }
208
209    /// Invokes a function in an instance provided its name.
210    ///
211    /// If a function was already running, it will resume once the function being called terminates.
212    /// In other words, execution satisfies a stack property. Without this, the stack of the module
213    /// may be corrupted.
214    pub fn invoke<'a>(
215        &'a mut self, inst: InstId, name: &str, args: Vec<Val>,
216    ) -> Result<RunResult<'a, 'm>, Error> {
217        let inst_id = self.inst_id(inst)?;
218        let inst = &self.insts[inst_id];
219        let ptr = match inst.module.export(name).ok_or_else(not_found)? {
220            ExportDesc::Func(x) => inst.funcs.ptr(inst_id, x),
221            _ => return Err(Error::Invalid),
222        };
223        let inst_id = ptr.instance().unwrap_wasm();
224        let inst = &self.insts[inst_id];
225        let x = ptr.index();
226        let t = inst.module.func_type(x);
227        let (mut parser, side_table) = inst.module.func(x);
228        check_types(&t.params, &args)?;
229        let mut locals = args;
230        append_locals(&mut parser, &mut locals);
231        let ret = Parser::default();
232        let frame = Frame::new(inst_id, t.results.len(), ret, locals, side_table, 0);
233        Thread::new(parser, frame).run(self)
234    }
235
236    /// Returns the value of a global of an instance.
237    pub fn get_global(&mut self, inst: InstId, name: &str) -> Result<Val, Error> {
238        let inst_id = self.inst_id(inst)?;
239        let inst = &self.insts[inst_id];
240        let ptr = match inst.module.export(name).ok_or_else(not_found)? {
241            ExportDesc::Global(x) => inst.globals.ptr(inst_id, x),
242            _ => return Err(Error::Invalid),
243        };
244        let inst_id = ptr.instance().unwrap_wasm();
245        let x = ptr.index() as usize;
246        Ok(self.insts[inst_id].globals.int[x].value)
247    }
248
249    /// Sets the name of an instance.
250    pub fn set_name(&mut self, inst: InstId, name: &'m str) -> Result<(), Error> {
251        let inst_id = self.inst_id(inst)?;
252        self.insts[inst_id].name = name;
253        Ok(())
254    }
255
256    /// Links a host function provided its signature.
257    ///
258    /// This is a convenient wrapper around [`Self::link_func_custom()`] for functions which
259    /// parameter and return types are only `i32`. The `params` and `results` parameters describe
260    /// how many `i32` are taken as parameters and returned as results respectively.
261    pub fn link_func(
262        &mut self, module: &'m str, name: &'m str, params: usize, results: usize,
263    ) -> Result<(), Error> {
264        static TYPES: &[ValType] = &[ValType::I32; 8];
265        check(params <= TYPES.len() && results <= TYPES.len())?;
266        let type_ = FuncType { params: TYPES[.. params].into(), results: TYPES[.. results].into() };
267        self.link_func_custom(module, name, type_)
268    }
269
270    /// Enables linking unresolved imported function for the given module.
271    ///
272    /// For each unresolved imported function type that returns exactly one `i32`, a fake host
273    /// function is created (as if `link_func` was used). As such, out-of-bound indices with respect
274    /// to real calls to [`Self::link_func()`] represent such fake host functions. Callers must thus
275    /// expect and support out-of-bound indices returned by [`Call::index()`].
276    ///
277    /// This function can be called at most once, and once called `link_func` cannot be called.
278    pub fn link_func_default(&mut self, module: &'m str) -> Result<(), Error> {
279        check(self.func_default.is_none())?;
280        self.func_default = Some((module, self.funcs.len()));
281        Ok(())
282    }
283
284    /// Links a host function provided its signature.
285    ///
286    /// Note that the order in which functions are linked defines their index. The first linked
287    /// function has index 0, the second has index 1, etc. This index is used when a module calls in
288    /// the host to identify the function.
289    pub fn link_func_custom(
290        &mut self, module: &'m str, name: &'m str, type_: FuncType<'m>,
291    ) -> Result<(), Error> {
292        let name = HostName { module, name };
293        check(self.func_default.is_none())?;
294        check(self.insts.is_empty())?;
295        check(self.funcs.last().is_none_or(|x| x.0 < name))?;
296        self.funcs.push((name, type_));
297        Ok(())
298    }
299
300    /// Returns the call in the host, if any.
301    ///
302    /// This function returns `None` if nothing is running.
303    // NOTE: This is like poll. Could be called next.
304    pub fn last_call(&mut self) -> Option<Call<'_, 'm>> {
305        if self.threads.is_empty() { None } else { Some(Call { store: self }) }
306    }
307
308    /// Returns the memory of the given instance.
309    pub fn memory(&mut self, inst: InstId) -> Result<&mut [u8], Error> {
310        check(self.id == inst.store_id)?;
311        Ok(self.mem(inst.inst_id, 0).data)
312    }
313}
314
315impl<'a, 'm> Call<'a, 'm> {
316    /// Returns the index of the host function being called.
317    pub fn index(&self) -> usize {
318        self.cont().index
319    }
320
321    /// Returns the arguments to the host function being called.
322    pub fn args(&self) -> &[Val] {
323        &self.cont().args
324    }
325
326    /// Returns the identifier of the instance calling the host.
327    pub fn inst(&self) -> InstId {
328        self.cont().thread.inst(self.store)
329    }
330
331    /// Returns the memory of the instance calling the host.
332    pub fn mem(self) -> &'a mut [u8] {
333        self.store.mem(self.inst().inst_id, 0).data
334    }
335
336    /// Returns the memory of the instance calling the host.
337    pub fn mem_mut(&mut self) -> &mut [u8] {
338        self.store.mem(self.inst().inst_id, 0).data
339    }
340
341    /// Resumes execution with the results from the host.
342    pub fn resume(self, results: &[Val]) -> Result<RunResult<'a, 'm>, Error> {
343        let Continuation { mut thread, arity, .. } = self.store.threads.pop().unwrap();
344        check(results.len() == arity)?;
345        thread.push_values(results);
346        thread.run(self.store)
347    }
348
349    fn cont(&self) -> &Continuation<'_> {
350        self.store.threads.last().unwrap()
351    }
352}
353
354#[derive(Copy, Clone, PartialEq, Eq)]
355pub struct Ptr(u32);
356
357impl core::fmt::Debug for Ptr {
358    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
359        f.debug_struct("Ptr")
360            .field("instance", &self.instance())
361            .field("index", &self.index())
362            .finish()
363    }
364}
365
366#[derive(Debug, Copy, Clone, PartialEq, Eq)]
367enum Side {
368    Host,
369    Wasm(usize),
370}
371
372impl Side {
373    fn into_repr(self) -> usize {
374        match self {
375            Side::Host => 0,
376            Side::Wasm(x) => 1 + x,
377        }
378    }
379
380    fn from_repr(x: usize) -> Self {
381        match x.checked_sub(1) {
382            None => Side::Host,
383            Some(x) => Side::Wasm(x),
384        }
385    }
386
387    fn unwrap_wasm(self) -> usize {
388        match self {
389            Side::Host => unreachable!(),
390            Side::Wasm(x) => x,
391        }
392    }
393}
394
395impl Ptr {
396    // 4k modules with 1M indices (per component)
397    const INDEX_BITS: usize = 20;
398    const INDEX_MASK: u32 = (1 << Self::INDEX_BITS) - 1;
399    const INST_MASK: u32 = (1 << (32 - Self::INDEX_BITS)) - 1;
400
401    fn new(inst: Side, idx: u32) -> Self {
402        let inst = inst.into_repr() as u32;
403        assert_eq!(inst & !Self::INST_MASK, 0);
404        assert_eq!(idx & !Self::INDEX_MASK, 0);
405        Self((inst << Self::INDEX_BITS) | idx)
406    }
407
408    fn instance(self) -> Side {
409        Side::from_repr((self.0 >> Self::INDEX_BITS) as usize)
410    }
411
412    fn index(self) -> u32 {
413        self.0 & Self::INDEX_MASK
414    }
415}
416
417impl core::fmt::Debug for Val {
418    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
419        match *self {
420            Val::I32(x) => write!(f, "{x}"),
421            Val::I64(x) => write!(f, "{x}"),
422            #[cfg(feature = "float-types")]
423            Val::F32(x) => write!(f, "{}", f32::from_bits(x)),
424            #[cfg(feature = "float-types")]
425            Val::F64(x) => write!(f, "{}", f64::from_bits(x)),
426            #[cfg(feature = "vector-types")]
427            Val::V128(_) => todo!(),
428            Val::Null(_) => write!(f, "null"),
429            Val::Ref(p) => write!(f, "ref@{:?}:{}", p.instance(), p.index()),
430            Val::RefExtern(p) => write!(f, "ext@{p}"),
431        }
432    }
433}
434
435impl Val {
436    pub fn type_(self) -> ValType {
437        match self {
438            Val::I32(_) => ValType::I32,
439            Val::I64(_) => ValType::I64,
440            #[cfg(feature = "float-types")]
441            Val::F32(_) => ValType::F32,
442            #[cfg(feature = "float-types")]
443            Val::F64(_) => ValType::F64,
444            #[cfg(feature = "vector-types")]
445            Val::V128(_) => ValType::V128,
446            Val::Null(t) => t.into(),
447            Val::Ref(_) => ValType::FuncRef,
448            Val::RefExtern(_) => ValType::ExternRef,
449        }
450    }
451}
452
453#[derive(Debug)]
454struct Instance<'m> {
455    // TODO: Make sure names are unique. Empty name means exports are not linked.
456    name: &'m str,
457    module: Module<'m>,
458    funcs: Component<()>,
459    tables: Component<Vec<Table>>,
460    mems: Component<Memory<'m>>,
461    globals: Component<Vec<Global>>,
462    elems: Vec<bool>, // whether the elem segment is dropped
463    datas: Vec<bool>, // whether the data segment is dropped
464}
465
466#[derive(Debug)]
467struct Thread<'m> {
468    parser: Parser<'m>,
469    frames: Vec<Frame<'m>>,
470    // TODO: Consider the performance tradeoff between keeping the locals in and out of the value
471    // stack. See the comments in PR #605 for more details.
472    values: Vec<Val>,
473}
474
475/// Runtime result.
476#[derive(Debug)]
477pub enum RunResult<'a, 'm> {
478    /// Execution terminated successfully with those values.
479    Done(Vec<Val>),
480
481    /// Execution is calling into the host.
482    Host(Call<'a, 'm>),
483}
484
485/// Runtime result without host call information.
486#[derive(Debug)]
487pub enum RunAnswer {
488    Done(Vec<Val>),
489    Host,
490}
491
492impl RunResult<'_, '_> {
493    pub fn forget(self) -> RunAnswer {
494        match self {
495            RunResult::Done(result) => RunAnswer::Done(result),
496            RunResult::Host(_) => RunAnswer::Host,
497        }
498    }
499}
500
501#[derive(Debug)]
502struct Continuation<'m> {
503    thread: Thread<'m>,
504    index: usize,
505    args: Vec<Val>,
506    arity: usize,
507}
508
509impl<'m> Store<'m> {
510    fn last_inst(&mut self) -> &mut Instance<'m> {
511        self.insts.last_mut().unwrap()
512    }
513
514    fn inst_id(&self, inst: InstId) -> Result<usize, Error> {
515        check(self.id == inst.store_id)?;
516        Ok(inst.inst_id)
517    }
518
519    fn resolve_inst(&self, name: &str) -> Result<usize, Error> {
520        self.insts.iter().position(|x| x.name == name).ok_or_else(not_found)
521    }
522
523    fn func_type(&self, ptr: Ptr) -> FuncType<'m> {
524        match ptr.instance() {
525            Side::Host => self.funcs[ptr.index() as usize].1,
526            Side::Wasm(x) => self.insts[x].module.func_type(ptr.index()),
527        }
528    }
529
530    fn func_ptr(&self, inst_id: usize, x: FuncIdx) -> Ptr {
531        self.insts[inst_id].funcs.ptr(inst_id, x)
532    }
533
534    fn table_ptr(&self, inst_id: usize, x: TableIdx) -> Ptr {
535        self.insts[inst_id].tables.ptr(inst_id, x)
536    }
537
538    fn mem_ptr(&self, inst_id: usize, x: MemIdx) -> Ptr {
539        self.insts[inst_id].mems.ptr(inst_id, x)
540    }
541
542    fn global_ptr(&self, inst_id: usize, x: GlobalIdx) -> Ptr {
543        self.insts[inst_id].globals.ptr(inst_id, x)
544    }
545
546    fn table(&mut self, inst_id: usize, x: TableIdx) -> &mut Table {
547        let ptr = self.table_ptr(inst_id, x);
548        let x = ptr.instance().unwrap_wasm();
549        &mut self.insts[x].tables.int[ptr.index() as usize]
550    }
551
552    fn mem(&mut self, inst_id: usize, x: MemIdx) -> &mut Memory<'m> {
553        let ptr = self.mem_ptr(inst_id, x);
554        let x = ptr.instance().unwrap_wasm();
555        assert_eq!(ptr.index(), 0);
556        &mut self.insts[x].mems.int
557    }
558
559    fn global(&mut self, inst_id: usize, x: GlobalIdx) -> &mut Global {
560        let ptr = self.global_ptr(inst_id, x);
561        let x = ptr.instance().unwrap_wasm();
562        &mut self.insts[x].globals.int[ptr.index() as usize]
563    }
564
565    fn resolve(&mut self, import: &Import<'m>, imp_type_: ExternType<'m>) -> Result<Ptr, Error> {
566        let host_name = HostName { module: import.module, name: import.name };
567        let mut found = None;
568        let funcs_len = match self.func_default {
569            Some((_, x)) => x,
570            None => self.funcs.len(),
571        };
572        if let Ok(x) = self.funcs[.. funcs_len].binary_search_by(|x| x.0.cmp(&host_name)) {
573            found = Some((Ptr::new(Side::Host, x as u32), ExternType::Func(self.funcs[x].1)));
574        } else if matches!(imp_type_, ExternType::Func(x) if *x.results == [ValType::I32])
575            && matches!(self.func_default, Some((x, _)) if x == host_name.module)
576        {
577            let type_ = match imp_type_ {
578                ExternType::Func(x) => x,
579                _ => unreachable!(),
580            };
581            let idx = match self.funcs[funcs_len ..].iter().position(|x| x.1 == type_) {
582                Some(x) => funcs_len + x,
583                None => {
584                    let idx = self.funcs.len();
585                    self.funcs.push((host_name, type_));
586                    idx
587                }
588            };
589            found = Some((Ptr::new(Side::Host, idx as u32), ExternType::Func(type_)));
590        } else {
591            let inst_id = self.resolve_inst(import.module)?;
592            let inst = &self.insts[inst_id];
593            if let Some(mut parser) = inst.module.section(SectionId::Export) {
594                for _ in 0 .. parser.parse_vec().into_ok() {
595                    let name = parser.parse_name().into_ok();
596                    let desc = parser.parse_exportdesc().into_ok();
597                    if name != import.name {
598                        continue;
599                    }
600                    found = Some(match desc {
601                        ExportDesc::Func(x) => {
602                            let ptr = self.func_ptr(inst_id, x);
603                            (ptr, ExternType::Func(self.func_type(ptr)))
604                        }
605                        ExportDesc::Table(x) => {
606                            let ptr = self.table_ptr(inst_id, x);
607                            let inst = &self.insts[ptr.instance().unwrap_wasm()];
608                            let mut t = inst.module.table_type(ptr.index());
609                            t.limits.min = inst.tables.int[ptr.index() as usize].size();
610                            (ptr, ExternType::Table(t))
611                        }
612                        ExportDesc::Mem(x) => {
613                            let ptr = self.mem_ptr(inst_id, x);
614                            let inst = &self.insts[ptr.instance().unwrap_wasm()];
615                            let mut t = inst.module.mem_type(ptr.index());
616                            assert_eq!(ptr.index(), 0);
617                            t.min = inst.mems.int.size();
618                            (ptr, ExternType::Mem(t))
619                        }
620                        ExportDesc::Global(x) => {
621                            let ptr = self.global_ptr(inst_id, x);
622                            let inst = &self.insts[ptr.instance().unwrap_wasm()];
623                            (ptr, ExternType::Global(inst.module.global_type(ptr.index())))
624                        }
625                    });
626                    break;
627                }
628            }
629        }
630        let (ptr, ext_type_) = found.ok_or_else(not_found)?;
631        if ext_type_.matches(&imp_type_) { Ok(ptr) } else { Err(not_found()) }
632    }
633}
634
635impl<'m> Instance<'m> {
636    fn new(module: Module<'m>) -> Self {
637        Instance {
638            name: "",
639            module,
640            funcs: Component::default(),
641            tables: Component::default(),
642            mems: Component::default(),
643            globals: Component::default(),
644            elems: Vec::new(),
645            datas: Vec::new(),
646        }
647    }
648}
649
650#[derive(Debug)]
651enum ElemMode {
652    Passive,
653    Active { table: TableIdx, offset: usize },
654    Declarative,
655}
656
657struct ComputeElem<'a, 'm> {
658    store: &'a mut Store<'m>,
659    inst_id: usize,
660    mode: ElemMode,
661    init: Vec<Val>,
662}
663
664impl<'a, 'm> ComputeElem<'a, 'm> {
665    fn new(store: &'a mut Store<'m>, inst_id: usize) -> Self {
666        Self { store, inst_id, mode: ElemMode::Passive, init: Vec::new() }
667    }
668}
669
670impl<'m> parser::ParseElem<'m, Use> for ComputeElem<'_, 'm> {
671    fn mode(&mut self, mode: parser::ElemMode<'_, 'm, Use>) -> MResult<(), Use> {
672        let mode = match mode {
673            parser::ElemMode::Passive => ElemMode::Passive,
674            parser::ElemMode::Active { table, offset } => ElemMode::Active {
675                table,
676                offset: Thread::const_expr(self.store, self.inst_id, offset).unwrap_i32() as usize,
677            },
678            parser::ElemMode::Declarative => ElemMode::Declarative,
679        };
680        self.mode = mode;
681        Ok(())
682    }
683
684    fn init_funcidx(&mut self, x: FuncIdx) -> MResult<(), Use> {
685        self.init.push(Val::Ref(self.store.func_ptr(self.inst_id, x)));
686        Ok(())
687    }
688
689    fn init_expr(&mut self, parser: &mut Parser<'m>) -> MResult<(), Use> {
690        self.init.push(Thread::const_expr(self.store, self.inst_id, parser));
691        Ok(())
692    }
693}
694
695#[derive(Debug)]
696enum DataMode {
697    Passive,
698    Active { memory: MemIdx, offset: usize },
699}
700
701struct ComputeData<'a, 'm> {
702    store: &'a mut Store<'m>,
703    inst_id: usize,
704    mode: DataMode,
705    init: &'m [u8],
706}
707
708impl<'a, 'm> ComputeData<'a, 'm> {
709    fn new(store: &'a mut Store<'m>, inst_id: usize) -> Self {
710        Self { store, inst_id, mode: DataMode::Passive, init: &[] }
711    }
712}
713
714impl<'m> parser::ParseData<'m, Use> for ComputeData<'_, 'm> {
715    fn mode(&mut self, mode: parser::DataMode<'_, 'm, Use>) -> MResult<(), Use> {
716        let mode = match mode {
717            parser::DataMode::Passive => DataMode::Passive,
718            parser::DataMode::Active { memory, offset } => DataMode::Active {
719                memory,
720                offset: Thread::const_expr(self.store, self.inst_id, offset).unwrap_i32() as usize,
721            },
722        };
723        self.mode = mode;
724        Ok(())
725    }
726
727    fn init(&mut self, init: &'m [u8]) -> MResult<(), Use> {
728        self.init = init;
729        Ok(())
730    }
731}
732
733#[derive(Debug)]
734struct Table {
735    max: u32,
736    elems: Vec<Val>,
737}
738
739#[derive(Debug)]
740struct Global {
741    value: Val,
742}
743
744enum ThreadResult<'m> {
745    Continue(Thread<'m>),
746    Done(Vec<Val>),
747    Host,
748}
749
750impl<'m> Thread<'m> {
751    fn new(parser: Parser<'m>, frame: Frame<'m>) -> Thread<'m> {
752        Thread { parser, frames: vec![frame], values: vec![] }
753    }
754
755    fn const_expr(store: &mut Store<'m>, inst_id: usize, mut_parser: &mut Parser<'m>) -> Val {
756        let mut thread = Thread::new(
757            mut_parser.clone(),
758            Frame::new(inst_id, 1, Parser::default(), Vec::new(), Cursor::default(), 0),
759        );
760        let (state, results) = loop {
761            let s = thread.parser.save();
762            match thread.step(store).unwrap() {
763                ThreadResult::Continue(x) => thread = x,
764                ThreadResult::Done(x) => break (s, x),
765                ThreadResult::Host => unreachable!(),
766            }
767        };
768        unsafe { mut_parser.restore(state) };
769        let instr = mut_parser.parse_instr().into_ok();
770        debug_assert_eq!(instr, Instr::End);
771        debug_assert_eq!(results.len(), 1);
772        results[0]
773    }
774
775    fn run<'a>(mut self, store: &'a mut Store<'m>) -> Result<RunResult<'a, 'm>, Error> {
776        loop {
777            // TODO: When trapping, we could return some CoreDump<'m> that contains the Thread<'m>.
778            // This permits to dump the frames.
779            match self.step(store)? {
780                ThreadResult::Continue(x) => self = x,
781                ThreadResult::Done(x) => return Ok(RunResult::Done(x)),
782                ThreadResult::Host => return Ok(RunResult::Host(Call { store })),
783            }
784        }
785    }
786
787    fn step(mut self, store: &mut Store<'m>) -> Result<ThreadResult<'m>, Error> {
788        use Instr::*;
789        let inst_id = self.frame().inst_id;
790        let inst = &mut store.insts[inst_id];
791        match self.parser.parse_instr().into_ok() {
792            Unreachable => return Err(trap()),
793            Nop => (),
794            Block(_) => self.push_label(),
795            Loop(_) => self.push_label(),
796            If(_) => match self.pop_value().unwrap_i32() {
797                0 => {
798                    self.take_jump(0);
799                    self.push_label();
800                }
801                _ => {
802                    self.frame().skip_jump();
803                    self.push_label();
804                }
805            },
806            Else => {
807                self.take_jump(0);
808                return Ok(self.exit_label());
809            }
810            End => return Ok(self.exit_label()),
811            Br(l) => return Ok(self.pop_label(l, 0)),
812            BrIf(l) => {
813                if self.pop_value().unwrap_i32() != 0 {
814                    return Ok(self.pop_label(l, 0));
815                }
816                self.frame().skip_jump();
817            }
818            BrTable(ls, ln) => {
819                let i = self.pop_value().unwrap_i32() as usize;
820                let (l, offset) = match ls.get(i) {
821                    None => (ln, 0),
822                    Some(&li) => (li, i + 1),
823                };
824                return Ok(self.pop_label(l, offset));
825            }
826            Return => return Ok(self.exit_frame()),
827            Call(x) => return self.invoke(store, store.func_ptr(inst_id, x)),
828            CallIndirect(x, y) => {
829                let i = self.pop_value().unwrap_i32();
830                let x = match store.table(inst_id, x).elems.get(i as usize) {
831                    None | Some(Val::Null(_)) => return Err(trap()),
832                    Some(x) => x.unwrap_ref(),
833                };
834                if store.func_type(x) != store.insts[inst_id].module.types()[y as usize] {
835                    return Err(trap());
836                }
837                return self.invoke(store, x);
838            }
839            Drop => drop(self.pop_value()),
840            Select(_) => {
841                let c = self.pop_value().unwrap_i32();
842                let v2 = self.pop_value();
843                let v1 = self.pop_value();
844                self.push_value(match c {
845                    0 => v2,
846                    _ => v1,
847                });
848            }
849            LocalGet(x) => {
850                let v = self.frame().locals[x as usize];
851                self.push_value(v);
852            }
853            LocalSet(x) => {
854                let v = self.pop_value();
855                self.frame().locals[x as usize] = v;
856            }
857            LocalTee(x) => {
858                let v = self.peek_value();
859                self.frame().locals[x as usize] = v;
860            }
861            GlobalGet(x) => self.push_value(store.global(inst_id, x).value),
862            GlobalSet(x) => store.global(inst_id, x).value = self.pop_value(),
863            TableGet(x) => {
864                let i = self.pop_value().unwrap_i32();
865                let v = *store.table(inst_id, x).elems.get(i as usize).ok_or_else(trap)?;
866                self.push_value(v);
867            }
868            TableSet(x) => {
869                let val = self.pop_value();
870                let i = self.pop_value().unwrap_i32();
871                let v = store.table(inst_id, x).elems.get_mut(i as usize).ok_or_else(trap)?;
872                *v = val;
873            }
874            ILoad(n, m) => self.load(store.mem(inst_id, 0), NumType::i(n), n.into(), Sx::U, m)?,
875            #[cfg(feature = "float-types")]
876            FLoad(n, m) => self.load(store.mem(inst_id, 0), NumType::f(n), n.into(), Sx::U, m)?,
877            ILoad_(b, s, m) => {
878                self.load(store.mem(inst_id, 0), NumType::i(b.into()), b.into(), s, m)?
879            }
880            IStore(n, m) => self.store(store.mem(inst_id, 0), NumType::i(n), n.into(), m)?,
881            #[cfg(feature = "float-types")]
882            FStore(n, m) => self.store(store.mem(inst_id, 0), NumType::f(n), n.into(), m)?,
883            IStore_(b, m) => {
884                self.store(store.mem(inst_id, 0), NumType::i(b.into()), b.into(), m)?
885            }
886            MemorySize => self.push_value(Val::I32(store.mem(inst_id, 0).size())),
887            MemoryGrow => {
888                let n = self.pop_value().unwrap_i32();
889                self.push_value(Val::I32(grow(store.mem(inst_id, 0), n, ())));
890            }
891            I32Const(c) => self.push_value(Val::I32(c)),
892            I64Const(c) => self.push_value(Val::I64(c)),
893            #[cfg(feature = "float-types")]
894            F32Const(c) => self.push_value(Val::F32(c)),
895            #[cfg(feature = "float-types")]
896            F64Const(c) => self.push_value(Val::F64(c)),
897            ITestOp(n, op) => self.itestop(n, op),
898            IRelOp(n, op) => self.irelop(n, op),
899            #[cfg(feature = "float-types")]
900            FRelOp(n, op) => self.frelop(n, op),
901            IUnOp(n, op) => self.iunop(n, op)?,
902            #[cfg(feature = "float-types")]
903            FUnOp(n, op) => self.funop(n, op),
904            IBinOp(n, op) => self.ibinop(n, op)?,
905            #[cfg(feature = "float-types")]
906            FBinOp(n, op) => self.fbinop(n, op),
907            CvtOp(op) => self.cvtop(op)?,
908            IExtend(b) => self.extend(b),
909            RefNull(t) => self.push_value(Val::Null(t)),
910            RefIsNull => {
911                let c = matches!(self.pop_value(), Val::Null(_)) as u32;
912                self.push_value(Val::I32(c));
913            }
914            RefFunc(x) => self.push_value(Val::Ref(store.func_ptr(inst_id, x))),
915            MemoryInit(x) => {
916                let n = self.pop_value().unwrap_i32() as usize;
917                let s = self.pop_value().unwrap_i32() as usize;
918                let d = self.pop_value().unwrap_i32() as usize;
919                let data = if inst.datas[x as usize] {
920                    &[]
921                } else {
922                    let mut parser = inst.module.data(x);
923                    let mut data = ComputeData::new(store, inst_id);
924                    parser.parse_data(&mut data).into_ok();
925                    data.init
926                };
927                let mem = store.mem(inst_id, 0);
928                memory_init(d, s, n, mem, data)?;
929            }
930            DataDrop(x) => inst.datas[x as usize] = true,
931            MemoryCopy => {
932                let n = self.pop_value().unwrap_i32() as usize;
933                let s = self.pop_value().unwrap_i32() as usize;
934                let d = self.pop_value().unwrap_i32() as usize;
935                let mem = store.mem(inst_id, 0);
936                if core::cmp::max(s, d).checked_add(n).is_none_or(|x| x > mem.len() as usize) {
937                    return Err(trap());
938                }
939                mem.data.copy_within(s .. s + n, d);
940            }
941            MemoryFill => {
942                let n = self.pop_value().unwrap_i32() as usize;
943                let val = self.pop_value().unwrap_i32() as u8;
944                let d = self.pop_value().unwrap_i32() as usize;
945                let mem = store.mem(inst_id, 0);
946                if d.checked_add(n).is_none_or(|x| x > mem.len() as usize) {
947                    memory_too_small(d, n, mem);
948                    return Err(trap());
949                }
950                mem.data[d ..][.. n].fill(val);
951            }
952            TableInit(x, y) => {
953                let n = self.pop_value().unwrap_i32() as usize;
954                let s = self.pop_value().unwrap_i32() as usize;
955                let d = self.pop_value().unwrap_i32() as usize;
956                let elems = if inst.elems[y as usize] {
957                    Vec::new()
958                } else {
959                    let mut parser = inst.module.elem(y);
960                    let mut elems = ComputeElem::new(store, inst_id);
961                    parser.parse_elem(&mut elems).into_ok();
962                    elems.init
963                };
964                let table = store.table(inst_id, x);
965                table_init(d, s, n, table, &elems)?;
966            }
967            ElemDrop(x) => inst.elems[x as usize] = true,
968            TableCopy(x, y) => {
969                let n = self.pop_value().unwrap_i32() as usize;
970                let s = self.pop_value().unwrap_i32() as usize;
971                let d = self.pop_value().unwrap_i32() as usize;
972                let sn = s.checked_add(n).ok_or_else(trap)?;
973                let dn = d.checked_add(n).ok_or_else(trap)?;
974                // TODO: This is not efficient.
975                let ys = store.table(inst_id, y).elems.get(s .. sn).ok_or_else(trap)?.to_vec();
976                let xs = store.table(inst_id, x).elems.get_mut(d .. dn).ok_or_else(trap)?;
977                xs.copy_from_slice(&ys);
978            }
979            TableGrow(x) => {
980                let n = self.pop_value().unwrap_i32();
981                let val = self.pop_value();
982                let table = store.table(inst_id, x);
983                self.push_value(Val::I32(grow(table, n, val)));
984            }
985            TableSize(x) => self.push_value(Val::I32(store.table(inst_id, x).size())),
986            TableFill(x) => {
987                let n = self.pop_value().unwrap_i32() as usize;
988                let val = self.pop_value();
989                let i = self.pop_value().unwrap_i32() as usize;
990                let table = store.table(inst_id, x);
991                if i.checked_add(n).is_none_or(|x| x > table.elems.len()) {
992                    return Err(trap());
993                }
994                table.elems[i ..][.. n].fill(val);
995            }
996        }
997        Ok(ThreadResult::Continue(self))
998    }
999
1000    fn inst_id(&self) -> usize {
1001        self.frames.last().unwrap().inst_id
1002    }
1003
1004    fn inst(&self, store: &Store<'m>) -> InstId {
1005        InstId { store_id: store.id, inst_id: self.inst_id() }
1006    }
1007
1008    fn frame(&mut self) -> &mut Frame<'m> {
1009        self.frames.last_mut().unwrap()
1010    }
1011
1012    fn values(&mut self) -> &mut Vec<Val> {
1013        &mut self.values
1014    }
1015
1016    fn peek_value(&mut self) -> Val {
1017        *self.values().last().unwrap()
1018    }
1019
1020    fn push_value(&mut self, value: Val) {
1021        self.values().push(value);
1022    }
1023
1024    fn push_value_or_trap(&mut self, value: Option<Val>) -> Result<(), Error> {
1025        if let Some(x) = value {
1026            self.push_value(x);
1027            Ok(())
1028        } else {
1029            Err(trap())
1030        }
1031    }
1032
1033    fn push_values(&mut self, values: &[Val]) {
1034        self.values().extend_from_slice(values);
1035    }
1036
1037    fn pop_value(&mut self) -> Val {
1038        self.values().pop().unwrap()
1039    }
1040
1041    fn pop_values(&mut self, n: usize) -> Vec<Val> {
1042        let len = self.values().len() - n;
1043        self.values().split_off(len)
1044    }
1045
1046    fn push_label(&mut self) {
1047        self.frame().labels_cnt += 1;
1048    }
1049
1050    fn pop_label(mut self, l: LabelIdx, offset: usize) -> ThreadResult<'m> {
1051        let frame = self.frame();
1052        let i = frame.labels_cnt - l as usize - 1;
1053        if i == 0 {
1054            return self.exit_frame();
1055        }
1056        frame.labels_cnt = i;
1057        let Ok(BranchTableEntryView { val_cnt, pop_cnt, .. }) =
1058            frame.side_table.get(offset).view::<Use>();
1059        let val_pos = self.values().len() - val_cnt as usize;
1060        self.values().drain(val_pos - pop_cnt as usize .. val_pos);
1061        self.take_jump(offset);
1062        ThreadResult::Continue(self)
1063    }
1064
1065    fn exit_label(mut self) -> ThreadResult<'m> {
1066        let frame = self.frame();
1067        frame.labels_cnt -= 1;
1068        if frame.labels_cnt == 0 {
1069            let arity = frame.arity;
1070            let values = self.pop_values(arity);
1071            let frame = self.frames.pop().unwrap();
1072            if self.frames.is_empty() {
1073                return ThreadResult::Done(values);
1074            }
1075            self.parser = frame.ret;
1076            self.values().extend(values);
1077        }
1078        ThreadResult::Continue(self)
1079    }
1080
1081    fn exit_frame(mut self) -> ThreadResult<'m> {
1082        let prev_stack = self.frame().prev_stack;
1083        let mut values = self.values().split_off(prev_stack);
1084        let frame = self.frames.pop().unwrap();
1085        let mid = values.len() - frame.arity;
1086        if self.frames.is_empty() {
1087            values.drain(0 .. mid);
1088            return ThreadResult::Done(values);
1089        }
1090        self.parser = frame.ret;
1091        self.values().extend_from_slice(&values[mid ..]);
1092        ThreadResult::Continue(self)
1093    }
1094
1095    fn take_jump(&mut self, offset: usize) {
1096        let offset = self.frame().take_jump(offset);
1097        self.parser.update(offset);
1098    }
1099
1100    fn mem_slice<'a>(
1101        &mut self, mem: &'a mut Memory<'m>, m: MemArg, i: u32, len: usize,
1102    ) -> Option<&'a mut [u8]> {
1103        let ea = i.checked_add(m.offset)?;
1104        if ea.checked_add(len as u32)? > mem.len() {
1105            memory_too_small(ea as usize, len, mem);
1106            return None;
1107        }
1108        Some(&mut mem.data[ea as usize ..][.. len])
1109    }
1110
1111    fn load(
1112        &mut self, mem: &mut Memory<'m>, t: NumType, n: usize, s: Sx, m: MemArg,
1113    ) -> Result<(), Error> {
1114        let i = self.pop_value().unwrap_i32();
1115        let mem = match self.mem_slice(mem, m, i, n / 8) {
1116            None => return Err(trap()),
1117            Some(x) => x,
1118        };
1119        macro_rules! convert {
1120            ($T:ident, $t:ident, $s:ident) => {
1121                Val::$T($s::from_le_bytes(mem.try_into().unwrap()) as $t)
1122            };
1123        }
1124        let c = match (t, n, s) {
1125            (NumType::I32, 32, Sx::U) => convert!(I32, u32, u32),
1126            (NumType::I32, 16, Sx::U) => convert!(I32, u32, u16),
1127            (NumType::I32, 16, Sx::S) => convert!(I32, u32, i16),
1128            (NumType::I32, 8, Sx::U) => convert!(I32, u32, u8),
1129            (NumType::I32, 8, Sx::S) => convert!(I32, u32, i8),
1130            (NumType::I64, 64, Sx::U) => convert!(I64, u64, u64),
1131            (NumType::I64, 32, Sx::U) => convert!(I64, u64, u32),
1132            (NumType::I64, 32, Sx::S) => convert!(I64, u64, i32),
1133            (NumType::I64, 16, Sx::U) => convert!(I64, u64, u16),
1134            (NumType::I64, 16, Sx::S) => convert!(I64, u64, i16),
1135            (NumType::I64, 8, Sx::U) => convert!(I64, u64, u8),
1136            (NumType::I64, 8, Sx::S) => convert!(I64, u64, i8),
1137            #[cfg(feature = "float-types")]
1138            (NumType::F32, 32, _) => convert!(F32, u32, u32),
1139            #[cfg(feature = "float-types")]
1140            (NumType::F64, 64, _) => convert!(F64, u64, u64),
1141            _ => unreachable!(),
1142        };
1143        self.push_value(c);
1144        Ok(())
1145    }
1146
1147    fn store(
1148        &mut self, mem: &mut Memory<'m>, t: NumType, n: usize, m: MemArg,
1149    ) -> Result<(), Error> {
1150        let c = self.pop_value();
1151        let i = self.pop_value().unwrap_i32();
1152        let mem = match self.mem_slice(mem, m, i, n / 8) {
1153            None => return Err(trap()),
1154            Some(x) => x,
1155        };
1156        macro_rules! convert {
1157            ($s:ident, $t:ident) => {
1158                paste::paste! {
1159                    mem.copy_from_slice(&(c.[<unwrap_ $s>]() as $t).to_le_bytes())
1160                }
1161            };
1162        }
1163        match (t, n) {
1164            (NumType::I32, 32) => convert!(i32, u32),
1165            (NumType::I32, 16) => convert!(i32, u16),
1166            (NumType::I32, 8) => convert!(i32, u8),
1167            (NumType::I64, 64) => convert!(i64, u64),
1168            (NumType::I64, 32) => convert!(i64, u32),
1169            (NumType::I64, 16) => convert!(i64, u16),
1170            (NumType::I64, 8) => convert!(i64, u8),
1171            #[cfg(feature = "float-types")]
1172            (NumType::F32, 32) => convert!(f32, u32),
1173            #[cfg(feature = "float-types")]
1174            (NumType::F64, 64) => convert!(f64, u64),
1175            _ => unreachable!(),
1176        }
1177        Ok(())
1178    }
1179
1180    fn itestop(&mut self, n: Nx, op: ITestOp) {
1181        let x = self.pop_value();
1182        let z = match n {
1183            Nx::N32 => op.n32(x.unwrap_i32()),
1184            Nx::N64 => op.n64(x.unwrap_i64()),
1185        };
1186        self.push_value(Val::I32(z as u32))
1187    }
1188
1189    fn irelop(&mut self, n: Nx, op: IRelOp) {
1190        let y = self.pop_value();
1191        let x = self.pop_value();
1192        let z = match n {
1193            Nx::N32 => op.n32(x.unwrap_i32(), y.unwrap_i32()),
1194            Nx::N64 => op.n64(x.unwrap_i64(), y.unwrap_i64()),
1195        };
1196        self.push_value(Val::I32(z as u32))
1197    }
1198
1199    fn iunop(&mut self, n: Nx, op: IUnOp) -> Result<(), Error> {
1200        let x = self.pop_value();
1201        let z = try {
1202            match n {
1203                Nx::N32 => Val::I32(op.n32(x.unwrap_i32())?),
1204                Nx::N64 => Val::I64(op.n64(x.unwrap_i64())?),
1205            }
1206        };
1207        self.push_value_or_trap(z)
1208    }
1209
1210    fn ibinop(&mut self, n: Nx, op: IBinOp) -> Result<(), Error> {
1211        let y = self.pop_value();
1212        let x = self.pop_value();
1213        let z = try {
1214            match n {
1215                Nx::N32 => Val::I32(op.n32(x.unwrap_i32(), y.unwrap_i32())?),
1216                Nx::N64 => Val::I64(op.n64(x.unwrap_i64(), y.unwrap_i64())?),
1217            }
1218        };
1219        self.push_value_or_trap(z)
1220    }
1221
1222    #[cfg(feature = "float-types")]
1223    fn frelop(&mut self, n: Nx, op: FRelOp) {
1224        let y = self.pop_value();
1225        let x = self.pop_value();
1226        let z = match n {
1227            Nx::N32 => op.n32(x.unwrap_f32(), y.unwrap_f32()),
1228            Nx::N64 => op.n64(x.unwrap_f64(), y.unwrap_f64()),
1229        };
1230        self.push_value(Val::I32(z as u32))
1231    }
1232
1233    #[cfg(feature = "float-types")]
1234    fn funop(&mut self, n: Nx, op: FUnOp) {
1235        let x = self.pop_value();
1236        let z = match n {
1237            Nx::N32 => Val::F32(op.n32(x.unwrap_f32())),
1238            Nx::N64 => Val::F64(op.n64(x.unwrap_f64())),
1239        };
1240        self.push_value(z);
1241    }
1242
1243    #[cfg(feature = "float-types")]
1244    fn fbinop(&mut self, n: Nx, op: FBinOp) {
1245        let y = self.pop_value();
1246        let x = self.pop_value();
1247        let z = match n {
1248            Nx::N32 => Val::F32(op.n32(x.unwrap_f32(), y.unwrap_f32())),
1249            Nx::N64 => Val::F64(op.n64(x.unwrap_f64(), y.unwrap_f64())),
1250        };
1251        self.push_value(z);
1252    }
1253
1254    fn cvtop(&mut self, op: CvtOp) -> Result<(), Error> {
1255        #[cfg(feature = "float-types")]
1256        macro_rules! trunc {
1257            ($x:expr, $n:tt, $m:tt, $s:tt) => {{
1258                paste::paste! {
1259                    let x = [<f $m>]::from_bits($x.[<unwrap_f $m>]());
1260                    let min = ([<$s $n>]::MIN as [<f $m>]);
1261                    let max = ([<$s $n>]::MAX as [<f $m>]);
1262                    let min = if min - 1. == min { min <= x } else { min - 1. < x };
1263                    (min && x < max + 1.).then(|| Val::[<I $n>](x as [<$s $n>] as [<u $n>]))?
1264                }
1265            }};
1266        }
1267        #[cfg(feature = "float-types")]
1268        macro_rules! trunc_sat {
1269            ($x:expr, $n:tt, $m:tt, $s:tt) => {
1270                paste::paste! {
1271                    Val::[<I $n>](match [<f $m>]::from_bits($x.[<unwrap_f $m>]()) {
1272                        x if x.is_nan() => 0,
1273                        x if x.is_infinite() && x.is_sign_positive() => [<$s $n>]::MAX,
1274                        x if x.is_infinite() && x.is_sign_negative() => [<$s $n>]::MIN,
1275                        x => x as [<$s $n>],
1276                    } as [<u $n>])
1277                }
1278            };
1279        }
1280        #[cfg(feature = "float-types")]
1281        macro_rules! convert {
1282            ($x:expr, $n:tt, $m:tt, $s:tt) => {
1283                paste::paste! {
1284                    Val::[<F $n>](($x.[<unwrap_i $m>]() as [<$s $m>] as [<f $n>]).to_bits())
1285                }
1286            };
1287        }
1288        #[cfg(feature = "float-types")]
1289        macro_rules! dispatch {
1290            ($f:ident, $x:expr, $n:expr, $m:expr, $s:expr) => {
1291                match ($n, $m, $s) {
1292                    (Nx::N32, Nx::N32, Sx::U) => $f!($x, 32, 32, u),
1293                    (Nx::N32, Nx::N32, Sx::S) => $f!($x, 32, 32, i),
1294                    (Nx::N32, Nx::N64, Sx::U) => $f!($x, 32, 64, u),
1295                    (Nx::N32, Nx::N64, Sx::S) => $f!($x, 32, 64, i),
1296                    (Nx::N64, Nx::N32, Sx::U) => $f!($x, 64, 32, u),
1297                    (Nx::N64, Nx::N32, Sx::S) => $f!($x, 64, 32, i),
1298                    (Nx::N64, Nx::N64, Sx::U) => $f!($x, 64, 64, u),
1299                    (Nx::N64, Nx::N64, Sx::S) => $f!($x, 64, 64, i),
1300                }
1301            };
1302        }
1303        use CvtOp::*;
1304        let x = self.pop_value();
1305        let z = try {
1306            match op {
1307                Wrap => Val::I32(x.unwrap_i64() as u32),
1308                Extend(Sx::U) => Val::I64(x.unwrap_i32() as u64),
1309                Extend(Sx::S) => Val::I64(x.unwrap_i32() as i32 as u64),
1310                #[cfg(feature = "float-types")]
1311                Trunc(n, m, s) => dispatch!(trunc, x, n, m, s),
1312                #[cfg(feature = "float-types")]
1313                TruncSat(n, m, s) => dispatch!(trunc_sat, x, n, m, s),
1314                #[cfg(feature = "float-types")]
1315                Convert(n, m, s) => dispatch!(convert, x, n, m, s),
1316                #[cfg(feature = "float-types")]
1317                Demote => Val::F32((f64::from_bits(x.unwrap_f64()) as f32).to_bits()),
1318                #[cfg(feature = "float-types")]
1319                Promote => Val::F64((f32::from_bits(x.unwrap_f32()) as f64).to_bits()),
1320                #[cfg(feature = "float-types")]
1321                IReinterpret(n) => match n {
1322                    Nx::N32 => Val::I32(x.unwrap_f32()),
1323                    Nx::N64 => Val::I64(x.unwrap_f64()),
1324                },
1325                #[cfg(feature = "float-types")]
1326                FReinterpret(n) => match n {
1327                    Nx::N32 => Val::F32(x.unwrap_i32()),
1328                    Nx::N64 => Val::F64(x.unwrap_i64()),
1329                },
1330            }
1331        };
1332        self.push_value_or_trap(z)
1333    }
1334
1335    fn extend(&mut self, n: Bx) {
1336        let x = self.pop_value();
1337        let z = match n {
1338            Bx::N32B8 => Val::I32(x.unwrap_i32() as i8 as u32),
1339            Bx::N32B16 => Val::I32(x.unwrap_i32() as i16 as u32),
1340            Bx::N64B8 => Val::I64(x.unwrap_i64() as i8 as u64),
1341            Bx::N64B16 => Val::I64(x.unwrap_i64() as i16 as u64),
1342            Bx::N64B32 => Val::I64(x.unwrap_i64() as i32 as u64),
1343        };
1344        self.push_value(z)
1345    }
1346
1347    fn invoke(mut self, store: &mut Store<'m>, ptr: Ptr) -> Result<ThreadResult<'m>, Error> {
1348        // TODO: This should be based on actual size in RAM.
1349        const MAX_FRAMES: usize = 1000;
1350        if self.frames.len() >= MAX_FRAMES {
1351            return Err(trap());
1352        }
1353        let t = store.func_type(ptr);
1354        let inst_id = match ptr.instance() {
1355            Side::Host => {
1356                let index = ptr.index() as usize;
1357                let t = store.funcs[index].1;
1358                let arity = t.results.len();
1359                let args = self.pop_values(t.params.len());
1360                store.threads.push(Continuation { thread: self, arity, index, args });
1361                return Ok(ThreadResult::Host);
1362            }
1363            Side::Wasm(x) => x,
1364        };
1365        let (mut parser, side_table) = store.insts[inst_id].module.func(ptr.index());
1366        let mut locals = self.pop_values(t.params.len());
1367        append_locals(&mut parser, &mut locals);
1368        let ret = self.parser;
1369        self.parser = parser;
1370        let prev_stack = self.values().len();
1371        let frame = Frame::new(inst_id, t.results.len(), ret, locals, side_table, prev_stack);
1372        self.frames.push(frame);
1373        Ok(ThreadResult::Continue(self))
1374    }
1375}
1376
1377fn table_init(d: usize, s: usize, n: usize, table: &mut Table, elems: &[Val]) -> Result<(), Error> {
1378    if s.checked_add(n).is_none_or(|x| x > elems.len())
1379        || d.checked_add(n).is_none_or(|x| x > table.elems.len())
1380    {
1381        Err(trap())
1382    } else {
1383        table.elems[d ..][.. n].copy_from_slice(&elems[s ..][.. n]);
1384        Ok(())
1385    }
1386}
1387
1388fn memory_init(d: usize, s: usize, n: usize, mem: &mut Memory, data: &[u8]) -> Result<(), Error> {
1389    if s.checked_add(n).is_none_or(|x| x > data.len())
1390        || d.checked_add(n).is_none_or(|x| x > mem.len() as usize)
1391    {
1392        memory_too_small(d, n, mem);
1393        Err(trap())
1394    } else {
1395        mem.data[d ..][.. n].copy_from_slice(&data[s ..][.. n]);
1396        Ok(())
1397    }
1398}
1399
1400#[derive(Debug)]
1401struct Frame<'m> {
1402    inst_id: usize,
1403    arity: usize,
1404    ret: Parser<'m>,
1405    locals: Vec<Val>,
1406    side_table: Cursor<'m, BranchTableEntry>,
1407    /// Total length of the value stack in the thread prior to this frame.
1408    prev_stack: usize,
1409    // TODO: We should be able to get rid of this by using the side-table.
1410    labels_cnt: usize,
1411}
1412
1413impl<'m> Frame<'m> {
1414    fn new(
1415        inst_id: usize, arity: usize, ret: Parser<'m>, locals: Vec<Val>,
1416        side_table: Cursor<'m, BranchTableEntry>, prev_stack: usize,
1417    ) -> Self {
1418        Frame { inst_id, arity, ret, locals, side_table, prev_stack, labels_cnt: 1 }
1419    }
1420
1421    fn skip_jump(&mut self) {
1422        self.side_table.adjust_start(1);
1423    }
1424
1425    fn take_jump(&mut self, offset: usize) -> isize {
1426        self.side_table.adjust_start(offset as isize);
1427        let entry = self.side_table.get(0).view::<Use>().into_ok();
1428        self.side_table.adjust_start(entry.delta_stp as isize);
1429        entry.delta_ip as isize
1430    }
1431}
1432
1433impl Table {
1434    fn new(type_: TableType) -> Self {
1435        Table {
1436            max: type_.limits.max,
1437            elems: vec![Val::Null(type_.item); type_.limits.min as usize],
1438        }
1439    }
1440}
1441
1442#[derive(Debug, Default)]
1443struct Memory<'m> {
1444    // May be shorter than the maximum length for the module, but not larger.
1445    data: &'m mut [u8],
1446    // The size currently available to the module. May be larger than the actual data.
1447    size: u32,
1448    max: u32,
1449}
1450
1451impl<'m> Memory<'m> {
1452    fn init(&mut self, mut data: &'m mut [u8], limits: Limits) -> Result<(), Error> {
1453        if !data.as_ptr().is_aligned_to(MEMORY_ALIGN) {
1454            return Err(invalid());
1455        }
1456        if limits.max < 0x10000 {
1457            let max = core::cmp::min(limits.max as usize * 0x10000, data.len());
1458            data = &mut data[.. max];
1459        }
1460        self.data = data;
1461        // TODO: Figure out if we need to do this or whether we can rely on the caller to provide a
1462        // zeroed-out slice.
1463        self.data.fill(0);
1464        self.size = limits.min;
1465        self.max = limits.max;
1466        Ok(())
1467    }
1468
1469    fn len(&self) -> u32 {
1470        core::cmp::min(self.data.len() as u32, self.size * 0x10000)
1471    }
1472}
1473
1474impl Global {
1475    fn new(value: Val) -> Self {
1476        Global { value }
1477    }
1478}
1479
1480trait Growable {
1481    type Item: Copy;
1482    fn size(&self) -> u32;
1483    fn max(&self) -> u32;
1484    fn grow(&mut self, n: u32, x: Self::Item);
1485}
1486
1487impl Growable for Memory<'_> {
1488    type Item = ();
1489    fn size(&self) -> u32 {
1490        self.size
1491    }
1492    fn max(&self) -> u32 {
1493        self.max
1494    }
1495    fn grow(&mut self, n: u32, _: Self::Item) {
1496        self.size = n;
1497    }
1498}
1499
1500impl Growable for Table {
1501    type Item = Val;
1502    fn size(&self) -> u32 {
1503        self.elems.len() as u32
1504    }
1505    fn max(&self) -> u32 {
1506        self.max
1507    }
1508    fn grow(&mut self, n: u32, x: Self::Item) {
1509        self.elems.resize(n as usize, x);
1510    }
1511}
1512
1513/// Returns the old size or u32::MAX.
1514fn grow<T: Growable>(elems: &mut T, n: u32, item: T::Item) -> u32 {
1515    let sz = elems.size();
1516    let len = match sz.checked_add(n) {
1517        Some(x) if x <= elems.max() => x,
1518        _ => return u32::MAX,
1519    };
1520    elems.grow(len, item);
1521    sz
1522}
1523
1524#[derive(Debug, Default)]
1525struct Component<T> {
1526    ext: Vec<Ptr>,
1527    int: T,
1528}
1529
1530impl<T> Component<T> {
1531    fn ptr(&self, inst_id: usize, x: u32) -> Ptr {
1532        match x.checked_sub(self.ext.len() as u32) {
1533            None => self.ext[x as usize],
1534            Some(x) => Ptr::new(Side::Wasm(inst_id), x),
1535        }
1536    }
1537}
1538
1539macro_rules! impl_val_unwrap {
1540    ($n:ident, $T:ident, $t:ident) => {
1541        impl Val {
1542            pub fn $n(self) -> $t {
1543                match self {
1544                    Val::$T(x) => x,
1545                    _ => unreachable!(),
1546                }
1547            }
1548        }
1549    };
1550}
1551impl_val_unwrap!(unwrap_i32, I32, u32);
1552impl_val_unwrap!(unwrap_i64, I64, u64);
1553#[cfg(feature = "float-types")]
1554impl_val_unwrap!(unwrap_f32, F32, u32);
1555#[cfg(feature = "float-types")]
1556impl_val_unwrap!(unwrap_f64, F64, u64);
1557impl_val_unwrap!(unwrap_ref, Ref, Ptr);
1558
1559impl ValType {
1560    fn default(self) -> Val {
1561        match self {
1562            ValType::I32 => Val::I32(0),
1563            ValType::I64 => Val::I64(0),
1564            ValType::F32 => support_if!("float-types"[], Val::F32(0), unreachable!()),
1565            ValType::F64 => support_if!("float-types"[], Val::F64(0), unreachable!()),
1566            ValType::V128 => support_if!("vector-types"[], Val::V128(0), unreachable!()),
1567            ValType::FuncRef => Val::Null(RefType::FuncRef),
1568            ValType::ExternRef => Val::Null(RefType::ExternRef),
1569        }
1570    }
1571
1572    fn contains(self, value: Val) -> bool {
1573        match (self, value) {
1574            (ValType::I32, Val::I32(_))
1575            | (ValType::I64, Val::I64(_))
1576            | (ValType::FuncRef, Val::Null(RefType::FuncRef) | Val::Ref(_))
1577            | (ValType::ExternRef, Val::Null(RefType::ExternRef) | Val::RefExtern(_)) => true,
1578            #[cfg(feature = "float-types")]
1579            (ValType::F32, Val::F32(_)) | (ValType::F64, Val::F64(_)) => true,
1580            #[cfg(feature = "vector-types")]
1581            (ValType::V128, Val::V128(_)) => true,
1582            _ => false,
1583        }
1584    }
1585}
1586
1587fn append_locals(parser: &mut Parser, locals: &mut Vec<Val>) {
1588    for _ in 0 .. parser.parse_vec().into_ok() {
1589        let len = parser.parse_u32().into_ok() as usize;
1590        let val = parser.parse_valtype().into_ok().default();
1591        locals.extend(core::iter::repeat_n(val, len));
1592    }
1593}
1594
1595fn check_types(types: &[ValType], values: &[Val]) -> Result<(), Error> {
1596    check(types.len() == values.len())?;
1597    check(types.iter().zip(values.iter()).all(|(t, x)| t.contains(*x)))
1598}
1599
1600fn memory_too_small(x: usize, n: usize, mem: &Memory) {
1601    #[cfg(not(feature = "debug"))]
1602    let _ = (x, n, mem);
1603    #[cfg(feature = "debug")]
1604    eprintln!("Memory too small: {x} + {n} > {}", mem.len());
1605}