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