1use crate::environ::{
9 FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmResult,
10};
11use crate::func_translator::FuncTranslator;
12use crate::state::ModuleTranslationState;
13use crate::translation_utils::{
14 DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, PassiveDataIndex,
15 PassiveElemIndex, SignatureIndex, Table, TableIndex,
16};
17use core::convert::TryFrom;
18use cranelift_codegen::cursor::FuncCursor;
19use cranelift_codegen::ir::immediates::{Offset32, Uimm64};
20use cranelift_codegen::ir::types::*;
21use cranelift_codegen::ir::{self, InstBuilder};
22use cranelift_codegen::isa::TargetFrontendConfig;
23use cranelift_entity::{EntityRef, PrimaryMap, SecondaryMap};
24use std::boxed::Box;
25use std::string::String;
26use std::vec::Vec;
27
28fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
30 ir::ExternalName::user(0, func_index.as_u32())
31}
32
33pub struct Exportable<T> {
35 pub entity: T,
37
38 pub export_names: Vec<String>,
40}
41
42impl<T> Exportable<T> {
43 pub fn new(entity: T) -> Self {
44 Self {
45 entity,
46 export_names: Vec::new(),
47 }
48 }
49}
50
51pub struct DummyModuleInfo {
55 config: TargetFrontendConfig,
57
58 pub signatures: PrimaryMap<SignatureIndex, ir::Signature>,
60
61 pub imported_funcs: Vec<(String, String)>,
63
64 pub imported_globals: Vec<(String, String)>,
66
67 pub imported_tables: Vec<(String, String)>,
69
70 pub imported_memories: Vec<(String, String)>,
72
73 pub functions: PrimaryMap<FuncIndex, Exportable<SignatureIndex>>,
75
76 pub function_bodies: PrimaryMap<DefinedFuncIndex, ir::Function>,
78
79 pub tables: PrimaryMap<TableIndex, Exportable<Table>>,
81
82 pub memories: PrimaryMap<MemoryIndex, Exportable<Memory>>,
84
85 pub globals: PrimaryMap<GlobalIndex, Exportable<Global>>,
87
88 pub start_func: Option<FuncIndex>,
90}
91
92impl DummyModuleInfo {
93 pub fn new(config: TargetFrontendConfig) -> Self {
95 Self {
96 config,
97 signatures: PrimaryMap::new(),
98 imported_funcs: Vec::new(),
99 imported_globals: Vec::new(),
100 imported_tables: Vec::new(),
101 imported_memories: Vec::new(),
102 functions: PrimaryMap::new(),
103 function_bodies: PrimaryMap::new(),
104 tables: PrimaryMap::new(),
105 memories: PrimaryMap::new(),
106 globals: PrimaryMap::new(),
107 start_func: None,
108 }
109 }
110}
111
112pub struct DummyEnvironment {
116 pub info: DummyModuleInfo,
118
119 trans: FuncTranslator,
121
122 pub func_bytecode_sizes: Vec<usize>,
124
125 return_mode: ReturnMode,
127
128 debug_info: bool,
130
131 function_names: SecondaryMap<FuncIndex, String>,
133}
134
135impl DummyEnvironment {
136 pub fn new(config: TargetFrontendConfig, return_mode: ReturnMode, debug_info: bool) -> Self {
138 Self {
139 info: DummyModuleInfo::new(config),
140 trans: FuncTranslator::new(),
141 func_bytecode_sizes: Vec::new(),
142 return_mode,
143 debug_info,
144 function_names: SecondaryMap::new(),
145 }
146 }
147
148 pub fn func_env(&self) -> DummyFuncEnvironment {
151 DummyFuncEnvironment::new(&self.info, self.return_mode)
152 }
153
154 fn get_func_type(&self, func_index: FuncIndex) -> SignatureIndex {
155 self.info.functions[func_index].entity
156 }
157
158 pub fn get_num_func_imports(&self) -> usize {
160 self.info.imported_funcs.len()
161 }
162
163 pub fn get_func_name(&self, func_index: FuncIndex) -> Option<&str> {
166 self.function_names.get(func_index).map(String::as_ref)
167 }
168}
169
170pub struct DummyFuncEnvironment<'dummy_environment> {
172 pub mod_info: &'dummy_environment DummyModuleInfo,
173
174 return_mode: ReturnMode,
175}
176
177impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
178 pub fn new(mod_info: &'dummy_environment DummyModuleInfo, return_mode: ReturnMode) -> Self {
179 Self {
180 mod_info,
181 return_mode,
182 }
183 }
184
185 fn vmctx_sig(&self, sigidx: SignatureIndex) -> ir::Signature {
188 let mut sig = self.mod_info.signatures[sigidx].clone();
189 sig.params.push(ir::AbiParam::special(
190 self.pointer_type(),
191 ir::ArgumentPurpose::VMContext,
192 ));
193 sig
194 }
195}
196
197impl<'dummy_environment> TargetEnvironment for DummyFuncEnvironment<'dummy_environment> {
198 fn target_config(&self) -> TargetFrontendConfig {
199 self.mod_info.config
200 }
201}
202
203impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
204 fn return_mode(&self) -> ReturnMode {
205 self.return_mode
206 }
207
208 fn make_global(
209 &mut self,
210 func: &mut ir::Function,
211 index: GlobalIndex,
212 ) -> WasmResult<GlobalVariable> {
213 let offset = i32::try_from((index.index() * 8) + 8).unwrap().into();
215 let vmctx = func.create_global_value(ir::GlobalValueData::VMContext {});
216 Ok(GlobalVariable::Memory {
217 gv: vmctx,
218 offset,
219 ty: self.mod_info.globals[index].entity.ty,
220 })
221 }
222
223 fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> WasmResult<ir::Heap> {
224 let addr = func.create_global_value(ir::GlobalValueData::VMContext);
226 let gv = func.create_global_value(ir::GlobalValueData::Load {
227 base: addr,
228 offset: Offset32::new(0),
229 global_type: self.pointer_type(),
230 readonly: true,
231 });
232
233 Ok(func.create_heap(ir::HeapData {
234 base: gv,
235 min_size: 0.into(),
236 offset_guard_size: 0x8000_0000.into(),
237 style: ir::HeapStyle::Static {
238 bound: 0x1_0000_0000.into(),
239 },
240 index_type: I32,
241 }))
242 }
243
244 fn make_table(&mut self, func: &mut ir::Function, _index: TableIndex) -> WasmResult<ir::Table> {
245 let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
247 let base_gv = func.create_global_value(ir::GlobalValueData::Load {
248 base: vmctx,
249 offset: Offset32::new(0),
250 global_type: self.pointer_type(),
251 readonly: true, });
253 let bound_gv = func.create_global_value(ir::GlobalValueData::Load {
254 base: vmctx,
255 offset: Offset32::new(0),
256 global_type: I32,
257 readonly: true,
258 });
259
260 Ok(func.create_table(ir::TableData {
261 base_gv,
262 min_size: Uimm64::new(0),
263 bound_gv,
264 element_size: Uimm64::from(u64::from(self.pointer_bytes()) * 2),
265 index_type: I32,
266 }))
267 }
268
269 fn make_indirect_sig(
270 &mut self,
271 func: &mut ir::Function,
272 index: SignatureIndex,
273 ) -> WasmResult<ir::SigRef> {
274 Ok(func.import_signature(self.vmctx_sig(index)))
277 }
278
279 fn make_direct_func(
280 &mut self,
281 func: &mut ir::Function,
282 index: FuncIndex,
283 ) -> WasmResult<ir::FuncRef> {
284 let sigidx = self.mod_info.functions[index].entity;
285 let signature = func.import_signature(self.vmctx_sig(sigidx));
288 let name = get_func_name(index);
289 Ok(func.import_function(ir::ExtFuncData {
290 name,
291 signature,
292 colocated: false,
293 }))
294 }
295
296 fn translate_call_indirect(
297 &mut self,
298 mut pos: FuncCursor,
299 _table_index: TableIndex,
300 _table: ir::Table,
301 _sig_index: SignatureIndex,
302 sig_ref: ir::SigRef,
303 callee: ir::Value,
304 call_args: &[ir::Value],
305 ) -> WasmResult<ir::Inst> {
306 let vmctx = pos
308 .func
309 .special_param(ir::ArgumentPurpose::VMContext)
310 .expect("Missing vmctx parameter");
311
312 let ptr = self.pointer_type();
316 let callee_offset = if ptr == I32 {
317 pos.ins().imul_imm(callee, 4)
318 } else {
319 let ext = pos.ins().uextend(I64, callee);
320 pos.ins().imul_imm(ext, 4)
321 };
322 let mflags = ir::MemFlags::trusted();
323 let func_ptr = pos.ins().load(ptr, mflags, callee_offset, 0);
324
325 let mut args = ir::ValueList::default();
328 args.push(func_ptr, &mut pos.func.dfg.value_lists);
329 args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
330 args.push(vmctx, &mut pos.func.dfg.value_lists);
331
332 Ok(pos
333 .ins()
334 .CallIndirect(ir::Opcode::CallIndirect, INVALID, sig_ref, args)
335 .0)
336 }
337
338 fn translate_call(
339 &mut self,
340 mut pos: FuncCursor,
341 _callee_index: FuncIndex,
342 callee: ir::FuncRef,
343 call_args: &[ir::Value],
344 ) -> WasmResult<ir::Inst> {
345 let vmctx = pos
347 .func
348 .special_param(ir::ArgumentPurpose::VMContext)
349 .expect("Missing vmctx parameter");
350
351 let mut args = ir::ValueList::default();
354 args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
355 args.push(vmctx, &mut pos.func.dfg.value_lists);
356
357 Ok(pos.ins().Call(ir::Opcode::Call, INVALID, callee, args).0)
358 }
359
360 fn translate_memory_grow(
361 &mut self,
362 mut pos: FuncCursor,
363 _index: MemoryIndex,
364 _heap: ir::Heap,
365 _val: ir::Value,
366 ) -> WasmResult<ir::Value> {
367 Ok(pos.ins().iconst(I32, -1))
368 }
369
370 fn translate_memory_size(
371 &mut self,
372 mut pos: FuncCursor,
373 _index: MemoryIndex,
374 _heap: ir::Heap,
375 ) -> WasmResult<ir::Value> {
376 Ok(pos.ins().iconst(I32, -1))
377 }
378
379 fn translate_memory_copy(
380 &mut self,
381 _pos: FuncCursor,
382 _index: MemoryIndex,
383 _heap: ir::Heap,
384 _dst: ir::Value,
385 _src: ir::Value,
386 _len: ir::Value,
387 ) -> WasmResult<()> {
388 Ok(())
389 }
390
391 fn translate_memory_fill(
392 &mut self,
393 _pos: FuncCursor,
394 _index: MemoryIndex,
395 _heap: ir::Heap,
396 _dst: ir::Value,
397 _val: ir::Value,
398 _len: ir::Value,
399 ) -> WasmResult<()> {
400 Ok(())
401 }
402
403 fn translate_memory_init(
404 &mut self,
405 _pos: FuncCursor,
406 _index: MemoryIndex,
407 _heap: ir::Heap,
408 _seg_index: u32,
409 _dst: ir::Value,
410 _src: ir::Value,
411 _len: ir::Value,
412 ) -> WasmResult<()> {
413 Ok(())
414 }
415
416 fn translate_data_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> {
417 Ok(())
418 }
419
420 fn translate_table_size(
421 &mut self,
422 mut pos: FuncCursor,
423 _index: TableIndex,
424 _table: ir::Table,
425 ) -> WasmResult<ir::Value> {
426 Ok(pos.ins().iconst(I32, -1))
427 }
428
429 fn translate_table_grow(
430 &mut self,
431 mut pos: FuncCursor,
432 _table_index: u32,
433 _delta: ir::Value,
434 _init_value: ir::Value,
435 ) -> WasmResult<ir::Value> {
436 Ok(pos.ins().iconst(I32, -1))
437 }
438
439 fn translate_table_get(
440 &mut self,
441 mut pos: FuncCursor,
442 _table_index: u32,
443 _index: ir::Value,
444 ) -> WasmResult<ir::Value> {
445 Ok(pos.ins().null(self.reference_type()))
446 }
447
448 fn translate_table_set(
449 &mut self,
450 _pos: FuncCursor,
451 _table_index: u32,
452 _value: ir::Value,
453 _index: ir::Value,
454 ) -> WasmResult<()> {
455 Ok(())
456 }
457
458 fn translate_table_copy(
459 &mut self,
460 _pos: FuncCursor,
461 _dst_index: TableIndex,
462 _dst_table: ir::Table,
463 _src_index: TableIndex,
464 _src_table: ir::Table,
465 _dst: ir::Value,
466 _src: ir::Value,
467 _len: ir::Value,
468 ) -> WasmResult<()> {
469 Ok(())
470 }
471
472 fn translate_table_fill(
473 &mut self,
474 _pos: FuncCursor,
475 _table_index: u32,
476 _dst: ir::Value,
477 _val: ir::Value,
478 _len: ir::Value,
479 ) -> WasmResult<()> {
480 Ok(())
481 }
482
483 fn translate_table_init(
484 &mut self,
485 _pos: FuncCursor,
486 _seg_index: u32,
487 _table_index: TableIndex,
488 _table: ir::Table,
489 _dst: ir::Value,
490 _src: ir::Value,
491 _len: ir::Value,
492 ) -> WasmResult<()> {
493 Ok(())
494 }
495
496 fn translate_elem_drop(&mut self, _pos: FuncCursor, _seg_index: u32) -> WasmResult<()> {
497 Ok(())
498 }
499
500 fn translate_ref_func(
501 &mut self,
502 mut pos: FuncCursor,
503 _func_index: u32,
504 ) -> WasmResult<ir::Value> {
505 Ok(pos.ins().null(self.reference_type()))
506 }
507
508 fn translate_custom_global_get(
509 &mut self,
510 mut pos: FuncCursor,
511 _global_index: GlobalIndex,
512 ) -> WasmResult<ir::Value> {
513 Ok(pos.ins().iconst(I32, -1))
514 }
515
516 fn translate_custom_global_set(
517 &mut self,
518 _pos: FuncCursor,
519 _global_index: GlobalIndex,
520 _val: ir::Value,
521 ) -> WasmResult<()> {
522 Ok(())
523 }
524}
525
526impl TargetEnvironment for DummyEnvironment {
527 fn target_config(&self) -> TargetFrontendConfig {
528 self.info.config
529 }
530}
531
532impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
533 fn declare_signature(&mut self, sig: ir::Signature) -> WasmResult<()> {
534 self.info.signatures.push(sig);
535 Ok(())
536 }
537
538 fn declare_func_import(
539 &mut self,
540 sig_index: SignatureIndex,
541 module: &'data str,
542 field: &'data str,
543 ) -> WasmResult<()> {
544 assert_eq!(
545 self.info.functions.len(),
546 self.info.imported_funcs.len(),
547 "Imported functions must be declared first"
548 );
549 self.info.functions.push(Exportable::new(sig_index));
550 self.info
551 .imported_funcs
552 .push((String::from(module), String::from(field)));
553 Ok(())
554 }
555
556 fn declare_func_type(&mut self, sig_index: SignatureIndex) -> WasmResult<()> {
557 self.info.functions.push(Exportable::new(sig_index));
558 Ok(())
559 }
560
561 fn declare_global(&mut self, global: Global) -> WasmResult<()> {
562 self.info.globals.push(Exportable::new(global));
563 Ok(())
564 }
565
566 fn declare_global_import(
567 &mut self,
568 global: Global,
569 module: &'data str,
570 field: &'data str,
571 ) -> WasmResult<()> {
572 self.info.globals.push(Exportable::new(global));
573 self.info
574 .imported_globals
575 .push((String::from(module), String::from(field)));
576 Ok(())
577 }
578
579 fn declare_table(&mut self, table: Table) -> WasmResult<()> {
580 self.info.tables.push(Exportable::new(table));
581 Ok(())
582 }
583
584 fn declare_table_import(
585 &mut self,
586 table: Table,
587 module: &'data str,
588 field: &'data str,
589 ) -> WasmResult<()> {
590 self.info.tables.push(Exportable::new(table));
591 self.info
592 .imported_tables
593 .push((String::from(module), String::from(field)));
594 Ok(())
595 }
596
597 fn declare_table_elements(
598 &mut self,
599 _table_index: TableIndex,
600 _base: Option<GlobalIndex>,
601 _offset: usize,
602 _elements: Box<[FuncIndex]>,
603 ) -> WasmResult<()> {
604 Ok(())
606 }
607
608 fn declare_passive_element(
609 &mut self,
610 _elem_index: PassiveElemIndex,
611 _segments: Box<[FuncIndex]>,
612 ) -> WasmResult<()> {
613 Ok(())
614 }
615
616 fn declare_passive_data(
617 &mut self,
618 _elem_index: PassiveDataIndex,
619 _segments: &'data [u8],
620 ) -> WasmResult<()> {
621 Ok(())
622 }
623
624 fn declare_memory(&mut self, memory: Memory) -> WasmResult<()> {
625 self.info.memories.push(Exportable::new(memory));
626 Ok(())
627 }
628
629 fn declare_memory_import(
630 &mut self,
631 memory: Memory,
632 module: &'data str,
633 field: &'data str,
634 ) -> WasmResult<()> {
635 self.info.memories.push(Exportable::new(memory));
636 self.info
637 .imported_memories
638 .push((String::from(module), String::from(field)));
639 Ok(())
640 }
641
642 fn declare_data_initialization(
643 &mut self,
644 _memory_index: MemoryIndex,
645 _base: Option<GlobalIndex>,
646 _offset: usize,
647 _data: &'data [u8],
648 ) -> WasmResult<()> {
649 Ok(())
651 }
652
653 fn declare_func_export(&mut self, func_index: FuncIndex, name: &'data str) -> WasmResult<()> {
654 self.info.functions[func_index]
655 .export_names
656 .push(String::from(name));
657 Ok(())
658 }
659
660 fn declare_table_export(
661 &mut self,
662 table_index: TableIndex,
663 name: &'data str,
664 ) -> WasmResult<()> {
665 self.info.tables[table_index]
666 .export_names
667 .push(String::from(name));
668 Ok(())
669 }
670
671 fn declare_memory_export(
672 &mut self,
673 memory_index: MemoryIndex,
674 name: &'data str,
675 ) -> WasmResult<()> {
676 self.info.memories[memory_index]
677 .export_names
678 .push(String::from(name));
679 Ok(())
680 }
681
682 fn declare_global_export(
683 &mut self,
684 global_index: GlobalIndex,
685 name: &'data str,
686 ) -> WasmResult<()> {
687 self.info.globals[global_index]
688 .export_names
689 .push(String::from(name));
690 Ok(())
691 }
692
693 fn declare_start_func(&mut self, func_index: FuncIndex) -> WasmResult<()> {
694 debug_assert!(self.info.start_func.is_none());
695 self.info.start_func = Some(func_index);
696 Ok(())
697 }
698
699 fn define_function_body(
700 &mut self,
701 module_translation_state: &ModuleTranslationState,
702 body_bytes: &'data [u8],
703 body_offset: usize,
704 ) -> WasmResult<()> {
705 let func = {
706 let mut func_environ = DummyFuncEnvironment::new(&self.info, self.return_mode);
707 let func_index =
708 FuncIndex::new(self.get_num_func_imports() + self.info.function_bodies.len());
709 let name = get_func_name(func_index);
710 let sig = func_environ.vmctx_sig(self.get_func_type(func_index));
711 let mut func = ir::Function::with_name_signature(name, sig);
712 if self.debug_info {
713 func.collect_debug_info();
714 }
715 self.trans.translate(
716 module_translation_state,
717 body_bytes,
718 body_offset,
719 &mut func,
720 &mut func_environ,
721 )?;
722 func
723 };
724 self.func_bytecode_sizes.push(body_bytes.len());
725 self.info.function_bodies.push(func);
726 Ok(())
727 }
728
729 fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) -> WasmResult<()> {
730 self.function_names[func_index] = String::from(name);
731 Ok(())
732 }
733}