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