1use crate::{
5 HashMap,
6 abi::{self},
7 heap::{Heap, HeapData, HeapStyle},
8 table::{TableData, TableSize},
9 translator::{EXN_REF_TYPE, LandingPad, TAG_TYPE, materialize_global_value},
10};
11use cranelift_codegen::{
12 cursor::FuncCursor,
13 ir::{
14 self, AbiParam, ArgumentPurpose, BlockArg, Endianness, ExceptionTableData,
15 ExceptionTableItem, ExceptionTag, Function, InstBuilder, MemFlagsData, Signature,
16 UserExternalName,
17 condcodes::IntCC,
18 immediates::{Offset32, Uimm64},
19 types::*,
20 },
21 isa::TargetFrontendConfig,
22};
23use cranelift_frontend::FunctionBuilder;
24use smallvec::SmallVec;
25use std::convert::TryFrom;
26use target_lexicon::Architecture;
27use wasmer_compiler::abi::ReturnAbi;
28use wasmer_compiler::wasmparser::HeapType;
29use wasmer_types::{
30 CompileError, FunctionIndex, GlobalIndex, LocalFunctionIndex, MemoryIndex, MemoryStyle,
31 ModuleInfo, SignatureHash, SignatureIndex, TableIndex, TableStyle, TagIndex,
32 Type as WasmerType, VMBuiltinFunctionIndex, VMOffsets, WasmError, WasmResult,
33 entity::{EntityRef, PrimaryMap, SecondaryMap},
34 vmctx_offset,
35};
36
37fn insert_mem_flags(func: &mut Function, flags: ir::MemFlagsData) -> ir::MemFlags {
38 func.dfg.mem_flags.insert(flags).unwrap()
39}
40
41pub fn get_function_name(func: &mut Function, func_index: FunctionIndex) -> ir::ExternalName {
43 ir::ExternalName::user(
44 func.params
45 .ensure_user_func_name(UserExternalName::new(0, func_index.as_u32())),
46 )
47}
48
49#[allow(unused)]
51pub fn type_of_vmtable_definition_current_elements(vmoffsets: &VMOffsets) -> ir::Type {
52 ir::Type::int(u16::from(vmoffsets.size_of_vmtable_definition_current_elements()) * 8).unwrap()
53}
54
55#[derive(Clone)]
56struct ExceptionFieldLayout {
57 offset: u32,
58 ty: ir::Type,
59}
60
61#[derive(Clone)]
62struct ExceptionTypeLayout {
63 fields: SmallVec<[ExceptionFieldLayout; 4]>,
64}
65
66#[derive(Clone, Copy)]
68pub enum GlobalVariable {
69 #[allow(dead_code)]
70 Const(ir::Value),
72
73 Memory {
75 gv: ir::GlobalValue,
77 offset: Offset32,
79 ty: ir::Type,
81 },
82
83 #[allow(dead_code)]
84 Custom,
86}
87
88pub struct FuncEnvironment<'module_environment> {
90 target_config: TargetFrontendConfig,
92
93 architecture: Architecture,
95
96 return_types: Vec<WasmerType>,
98
99 module: &'module_environment ModuleInfo,
101
102 type_stack: Vec<WasmerType>,
104
105 signatures: &'module_environment PrimaryMap<SignatureIndex, ir::Signature>,
107
108 signature_hashes: &'module_environment PrimaryMap<SignatureIndex, SignatureHash>,
110
111 heaps: PrimaryMap<Heap, HeapData>,
113
114 vmctx: Option<ir::GlobalValue>,
116
117 memory32_size_sig: Option<ir::SigRef>,
120
121 table_size_sig: Option<ir::SigRef>,
124
125 memory_grow_sig: Option<ir::SigRef>,
128
129 table_grow_sig: Option<ir::SigRef>,
132
133 table_copy_sig: Option<ir::SigRef>,
136
137 table_init_sig: Option<ir::SigRef>,
139
140 elem_drop_sig: Option<ir::SigRef>,
142
143 memory_copy_sig: Option<ir::SigRef>,
146
147 memory_fill_sig: Option<ir::SigRef>,
150
151 memory_init_sig: Option<ir::SigRef>,
153
154 data_drop_sig: Option<ir::SigRef>,
156
157 table_get_sig: Option<ir::SigRef>,
159
160 table_set_sig: Option<ir::SigRef>,
162
163 func_ref_sig: Option<ir::SigRef>,
165
166 table_fill_sig: Option<ir::SigRef>,
168
169 memory32_atomic_wait32_sig: Option<ir::SigRef>,
171
172 memory32_atomic_wait64_sig: Option<ir::SigRef>,
174
175 memory32_atomic_notify_sig: Option<ir::SigRef>,
177
178 raise_trap_sig: Option<ir::SigRef>,
180 personality2_sig: Option<ir::SigRef>,
181 throw_sig: Option<ir::SigRef>,
182 alloc_exception_sig: Option<ir::SigRef>,
183 read_exception_sig: Option<ir::SigRef>,
184 read_exnref_sig: Option<ir::SigRef>,
185
186 exception_type_layouts: HashMap<u32, ExceptionTypeLayout>,
188
189 offsets: VMOffsets,
191
192 memory_styles: &'module_environment PrimaryMap<MemoryIndex, MemoryStyle>,
194
195 tables: SecondaryMap<TableIndex, Option<TableData>>,
197
198 table_styles: &'module_environment PrimaryMap<TableIndex, TableStyle>,
199}
200
201impl<'module_environment> FuncEnvironment<'module_environment> {
202 pub fn new(
203 target_config: TargetFrontendConfig,
204 architecture: Architecture,
205 module: &'module_environment ModuleInfo,
206 signatures: &'module_environment PrimaryMap<SignatureIndex, ir::Signature>,
207 signature_hashes: &'module_environment PrimaryMap<SignatureIndex, SignatureHash>,
208 memory_styles: &'module_environment PrimaryMap<MemoryIndex, MemoryStyle>,
209 table_styles: &'module_environment PrimaryMap<TableIndex, TableStyle>,
210 ) -> Result<Self, CompileError> {
211 Ok(Self {
212 target_config,
213 architecture,
214 return_types: Vec::new(),
215 module,
216 signatures,
217 signature_hashes,
218 type_stack: vec![],
219 heaps: PrimaryMap::new(),
220 vmctx: None,
221 memory32_size_sig: None,
222 table_size_sig: None,
223 memory_grow_sig: None,
224 table_grow_sig: None,
225 table_copy_sig: None,
226 table_init_sig: None,
227 elem_drop_sig: None,
228 memory_copy_sig: None,
229 memory_fill_sig: None,
230 memory_init_sig: None,
231 table_get_sig: None,
232 table_set_sig: None,
233 data_drop_sig: None,
234 func_ref_sig: None,
235 table_fill_sig: None,
236 memory32_atomic_wait32_sig: None,
237 memory32_atomic_wait64_sig: None,
238 memory32_atomic_notify_sig: None,
239 raise_trap_sig: None,
240 personality2_sig: None,
241 throw_sig: None,
242 alloc_exception_sig: None,
243 read_exception_sig: None,
244 read_exnref_sig: None,
245 exception_type_layouts: HashMap::new(),
246 offsets: VMOffsets::try_new(target_config.pointer_bytes(), module)
247 .map_err(CompileError::Resource)?,
248 memory_styles,
249 tables: Default::default(),
250 table_styles,
251 })
252 }
253
254 pub(crate) fn target_config(&self) -> TargetFrontendConfig {
255 self.target_config
256 }
257
258 pub(crate) fn pointer_type(&self) -> ir::Type {
259 self.target_config.pointer_type()
260 }
261
262 pub(crate) fn reference_type(&self) -> ir::Type {
263 self.target_config.pointer_type()
264 }
265
266 fn ensure_table_exists(
267 &mut self,
268 func: &mut ir::Function,
269 index: TableIndex,
270 ) -> WasmResult<()> {
271 if self.tables[index].is_some() {
272 return Ok(());
273 }
274
275 let pointer_type = self.pointer_type();
276 let table = &self.module.tables[index];
277
278 let (base_gv, table_base_offset, bound, element_size, inline_anyfunc) =
279 if let Some(def_index) = self.module.local_table_index(index)
280 && table.is_fixed_funcref_table()
281 {
282 (
283 self.vmctx(func),
284 vmctx_offset(
285 self.offsets
286 .vmctx_fixed_funcref_table_anyfuncs(def_index)
287 .expect("fixed funcref table must have inline VMContext storage"),
288 )?,
289 TableSize::Static {
290 bound: table.minimum,
291 },
292 u32::from(self.offsets.size_of_vmcaller_checked_anyfunc()),
293 true,
294 )
295 } else {
296 let (ptr, base_offset, current_elements_offset) = {
297 let vmctx = self.vmctx(func);
298 if let Some(def_index) = self.module.local_table_index(index) {
299 let base_offset =
300 vmctx_offset(self.offsets.vmctx_vmtable_definition_base(def_index))?;
301 let current_elements_offset = vmctx_offset(
302 self.offsets
303 .vmctx_vmtable_definition_current_elements(def_index),
304 )?;
305 (vmctx, base_offset, current_elements_offset)
306 } else {
307 let from_offset = self.offsets.vmctx_vmtable_import(index);
308 let flags = insert_mem_flags(func, MemFlagsData::trusted().with_readonly());
309 let table = func.create_global_value(ir::GlobalValueData::Load {
310 base: vmctx,
311 offset: Offset32::new(vmctx_offset(from_offset)?),
312 global_type: pointer_type,
313 flags,
314 });
315 let base_offset = i32::from(self.offsets.vmtable_definition_base());
316 let current_elements_offset =
317 i32::from(self.offsets.vmtable_definition_current_elements());
318 (table, base_offset, current_elements_offset)
319 }
320 };
321
322 let flags = if Some(table.minimum) == table.maximum {
323 insert_mem_flags(func, MemFlagsData::trusted().with_readonly())
326 } else {
327 insert_mem_flags(func, MemFlagsData::trusted())
328 };
329 let base_gv = func.create_global_value(ir::GlobalValueData::Load {
330 base: ptr,
331 offset: Offset32::new(base_offset),
332 global_type: pointer_type,
333 flags,
334 });
335
336 let bound = if Some(table.minimum) == table.maximum {
337 TableSize::Static {
338 bound: table.minimum,
339 }
340 } else {
341 let flags = insert_mem_flags(func, MemFlagsData::trusted());
342 TableSize::Dynamic {
343 bound_gv: func.create_global_value(ir::GlobalValueData::Load {
344 base: ptr,
345 offset: Offset32::new(current_elements_offset),
346 global_type: ir::Type::int(
347 u16::from(
348 self.offsets.size_of_vmtable_definition_current_elements(),
349 ) * 8,
350 )
351 .unwrap(),
352 flags,
353 }),
354 }
355 };
356
357 (base_gv, 0, bound, self.reference_type().bytes(), false)
358 };
359
360 self.tables[index] = Some(TableData {
361 base_gv,
362 base_offset: table_base_offset,
363 bound,
364 element_size,
365 inline_anyfunc,
366 });
367 Ok(())
368 }
369
370 fn vmctx(&mut self, func: &mut Function) -> ir::GlobalValue {
371 self.vmctx.unwrap_or_else(|| {
372 let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
373 self.vmctx = Some(vmctx);
374 vmctx
375 })
376 }
377
378 fn get_table_fill_sig(&mut self, func: &mut Function) -> ir::SigRef {
379 let sig = self.table_fill_sig.unwrap_or_else(|| {
380 func.import_signature(Signature {
381 params: vec![
382 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
383 AbiParam::new(I32),
385 AbiParam::new(I32),
387 AbiParam::new(self.reference_type()),
389 AbiParam::new(I32),
391 ],
392 returns: vec![],
393 call_conv: self.target_config.default_call_conv,
394 })
395 });
396 self.table_fill_sig = Some(sig);
397 sig
398 }
399
400 fn get_table_fill_func(
401 &mut self,
402 func: &mut Function,
403 table_index: TableIndex,
404 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
405 (
406 self.get_table_fill_sig(func),
407 table_index.index(),
408 VMBuiltinFunctionIndex::get_table_fill_index(),
409 )
410 }
411
412 fn get_func_ref_sig(&mut self, func: &mut Function) -> ir::SigRef {
413 let sig = self.func_ref_sig.unwrap_or_else(|| {
414 func.import_signature(Signature {
415 params: vec![
416 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
417 AbiParam::new(I32),
418 ],
419 returns: vec![AbiParam::new(self.reference_type())],
420 call_conv: self.target_config.default_call_conv,
421 })
422 });
423 self.func_ref_sig = Some(sig);
424 sig
425 }
426
427 fn get_func_ref_func(
428 &mut self,
429 func: &mut Function,
430 function_index: FunctionIndex,
431 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
432 (
433 self.get_func_ref_sig(func),
434 function_index.index(),
435 VMBuiltinFunctionIndex::get_func_ref_index(),
436 )
437 }
438
439 fn get_table_get_sig(&mut self, func: &mut Function) -> ir::SigRef {
440 let sig = self.table_get_sig.unwrap_or_else(|| {
441 func.import_signature(Signature {
442 params: vec![
443 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
444 AbiParam::new(I32),
445 AbiParam::new(I32),
446 ],
447 returns: vec![AbiParam::new(self.reference_type())],
448 call_conv: self.target_config.default_call_conv,
449 })
450 });
451 self.table_get_sig = Some(sig);
452 sig
453 }
454
455 fn get_table_get_func(
456 &mut self,
457 func: &mut Function,
458 table_index: TableIndex,
459 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
460 if self.module.is_imported_table(table_index) {
461 (
462 self.get_table_get_sig(func),
463 table_index.index(),
464 VMBuiltinFunctionIndex::get_imported_table_get_index(),
465 )
466 } else {
467 (
468 self.get_table_get_sig(func),
469 self.module.local_table_index(table_index).unwrap().index(),
470 VMBuiltinFunctionIndex::get_table_get_index(),
471 )
472 }
473 }
474
475 fn get_table_set_sig(&mut self, func: &mut Function) -> ir::SigRef {
476 let sig = self.table_set_sig.unwrap_or_else(|| {
477 func.import_signature(Signature {
478 params: vec![
479 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
480 AbiParam::new(I32),
481 AbiParam::new(I32),
482 AbiParam::new(self.reference_type()),
483 ],
484 returns: vec![],
485 call_conv: self.target_config.default_call_conv,
486 })
487 });
488 self.table_set_sig = Some(sig);
489 sig
490 }
491
492 fn get_table_set_func(
493 &mut self,
494 func: &mut Function,
495 table_index: TableIndex,
496 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
497 if self.module.is_imported_table(table_index) {
498 (
499 self.get_table_set_sig(func),
500 table_index.index(),
501 VMBuiltinFunctionIndex::get_imported_table_set_index(),
502 )
503 } else {
504 (
505 self.get_table_set_sig(func),
506 self.module.local_table_index(table_index).unwrap().index(),
507 VMBuiltinFunctionIndex::get_table_set_index(),
508 )
509 }
510 }
511
512 fn get_table_grow_sig(&mut self, func: &mut Function) -> ir::SigRef {
513 let sig = self.table_grow_sig.unwrap_or_else(|| {
514 func.import_signature(Signature {
515 params: vec![
516 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
517 AbiParam::new(self.reference_type()),
519 AbiParam::new(I32),
520 AbiParam::new(I32),
521 ],
522 returns: vec![AbiParam::new(I32)],
523 call_conv: self.target_config.default_call_conv,
524 })
525 });
526 self.table_grow_sig = Some(sig);
527 sig
528 }
529
530 fn get_table_grow_func(
533 &mut self,
534 func: &mut Function,
535 index: TableIndex,
536 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
537 if self.module.is_imported_table(index) {
538 (
539 self.get_table_grow_sig(func),
540 index.index(),
541 VMBuiltinFunctionIndex::get_imported_table_grow_index(),
542 )
543 } else {
544 (
545 self.get_table_grow_sig(func),
546 self.module.local_table_index(index).unwrap().index(),
547 VMBuiltinFunctionIndex::get_table_grow_index(),
548 )
549 }
550 }
551
552 fn get_memory_grow_sig(&mut self, func: &mut Function) -> ir::SigRef {
553 let sig = self.memory_grow_sig.unwrap_or_else(|| {
554 func.import_signature(Signature {
555 params: vec![
556 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
557 AbiParam::new(I32),
558 AbiParam::new(I32),
559 ],
560 returns: vec![AbiParam::new(I32)],
561 call_conv: self.target_config.default_call_conv,
562 })
563 });
564 self.memory_grow_sig = Some(sig);
565 sig
566 }
567
568 fn get_memory_grow_func(
571 &mut self,
572 func: &mut Function,
573 index: MemoryIndex,
574 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
575 if self.module.is_imported_memory(index) {
576 (
577 self.get_memory_grow_sig(func),
578 index.index(),
579 VMBuiltinFunctionIndex::get_imported_memory32_grow_index(),
580 )
581 } else {
582 (
583 self.get_memory_grow_sig(func),
584 self.module.local_memory_index(index).unwrap().index(),
585 VMBuiltinFunctionIndex::get_memory32_grow_index(),
586 )
587 }
588 }
589
590 fn get_table_size_sig(&mut self, func: &mut Function) -> ir::SigRef {
591 let sig = self.table_size_sig.unwrap_or_else(|| {
592 func.import_signature(Signature {
593 params: vec![
594 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
595 AbiParam::new(I32),
596 ],
597 returns: vec![AbiParam::new(I32)],
598 call_conv: self.target_config.default_call_conv,
599 })
600 });
601 self.table_size_sig = Some(sig);
602 sig
603 }
604
605 fn get_table_size_func(
608 &mut self,
609 func: &mut Function,
610 index: TableIndex,
611 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
612 if self.module.is_imported_table(index) {
613 (
614 self.get_table_size_sig(func),
615 index.index(),
616 VMBuiltinFunctionIndex::get_imported_table_size_index(),
617 )
618 } else {
619 (
620 self.get_table_size_sig(func),
621 self.module.local_table_index(index).unwrap().index(),
622 VMBuiltinFunctionIndex::get_table_size_index(),
623 )
624 }
625 }
626
627 fn get_memory32_size_sig(&mut self, func: &mut Function) -> ir::SigRef {
628 let sig = self.memory32_size_sig.unwrap_or_else(|| {
629 func.import_signature(Signature {
630 params: vec![
631 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
632 AbiParam::new(I32),
633 ],
634 returns: vec![AbiParam::new(I32)],
635 call_conv: self.target_config.default_call_conv,
636 })
637 });
638 self.memory32_size_sig = Some(sig);
639 sig
640 }
641
642 fn get_memory_size_func(
645 &mut self,
646 func: &mut Function,
647 index: MemoryIndex,
648 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
649 if self.module.is_imported_memory(index) {
650 (
651 self.get_memory32_size_sig(func),
652 index.index(),
653 VMBuiltinFunctionIndex::get_imported_memory32_size_index(),
654 )
655 } else {
656 (
657 self.get_memory32_size_sig(func),
658 self.module.local_memory_index(index).unwrap().index(),
659 VMBuiltinFunctionIndex::get_memory32_size_index(),
660 )
661 }
662 }
663
664 fn get_table_copy_sig(&mut self, func: &mut Function) -> ir::SigRef {
665 let sig = self.table_copy_sig.unwrap_or_else(|| {
666 func.import_signature(Signature {
667 params: vec![
668 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
669 AbiParam::new(I32),
671 AbiParam::new(I32),
673 AbiParam::new(I32),
675 AbiParam::new(I32),
677 AbiParam::new(I32),
679 ],
680 returns: vec![],
681 call_conv: self.target_config.default_call_conv,
682 })
683 });
684 self.table_copy_sig = Some(sig);
685 sig
686 }
687
688 fn get_table_copy_func(
689 &mut self,
690 func: &mut Function,
691 dst_table_index: TableIndex,
692 src_table_index: TableIndex,
693 ) -> (ir::SigRef, usize, usize, VMBuiltinFunctionIndex) {
694 let sig = self.get_table_copy_sig(func);
695 (
696 sig,
697 dst_table_index.as_u32() as usize,
698 src_table_index.as_u32() as usize,
699 VMBuiltinFunctionIndex::get_table_copy_index(),
700 )
701 }
702
703 fn get_table_init_sig(&mut self, func: &mut Function) -> ir::SigRef {
704 let sig = self.table_init_sig.unwrap_or_else(|| {
705 func.import_signature(Signature {
706 params: vec![
707 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
708 AbiParam::new(I32),
710 AbiParam::new(I32),
712 AbiParam::new(I32),
714 AbiParam::new(I32),
716 AbiParam::new(I32),
718 ],
719 returns: vec![],
720 call_conv: self.target_config.default_call_conv,
721 })
722 });
723 self.table_init_sig = Some(sig);
724 sig
725 }
726
727 fn get_table_init_func(
728 &mut self,
729 func: &mut Function,
730 table_index: TableIndex,
731 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
732 let sig = self.get_table_init_sig(func);
733 let table_index = table_index.as_u32() as usize;
734 (
735 sig,
736 table_index,
737 VMBuiltinFunctionIndex::get_table_init_index(),
738 )
739 }
740
741 fn get_elem_drop_sig(&mut self, func: &mut Function) -> ir::SigRef {
742 let sig = self.elem_drop_sig.unwrap_or_else(|| {
743 func.import_signature(Signature {
744 params: vec![
745 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
746 AbiParam::new(I32),
748 ],
749 returns: vec![],
750 call_conv: self.target_config.default_call_conv,
751 })
752 });
753 self.elem_drop_sig = Some(sig);
754 sig
755 }
756
757 fn get_elem_drop_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
758 let sig = self.get_elem_drop_sig(func);
759 (sig, VMBuiltinFunctionIndex::get_elem_drop_index())
760 }
761
762 fn get_memory_copy_sig(&mut self, func: &mut Function) -> ir::SigRef {
763 let sig = self.memory_copy_sig.unwrap_or_else(|| {
764 func.import_signature(Signature {
765 params: vec![
766 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
767 AbiParam::new(I32),
769 AbiParam::new(I32),
771 AbiParam::new(I32),
773 AbiParam::new(I32),
775 AbiParam::new(I32),
777 ],
778 returns: vec![],
779 call_conv: self.target_config.default_call_conv,
780 })
781 });
782 self.memory_copy_sig = Some(sig);
783 sig
784 }
785
786 fn get_memory_copy_func(
787 &mut self,
788 func: &mut Function,
789 ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
790 (
791 self.get_memory_copy_sig(func),
792 VMBuiltinFunctionIndex::get_memory_copy_index(),
793 )
794 }
795
796 fn get_memory_fill_sig(&mut self, func: &mut Function) -> ir::SigRef {
797 let sig = self.memory_fill_sig.unwrap_or_else(|| {
798 func.import_signature(Signature {
799 params: vec![
800 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
801 AbiParam::new(I32),
803 AbiParam::new(I32),
805 AbiParam::new(I32),
807 AbiParam::new(I32),
809 ],
810 returns: vec![],
811 call_conv: self.target_config.default_call_conv,
812 })
813 });
814 self.memory_fill_sig = Some(sig);
815 sig
816 }
817
818 fn get_memory_fill_func(
819 &mut self,
820 func: &mut Function,
821 memory_index: MemoryIndex,
822 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
823 let sig = self.get_memory_fill_sig(func);
824 if let Some(local_memory_index) = self.module.local_memory_index(memory_index) {
825 (
826 sig,
827 local_memory_index.index(),
828 VMBuiltinFunctionIndex::get_memory_fill_index(),
829 )
830 } else {
831 (
832 sig,
833 memory_index.index(),
834 VMBuiltinFunctionIndex::get_imported_memory_fill_index(),
835 )
836 }
837 }
838
839 fn get_memory_init_sig(&mut self, func: &mut Function) -> ir::SigRef {
840 let sig = self.memory_init_sig.unwrap_or_else(|| {
841 func.import_signature(Signature {
842 params: vec![
843 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
844 AbiParam::new(I32),
846 AbiParam::new(I32),
848 AbiParam::new(I32),
850 AbiParam::new(I32),
852 AbiParam::new(I32),
854 ],
855 returns: vec![],
856 call_conv: self.target_config.default_call_conv,
857 })
858 });
859 self.memory_init_sig = Some(sig);
860 sig
861 }
862
863 fn get_memory_init_func(
864 &mut self,
865 func: &mut Function,
866 ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
867 let sig = self.get_memory_init_sig(func);
868 (sig, VMBuiltinFunctionIndex::get_memory_init_index())
869 }
870
871 fn get_data_drop_sig(&mut self, func: &mut Function) -> ir::SigRef {
872 let sig = self.data_drop_sig.unwrap_or_else(|| {
873 func.import_signature(Signature {
874 params: vec![
875 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
876 AbiParam::new(I32),
878 ],
879 returns: vec![],
880 call_conv: self.target_config.default_call_conv,
881 })
882 });
883 self.data_drop_sig = Some(sig);
884 sig
885 }
886
887 fn get_data_drop_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
888 let sig = self.get_data_drop_sig(func);
889 (sig, VMBuiltinFunctionIndex::get_data_drop_index())
890 }
891
892 fn get_memory32_atomic_wait32_sig(&mut self, func: &mut Function) -> ir::SigRef {
893 let sig = self.memory32_atomic_wait32_sig.unwrap_or_else(|| {
894 func.import_signature(Signature {
895 params: vec![
896 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
897 AbiParam::new(I32),
899 AbiParam::new(I32),
901 AbiParam::new(I32),
903 AbiParam::new(I64),
905 ],
906 returns: vec![AbiParam::new(I32)],
907 call_conv: self.target_config.default_call_conv,
908 })
909 });
910 self.memory32_atomic_wait32_sig = Some(sig);
911 sig
912 }
913
914 fn get_memory_atomic_wait32_func(
918 &mut self,
919 func: &mut Function,
920 index: MemoryIndex,
921 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
922 if self.module.is_imported_memory(index) {
923 (
924 self.get_memory32_atomic_wait32_sig(func),
925 index.index(),
926 VMBuiltinFunctionIndex::get_imported_memory_atomic_wait32_index(),
927 )
928 } else {
929 (
930 self.get_memory32_atomic_wait32_sig(func),
931 self.module.local_memory_index(index).unwrap().index(),
932 VMBuiltinFunctionIndex::get_memory_atomic_wait32_index(),
933 )
934 }
935 }
936
937 fn get_memory32_atomic_wait64_sig(&mut self, func: &mut Function) -> ir::SigRef {
938 let sig = self.memory32_atomic_wait64_sig.unwrap_or_else(|| {
939 func.import_signature(Signature {
940 params: vec![
941 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
942 AbiParam::new(I32),
944 AbiParam::new(I32),
946 AbiParam::new(I64),
948 AbiParam::new(I64),
950 ],
951 returns: vec![AbiParam::new(I32)],
952 call_conv: self.target_config.default_call_conv,
953 })
954 });
955 self.memory32_atomic_wait64_sig = Some(sig);
956 sig
957 }
958
959 fn get_memory_atomic_wait64_func(
963 &mut self,
964 func: &mut Function,
965 index: MemoryIndex,
966 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
967 if self.module.is_imported_memory(index) {
968 (
969 self.get_memory32_atomic_wait64_sig(func),
970 index.index(),
971 VMBuiltinFunctionIndex::get_imported_memory_atomic_wait64_index(),
972 )
973 } else {
974 (
975 self.get_memory32_atomic_wait64_sig(func),
976 self.module.local_memory_index(index).unwrap().index(),
977 VMBuiltinFunctionIndex::get_memory_atomic_wait64_index(),
978 )
979 }
980 }
981
982 fn get_memory32_atomic_notify_sig(&mut self, func: &mut Function) -> ir::SigRef {
983 let sig = self.memory32_atomic_notify_sig.unwrap_or_else(|| {
984 func.import_signature(Signature {
985 params: vec![
986 AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext),
987 AbiParam::new(I32),
989 AbiParam::new(I32),
991 AbiParam::new(I32),
993 ],
994 returns: vec![AbiParam::new(I32)],
995 call_conv: self.target_config.default_call_conv,
996 })
997 });
998 self.memory32_atomic_notify_sig = Some(sig);
999 sig
1000 }
1001
1002 fn get_memory_atomic_notify_func(
1006 &mut self,
1007 func: &mut Function,
1008 index: MemoryIndex,
1009 ) -> (ir::SigRef, usize, VMBuiltinFunctionIndex) {
1010 if self.module.is_imported_memory(index) {
1011 (
1012 self.get_memory32_atomic_notify_sig(func),
1013 index.index(),
1014 VMBuiltinFunctionIndex::get_imported_memory_atomic_notify_index(),
1015 )
1016 } else {
1017 (
1018 self.get_memory32_atomic_notify_sig(func),
1019 self.module.local_memory_index(index).unwrap().index(),
1020 VMBuiltinFunctionIndex::get_memory_atomic_notify_index(),
1021 )
1022 }
1023 }
1024
1025 fn get_personality2_func(
1026 &mut self,
1027 func: &mut Function,
1028 ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1029 let sig = self.personality2_sig.unwrap_or_else(|| {
1030 let mut signature = Signature::new(self.target_config.default_call_conv);
1031 signature.params.push(AbiParam::new(self.pointer_type()));
1032 signature.params.push(AbiParam::new(self.pointer_type()));
1033 signature.returns.push(AbiParam::new(TAG_TYPE));
1034 let sig = func.import_signature(signature);
1035 self.personality2_sig = Some(sig);
1036 sig
1037 });
1038 (
1039 sig,
1040 VMBuiltinFunctionIndex::get_imported_personality2_index(),
1041 )
1042 }
1043
1044 fn get_throw_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1045 let sig = self.throw_sig.unwrap_or_else(|| {
1046 let mut signature = Signature::new(self.target_config.default_call_conv);
1047 signature.params.push(AbiParam::special(
1048 self.pointer_type(),
1049 ArgumentPurpose::VMContext,
1050 ));
1051 signature.params.push(AbiParam::new(EXN_REF_TYPE));
1052 let sig = func.import_signature(signature);
1053 self.throw_sig = Some(sig);
1054 sig
1055 });
1056 (sig, VMBuiltinFunctionIndex::get_imported_throw_index())
1057 }
1058
1059 fn get_raise_trap_func(&mut self, func: &mut Function) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1060 let sig = self.raise_trap_sig.unwrap_or_else(|| {
1061 let mut signature = Signature::new(self.target_config.default_call_conv);
1062 signature.params.push(AbiParam::new(I32));
1063 let sig = func.import_signature(signature);
1064 self.raise_trap_sig = Some(sig);
1065 sig
1066 });
1067 (sig, VMBuiltinFunctionIndex::get_raise_trap_index())
1068 }
1069
1070 fn get_alloc_exception_func(
1071 &mut self,
1072 func: &mut Function,
1073 ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1074 let sig = self.alloc_exception_sig.unwrap_or_else(|| {
1075 let mut signature = Signature::new(self.target_config.default_call_conv);
1076 signature.params.push(AbiParam::special(
1077 self.pointer_type(),
1078 ArgumentPurpose::VMContext,
1079 ));
1080 signature.params.push(AbiParam::new(TAG_TYPE));
1081 signature.returns.push(AbiParam::new(EXN_REF_TYPE));
1082 let sig = func.import_signature(signature);
1083 self.alloc_exception_sig = Some(sig);
1084 sig
1085 });
1086 (
1087 sig,
1088 VMBuiltinFunctionIndex::get_imported_alloc_exception_index(),
1089 )
1090 }
1091
1092 fn get_read_exnref_func(
1093 &mut self,
1094 func: &mut Function,
1095 ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1096 let sig = self.read_exnref_sig.unwrap_or_else(|| {
1097 let mut signature = Signature::new(self.target_config.default_call_conv);
1098 signature.params.push(AbiParam::special(
1099 self.pointer_type(),
1100 ArgumentPurpose::VMContext,
1101 ));
1102 signature.params.push(AbiParam::new(EXN_REF_TYPE));
1103 signature.returns.push(AbiParam::new(self.pointer_type()));
1104 let sig = func.import_signature(signature);
1105 self.read_exnref_sig = Some(sig);
1106 sig
1107 });
1108 (
1109 sig,
1110 VMBuiltinFunctionIndex::get_imported_read_exnref_index(),
1111 )
1112 }
1113
1114 fn get_read_exception_func(
1115 &mut self,
1116 func: &mut Function,
1117 ) -> (ir::SigRef, VMBuiltinFunctionIndex) {
1118 let sig = self.read_exception_sig.unwrap_or_else(|| {
1119 let mut signature = Signature::new(self.target_config.default_call_conv);
1120 signature.params.push(AbiParam::new(self.pointer_type()));
1121 signature.returns.push(AbiParam::new(EXN_REF_TYPE));
1122 let sig = func.import_signature(signature);
1123 self.read_exception_sig = Some(sig);
1124 sig
1125 });
1126 (
1127 sig,
1128 VMBuiltinFunctionIndex::get_imported_exception_into_exnref_index(),
1129 )
1130 }
1131
1132 fn exception_type_layout(&mut self, tag_index: TagIndex) -> WasmResult<&ExceptionTypeLayout> {
1133 let key = tag_index.as_u32();
1134 if !self.exception_type_layouts.contains_key(&key) {
1135 let layout = self.compute_exception_type_layout(tag_index)?;
1136 self.exception_type_layouts.insert(key, layout);
1137 }
1138 Ok(self.exception_type_layouts.get(&key).unwrap())
1139 }
1140
1141 fn compute_exception_type_layout(
1142 &self,
1143 tag_index: TagIndex,
1144 ) -> WasmResult<ExceptionTypeLayout> {
1145 let sig_index = self.module.tags[tag_index];
1146 let func_type = &self.module.signatures[sig_index];
1147 let mut offset = 0u32;
1148 let mut max_align = 1u32;
1149 let mut fields = SmallVec::<[ExceptionFieldLayout; 4]>::new();
1150
1151 for wasm_ty in func_type.params() {
1152 let ir_ty = self.map_wasmer_type_to_ir(*wasm_ty)?;
1153 let field_size = ir_ty.bytes();
1154 let align = field_size.max(1);
1155 max_align = max_align.max(align);
1156 offset = offset.next_multiple_of(align);
1157 fields.push(ExceptionFieldLayout { offset, ty: ir_ty });
1158 offset = offset
1159 .checked_add(field_size)
1160 .ok_or_else(|| WasmError::Unsupported("exception payload too large".to_string()))?;
1161 }
1162
1163 Ok(ExceptionTypeLayout { fields })
1164 }
1165
1166 fn map_wasmer_type_to_ir(&self, ty: WasmerType) -> WasmResult<ir::Type> {
1167 Ok(match ty {
1168 WasmerType::I32 => ir::types::I32,
1169 WasmerType::I64 => ir::types::I64,
1170 WasmerType::F32 => ir::types::F32,
1171 WasmerType::F64 => ir::types::F64,
1172 WasmerType::V128 => ir::types::I8X16,
1173 WasmerType::FuncRef | WasmerType::ExternRef => self.reference_type(),
1174 WasmerType::ExceptionRef => EXN_REF_TYPE,
1175 })
1176 }
1177
1178 fn call_with_handlers(
1179 &mut self,
1180 builder: &mut FunctionBuilder,
1181 callee: ir::FuncRef,
1182 args: &[ir::Value],
1183 context: Option<ir::Value>,
1184 landing_pad: Option<LandingPad>,
1185 unreachable_on_return: bool,
1186 ) -> SmallVec<[ir::Value; 4]> {
1187 let sig_ref = builder.func.dfg.ext_funcs[callee].signature;
1188 let return_types: SmallVec<[ir::Type; 4]> = builder.func.dfg.signatures[sig_ref]
1189 .returns
1190 .iter()
1191 .map(|ret| ret.value_type)
1192 .collect();
1193
1194 if landing_pad.is_none() {
1195 let inst = builder.ins().call(callee, args);
1196 let results: SmallVec<[ir::Value; 4]> =
1197 builder.inst_results(inst).iter().copied().collect();
1198 if unreachable_on_return {
1199 builder.ins().trap(crate::TRAP_UNREACHABLE);
1200 }
1201 return results;
1202 }
1203
1204 let continuation = builder.create_block();
1205 let mut normal_args = SmallVec::<[BlockArg; 4]>::with_capacity(return_types.len());
1206 let mut result_values = SmallVec::<[ir::Value; 4]>::with_capacity(return_types.len());
1207 for (i, ty) in return_types.iter().enumerate() {
1208 let val = builder.append_block_param(continuation, *ty);
1209 result_values.push(val);
1210 normal_args.push(BlockArg::TryCallRet(u32::try_from(i).unwrap()));
1211 }
1212 let continuation_call = builder
1213 .func
1214 .dfg
1215 .block_call(continuation, normal_args.iter());
1216
1217 let mut table_items = Vec::new();
1218 if let Some(ctx) = context {
1219 table_items.push(ExceptionTableItem::Context(ctx));
1220 }
1221 if let Some(landing_pad) = landing_pad {
1222 for tag in landing_pad.clauses {
1223 let block_call = builder.func.dfg.block_call(
1224 landing_pad.block,
1225 &[BlockArg::TryCallExn(0), BlockArg::TryCallExn(1)],
1226 );
1227 table_items.push(match tag.wasm_tag {
1228 Some(tag) => ExceptionTableItem::Tag(ExceptionTag::from_u32(tag), block_call),
1229 None => ExceptionTableItem::Default(block_call),
1230 });
1231 }
1232 }
1233 let etd = ExceptionTableData::new(sig_ref, continuation_call, table_items);
1234 let et = builder.func.dfg.exception_tables.push(etd);
1235 builder.ins().try_call(callee, args, et);
1236 builder.switch_to_block(continuation);
1237 builder.seal_block(continuation);
1238 if unreachable_on_return {
1239 builder.ins().trap(crate::TRAP_UNREACHABLE);
1240 }
1241 result_values
1242 }
1243
1244 #[allow(clippy::too_many_arguments)]
1245 fn call_indirect_with_handlers(
1246 &mut self,
1247 builder: &mut FunctionBuilder,
1248 sig: ir::SigRef,
1249 func_addr: ir::Value,
1250 args: &[ir::Value],
1251 context: Option<ir::Value>,
1252 landing_pad: Option<LandingPad>,
1253 unreachable_on_return: bool,
1254 ) -> SmallVec<[ir::Value; 4]> {
1255 let return_types: SmallVec<[ir::Type; 4]> = builder.func.dfg.signatures[sig]
1256 .returns
1257 .iter()
1258 .map(|ret| ret.value_type)
1259 .collect();
1260
1261 if landing_pad.is_none() {
1262 let inst = builder.ins().call_indirect(sig, func_addr, args);
1263 let results: SmallVec<[ir::Value; 4]> =
1264 builder.inst_results(inst).iter().copied().collect();
1265 if unreachable_on_return {
1266 builder.ins().trap(crate::TRAP_UNREACHABLE);
1267 }
1268 return results;
1269 }
1270
1271 let continuation = builder.create_block();
1272 let current_block = builder.current_block().expect("current block");
1273 builder.insert_block_after(continuation, current_block);
1274
1275 let mut normal_args = SmallVec::<[BlockArg; 4]>::with_capacity(return_types.len());
1276 let mut result_values = SmallVec::<[ir::Value; 4]>::with_capacity(return_types.len());
1277 for (i, ty) in return_types.iter().enumerate() {
1278 let val = builder.append_block_param(continuation, *ty);
1279 result_values.push(val);
1280 normal_args.push(BlockArg::TryCallRet(u32::try_from(i).unwrap()));
1281 }
1282 let continuation_call = builder
1283 .func
1284 .dfg
1285 .block_call(continuation, normal_args.iter());
1286
1287 let mut table_items = Vec::new();
1288 if let Some(ctx) = context {
1289 table_items.push(ExceptionTableItem::Context(ctx));
1290 }
1291 if let Some(landing_pad) = landing_pad {
1292 for tag in landing_pad.clauses {
1293 let block_call = builder.func.dfg.block_call(
1294 landing_pad.block,
1295 &[BlockArg::TryCallExn(0), BlockArg::TryCallExn(1)],
1296 );
1297 table_items.push(match tag.wasm_tag {
1298 Some(tag) => ExceptionTableItem::Tag(ExceptionTag::from_u32(tag), block_call),
1299 None => ExceptionTableItem::Default(block_call),
1300 });
1301 }
1302 }
1303
1304 let etd = ExceptionTableData::new(sig, continuation_call, table_items);
1305 let et = builder.func.dfg.exception_tables.push(etd);
1306 builder.ins().try_call_indirect(func_addr, args, et);
1307 builder.switch_to_block(continuation);
1308 builder.seal_block(continuation);
1309 if unreachable_on_return {
1310 builder.ins().trap(crate::TRAP_UNREACHABLE);
1311 }
1312
1313 result_values
1314 }
1315
1316 fn translate_load_builtin_function_address(
1319 &mut self,
1320 pos: &mut FuncCursor<'_>,
1321 callee_func_idx: VMBuiltinFunctionIndex,
1322 ) -> WasmResult<(ir::Value, ir::Value)> {
1323 let pointer_type = self.pointer_type();
1325 let vmctx = self.vmctx(pos.func);
1326 let base = materialize_global_value(pos, pointer_type, vmctx);
1327
1328 let mut mem_flags = ir::MemFlagsData::trusted();
1329 mem_flags.set_readonly();
1330
1331 let body_offset = vmctx_offset(self.offsets.vmctx_builtin_function(callee_func_idx))?;
1333 let func_addr = pos.ins().load(pointer_type, mem_flags, base, body_offset);
1334
1335 Ok((base, func_addr))
1336 }
1337
1338 fn get_or_init_funcref_table_elem(
1339 &mut self,
1340 builder: &mut FunctionBuilder,
1341 table_index: TableIndex,
1342 index: ir::Value,
1343 ) -> WasmResult<(ir::Value, bool)> {
1344 let pointer_type = self.pointer_type();
1345 self.ensure_table_exists(builder.func, table_index)?;
1346 let table_data = self.tables[table_index].as_ref().unwrap();
1347
1348 let (table_entry_addr, flags) =
1349 table_data.prepare_table_addr(builder, index, pointer_type, false);
1350 Ok(if table_data.inline_anyfunc {
1351 (table_entry_addr, true)
1352 } else {
1353 (
1354 builder.ins().load(pointer_type, flags, table_entry_addr, 0),
1355 false,
1356 )
1357 })
1358 }
1359}
1360
1361impl FuncEnvironment<'_> {
1362 pub(crate) fn is_wasm_parameter(&self, signature: &ir::Signature, index: usize) -> bool {
1363 signature.params[index].purpose == ArgumentPurpose::Normal
1364 }
1365
1366 pub(crate) fn translate_unreachable(
1367 &mut self,
1368 builder: &mut FunctionBuilder,
1369 ) -> WasmResult<()> {
1370 let (func_sig, func_idx) = self.get_raise_trap_func(builder.func);
1371 let mut pos = builder.cursor();
1372 let (_, func_addr) = self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1373 let trap_code = pos
1374 .ins()
1375 .iconst(I32, wasmer_types::TrapCode::UnreachableCodeReached as i64);
1376 builder
1377 .ins()
1378 .call_indirect(func_sig, func_addr, &[trap_code]);
1379 builder.ins().trap(crate::TRAP_UNREACHABLE);
1382 Ok(())
1383 }
1384
1385 pub(crate) fn translate_table_grow(
1386 &mut self,
1387 mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
1388 table_index: TableIndex,
1389 delta: ir::Value,
1390 init_value: ir::Value,
1391 ) -> WasmResult<ir::Value> {
1392 self.ensure_table_exists(pos.func, table_index)?;
1393 let (func_sig, index_arg, func_idx) = self.get_table_grow_func(pos.func, table_index);
1394 let table_index = pos.ins().iconst(I32, index_arg as i64);
1395 let (vmctx, func_addr) =
1396 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1397 let call_inst = pos.ins().call_indirect(
1398 func_sig,
1399 func_addr,
1400 &[vmctx, init_value, delta, table_index],
1401 );
1402 Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
1403 }
1404
1405 pub(crate) fn translate_table_get(
1406 &mut self,
1407 builder: &mut FunctionBuilder,
1408 table_index: TableIndex,
1409 index: ir::Value,
1410 ) -> WasmResult<ir::Value> {
1411 self.ensure_table_exists(builder.func, table_index)?;
1412 let mut pos = builder.cursor();
1413
1414 let (func_sig, table_index_arg, func_idx) = self.get_table_get_func(pos.func, table_index);
1415 let table_index = pos.ins().iconst(I32, table_index_arg as i64);
1416 let (vmctx, func_addr) =
1417 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1418 let call_inst = pos
1419 .ins()
1420 .call_indirect(func_sig, func_addr, &[vmctx, table_index, index]);
1421 Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
1422 }
1423
1424 pub(crate) fn translate_table_set(
1425 &mut self,
1426 builder: &mut FunctionBuilder,
1427 table_index: TableIndex,
1428 value: ir::Value,
1429 index: ir::Value,
1430 ) -> WasmResult<()> {
1431 self.ensure_table_exists(builder.func, table_index)?;
1432 let mut pos = builder.cursor();
1433
1434 let (func_sig, table_index_arg, func_idx) = self.get_table_set_func(pos.func, table_index);
1435 let n_table_index = pos.ins().iconst(I32, table_index_arg as i64);
1436 let (vmctx, func_addr) =
1437 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1438 pos.ins()
1439 .call_indirect(func_sig, func_addr, &[vmctx, n_table_index, index, value]);
1440 Ok(())
1441 }
1442
1443 pub(crate) fn translate_table_fill(
1444 &mut self,
1445 mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
1446 table_index: TableIndex,
1447 dst: ir::Value,
1448 val: ir::Value,
1449 len: ir::Value,
1450 ) -> WasmResult<()> {
1451 self.ensure_table_exists(pos.func, table_index)?;
1452 let (func_sig, table_index_arg, func_idx) = self.get_table_fill_func(pos.func, table_index);
1453 let (vmctx, func_addr) =
1454 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1455
1456 let table_index_arg = pos.ins().iconst(I32, table_index_arg as i64);
1457 pos.ins().call_indirect(
1458 func_sig,
1459 func_addr,
1460 &[vmctx, table_index_arg, dst, val, len],
1461 );
1462
1463 Ok(())
1464 }
1465
1466 pub(crate) fn translate_ref_null(
1467 &mut self,
1468 mut pos: cranelift_codegen::cursor::FuncCursor,
1469 ty: HeapType,
1470 ) -> WasmResult<ir::Value> {
1471 Ok(match ty {
1472 HeapType::Abstract { ty, .. } => match ty {
1473 wasmer_compiler::wasmparser::AbstractHeapType::Func
1474 | wasmer_compiler::wasmparser::AbstractHeapType::Extern
1475 | wasmer_compiler::wasmparser::AbstractHeapType::Exn => pos.ins().iconst(
1476 if matches!(ty, wasmer_compiler::wasmparser::AbstractHeapType::Exn) {
1477 I32
1478 } else {
1479 self.reference_type()
1480 },
1481 0,
1482 ),
1483 _ => {
1484 return Err(WasmError::Unsupported(format!(
1485 "`ref.null T` that is not a `funcref`, an `externref` or an `exn`: {ty:?}"
1486 )));
1487 }
1488 },
1489 HeapType::Concrete(_) => {
1490 return Err(WasmError::Unsupported(
1491 "`ref.null T` that is not a `funcref` or an `externref`".into(),
1492 ));
1493 }
1494 HeapType::Exact(_) => {
1495 return Err(WasmError::Unsupported(
1496 "custom-descriptors not supported yet".into(),
1497 ));
1498 }
1499 })
1500 }
1501
1502 pub(crate) fn translate_ref_is_null(
1503 &mut self,
1504 mut pos: cranelift_codegen::cursor::FuncCursor,
1505 value: ir::Value,
1506 ) -> WasmResult<ir::Value> {
1507 let bool_is_null =
1508 pos.ins()
1509 .icmp_imm_s(cranelift_codegen::ir::condcodes::IntCC::Equal, value, 0);
1510 Ok(pos.ins().uextend(ir::types::I32, bool_is_null))
1511 }
1512
1513 pub(crate) fn translate_ref_func(
1514 &mut self,
1515 mut pos: cranelift_codegen::cursor::FuncCursor<'_>,
1516 func_index: FunctionIndex,
1517 ) -> WasmResult<ir::Value> {
1518 let (func_sig, func_index_arg, func_idx) = self.get_func_ref_func(pos.func, func_index);
1519 let (vmctx, func_addr) =
1520 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
1521
1522 let func_index_arg = pos.ins().iconst(I32, func_index_arg as i64);
1523 let call_inst = pos
1524 .ins()
1525 .call_indirect(func_sig, func_addr, &[vmctx, func_index_arg]);
1526
1527 Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
1528 }
1529
1530 pub(crate) fn translate_custom_global_get(
1531 &mut self,
1532 mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
1533 _index: GlobalIndex,
1534 ) -> WasmResult<ir::Value> {
1535 unreachable!("we don't make any custom globals")
1536 }
1537
1538 pub(crate) fn translate_custom_global_set(
1539 &mut self,
1540 mut _pos: cranelift_codegen::cursor::FuncCursor<'_>,
1541 _index: GlobalIndex,
1542 _value: ir::Value,
1543 ) -> WasmResult<()> {
1544 unreachable!("we don't make any custom globals")
1545 }
1546
1547 pub(crate) fn make_heap(
1548 &mut self,
1549 func: &mut ir::Function,
1550 index: MemoryIndex,
1551 ) -> WasmResult<Heap> {
1552 let pointer_type = self.pointer_type();
1553
1554 let (ptr, base_offset, current_length_offset) = {
1555 let vmctx = self.vmctx(func);
1556 if let Some(def_index) = self.module.local_memory_index(index) {
1557 let base_offset =
1558 vmctx_offset(self.offsets.vmctx_vmmemory_definition_base(def_index))?;
1559 let current_length_offset = vmctx_offset(
1560 self.offsets
1561 .vmctx_vmmemory_definition_current_length(def_index),
1562 )?;
1563 (vmctx, base_offset, current_length_offset)
1564 } else {
1565 let from_offset = self.offsets.vmctx_vmmemory_import_definition(index);
1566 let flags = insert_mem_flags(func, ir::MemFlagsData::trusted().with_readonly());
1567 let memory = func.create_global_value(ir::GlobalValueData::Load {
1568 base: vmctx,
1569 offset: Offset32::new(vmctx_offset(from_offset)?),
1570 global_type: pointer_type,
1571 flags,
1572 });
1573 let base_offset = i32::from(self.offsets.vmmemory_definition_base());
1574 let current_length_offset =
1575 i32::from(self.offsets.vmmemory_definition_current_length());
1576 (memory, base_offset, current_length_offset)
1577 }
1578 };
1579
1580 let (offset_guard_size, heap_style, readonly_base) = match self.memory_styles[index] {
1583 MemoryStyle::Dynamic { offset_guard_size } => {
1584 let flags = insert_mem_flags(func, ir::MemFlagsData::trusted());
1585 let heap_bound = func.create_global_value(ir::GlobalValueData::Load {
1586 base: ptr,
1587 offset: Offset32::new(current_length_offset),
1588 global_type: pointer_type,
1589 flags,
1590 });
1591 (
1592 Uimm64::new(offset_guard_size),
1593 HeapStyle::Dynamic {
1594 bound_gv: heap_bound,
1595 },
1596 false,
1597 )
1598 }
1599 MemoryStyle::Static => (
1600 Uimm64::new(MemoryStyle::static_offset_guard_size()),
1601 HeapStyle::Static,
1602 true,
1603 ),
1604 };
1605
1606 let flags = if readonly_base {
1607 insert_mem_flags(func, ir::MemFlagsData::trusted().with_readonly())
1608 } else {
1609 insert_mem_flags(func, ir::MemFlagsData::trusted())
1610 };
1611 let heap_base = func.create_global_value(ir::GlobalValueData::Load {
1612 base: ptr,
1613 offset: Offset32::new(base_offset),
1614 global_type: pointer_type,
1615 flags,
1616 });
1617 Ok(self.heaps.push(HeapData {
1618 base: heap_base,
1619 min_size: 0,
1620 max_size: None,
1621 offset_guard_size: offset_guard_size.into(),
1622 style: heap_style,
1623 index_type: I32,
1624 page_size_log2: self.target_config.page_size_align_log2,
1625 }))
1626 }
1627
1628 pub(crate) fn make_global(
1629 &mut self,
1630 func: &mut ir::Function,
1631 index: GlobalIndex,
1632 ) -> WasmResult<GlobalVariable> {
1633 let pointer_type = self.pointer_type();
1634
1635 let (ptr, offset) = {
1636 let vmctx = self.vmctx(func);
1637
1638 if let Some(def_index) = self.module.local_global_index(index) {
1639 let from_offset = self.offsets.vmctx_vmglobal_definition(def_index);
1640 let global = func.create_global_value(ir::GlobalValueData::VMContext);
1641 (global, vmctx_offset(from_offset)?)
1642 } else {
1643 let from_offset = self.offsets.vmctx_vmglobal_import_definition(index);
1644 let flags = insert_mem_flags(func, MemFlagsData::trusted());
1645 let global = func.create_global_value(ir::GlobalValueData::Load {
1646 base: vmctx,
1647 offset: Offset32::new(vmctx_offset(from_offset)?),
1648 global_type: pointer_type,
1649 flags,
1650 });
1651 (global, 0)
1652 }
1653 };
1654
1655 Ok(GlobalVariable::Memory {
1656 gv: ptr,
1657 offset: offset.into(),
1658 ty: match self.module.globals[index].ty {
1659 WasmerType::I32 => ir::types::I32,
1660 WasmerType::I64 => ir::types::I64,
1661 WasmerType::F32 => ir::types::F32,
1662 WasmerType::F64 => ir::types::F64,
1663 WasmerType::V128 => ir::types::I8X16,
1664 WasmerType::FuncRef | WasmerType::ExternRef => self.reference_type(),
1665 WasmerType::ExceptionRef => EXN_REF_TYPE,
1666 },
1667 })
1668 }
1669
1670 pub(crate) fn make_indirect_sig(
1671 &mut self,
1672 func: &mut ir::Function,
1673 index: SignatureIndex,
1674 ) -> WasmResult<ir::SigRef> {
1675 Ok(func.import_signature(self.signatures[index].clone()))
1676 }
1677
1678 pub(crate) fn make_direct_func(
1679 &mut self,
1680 func: &mut ir::Function,
1681 index: FunctionIndex,
1682 ) -> WasmResult<ir::FuncRef> {
1683 let sigidx = self.module.functions[index];
1684 let signature = func.import_signature(self.signatures[sigidx].clone());
1685 let name = get_function_name(func, index);
1686
1687 Ok(func.import_function(ir::ExtFuncData {
1688 name,
1689 signature,
1690 colocated: true,
1691 patchable: false,
1692 }))
1693 }
1694
1695 fn prepare_wasm_call(
1696 &self,
1697 builder: &mut FunctionBuilder,
1698 result_types: &[WasmerType],
1699 ) -> (ReturnAbi, Option<(ir::Value, abi::ReturnAreaLayout)>) {
1700 let return_abi = abi::classify_returns(self.architecture, result_types);
1701 let sret = match &return_abi {
1702 ReturnAbi::Sret(types) => Some(abi::allocate_return_area(
1703 builder,
1704 types,
1705 self.target_config,
1706 )),
1707 _ => None,
1708 };
1709 (return_abi, sret)
1710 }
1711
1712 fn finish_wasm_call(
1713 &self,
1714 builder: &mut FunctionBuilder,
1715 return_abi: &ReturnAbi,
1716 carriers: &[ir::Value],
1717 sret: Option<(ir::Value, abi::ReturnAreaLayout)>,
1718 ) -> SmallVec<[ir::Value; 4]> {
1719 match return_abi {
1720 ReturnAbi::Sret(types) => {
1721 let (ptr, layout) = sret.expect("sret call has a return area");
1722 abi::load_sret(builder, ptr, &layout, types, self.target_config)
1723 }
1724 _ => abi::unpack_register_returns(builder, return_abi, carriers, self.target_config),
1725 }
1726 }
1727
1728 #[allow(clippy::too_many_arguments)]
1729 pub(crate) fn translate_call_indirect(
1730 &mut self,
1731 builder: &mut FunctionBuilder,
1732 table_index: TableIndex,
1733 sig_index: SignatureIndex,
1734 sig_ref: ir::SigRef,
1735 callee: ir::Value,
1736 call_args: &[ir::Value],
1737 landing_pad: Option<LandingPad>,
1738 ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1739 let pointer_type = self.pointer_type();
1740
1741 let (anyfunc_ptr, inline_anyfunc) =
1743 self.get_or_init_funcref_table_elem(builder, table_index, callee)?;
1744
1745 let mem_flags = ir::MemFlagsData::trusted();
1747
1748 if !inline_anyfunc {
1750 builder
1751 .ins()
1752 .trapz(anyfunc_ptr, crate::TRAP_INDIRECT_CALL_TO_NULL);
1753 }
1754
1755 let func_addr = builder.ins().load(
1756 pointer_type,
1757 mem_flags,
1758 anyfunc_ptr,
1759 i32::from(self.offsets.vmcaller_checked_anyfunc_func_ptr()),
1760 );
1761
1762 if inline_anyfunc {
1763 builder
1764 .ins()
1765 .trapz(func_addr, crate::TRAP_INDIRECT_CALL_TO_NULL);
1766 }
1767
1768 match self.table_styles[table_index] {
1770 TableStyle::CallerChecksSignature => {
1771 let sig_hash_type = ir::types::I32;
1772 let expected_sig_hash = builder.ins().iconst(
1773 sig_hash_type,
1774 i64::from(self.signature_hashes[sig_index].as_u32()),
1775 );
1776
1777 let mem_flags = ir::MemFlagsData::trusted();
1779 let callee_sig_hash = builder.ins().load(
1780 sig_hash_type,
1781 mem_flags,
1782 anyfunc_ptr,
1783 i32::from(self.offsets.vmcaller_checked_anyfunc_signature_hash()),
1784 );
1785
1786 let cmp = builder
1788 .ins()
1789 .icmp(IntCC::Equal, callee_sig_hash, expected_sig_hash);
1790 builder.ins().trapz(cmp, crate::TRAP_BAD_SIGNATURE);
1791 }
1792 }
1793
1794 let (return_abi, sret) =
1795 self.prepare_wasm_call(builder, self.module.signatures[sig_index].results());
1796 let mut real_call_args = Vec::with_capacity(call_args.len() + 2);
1797 if let Some((ptr, _)) = &sret {
1798 real_call_args.push(*ptr);
1799 }
1800
1801 let vmctx = builder.ins().load(
1803 pointer_type,
1804 mem_flags,
1805 anyfunc_ptr,
1806 i32::from(self.offsets.vmcaller_checked_anyfunc_vmctx()),
1807 );
1808 real_call_args.push(vmctx);
1809
1810 real_call_args.extend_from_slice(call_args);
1812
1813 let results = self.call_indirect_with_handlers(
1814 builder,
1815 sig_ref,
1816 func_addr,
1817 &real_call_args,
1818 Some(vmctx),
1819 landing_pad,
1820 false,
1821 );
1822 Ok(self.finish_wasm_call(builder, &return_abi, &results, sret))
1823 }
1824
1825 pub(crate) fn translate_call(
1826 &mut self,
1827 builder: &mut FunctionBuilder,
1828 callee_index: FunctionIndex,
1829 callee: ir::FuncRef,
1830 call_args: &[ir::Value],
1831 landing_pad: Option<LandingPad>,
1832 ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1833 let sig_index = self.module.functions[callee_index];
1834 let (return_abi, sret) =
1835 self.prepare_wasm_call(builder, self.module.signatures[sig_index].results());
1836 let mut real_call_args = Vec::with_capacity(call_args.len() + 2);
1837 if let Some((ptr, _)) = &sret {
1838 real_call_args.push(*ptr);
1839 }
1840
1841 if !self.module.is_imported_function(callee_index) {
1843 let caller_vmctx = builder
1845 .func
1846 .special_param(ArgumentPurpose::VMContext)
1847 .unwrap();
1848 real_call_args.push(caller_vmctx);
1851
1852 real_call_args.extend_from_slice(call_args);
1854
1855 let results = self.call_with_handlers(
1856 builder,
1857 callee,
1858 &real_call_args,
1859 Some(caller_vmctx),
1860 landing_pad,
1861 false,
1862 );
1863 return Ok(self.finish_wasm_call(builder, &return_abi, &results, sret));
1864 }
1865
1866 let pointer_type = self.pointer_type();
1869 let sig_ref = builder.func.dfg.ext_funcs[callee].signature;
1870 let vmctx = self.vmctx(builder.func);
1871 let base = materialize_global_value(&mut builder.cursor(), pointer_type, vmctx);
1872
1873 let mem_flags = ir::MemFlagsData::trusted();
1874
1875 let body_offset = vmctx_offset(self.offsets.vmctx_vmfunction_import_body(callee_index))?;
1877 let func_addr = builder
1878 .ins()
1879 .load(pointer_type, mem_flags, base, body_offset);
1880
1881 let vmctx_arg_offset =
1883 vmctx_offset(self.offsets.vmctx_vmfunction_import_vmctx(callee_index))?;
1884 let vmctx = builder
1885 .ins()
1886 .load(pointer_type, mem_flags, base, vmctx_arg_offset);
1887 real_call_args.push(vmctx);
1888
1889 real_call_args.extend_from_slice(call_args);
1891
1892 let results = self.call_indirect_with_handlers(
1893 builder,
1894 sig_ref,
1895 func_addr,
1896 &real_call_args,
1897 Some(vmctx),
1898 landing_pad,
1899 false,
1900 );
1901 Ok(self.finish_wasm_call(builder, &return_abi, &results, sret))
1902 }
1903
1904 pub(crate) fn tag_param_arity(&self, tag_index: TagIndex) -> usize {
1905 let sig_index = self.module.tags[tag_index];
1906 let signature = &self.module.signatures[sig_index];
1907 signature.params().len()
1908 }
1909
1910 pub(crate) fn translate_exn_pointer_to_ref(
1911 &mut self,
1912 builder: &mut FunctionBuilder,
1913 exn_ptr: ir::Value,
1914 ) -> WasmResult<ir::Value> {
1915 let (read_sig, read_idx) = self.get_read_exception_func(builder.func);
1916 let mut pos = builder.cursor();
1917 let (_, read_addr) = self.translate_load_builtin_function_address(&mut pos, read_idx)?;
1918 let read_call = builder.ins().call_indirect(read_sig, read_addr, &[exn_ptr]);
1919 Ok(builder.inst_results(read_call)[0])
1920 }
1921
1922 pub(crate) fn translate_exn_unbox(
1923 &mut self,
1924 builder: &mut FunctionBuilder,
1925 tag_index: TagIndex,
1926 exnref: ir::Value,
1927 ) -> WasmResult<SmallVec<[ir::Value; 4]>> {
1928 let layout = self.exception_type_layout(tag_index)?.clone();
1929
1930 let (read_exnref_sig, read_exnref_idx) = self.get_read_exnref_func(builder.func);
1931 let mut pos = builder.cursor();
1932 let (vmctx, read_exnref_addr) =
1933 self.translate_load_builtin_function_address(&mut pos, read_exnref_idx)?;
1934 let read_exnref_call =
1935 builder
1936 .ins()
1937 .call_indirect(read_exnref_sig, read_exnref_addr, &[vmctx, exnref]);
1938 let payload_ptr = builder.inst_results(read_exnref_call)[0];
1939
1940 let mut values = SmallVec::<[ir::Value; 4]>::with_capacity(layout.fields.len());
1941 let data_flags = ir::MemFlagsData::trusted();
1942 for field in &layout.fields {
1943 let value = builder.ins().load(
1944 field.ty,
1945 data_flags,
1946 payload_ptr,
1947 Offset32::new(field.offset as i32),
1948 );
1949 values.push(value);
1950 }
1951
1952 Ok(values)
1953 }
1954
1955 pub(crate) fn translate_exn_throw(
1956 &mut self,
1957 builder: &mut FunctionBuilder,
1958 tag_index: TagIndex,
1959 args: &[ir::Value],
1960 landing_pad: Option<LandingPad>,
1961 ) -> WasmResult<()> {
1962 let layout = self.exception_type_layout(tag_index)?.clone();
1963 if layout.fields.len() != args.len() {
1964 return Err(WasmError::Generic(format!(
1965 "exception payload arity mismatch: expected {}, got {}",
1966 layout.fields.len(),
1967 args.len()
1968 )));
1969 }
1970
1971 let (alloc_sig, alloc_idx) = self.get_alloc_exception_func(builder.func);
1972 let mut pos = builder.cursor();
1973 let (vmctx, alloc_addr) =
1974 self.translate_load_builtin_function_address(&mut pos, alloc_idx)?;
1975 let tag_value = builder
1976 .ins()
1977 .iconst(TAG_TYPE, i64::from(tag_index.as_u32()));
1978 let alloc_call = builder
1979 .ins()
1980 .call_indirect(alloc_sig, alloc_addr, &[vmctx, tag_value]);
1981 let exnref = builder.inst_results(alloc_call)[0];
1982
1983 let (read_exnref_sig, read_exnref_idx) = self.get_read_exnref_func(builder.func);
1984 let mut pos = builder.cursor();
1985 let (vmctx, read_exnref_addr) =
1986 self.translate_load_builtin_function_address(&mut pos, read_exnref_idx)?;
1987 let read_exnref_call =
1988 builder
1989 .ins()
1990 .call_indirect(read_exnref_sig, read_exnref_addr, &[vmctx, exnref]);
1991 let payload_ptr = builder.inst_results(read_exnref_call)[0];
1992
1993 let store_flags = ir::MemFlagsData::trusted();
1994 for (field, value) in layout.fields.iter().zip(args.iter()) {
1995 debug_assert_eq!(
1996 builder.func.dfg.value_type(*value),
1997 field.ty,
1998 "exception payload type mismatch"
1999 );
2000 builder.ins().store(
2001 store_flags,
2002 *value,
2003 payload_ptr,
2004 Offset32::new(field.offset as i32),
2005 );
2006 }
2007
2008 let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2009 let mut pos = builder.cursor();
2010 let (vmctx_value, throw_addr) =
2011 self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2012 let call_args = [vmctx_value, exnref];
2013
2014 let _ = self.call_indirect_with_handlers(
2015 builder,
2016 throw_sig,
2017 throw_addr,
2018 &call_args,
2019 Some(vmctx_value),
2020 landing_pad,
2021 true,
2022 );
2023
2024 Ok(())
2025 }
2026
2027 pub(crate) fn translate_exn_throw_ref(
2028 &mut self,
2029 builder: &mut FunctionBuilder,
2030 exnref: ir::Value,
2031 landing_pad: Option<LandingPad>,
2032 ) -> WasmResult<()> {
2033 let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2034 let mut pos = builder.cursor();
2035 let (vmctx_value, throw_addr) =
2036 self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2037 let call_args = [vmctx_value, exnref];
2038
2039 let _ = self.call_indirect_with_handlers(
2040 builder,
2041 throw_sig,
2042 throw_addr,
2043 &call_args,
2044 Some(vmctx_value),
2045 landing_pad,
2046 true,
2047 );
2048
2049 Ok(())
2050 }
2051
2052 pub(crate) fn translate_exn_personality_selector(
2053 &mut self,
2054 builder: &mut FunctionBuilder,
2055 exn_ptr: ir::Value,
2056 ) -> WasmResult<ir::Value> {
2057 let (sig, idx) = self.get_personality2_func(builder.func);
2058 let pointer_type = self.pointer_type();
2059 let exn_ty = builder.func.dfg.value_type(exn_ptr);
2060 let exn_arg = if exn_ty == pointer_type {
2061 exn_ptr
2062 } else {
2063 let mut flags = MemFlagsData::new();
2064 flags.set_endianness(Endianness::Little);
2065 builder.ins().bitcast(pointer_type, flags, exn_ptr)
2066 };
2067
2068 let mut pos = builder.cursor();
2069 let (vmctx_value, func_addr) =
2070 self.translate_load_builtin_function_address(&mut pos, idx)?;
2071 let call = builder
2072 .ins()
2073 .call_indirect(sig, func_addr, &[vmctx_value, exn_arg]);
2074 Ok(builder.inst_results(call)[0])
2075 }
2076
2077 pub(crate) fn translate_exn_reraise_unmatched(
2078 &mut self,
2079 builder: &mut FunctionBuilder,
2080 exnref: ir::Value,
2081 ) -> WasmResult<()> {
2082 let (throw_sig, throw_idx) = self.get_throw_func(builder.func);
2083 let mut pos = builder.cursor();
2084 let (vmctx_value, throw_addr) =
2085 self.translate_load_builtin_function_address(&mut pos, throw_idx)?;
2086 builder
2087 .ins()
2088 .call_indirect(throw_sig, throw_addr, &[vmctx_value, exnref]);
2089 builder.ins().trap(crate::TRAP_UNREACHABLE);
2090 Ok(())
2091 }
2092
2093 pub(crate) fn translate_memory_grow(
2094 &mut self,
2095 mut pos: FuncCursor<'_>,
2096 index: MemoryIndex,
2097 _heap: Heap,
2098 val: ir::Value,
2099 ) -> WasmResult<ir::Value> {
2100 let (func_sig, index_arg, func_idx) = self.get_memory_grow_func(pos.func, index);
2101 let memory_index = pos.ins().iconst(I32, index_arg as i64);
2102 let (vmctx, func_addr) =
2103 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2104 let call_inst = pos
2105 .ins()
2106 .call_indirect(func_sig, func_addr, &[vmctx, val, memory_index]);
2107 Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2108 }
2109
2110 pub(crate) fn translate_memory_size(
2111 &mut self,
2112 mut pos: FuncCursor<'_>,
2113 index: MemoryIndex,
2114 _heap: Heap,
2115 ) -> WasmResult<ir::Value> {
2116 let (func_sig, index_arg, func_idx) = self.get_memory_size_func(pos.func, index);
2117 let memory_index = pos.ins().iconst(I32, index_arg as i64);
2118 let (vmctx, func_addr) =
2119 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2120 let call_inst = pos
2121 .ins()
2122 .call_indirect(func_sig, func_addr, &[vmctx, memory_index]);
2123 Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2124 }
2125
2126 #[allow(clippy::too_many_arguments)]
2127 pub(crate) fn translate_memory_copy(
2128 &mut self,
2129 mut pos: FuncCursor,
2130 src_index: MemoryIndex,
2131 _src_heap: Heap,
2132 dst_index: MemoryIndex,
2133 _dst_heap: Heap,
2134 dst: ir::Value,
2135 src: ir::Value,
2136 len: ir::Value,
2137 ) -> WasmResult<()> {
2138 let (func_sig, func_idx) = self.get_memory_copy_func(pos.func);
2139
2140 let dst_index_arg = pos.ins().iconst(I32, dst_index.index() as i64);
2141 let src_index_arg = pos.ins().iconst(I32, src_index.index() as i64);
2142
2143 let (vmctx, func_addr) =
2144 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2145
2146 pos.ins().call_indirect(
2147 func_sig,
2148 func_addr,
2149 &[vmctx, dst_index_arg, src_index_arg, dst, src, len],
2150 );
2151
2152 Ok(())
2153 }
2154
2155 pub(crate) fn translate_memory_fill(
2156 &mut self,
2157 mut pos: FuncCursor,
2158 memory_index: MemoryIndex,
2159 _heap: Heap,
2160 dst: ir::Value,
2161 val: ir::Value,
2162 len: ir::Value,
2163 ) -> WasmResult<()> {
2164 let (func_sig, memory_index, func_idx) = self.get_memory_fill_func(pos.func, memory_index);
2165
2166 let memory_index_arg = pos.ins().iconst(I32, memory_index as i64);
2167
2168 let (vmctx, func_addr) =
2169 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2170
2171 pos.ins().call_indirect(
2172 func_sig,
2173 func_addr,
2174 &[vmctx, memory_index_arg, dst, val, len],
2175 );
2176
2177 Ok(())
2178 }
2179
2180 #[allow(clippy::too_many_arguments)]
2181 pub(crate) fn translate_memory_init(
2182 &mut self,
2183 mut pos: FuncCursor,
2184 memory_index: MemoryIndex,
2185 _heap: Heap,
2186 seg_index: u32,
2187 dst: ir::Value,
2188 src: ir::Value,
2189 len: ir::Value,
2190 ) -> WasmResult<()> {
2191 let (func_sig, func_idx) = self.get_memory_init_func(pos.func);
2192
2193 let memory_index_arg = pos.ins().iconst(I32, memory_index.index() as i64);
2194 let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2195
2196 let (vmctx, func_addr) =
2197 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2198
2199 pos.ins().call_indirect(
2200 func_sig,
2201 func_addr,
2202 &[vmctx, memory_index_arg, seg_index_arg, dst, src, len],
2203 );
2204
2205 Ok(())
2206 }
2207
2208 pub(crate) fn translate_data_drop(
2209 &mut self,
2210 mut pos: FuncCursor,
2211 seg_index: u32,
2212 ) -> WasmResult<()> {
2213 let (func_sig, func_idx) = self.get_data_drop_func(pos.func);
2214 let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2215 let (vmctx, func_addr) =
2216 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2217 pos.ins()
2218 .call_indirect(func_sig, func_addr, &[vmctx, seg_index_arg]);
2219 Ok(())
2220 }
2221
2222 pub(crate) fn translate_table_size(
2223 &mut self,
2224 mut pos: FuncCursor,
2225 table_index: TableIndex,
2226 ) -> WasmResult<ir::Value> {
2227 self.ensure_table_exists(pos.func, table_index)?;
2228 let (func_sig, index_arg, func_idx) = self.get_table_size_func(pos.func, table_index);
2229 let table_index = pos.ins().iconst(I32, index_arg as i64);
2230 let (vmctx, func_addr) =
2231 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2232 let call_inst = pos
2233 .ins()
2234 .call_indirect(func_sig, func_addr, &[vmctx, table_index]);
2235 Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2236 }
2237
2238 pub(crate) fn translate_table_copy(
2239 &mut self,
2240 mut pos: FuncCursor,
2241 dst_table_index: TableIndex,
2242 src_table_index: TableIndex,
2243 dst: ir::Value,
2244 src: ir::Value,
2245 len: ir::Value,
2246 ) -> WasmResult<()> {
2247 self.ensure_table_exists(pos.func, src_table_index)?;
2248 self.ensure_table_exists(pos.func, dst_table_index)?;
2249 let (func_sig, dst_table_index_arg, src_table_index_arg, func_idx) =
2250 self.get_table_copy_func(pos.func, dst_table_index, src_table_index);
2251
2252 let dst_table_index_arg = pos.ins().iconst(I32, dst_table_index_arg as i64);
2253 let src_table_index_arg = pos.ins().iconst(I32, src_table_index_arg as i64);
2254
2255 let (vmctx, func_addr) =
2256 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2257
2258 pos.ins().call_indirect(
2259 func_sig,
2260 func_addr,
2261 &[
2262 vmctx,
2263 dst_table_index_arg,
2264 src_table_index_arg,
2265 dst,
2266 src,
2267 len,
2268 ],
2269 );
2270
2271 Ok(())
2272 }
2273
2274 pub(crate) fn translate_table_init(
2275 &mut self,
2276 mut pos: FuncCursor,
2277 seg_index: u32,
2278 table_index: TableIndex,
2279 dst: ir::Value,
2280 src: ir::Value,
2281 len: ir::Value,
2282 ) -> WasmResult<()> {
2283 self.ensure_table_exists(pos.func, table_index)?;
2284 let (func_sig, table_index_arg, func_idx) = self.get_table_init_func(pos.func, table_index);
2285
2286 let table_index_arg = pos.ins().iconst(I32, table_index_arg as i64);
2287 let seg_index_arg = pos.ins().iconst(I32, seg_index as i64);
2288
2289 let (vmctx, func_addr) =
2290 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2291
2292 pos.ins().call_indirect(
2293 func_sig,
2294 func_addr,
2295 &[vmctx, table_index_arg, seg_index_arg, dst, src, len],
2296 );
2297
2298 Ok(())
2299 }
2300
2301 pub(crate) fn translate_elem_drop(
2302 &mut self,
2303 mut pos: FuncCursor,
2304 elem_index: u32,
2305 ) -> WasmResult<()> {
2306 let (func_sig, func_idx) = self.get_elem_drop_func(pos.func);
2307
2308 let elem_index_arg = pos.ins().iconst(I32, elem_index as i64);
2309
2310 let (vmctx, func_addr) =
2311 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2312
2313 pos.ins()
2314 .call_indirect(func_sig, func_addr, &[vmctx, elem_index_arg]);
2315
2316 Ok(())
2317 }
2318
2319 pub(crate) fn translate_atomic_wait(
2320 &mut self,
2321 mut pos: FuncCursor,
2322 index: MemoryIndex,
2323 _heap: Heap,
2324 addr: ir::Value,
2325 expected: ir::Value,
2326 timeout: ir::Value,
2327 ) -> WasmResult<ir::Value> {
2328 let (func_sig, index_arg, func_idx) = if pos.func.dfg.value_type(expected) == I64 {
2329 self.get_memory_atomic_wait64_func(pos.func, index)
2330 } else {
2331 self.get_memory_atomic_wait32_func(pos.func, index)
2332 };
2333 let memory_index = pos.ins().iconst(I32, index_arg as i64);
2334 let (vmctx, func_addr) =
2335 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2336 let call_inst = pos.ins().call_indirect(
2337 func_sig,
2338 func_addr,
2339 &[vmctx, memory_index, addr, expected, timeout],
2340 );
2341 Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2342 }
2343
2344 pub(crate) fn translate_atomic_notify(
2345 &mut self,
2346 mut pos: FuncCursor,
2347 index: MemoryIndex,
2348 _heap: Heap,
2349 addr: ir::Value,
2350 count: ir::Value,
2351 ) -> WasmResult<ir::Value> {
2352 let (func_sig, index_arg, func_idx) = self.get_memory_atomic_notify_func(pos.func, index);
2353 let memory_index = pos.ins().iconst(I32, index_arg as i64);
2354 let (vmctx, func_addr) =
2355 self.translate_load_builtin_function_address(&mut pos, func_idx)?;
2356 let call_inst =
2357 pos.ins()
2358 .call_indirect(func_sig, func_addr, &[vmctx, memory_index, addr, count]);
2359 Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
2360 }
2361
2362 pub(crate) fn push_local_decl_on_stack(&mut self, ty: WasmerType) {
2363 self.type_stack.push(ty);
2364 }
2365
2366 pub(crate) fn push_params_on_stack(&mut self, function_index: LocalFunctionIndex) {
2367 let func_index = self.module.func_index(function_index);
2368 let sig_idx = self.module.functions[func_index];
2369 let signature = &self.module.signatures[sig_idx];
2370 self.return_types = signature.results().to_vec();
2371 for param in signature.params() {
2372 self.type_stack.push(*param);
2373 }
2374 }
2375
2376 pub(crate) fn return_types(&self) -> &[WasmerType] {
2377 &self.return_types
2378 }
2379
2380 pub(crate) fn emit_wasm_return(&mut self, builder: &mut FunctionBuilder, values: &[ir::Value]) {
2381 let return_abi = abi::classify_returns(self.architecture, &self.return_types);
2382 match &return_abi {
2383 ReturnAbi::Sret(types) => {
2384 let ptr = builder
2385 .func
2386 .special_param(ArgumentPurpose::StructReturn)
2387 .expect("sret function has a StructReturn parameter");
2388 let layout = abi::return_area_layout(types);
2389 abi::store_sret(builder, ptr, &layout, values);
2390 builder.ins().return_(&[]);
2391 }
2392 _ => {
2393 let packed = abi::pack_register_returns(builder, &return_abi, values);
2394 builder.ins().return_(&packed);
2395 }
2396 }
2397 }
2398
2399 pub(crate) fn heap_access_spectre_mitigation(&self) -> bool {
2400 false
2401 }
2402
2403 pub(crate) fn heaps(&self) -> &PrimaryMap<Heap, HeapData> {
2404 &self.heaps
2405 }
2406}