cranelift_wasm/environ/
dummy.rs

1//! "Dummy" implementations of `ModuleEnvironment` and `FuncEnvironment` for testing
2//! wasm translation. For complete implementations of `ModuleEnvironment` and
3//! `FuncEnvironment`, see [wasmtime-environ] in [Wasmtime].
4//!
5//! [wasmtime-environ]: https://crates.io/crates/wasmtime-environ
6//! [Wasmtime]: https://github.com/bytecodealliance/wasmtime
7
8use crate::environ::{FuncEnvironment, GlobalVariable, ModuleEnvironment, TargetEnvironment};
9use crate::func_translator::FuncTranslator;
10use crate::state::FuncTranslationState;
11use crate::WasmType;
12use crate::{
13    DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex, Heap, HeapData,
14    HeapStyle, Memory, MemoryIndex, Table, TableIndex, TypeIndex, WasmFuncType, WasmResult,
15};
16use core::convert::TryFrom;
17use cranelift_codegen::cursor::FuncCursor;
18use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
19use cranelift_codegen::ir::{self, InstBuilder};
20use cranelift_codegen::ir::{types::*, UserFuncName};
21use cranelift_codegen::isa::{CallConv, TargetFrontendConfig};
22use cranelift_entity::{EntityRef, PrimaryMap, SecondaryMap};
23use cranelift_frontend::FunctionBuilder;
24use std::boxed::Box;
25use std::string::String;
26use std::vec::Vec;
27use wasmparser::{FuncValidator, FunctionBody, Operator, ValidatorResources, WasmFeatures};
28
29/// A collection of names under which a given entity is exported.
30pub struct Exportable<T> {
31    /// A wasm entity.
32    pub entity: T,
33
34    /// Names under which the entity is exported.
35    pub export_names: Vec<String>,
36}
37
38impl<T> Exportable<T> {
39    pub fn new(entity: T) -> Self {
40        Self {
41            entity,
42            export_names: Vec::new(),
43        }
44    }
45}
46
47/// The main state belonging to a `DummyEnvironment`. This is split out from
48/// `DummyEnvironment` to allow it to be borrowed separately from the
49/// `FuncTranslator` field.
50pub struct DummyModuleInfo {
51    /// Target description relevant to frontends producing Cranelift IR.
52    config: TargetFrontendConfig,
53
54    /// Signatures as provided by `declare_signature`.
55    pub signatures: PrimaryMap<TypeIndex, ir::Signature>,
56
57    /// Module and field names of imported functions as provided by `declare_func_import`.
58    pub imported_funcs: Vec<(String, String)>,
59
60    /// Module and field names of imported globals as provided by `declare_global_import`.
61    pub imported_globals: Vec<(String, String)>,
62
63    /// Module and field names of imported tables as provided by `declare_table_import`.
64    pub imported_tables: Vec<(String, String)>,
65
66    /// Module and field names of imported memories as provided by `declare_memory_import`.
67    pub imported_memories: Vec<(String, String)>,
68
69    /// Functions, imported and local.
70    pub functions: PrimaryMap<FuncIndex, Exportable<TypeIndex>>,
71
72    /// Function bodies.
73    pub function_bodies: PrimaryMap<DefinedFuncIndex, ir::Function>,
74
75    /// Tables as provided by `declare_table`.
76    pub tables: PrimaryMap<TableIndex, Exportable<Table>>,
77
78    /// Memories as provided by `declare_memory`.
79    pub memories: PrimaryMap<MemoryIndex, Exportable<Memory>>,
80
81    /// Globals as provided by `declare_global`.
82    pub globals: PrimaryMap<GlobalIndex, Exportable<Global>>,
83
84    /// The start function.
85    pub start_func: Option<FuncIndex>,
86}
87
88impl DummyModuleInfo {
89    /// Creates a new `DummyModuleInfo` instance.
90    pub fn new(config: TargetFrontendConfig) -> Self {
91        Self {
92            config,
93            signatures: PrimaryMap::new(),
94            imported_funcs: Vec::new(),
95            imported_globals: Vec::new(),
96            imported_tables: Vec::new(),
97            imported_memories: Vec::new(),
98            functions: PrimaryMap::new(),
99            function_bodies: PrimaryMap::new(),
100            tables: PrimaryMap::new(),
101            memories: PrimaryMap::new(),
102            globals: PrimaryMap::new(),
103            start_func: None,
104        }
105    }
106}
107
108/// State for tracking and checking reachability at each operator. Used for unit testing with the
109/// `DummyEnvironment`.
110#[derive(Clone)]
111pub struct ExpectedReachability {
112    /// Before- and after-reachability
113    reachability: Vec<(bool, bool)>,
114    before_idx: usize,
115    after_idx: usize,
116}
117
118impl ExpectedReachability {
119    fn check_before(&mut self, reachable: bool) {
120        assert_eq!(reachable, self.reachability[self.before_idx].0);
121        self.before_idx += 1;
122    }
123    fn check_after(&mut self, reachable: bool) {
124        assert_eq!(reachable, self.reachability[self.after_idx].1);
125        self.after_idx += 1;
126    }
127    fn check_end(&self) {
128        assert_eq!(self.before_idx, self.reachability.len());
129        assert_eq!(self.after_idx, self.reachability.len());
130    }
131}
132
133/// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and
134/// emitting placeholders when forced to. Don't try to execute code translated for this
135/// environment, essentially here for translation debug purposes.
136pub struct DummyEnvironment {
137    /// Module information.
138    pub info: DummyModuleInfo,
139
140    /// Function translation.
141    pub trans: FuncTranslator,
142
143    /// Vector of wasm bytecode size for each function.
144    pub func_bytecode_sizes: Vec<usize>,
145
146    /// Instructs to collect debug data during translation.
147    pub debug_info: bool,
148
149    /// Name of the module from the wasm file.
150    pub module_name: Option<String>,
151
152    /// Function names.
153    function_names: SecondaryMap<FuncIndex, String>,
154
155    /// Expected reachability data (before/after for each op) to assert. This is used for testing.
156    #[doc(hidden)]
157    pub expected_reachability: Option<ExpectedReachability>,
158}
159
160impl DummyEnvironment {
161    /// Creates a new `DummyEnvironment` instance.
162    pub fn new(config: TargetFrontendConfig, debug_info: bool) -> Self {
163        Self {
164            info: DummyModuleInfo::new(config),
165            trans: FuncTranslator::new(),
166            func_bytecode_sizes: Vec::new(),
167            debug_info,
168            module_name: None,
169            function_names: SecondaryMap::new(),
170            expected_reachability: None,
171        }
172    }
173
174    /// Return a `DummyFuncEnvironment` for translating functions within this
175    /// `DummyEnvironment`.
176    pub fn func_env(&self) -> DummyFuncEnvironment {
177        DummyFuncEnvironment::new(&self.info, self.expected_reachability.clone())
178    }
179
180    /// Get the type for the function at the given index.
181    pub fn get_func_type(&self, func_index: FuncIndex) -> TypeIndex {
182        self.info.functions[func_index].entity
183    }
184
185    /// Return the number of imported functions within this `DummyEnvironment`.
186    pub fn get_num_func_imports(&self) -> usize {
187        self.info.imported_funcs.len()
188    }
189
190    /// Return the name of the function, if a name for the function with
191    /// the corresponding index exists.
192    pub fn get_func_name(&self, func_index: FuncIndex) -> Option<&str> {
193        self.function_names.get(func_index).map(String::as_ref)
194    }
195
196    /// Test reachability bits before and after every opcode during translation, as provided by the
197    /// `FuncTranslationState`. This is generally used only for unit tests. This is applied to
198    /// every function in the module (so is likely only useful for test modules with one function).
199    pub fn test_expected_reachability(&mut self, reachability: Vec<(bool, bool)>) {
200        self.expected_reachability = Some(ExpectedReachability {
201            reachability,
202            before_idx: 0,
203            after_idx: 0,
204        });
205    }
206}
207
208/// The `FuncEnvironment` implementation for use by the `DummyEnvironment`.
209pub struct DummyFuncEnvironment<'dummy_environment> {
210    /// This function environment's module info.
211    pub mod_info: &'dummy_environment DummyModuleInfo,
212
213    /// Expected reachability data (before/after for each op) to assert. This is used for testing.
214    expected_reachability: Option<ExpectedReachability>,
215
216    /// Heaps we have created to implement Wasm linear memories.
217    pub heaps: PrimaryMap<Heap, HeapData>,
218}
219
220impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
221    /// Construct a new `DummyFuncEnvironment`.
222    pub fn new(
223        mod_info: &'dummy_environment DummyModuleInfo,
224        expected_reachability: Option<ExpectedReachability>,
225    ) -> Self {
226        Self {
227            mod_info,
228            expected_reachability,
229            heaps: Default::default(),
230        }
231    }
232
233    /// Create a signature for `sigidx` amended with a `vmctx` argument after
234    /// the standard wasm arguments.
235    pub fn vmctx_sig(&self, sigidx: TypeIndex) -> ir::Signature {
236        let mut sig = self.mod_info.signatures[sigidx].clone();
237        sig.params.push(ir::AbiParam::special(
238            self.pointer_type(),
239            ir::ArgumentPurpose::VMContext,
240        ));
241        sig
242    }
243
244    fn reference_type(&self) -> ir::Type {
245        match self.pointer_type() {
246            ir::types::I32 => ir::types::R32,
247            ir::types::I64 => ir::types::R64,
248            _ => panic!("unsupported pointer type"),
249        }
250    }
251}
252
253impl<'dummy_environment> TargetEnvironment for DummyFuncEnvironment<'dummy_environment> {
254    fn target_config(&self) -> TargetFrontendConfig {
255        self.mod_info.config
256    }
257
258    fn heap_access_spectre_mitigation(&self) -> bool {
259        false
260    }
261}
262
263impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
264    fn make_global(
265        &mut self,
266        func: &mut ir::Function,
267        index: GlobalIndex,
268    ) -> WasmResult<GlobalVariable> {
269        // Just create a dummy `vmctx` global.
270        let offset = i32::try_from((index.index() * 8) + 8).unwrap().into();
271        let vmctx = func.create_global_value(ir::GlobalValueData::VMContext {});
272        Ok(GlobalVariable::Memory {
273            gv: vmctx,
274            offset,
275            ty: match self.mod_info.globals[index].entity.wasm_ty {
276                WasmType::I32 => ir::types::I32,
277                WasmType::I64 => ir::types::I64,
278                WasmType::F32 => ir::types::F32,
279                WasmType::F64 => ir::types::F64,
280                WasmType::V128 => ir::types::I8X16,
281                WasmType::FuncRef | WasmType::ExternRef => ir::types::R64,
282            },
283        })
284    }
285
286    fn heaps(&self) -> &PrimaryMap<Heap, HeapData> {
287        &self.heaps
288    }
289
290    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> WasmResult<Heap> {
291        // Create a static heap whose base address is stored at `vmctx+0`.
292        let addr = func.create_global_value(ir::GlobalValueData::VMContext);
293        let gv = func.create_global_value(ir::GlobalValueData::Load {
294            base: addr,
295            offset: Offset32::new(0),
296            global_type: self.pointer_type(),
297            readonly: true,
298        });
299
300        Ok(self.heaps.push(HeapData {
301            base: gv,
302            min_size: 0,
303            offset_guard_size: 0x8000_0000,
304            style: HeapStyle::Static {
305                bound: 0x1_0000_0000,
306            },
307            index_type: I32,
308        }))
309    }
310
311    fn make_table(&mut self, func: &mut ir::Function, _index: TableIndex) -> WasmResult<ir::Table> {
312        // Create a table whose base address is stored at `vmctx+0`.
313        let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
314        let base_gv = func.create_global_value(ir::GlobalValueData::Load {
315            base: vmctx,
316            offset: Offset32::new(0),
317            global_type: self.pointer_type(),
318            readonly: true, // when tables in wasm become "growable", revisit whether this can be readonly or not.
319        });
320        let bound_gv = func.create_global_value(ir::GlobalValueData::Load {
321            base: vmctx,
322            offset: Offset32::new(0),
323            global_type: I32,
324            readonly: true,
325        });
326
327        Ok(func.create_table(ir::TableData {
328            base_gv,
329            min_size: Uimm64::new(0),
330            bound_gv,
331            element_size: Uimm64::from(u64::from(self.pointer_bytes()) * 2),
332            index_type: I32,
333        }))
334    }
335
336    fn make_indirect_sig(
337        &mut self,
338        func: &mut ir::Function,
339        index: TypeIndex,
340    ) -> WasmResult<ir::SigRef> {
341        // A real implementation would probably change the calling convention and add `vmctx` and
342        // signature index arguments.
343        Ok(func.import_signature(self.vmctx_sig(index)))
344    }
345
346    fn make_direct_func(
347        &mut self,
348        func: &mut ir::Function,
349        index: FuncIndex,
350    ) -> WasmResult<ir::FuncRef> {
351        let sigidx = self.mod_info.functions[index].entity;
352        // A real implementation would probably add a `vmctx` argument.
353        // And maybe attempt some signature de-duplication.
354        let signature = func.import_signature(self.vmctx_sig(sigidx));
355        let name =
356            ir::ExternalName::User(func.declare_imported_user_function(ir::UserExternalName {
357                namespace: 0,
358                index: index.as_u32(),
359            }));
360        Ok(func.import_function(ir::ExtFuncData {
361            name,
362            signature,
363            colocated: false,
364        }))
365    }
366
367    fn before_translate_operator(
368        &mut self,
369        _op: &Operator,
370        _builder: &mut FunctionBuilder,
371        state: &FuncTranslationState,
372    ) -> WasmResult<()> {
373        if let Some(ref mut r) = &mut self.expected_reachability {
374            r.check_before(state.reachable());
375        }
376        Ok(())
377    }
378
379    fn after_translate_operator(
380        &mut self,
381        _op: &Operator,
382        _builder: &mut FunctionBuilder,
383        state: &FuncTranslationState,
384    ) -> WasmResult<()> {
385        if let Some(ref mut r) = &mut self.expected_reachability {
386            r.check_after(state.reachable());
387        }
388        Ok(())
389    }
390
391    fn after_translate_function(
392        &mut self,
393        _builder: &mut FunctionBuilder,
394        _state: &FuncTranslationState,
395    ) -> WasmResult<()> {
396        if let Some(ref mut r) = &mut self.expected_reachability {
397            r.check_end();
398        }
399        Ok(())
400    }
401
402    fn translate_call_indirect(
403        &mut self,
404        builder: &mut FunctionBuilder,
405        _table_index: TableIndex,
406        _table: ir::Table,
407        _sig_index: TypeIndex,
408        sig_ref: ir::SigRef,
409        callee: ir::Value,
410        call_args: &[ir::Value],
411    ) -> WasmResult<ir::Inst> {
412        // Pass the current function's vmctx parameter on to the callee.
413        let vmctx = builder
414            .func
415            .special_param(ir::ArgumentPurpose::VMContext)
416            .expect("Missing vmctx parameter");
417
418        // The `callee` value is an index into a table of function pointers.
419        // Apparently, that table is stored at absolute address 0 in this dummy environment.
420        // TODO: Generate bounds checking code.
421        let ptr = self.pointer_type();
422        let callee_offset = if ptr == I32 {
423            builder.ins().imul_imm(callee, 4)
424        } else {
425            let ext = builder.ins().uextend(I64, callee);
426            builder.ins().imul_imm(ext, 4)
427        };
428        let mflags = ir::MemFlags::trusted();
429        let func_ptr = builder.ins().load(ptr, mflags, callee_offset, 0);
430
431        // Build a value list for the indirect call instruction containing the callee, call_args,
432        // and the vmctx parameter.
433        let mut args = ir::ValueList::default();
434        args.push(func_ptr, &mut builder.func.dfg.value_lists);
435        args.extend(call_args.iter().cloned(), &mut builder.func.dfg.value_lists);
436        args.push(vmctx, &mut builder.func.dfg.value_lists);
437
438        Ok(builder
439            .ins()
440            .CallIndirect(ir::Opcode::CallIndirect, INVALID, sig_ref, args)
441            .0)
442    }
443
444    fn translate_call(
445        &mut self,
446        mut pos: FuncCursor,
447        _callee_index: FuncIndex,
448        callee: ir::FuncRef,
449        call_args: &[ir::Value],
450    ) -> WasmResult<ir::Inst> {
451        // Pass the current function's vmctx parameter on to the callee.
452        let vmctx = pos
453            .func
454            .special_param(ir::ArgumentPurpose::VMContext)
455            .expect("Missing vmctx parameter");
456
457        // Build a value list for the call instruction containing the call_args and the vmctx
458        // parameter.
459        let mut args = ir::ValueList::default();
460        args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
461        args.push(vmctx, &mut pos.func.dfg.value_lists);
462
463        Ok(pos.ins().Call(ir::Opcode::Call, INVALID, callee, args).0)
464    }
465
466    fn translate_memory_grow(
467        &mut self,
468        mut pos: FuncCursor,
469        _index: MemoryIndex,
470        _heap: Heap,
471        _val: ir::Value,
472    ) -> WasmResult<ir::Value> {
473        Ok(pos.ins().iconst(I32, -1))
474    }
475
476    fn translate_memory_size(
477        &mut self,
478        mut pos: FuncCursor,
479        _index: MemoryIndex,
480        _heap: Heap,
481    ) -> WasmResult<ir::Value> {
482        Ok(pos.ins().iconst(I32, -1))
483    }
484
485    fn translate_memory_copy(
486        &mut self,
487        _pos: FuncCursor,
488        _src_index: MemoryIndex,
489        _src_heap: Heap,
490        _dst_index: MemoryIndex,
491        _dst_heap: Heap,
492        _dst: ir::Value,
493        _src: ir::Value,
494        _len: ir::Value,
495    ) -> WasmResult<()> {
496        Ok(())
497    }
498
499    fn translate_memory_fill(
500        &mut self,
501        _pos: FuncCursor,
502        _index: MemoryIndex,
503        _heap: Heap,
504        _dst: ir::Value,
505        _val: ir::Value,
506        _len: ir::Value,
507    ) -> WasmResult<()> {
508        Ok(())
509    }
510
511    fn translate_memory_init(
512        &mut self,
513        _pos: FuncCursor,
514        _index: MemoryIndex,
515        _heap: Heap,
516        _seg_index: u32,
517        _dst: ir::Value,
518        _src: ir::Value,
519        _len: ir::Value,
520    ) -> WasmResult<()> {
521        Ok(())
522    }
523
524    fn translate_data_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> {
525        Ok(())
526    }
527
528    fn translate_table_size(
529        &mut self,
530        mut pos: FuncCursor,
531        _index: TableIndex,
532        _table: ir::Table,
533    ) -> WasmResult<ir::Value> {
534        Ok(pos.ins().iconst(I32, -1))
535    }
536
537    fn translate_table_grow(
538        &mut self,
539        mut pos: FuncCursor,
540        _table_index: TableIndex,
541        _table: ir::Table,
542        _delta: ir::Value,
543        _init_value: ir::Value,
544    ) -> WasmResult<ir::Value> {
545        Ok(pos.ins().iconst(I32, -1))
546    }
547
548    fn translate_table_get(
549        &mut self,
550        builder: &mut FunctionBuilder,
551        _table_index: TableIndex,
552        _table: ir::Table,
553        _index: ir::Value,
554    ) -> WasmResult<ir::Value> {
555        Ok(builder.ins().null(self.reference_type()))
556    }
557
558    fn translate_table_set(
559        &mut self,
560        _builder: &mut FunctionBuilder,
561        _table_index: TableIndex,
562        _table: ir::Table,
563        _value: ir::Value,
564        _index: ir::Value,
565    ) -> WasmResult<()> {
566        Ok(())
567    }
568
569    fn translate_table_copy(
570        &mut self,
571        _pos: FuncCursor,
572        _dst_index: TableIndex,
573        _dst_table: ir::Table,
574        _src_index: TableIndex,
575        _src_table: ir::Table,
576        _dst: ir::Value,
577        _src: ir::Value,
578        _len: ir::Value,
579    ) -> WasmResult<()> {
580        Ok(())
581    }
582
583    fn translate_table_fill(
584        &mut self,
585        _pos: FuncCursor,
586        _table_index: TableIndex,
587        _dst: ir::Value,
588        _val: ir::Value,
589        _len: ir::Value,
590    ) -> WasmResult<()> {
591        Ok(())
592    }
593
594    fn translate_table_init(
595        &mut self,
596        _pos: FuncCursor,
597        _seg_index: u32,
598        _table_index: TableIndex,
599        _table: ir::Table,
600        _dst: ir::Value,
601        _src: ir::Value,
602        _len: ir::Value,
603    ) -> WasmResult<()> {
604        Ok(())
605    }
606
607    fn translate_elem_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> {
608        Ok(())
609    }
610
611    fn translate_ref_func(
612        &mut self,
613        mut pos: FuncCursor,
614        _func_index: FuncIndex,
615    ) -> WasmResult<ir::Value> {
616        Ok(pos.ins().null(self.reference_type()))
617    }
618
619    fn translate_custom_global_get(
620        &mut self,
621        mut pos: FuncCursor,
622        _global_index: GlobalIndex,
623    ) -> WasmResult<ir::Value> {
624        Ok(pos.ins().iconst(I32, -1))
625    }
626
627    fn translate_custom_global_set(
628        &mut self,
629        _pos: FuncCursor,
630        _global_index: GlobalIndex,
631        _val: ir::Value,
632    ) -> WasmResult<()> {
633        Ok(())
634    }
635
636    fn translate_atomic_wait(
637        &mut self,
638        mut pos: FuncCursor,
639        _index: MemoryIndex,
640        _heap: Heap,
641        _addr: ir::Value,
642        _expected: ir::Value,
643        _timeout: ir::Value,
644    ) -> WasmResult<ir::Value> {
645        Ok(pos.ins().iconst(I32, -1))
646    }
647
648    fn translate_atomic_notify(
649        &mut self,
650        mut pos: FuncCursor,
651        _index: MemoryIndex,
652        _heap: Heap,
653        _addr: ir::Value,
654        _count: ir::Value,
655    ) -> WasmResult<ir::Value> {
656        Ok(pos.ins().iconst(I32, 0))
657    }
658
659    fn unsigned_add_overflow_condition(&self) -> ir::condcodes::IntCC {
660        unimplemented!()
661    }
662}
663
664impl TargetEnvironment for DummyEnvironment {
665    fn target_config(&self) -> TargetFrontendConfig {
666        self.info.config
667    }
668
669    fn heap_access_spectre_mitigation(&self) -> bool {
670        false
671    }
672}
673
674impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
675    fn declare_type_func(&mut self, wasm: WasmFuncType) -> WasmResult<()> {
676        let mut sig = ir::Signature::new(CallConv::Fast);
677        let mut cvt = |ty: &WasmType| {
678            let reference_type = match self.pointer_type() {
679                ir::types::I32 => ir::types::R32,
680                ir::types::I64 => ir::types::R64,
681                _ => panic!("unsupported pointer type"),
682            };
683            ir::AbiParam::new(match ty {
684                WasmType::I32 => ir::types::I32,
685                WasmType::I64 => ir::types::I64,
686                WasmType::F32 => ir::types::F32,
687                WasmType::F64 => ir::types::F64,
688                WasmType::V128 => ir::types::I8X16,
689                WasmType::FuncRef | WasmType::ExternRef => reference_type,
690            })
691        };
692        sig.params.extend(wasm.params().iter().map(&mut cvt));
693        sig.returns.extend(wasm.returns().iter().map(&mut cvt));
694        self.info.signatures.push(sig);
695        Ok(())
696    }
697
698    fn declare_func_import(
699        &mut self,
700        index: TypeIndex,
701        module: &'data str,
702        field: &'data str,
703    ) -> WasmResult<()> {
704        assert_eq!(
705            self.info.functions.len(),
706            self.info.imported_funcs.len(),
707            "Imported functions must be declared first"
708        );
709        self.info.functions.push(Exportable::new(index));
710        self.info
711            .imported_funcs
712            .push((String::from(module), String::from(field)));
713        Ok(())
714    }
715
716    fn declare_func_type(&mut self, index: TypeIndex) -> WasmResult<()> {
717        self.info.functions.push(Exportable::new(index));
718        Ok(())
719    }
720
721    fn declare_global(&mut self, global: Global) -> WasmResult<()> {
722        self.info.globals.push(Exportable::new(global));
723        Ok(())
724    }
725
726    fn declare_global_import(
727        &mut self,
728        global: Global,
729        module: &'data str,
730        field: &'data str,
731    ) -> WasmResult<()> {
732        self.info.globals.push(Exportable::new(global));
733        self.info
734            .imported_globals
735            .push((String::from(module), String::from(field)));
736        Ok(())
737    }
738
739    fn declare_table(&mut self, table: Table) -> WasmResult<()> {
740        self.info.tables.push(Exportable::new(table));
741        Ok(())
742    }
743
744    fn declare_table_import(
745        &mut self,
746        table: Table,
747        module: &'data str,
748        field: &'data str,
749    ) -> WasmResult<()> {
750        self.info.tables.push(Exportable::new(table));
751        self.info
752            .imported_tables
753            .push((String::from(module), String::from(field)));
754        Ok(())
755    }
756
757    fn declare_table_elements(
758        &mut self,
759        _table_index: TableIndex,
760        _base: Option<GlobalIndex>,
761        _offset: u32,
762        _elements: Box<[FuncIndex]>,
763    ) -> WasmResult<()> {
764        // We do nothing
765        Ok(())
766    }
767
768    fn declare_passive_element(
769        &mut self,
770        _elem_index: ElemIndex,
771        _segments: Box<[FuncIndex]>,
772    ) -> WasmResult<()> {
773        Ok(())
774    }
775
776    fn declare_passive_data(
777        &mut self,
778        _elem_index: DataIndex,
779        _segments: &'data [u8],
780    ) -> WasmResult<()> {
781        Ok(())
782    }
783
784    fn declare_memory(&mut self, memory: Memory) -> WasmResult<()> {
785        self.info.memories.push(Exportable::new(memory));
786        Ok(())
787    }
788
789    fn declare_memory_import(
790        &mut self,
791        memory: Memory,
792        module: &'data str,
793        field: &'data str,
794    ) -> WasmResult<()> {
795        self.info.memories.push(Exportable::new(memory));
796        self.info
797            .imported_memories
798            .push((String::from(module), String::from(field)));
799        Ok(())
800    }
801
802    fn declare_data_initialization(
803        &mut self,
804        _memory_index: MemoryIndex,
805        _base: Option<GlobalIndex>,
806        _offset: u64,
807        _data: &'data [u8],
808    ) -> WasmResult<()> {
809        // We do nothing
810        Ok(())
811    }
812
813    fn declare_func_export(&mut self, func_index: FuncIndex, name: &'data str) -> WasmResult<()> {
814        self.info.functions[func_index]
815            .export_names
816            .push(String::from(name));
817        Ok(())
818    }
819
820    fn declare_table_export(
821        &mut self,
822        table_index: TableIndex,
823        name: &'data str,
824    ) -> WasmResult<()> {
825        self.info.tables[table_index]
826            .export_names
827            .push(String::from(name));
828        Ok(())
829    }
830
831    fn declare_memory_export(
832        &mut self,
833        memory_index: MemoryIndex,
834        name: &'data str,
835    ) -> WasmResult<()> {
836        self.info.memories[memory_index]
837            .export_names
838            .push(String::from(name));
839        Ok(())
840    }
841
842    fn declare_global_export(
843        &mut self,
844        global_index: GlobalIndex,
845        name: &'data str,
846    ) -> WasmResult<()> {
847        self.info.globals[global_index]
848            .export_names
849            .push(String::from(name));
850        Ok(())
851    }
852
853    fn declare_start_func(&mut self, func_index: FuncIndex) -> WasmResult<()> {
854        debug_assert!(self.info.start_func.is_none());
855        self.info.start_func = Some(func_index);
856        Ok(())
857    }
858
859    fn define_function_body(
860        &mut self,
861        mut validator: FuncValidator<ValidatorResources>,
862        body: FunctionBody<'data>,
863    ) -> WasmResult<()> {
864        self.func_bytecode_sizes
865            .push(body.get_binary_reader().bytes_remaining());
866        let func = {
867            let mut func_environ =
868                DummyFuncEnvironment::new(&self.info, self.expected_reachability.clone());
869            let func_index =
870                FuncIndex::new(self.get_num_func_imports() + self.info.function_bodies.len());
871
872            let sig = func_environ.vmctx_sig(self.get_func_type(func_index));
873            let mut func =
874                ir::Function::with_name_signature(UserFuncName::user(0, func_index.as_u32()), sig);
875
876            if self.debug_info {
877                func.collect_debug_info();
878            }
879
880            self.trans
881                .translate_body(&mut validator, body, &mut func, &mut func_environ)?;
882            func
883        };
884        self.info.function_bodies.push(func);
885        Ok(())
886    }
887
888    fn declare_module_name(&mut self, name: &'data str) {
889        self.module_name = Some(String::from(name));
890    }
891
892    fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) {
893        self.function_names[func_index] = String::from(name);
894    }
895
896    fn wasm_features(&self) -> WasmFeatures {
897        WasmFeatures {
898            multi_value: true,
899            simd: true,
900            reference_types: true,
901            bulk_memory: true,
902            ..WasmFeatures::default()
903        }
904    }
905}