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