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