1use crate::{TRAP_ALWAYS, TRAP_CANNOT_ENTER, TRAP_INTERNAL_ASSERT, compiler::Compiler};
4use anyhow::Result;
5use cranelift_codegen::ir::condcodes::IntCC;
6use cranelift_codegen::ir::{self, InstBuilder, MemFlags, Value};
7use cranelift_codegen::isa::{CallConv, TargetIsa};
8use cranelift_frontend::FunctionBuilder;
9use wasmtime_environ::{
10 Abi, CompiledFunctionBody, EntityRef, FuncKey, HostCall, ModuleInternedTypeIndex, PtrSize,
11 TrapSentinel, Tunables, WasmFuncType, WasmValType, component::*,
12 fact::PREPARE_CALL_FIXED_PARAMS,
13};
14
15struct TrampolineCompiler<'a> {
16 compiler: &'a Compiler,
17 isa: &'a (dyn TargetIsa + 'static),
18 builder: FunctionBuilder<'a>,
19 component: &'a Component,
20 types: &'a ComponentTypesBuilder,
21 offsets: VMComponentOffsets<u8>,
22 abi: Abi,
23 block0: ir::Block,
24 signature: ModuleInternedTypeIndex,
25 tunables: &'a Tunables,
26}
27
28enum HostCallee {
30 Lowering(LoweredIndex),
32 Libcall(GetLibcallFn),
34}
35
36type GetLibcallFn =
37 fn(&dyn TargetIsa, &mut ir::Function) -> (ir::SigRef, ComponentBuiltinFunctionIndex);
38
39impl From<LoweredIndex> for HostCallee {
40 fn from(index: LoweredIndex) -> HostCallee {
41 HostCallee::Lowering(index)
42 }
43}
44
45impl From<GetLibcallFn> for HostCallee {
46 fn from(f: GetLibcallFn) -> HostCallee {
47 HostCallee::Libcall(f)
48 }
49}
50
51enum HostResult {
53 None,
55
56 Sentinel(TrapSentinel),
59
60 MultiValue {
69 ptr: Option<ir::Value>,
71 len: Option<ir::Value>,
73 },
74}
75
76impl From<TrapSentinel> for HostResult {
77 fn from(sentinel: TrapSentinel) -> HostResult {
78 HostResult::Sentinel(sentinel)
79 }
80}
81
82#[derive(Debug, Copy, Clone)]
84enum WasmArgs {
85 InRegisters,
88
89 ValRawList,
92
93 InRegistersUpTo(usize),
96}
97
98impl<'a> TrampolineCompiler<'a> {
99 fn new(
100 compiler: &'a Compiler,
101 func_compiler: &'a mut super::FunctionCompiler<'_>,
102 component: &'a Component,
103 types: &'a ComponentTypesBuilder,
104 index: TrampolineIndex,
105 abi: Abi,
106 tunables: &'a Tunables,
107 ) -> TrampolineCompiler<'a> {
108 let isa = &*compiler.isa;
109 let signature = component.trampolines[index];
110 let ty = types[signature].unwrap_func();
111 let func = ir::Function::with_name_signature(
112 ir::UserFuncName::user(0, 0),
113 match abi {
114 Abi::Wasm => crate::wasm_call_signature(isa, ty, &compiler.tunables),
115 Abi::Array => crate::array_call_signature(isa),
116 },
117 );
118 let (builder, block0) = func_compiler.builder(func);
119 TrampolineCompiler {
120 compiler,
121 isa,
122 builder,
123 component,
124 types,
125 offsets: VMComponentOffsets::new(isa.pointer_bytes(), component),
126 abi,
127 block0,
128 signature,
129 tunables,
130 }
131 }
132
133 fn translate(&mut self, trampoline: &Trampoline) {
134 match trampoline {
135 Trampoline::Transcoder {
136 op,
137 from,
138 from64,
139 to,
140 to64,
141 } => {
142 match self.abi {
143 Abi::Wasm => {
144 self.translate_transcode(*op, *from, *from64, *to, *to64);
145 }
146 Abi::Array => {
149 self.builder.ins().trap(TRAP_INTERNAL_ASSERT);
150 }
151 }
152 }
153 Trampoline::LowerImport {
154 index,
155 options,
156 lower_ty,
157 } => {
158 let pointer_type = self.isa.pointer_type();
159 self.translate_hostcall(
160 HostCallee::Lowering(*index),
161 HostResult::MultiValue {
162 ptr: None,
163 len: None,
164 },
165 WasmArgs::ValRawList,
166 |me, params| {
167 let vmctx = params[0];
168 params.extend([
169 me.builder.ins().load(
170 pointer_type,
171 MemFlags::trusted(),
172 vmctx,
173 i32::try_from(me.offsets.lowering_data(*index)).unwrap(),
174 ),
175 me.index_value(*lower_ty),
176 me.index_value(*options),
177 ]);
178 },
179 );
180 }
181 Trampoline::AlwaysTrap => {
182 if self.tunables.signals_based_traps {
183 self.builder.ins().trap(TRAP_ALWAYS);
184 return;
185 }
186 self.translate_libcall(
187 host::trap,
188 TrapSentinel::Falsy,
189 WasmArgs::InRegisters,
190 |me, params| {
191 let code = wasmtime_environ::Trap::AlwaysTrapAdapter as u8;
192 params.push(me.builder.ins().iconst(ir::types::I8, i64::from(code)));
193 },
194 );
195 }
196 Trampoline::ResourceNew { instance, ty } => {
197 assert_eq!(
199 self.types[self.signature].unwrap_func().params()[0],
200 WasmValType::I32
201 );
202 self.translate_libcall(
203 host::resource_new32,
204 TrapSentinel::NegativeOne,
205 WasmArgs::InRegisters,
206 |me, params| {
207 params.push(me.index_value(*instance));
208 params.push(me.index_value(*ty));
209 },
210 );
211 }
212 Trampoline::ResourceRep { instance, ty } => {
213 assert_eq!(
215 self.types[self.signature].unwrap_func().returns()[0],
216 WasmValType::I32
217 );
218 self.translate_libcall(
219 host::resource_rep32,
220 TrapSentinel::NegativeOne,
221 WasmArgs::InRegisters,
222 |me, params| {
223 params.push(me.index_value(*instance));
224 params.push(me.index_value(*ty));
225 },
226 );
227 }
228 Trampoline::ResourceDrop { instance, ty } => {
229 self.translate_resource_drop(*instance, *ty);
230 }
231 Trampoline::BackpressureSet { instance } => {
232 self.translate_libcall(
233 host::backpressure_set,
234 TrapSentinel::Falsy,
235 WasmArgs::InRegisters,
236 |me, params| {
237 params.push(me.index_value(*instance));
238 },
239 );
240 }
241 Trampoline::BackpressureInc { instance } => {
242 self.translate_libcall(
243 host::backpressure_modify,
244 TrapSentinel::Falsy,
245 WasmArgs::InRegisters,
246 |me, params| {
247 params.push(me.index_value(*instance));
248 params.push(me.builder.ins().iconst(ir::types::I8, 1));
249 },
250 );
251 }
252 Trampoline::BackpressureDec { instance } => {
253 self.translate_libcall(
254 host::backpressure_modify,
255 TrapSentinel::Falsy,
256 WasmArgs::InRegisters,
257 |me, params| {
258 params.push(me.index_value(*instance));
259 params.push(me.builder.ins().iconst(ir::types::I8, 0));
260 },
261 );
262 }
263 Trampoline::TaskReturn {
264 instance,
265 results,
266 options,
267 } => {
268 self.translate_libcall(
269 host::task_return,
270 TrapSentinel::Falsy,
271 WasmArgs::ValRawList,
272 |me, params| {
273 params.push(me.index_value(*instance));
274 params.push(me.index_value(*results));
275 params.push(me.index_value(*options));
276 },
277 );
278 }
279 Trampoline::TaskCancel { instance } => {
280 self.translate_libcall(
281 host::task_cancel,
282 TrapSentinel::Falsy,
283 WasmArgs::InRegisters,
284 |me, params| {
285 params.push(me.index_value(*instance));
286 },
287 );
288 }
289 Trampoline::WaitableSetNew { instance } => {
290 self.translate_libcall(
291 host::waitable_set_new,
292 TrapSentinel::NegativeOne,
293 WasmArgs::InRegisters,
294 |me, params| {
295 params.push(me.index_value(*instance));
296 },
297 );
298 }
299 Trampoline::WaitableSetWait { instance, options } => {
300 self.translate_libcall(
301 host::waitable_set_wait,
302 TrapSentinel::NegativeOne,
303 WasmArgs::InRegisters,
304 |me, params| {
305 params.push(me.index_value(*instance));
306 params.push(me.index_value(*options));
307 },
308 );
309 }
310 Trampoline::WaitableSetPoll { instance, options } => {
311 self.translate_libcall(
312 host::waitable_set_poll,
313 TrapSentinel::NegativeOne,
314 WasmArgs::InRegisters,
315 |me, params| {
316 params.push(me.index_value(*instance));
317 params.push(me.index_value(*options));
318 },
319 );
320 }
321 Trampoline::WaitableSetDrop { instance } => {
322 self.translate_libcall(
323 host::waitable_set_drop,
324 TrapSentinel::Falsy,
325 WasmArgs::InRegisters,
326 |me, params| {
327 params.push(me.index_value(*instance));
328 },
329 );
330 }
331 Trampoline::WaitableJoin { instance } => {
332 self.translate_libcall(
333 host::waitable_join,
334 TrapSentinel::Falsy,
335 WasmArgs::InRegisters,
336 |me, params| {
337 params.push(me.index_value(*instance));
338 },
339 );
340 }
341 Trampoline::ThreadYield {
342 instance,
343 cancellable,
344 } => {
345 self.translate_libcall(
346 host::thread_yield,
347 TrapSentinel::NegativeOne,
348 WasmArgs::InRegisters,
349 |me, params| {
350 params.push(me.index_value(*instance));
351 params.push(
352 me.builder
353 .ins()
354 .iconst(ir::types::I8, i64::from(*cancellable)),
355 );
356 },
357 );
358 }
359 Trampoline::SubtaskDrop { instance } => {
360 self.translate_libcall(
361 host::subtask_drop,
362 TrapSentinel::Falsy,
363 WasmArgs::InRegisters,
364 |me, params| {
365 params.push(me.index_value(*instance));
366 },
367 );
368 }
369 Trampoline::SubtaskCancel { instance, async_ } => {
370 self.translate_libcall(
371 host::subtask_cancel,
372 TrapSentinel::NegativeOne,
373 WasmArgs::InRegisters,
374 |me, params| {
375 params.push(me.index_value(*instance));
376 params.push(me.builder.ins().iconst(ir::types::I8, i64::from(*async_)));
377 },
378 );
379 }
380 Trampoline::StreamNew { instance, ty } => {
381 self.translate_libcall(
382 host::stream_new,
383 TrapSentinel::NegativeOne,
384 WasmArgs::InRegisters,
385 |me, params| {
386 params.push(me.index_value(*instance));
387 params.push(me.index_value(*ty));
388 },
389 );
390 }
391 Trampoline::StreamRead {
392 instance,
393 ty,
394 options,
395 } => {
396 if let Some(info) = self.flat_stream_element_info(*ty).cloned() {
397 self.translate_libcall(
398 host::flat_stream_read,
399 TrapSentinel::NegativeOne,
400 WasmArgs::InRegisters,
401 |me, params| {
402 params.extend([
403 me.index_value(*instance),
404 me.index_value(*ty),
405 me.index_value(*options),
406 me.builder
407 .ins()
408 .iconst(ir::types::I32, i64::from(info.size32)),
409 me.builder
410 .ins()
411 .iconst(ir::types::I32, i64::from(info.align32)),
412 ]);
413 },
414 );
415 } else {
416 self.translate_libcall(
417 host::stream_read,
418 TrapSentinel::NegativeOne,
419 WasmArgs::InRegisters,
420 |me, params| {
421 params.push(me.index_value(*instance));
422 params.push(me.index_value(*ty));
423 params.push(me.index_value(*options));
424 },
425 );
426 }
427 }
428 Trampoline::StreamWrite {
429 instance,
430 ty,
431 options,
432 } => {
433 if let Some(info) = self.flat_stream_element_info(*ty).cloned() {
434 self.translate_libcall(
435 host::flat_stream_write,
436 TrapSentinel::NegativeOne,
437 WasmArgs::InRegisters,
438 |me, params| {
439 params.extend([
440 me.index_value(*instance),
441 me.index_value(*ty),
442 me.index_value(*options),
443 me.builder
444 .ins()
445 .iconst(ir::types::I32, i64::from(info.size32)),
446 me.builder
447 .ins()
448 .iconst(ir::types::I32, i64::from(info.align32)),
449 ]);
450 },
451 );
452 } else {
453 self.translate_libcall(
454 host::stream_write,
455 TrapSentinel::NegativeOne,
456 WasmArgs::InRegisters,
457 |me, params| {
458 params.push(me.index_value(*instance));
459 params.push(me.index_value(*ty));
460 params.push(me.index_value(*options));
461 },
462 );
463 }
464 }
465 Trampoline::StreamCancelRead {
466 instance,
467 ty,
468 async_,
469 } => {
470 self.translate_libcall(
471 host::stream_cancel_read,
472 TrapSentinel::NegativeOne,
473 WasmArgs::InRegisters,
474 |me, params| {
475 params.push(me.index_value(*instance));
476 params.push(me.index_value(*ty));
477 params.push(me.builder.ins().iconst(ir::types::I8, i64::from(*async_)));
478 },
479 );
480 }
481 Trampoline::StreamCancelWrite {
482 instance,
483 ty,
484 async_,
485 } => {
486 self.translate_libcall(
487 host::stream_cancel_write,
488 TrapSentinel::NegativeOne,
489 WasmArgs::InRegisters,
490 |me, params| {
491 params.push(me.index_value(*instance));
492 params.push(me.index_value(*ty));
493 params.push(me.builder.ins().iconst(ir::types::I8, i64::from(*async_)));
494 },
495 );
496 }
497 Trampoline::StreamDropReadable { instance, ty } => {
498 self.translate_libcall(
499 host::stream_drop_readable,
500 TrapSentinel::Falsy,
501 WasmArgs::InRegisters,
502 |me, params| {
503 params.push(me.index_value(*instance));
504 params.push(me.index_value(*ty));
505 },
506 );
507 }
508 Trampoline::StreamDropWritable { instance, ty } => {
509 self.translate_libcall(
510 host::stream_drop_writable,
511 TrapSentinel::Falsy,
512 WasmArgs::InRegisters,
513 |me, params| {
514 params.push(me.index_value(*instance));
515 params.push(me.index_value(*ty));
516 },
517 );
518 }
519 Trampoline::FutureNew { instance, ty } => {
520 self.translate_libcall(
521 host::future_new,
522 TrapSentinel::NegativeOne,
523 WasmArgs::InRegisters,
524 |me, params| {
525 params.push(me.index_value(*instance));
526 params.push(me.index_value(*ty));
527 },
528 );
529 }
530 Trampoline::FutureRead {
531 instance,
532 ty,
533 options,
534 } => {
535 self.translate_libcall(
536 host::future_read,
537 TrapSentinel::NegativeOne,
538 WasmArgs::InRegisters,
539 |me, params| {
540 params.push(me.index_value(*instance));
541 params.push(me.index_value(*ty));
542 params.push(me.index_value(*options));
543 },
544 );
545 }
546 Trampoline::FutureWrite {
547 instance,
548 ty,
549 options,
550 } => {
551 self.translate_libcall(
552 host::future_write,
553 TrapSentinel::NegativeOne,
554 WasmArgs::InRegisters,
555 |me, params| {
556 params.push(me.index_value(*instance));
557 params.push(me.index_value(*ty));
558 params.push(me.index_value(*options));
559 },
560 );
561 }
562 Trampoline::FutureCancelRead {
563 instance,
564 ty,
565 async_,
566 } => {
567 self.translate_libcall(
568 host::future_cancel_read,
569 TrapSentinel::NegativeOne,
570 WasmArgs::InRegisters,
571 |me, params| {
572 params.push(me.index_value(*instance));
573 params.push(me.index_value(*ty));
574 params.push(me.builder.ins().iconst(ir::types::I8, i64::from(*async_)));
575 },
576 );
577 }
578 Trampoline::FutureCancelWrite {
579 instance,
580 ty,
581 async_,
582 } => {
583 self.translate_libcall(
584 host::future_cancel_write,
585 TrapSentinel::NegativeOne,
586 WasmArgs::InRegisters,
587 |me, params| {
588 params.push(me.index_value(*instance));
589 params.push(me.index_value(*ty));
590 params.push(me.builder.ins().iconst(ir::types::I8, i64::from(*async_)));
591 },
592 );
593 }
594 Trampoline::FutureDropReadable { instance, ty } => {
595 self.translate_libcall(
596 host::future_drop_readable,
597 TrapSentinel::Falsy,
598 WasmArgs::InRegisters,
599 |me, params| {
600 params.push(me.index_value(*instance));
601 params.push(me.index_value(*ty));
602 },
603 );
604 }
605 Trampoline::FutureDropWritable { instance, ty } => {
606 self.translate_libcall(
607 host::future_drop_writable,
608 TrapSentinel::Falsy,
609 WasmArgs::InRegisters,
610 |me, params| {
611 params.push(me.index_value(*instance));
612 params.push(me.index_value(*ty));
613 },
614 );
615 }
616 Trampoline::ErrorContextNew {
617 instance,
618 ty,
619 options,
620 } => {
621 self.translate_libcall(
622 host::error_context_new,
623 TrapSentinel::NegativeOne,
624 WasmArgs::InRegisters,
625 |me, params| {
626 params.push(me.index_value(*instance));
627 params.push(me.index_value(*ty));
628 params.push(me.index_value(*options));
629 },
630 );
631 }
632 Trampoline::ErrorContextDebugMessage {
633 instance,
634 ty,
635 options,
636 } => {
637 self.translate_libcall(
638 host::error_context_debug_message,
639 TrapSentinel::Falsy,
640 WasmArgs::InRegisters,
641 |me, params| {
642 params.push(me.index_value(*instance));
643 params.push(me.index_value(*ty));
644 params.push(me.index_value(*options));
645 },
646 );
647 }
648 Trampoline::ErrorContextDrop { instance, ty } => {
649 self.translate_libcall(
650 host::error_context_drop,
651 TrapSentinel::Falsy,
652 WasmArgs::InRegisters,
653 |me, params| {
654 params.push(me.index_value(*instance));
655 params.push(me.index_value(*ty));
656 },
657 );
658 }
659 Trampoline::ResourceTransferOwn => {
660 self.translate_libcall(
661 host::resource_transfer_own,
662 TrapSentinel::NegativeOne,
663 WasmArgs::InRegisters,
664 |_, _| {},
665 );
666 }
667 Trampoline::ResourceTransferBorrow => {
668 self.translate_libcall(
669 host::resource_transfer_borrow,
670 TrapSentinel::NegativeOne,
671 WasmArgs::InRegisters,
672 |_, _| {},
673 );
674 }
675 Trampoline::ResourceEnterCall => {
676 self.translate_libcall(
677 host::resource_enter_call,
678 HostResult::None,
679 WasmArgs::InRegisters,
680 |_, _| {},
681 );
682 }
683 Trampoline::ResourceExitCall => {
684 self.translate_libcall(
685 host::resource_exit_call,
686 TrapSentinel::Falsy,
687 WasmArgs::InRegisters,
688 |_, _| {},
689 );
690 }
691 Trampoline::PrepareCall { memory } => {
692 self.translate_libcall(
693 host::prepare_call,
694 TrapSentinel::Falsy,
695 WasmArgs::InRegistersUpTo(PREPARE_CALL_FIXED_PARAMS.len()),
696 |me, params| {
697 let vmctx = params[0];
698 params.push(me.load_optional_memory(vmctx, *memory));
699 },
700 );
701 }
702 Trampoline::SyncStartCall { callback } => {
703 let pointer_type = self.isa.pointer_type();
704 let wasm_func_ty = &self.types[self.signature].unwrap_func();
705 let (values_vec_ptr, len) = self.compiler.allocate_stack_array_and_spill_args(
706 &WasmFuncType::new(
707 Box::new([]),
708 wasm_func_ty.returns().iter().copied().collect(),
709 ),
710 &mut self.builder,
711 &[],
712 );
713 let values_vec_len = self.builder.ins().iconst(pointer_type, i64::from(len));
714 self.translate_libcall(
715 host::sync_start,
716 HostResult::MultiValue {
717 ptr: Some(values_vec_ptr),
718 len: Some(values_vec_len),
719 },
720 WasmArgs::InRegisters,
721 |me, params| {
722 let vmctx = params[0];
723 params.push(me.load_callback(vmctx, *callback));
724 params.push(values_vec_ptr);
725 params.push(values_vec_len);
726 },
727 );
728 }
729 Trampoline::AsyncStartCall {
730 callback,
731 post_return,
732 } => {
733 self.translate_libcall(
734 host::async_start,
735 TrapSentinel::NegativeOne,
736 WasmArgs::InRegisters,
737 |me, params| {
738 let vmctx = params[0];
739 params.extend([
740 me.load_callback(vmctx, *callback),
741 me.load_post_return(vmctx, *post_return),
742 ]);
743 },
744 );
745 }
746 Trampoline::FutureTransfer => {
747 self.translate_libcall(
748 host::future_transfer,
749 TrapSentinel::NegativeOne,
750 WasmArgs::InRegisters,
751 |_, _| {},
752 );
753 }
754 Trampoline::StreamTransfer => {
755 self.translate_libcall(
756 host::stream_transfer,
757 TrapSentinel::NegativeOne,
758 WasmArgs::InRegisters,
759 |_, _| {},
760 );
761 }
762 Trampoline::ErrorContextTransfer => {
763 self.translate_libcall(
764 host::error_context_transfer,
765 TrapSentinel::NegativeOne,
766 WasmArgs::InRegisters,
767 |_, _| {},
768 );
769 }
770 Trampoline::ContextGet { instance, slot } => {
771 self.translate_libcall(
772 host::context_get,
773 TrapSentinel::NegativeOne,
774 WasmArgs::InRegisters,
775 |me, params| {
776 params.push(me.index_value(*instance));
777 params.push(me.builder.ins().iconst(ir::types::I32, i64::from(*slot)));
778 },
779 );
780 }
781 Trampoline::ContextSet { instance, slot } => {
782 self.translate_libcall(
783 host::context_set,
784 TrapSentinel::Falsy,
785 WasmArgs::InRegisters,
786 |me, params| {
787 params.push(me.index_value(*instance));
788 params.push(me.builder.ins().iconst(ir::types::I32, i64::from(*slot)));
789 },
790 );
791 }
792 }
793 }
794
795 fn flat_stream_element_info(&self, ty: TypeStreamTableIndex) -> Option<&CanonicalAbiInfo> {
803 let payload = self.types[self.types[ty].ty].payload;
804 match payload {
805 None => Some(&CanonicalAbiInfo::ZERO),
806 Some(
807 payload @ (InterfaceType::Bool
808 | InterfaceType::S8
809 | InterfaceType::U8
810 | InterfaceType::S16
811 | InterfaceType::U16
812 | InterfaceType::S32
813 | InterfaceType::U32
814 | InterfaceType::S64
815 | InterfaceType::U64
816 | InterfaceType::Float32
817 | InterfaceType::Float64
818 | InterfaceType::Char),
819 ) => Some(self.types.canonical_abi(&payload)),
820 _ => None,
823 }
824 }
825
826 fn store_wasm_arguments(&mut self, args: &[Value]) -> (Value, Value) {
829 let pointer_type = self.isa.pointer_type();
830 let wasm_func_ty = &self.types[self.signature].unwrap_func();
831
832 match self.abi {
833 Abi::Wasm => {
836 let (ptr, len) = self.compiler.allocate_stack_array_and_spill_args(
837 wasm_func_ty,
838 &mut self.builder,
839 args,
840 );
841 let len = self.builder.ins().iconst(pointer_type, i64::from(len));
842 (ptr, len)
843 }
844
845 Abi::Array => {
848 let params = self.builder.func.dfg.block_params(self.block0);
849 (params[2], params[3])
850 }
851 }
852 }
853
854 fn translate_libcall(
857 &mut self,
858 get_libcall: GetLibcallFn,
859 host_result: impl Into<HostResult>,
860 wasm_args: WasmArgs,
861 extra_host_args: impl FnOnce(&mut Self, &mut Vec<ir::Value>),
862 ) {
863 self.translate_hostcall(
864 HostCallee::Libcall(get_libcall),
865 host_result.into(),
866 wasm_args,
867 extra_host_args,
868 )
869 }
870
871 fn translate_hostcall(
885 &mut self,
886 host_callee: HostCallee,
887 host_result: impl Into<HostResult>,
888 wasm_args: WasmArgs,
889 extra_host_args: impl FnOnce(&mut Self, &mut Vec<ir::Value>),
890 ) {
891 let pointer_type = self.isa.pointer_type();
892 let wasm_func_ty = self.types[self.signature].unwrap_func();
893
894 let params = self.abi_load_params();
897 let vmctx = params[0];
898 let wasm_params = ¶ms[2..];
899
900 let mut host_args = vec![vmctx];
904 extra_host_args(self, &mut host_args);
905 let mut val_raw_ptr = None;
906 let mut val_raw_len = None;
907 match wasm_args {
908 WasmArgs::InRegisters => host_args.extend(wasm_params.iter().copied()),
910
911 WasmArgs::ValRawList => {
913 let (ptr, len) = self.store_wasm_arguments(wasm_params);
914 val_raw_ptr = Some(ptr);
915 val_raw_len = Some(len);
916 host_args.push(ptr);
917 host_args.push(len);
918 }
919
920 WasmArgs::InRegistersUpTo(n) => {
922 let (values_vec_ptr, len) = self.compiler.allocate_stack_array_and_spill_args(
923 &WasmFuncType::new(
924 wasm_func_ty.params().iter().skip(n).copied().collect(),
925 Box::new([]),
926 ),
927 &mut self.builder,
928 &wasm_params[n..],
929 );
930 let values_vec_len = self.builder.ins().iconst(pointer_type, i64::from(len));
931
932 host_args.extend(wasm_params[..n].iter().copied());
933 host_args.push(values_vec_ptr);
934 host_args.push(values_vec_len);
935 }
936 }
937
938 let call = match host_callee {
940 HostCallee::Libcall(get_libcall) => self.call_libcall(vmctx, get_libcall, &host_args),
941 HostCallee::Lowering(index) => {
942 let host_fn = self.builder.ins().load(
945 pointer_type,
946 MemFlags::trusted(),
947 vmctx,
948 i32::try_from(self.offsets.lowering_callee(index)).unwrap(),
949 );
950 let host_sig = {
951 let mut sig = ir::Signature::new(CallConv::triple_default(self.isa.triple()));
952 for param in host_args.iter() {
953 let ty = self.builder.func.dfg.value_type(*param);
954 sig.params.push(ir::AbiParam::new(ty));
955 }
956 sig.returns.push(ir::AbiParam::new(ir::types::I8));
958 self.builder.import_signature(sig)
959 };
960 self.compiler.call_indirect_host(
961 &mut self.builder,
962 HostCall::ComponentLowerImport,
963 host_sig,
964 host_fn,
965 &host_args,
966 )
967 }
968 };
969
970 let result = self.builder.func.dfg.inst_results(call).get(0).copied();
976 let result_ty = result.map(|v| self.builder.func.dfg.value_type(v));
977 let expected = wasm_func_ty.returns();
978 match host_result.into() {
979 HostResult::Sentinel(TrapSentinel::NegativeOne) => {
980 assert_eq!(expected.len(), 1);
981 let (result, result_ty) = (result.unwrap(), result_ty.unwrap());
982 let result = match (result_ty, expected[0]) {
983 (ir::types::I64, WasmValType::I32) => {
984 self.raise_if_negative_one_and_truncate(result)
985 }
986 (ir::types::I64, WasmValType::I64) | (ir::types::I32, WasmValType::I32) => {
987 self.raise_if_negative_one(result)
988 }
989 other => panic!("unsupported NegativeOne combo {other:?}"),
990 };
991 self.abi_store_results(&[result]);
992 }
993 HostResult::Sentinel(TrapSentinel::Falsy) => {
994 assert_eq!(expected.len(), 0);
995 self.raise_if_host_trapped(result.unwrap());
996 self.abi_store_results(&[]);
997 }
998 HostResult::Sentinel(_) => todo!("support additional return types if/when necessary"),
999 HostResult::None => {
1000 assert!(result.is_none());
1001 self.abi_store_results(&[]);
1002 }
1003
1004 HostResult::MultiValue { ptr, len } => {
1005 let ptr = ptr.or(val_raw_ptr).unwrap();
1006 let len = len.or(val_raw_len).unwrap();
1007 self.raise_if_host_trapped(result.unwrap());
1008 let results = self.compiler.load_values_from_array(
1009 wasm_func_ty.returns(),
1010 &mut self.builder,
1011 ptr,
1012 len,
1013 );
1014 self.abi_store_results(&results);
1015 }
1016 }
1017 }
1018
1019 fn index_value(&mut self, index: impl EntityRef) -> ir::Value {
1020 self.builder
1021 .ins()
1022 .iconst(ir::types::I32, i64::try_from(index.index()).unwrap())
1023 }
1024
1025 fn translate_resource_drop(
1026 &mut self,
1027 instance: RuntimeComponentInstanceIndex,
1028 resource: TypeResourceTableIndex,
1029 ) {
1030 let args = self.abi_load_params();
1031 let vmctx = args[0];
1032 let caller_vmctx = args[1];
1033 let pointer_type = self.isa.pointer_type();
1034
1035 let mut host_args = Vec::new();
1042 host_args.push(vmctx);
1043 host_args.push(
1044 self.builder
1045 .ins()
1046 .iconst(ir::types::I32, i64::from(instance.as_u32())),
1047 );
1048 host_args.push(
1049 self.builder
1050 .ins()
1051 .iconst(ir::types::I32, i64::from(resource.as_u32())),
1052 );
1053 host_args.push(args[2]);
1054
1055 let call = self.call_libcall(vmctx, host::resource_drop, &host_args);
1056
1057 let should_run_destructor =
1059 self.raise_if_negative_one(self.builder.func.dfg.inst_results(call)[0]);
1060
1061 let resource_ty = self.types[resource].ty;
1062 let resource_def = self
1063 .component
1064 .defined_resource_index(resource_ty)
1065 .map(|idx| {
1066 self.component
1067 .initializers
1068 .iter()
1069 .filter_map(|i| match i {
1070 GlobalInitializer::Resource(r) if r.index == idx => Some(r),
1071 _ => None,
1072 })
1073 .next()
1074 .unwrap()
1075 });
1076 let has_destructor = match resource_def {
1077 Some(def) => def.dtor.is_some(),
1078 None => true,
1079 };
1080 self.builder.ensure_inserted_block();
1113 let current_block = self.builder.current_block().unwrap();
1114 let run_destructor_block = self.builder.create_block();
1115 self.builder
1116 .insert_block_after(run_destructor_block, current_block);
1117 let return_block = self.builder.create_block();
1118 self.builder
1119 .insert_block_after(return_block, run_destructor_block);
1120
1121 self.builder.ins().brif(
1122 should_run_destructor,
1123 run_destructor_block,
1124 &[],
1125 return_block,
1126 &[],
1127 );
1128
1129 let trusted = ir::MemFlags::trusted().with_readonly();
1130
1131 self.builder.switch_to_block(run_destructor_block);
1132
1133 if let Some(def) = resource_def {
1139 if self.types[resource].instance != def.instance {
1140 let flags = self.builder.ins().load(
1141 ir::types::I32,
1142 trusted,
1143 vmctx,
1144 i32::try_from(self.offsets.instance_flags(def.instance)).unwrap(),
1145 );
1146 let masked = self
1147 .builder
1148 .ins()
1149 .band_imm(flags, i64::from(FLAG_MAY_ENTER));
1150 self.builder.ins().trapz(masked, TRAP_CANNOT_ENTER);
1151 }
1152 }
1153
1154 if has_destructor {
1157 let rep = self.builder.ins().ushr_imm(should_run_destructor, 1);
1158 let rep = self.builder.ins().ireduce(ir::types::I32, rep);
1159 let index = self.types[resource].ty;
1160 let dtor_func_ref = self.builder.ins().load(
1164 pointer_type,
1165 trusted,
1166 vmctx,
1167 i32::try_from(self.offsets.resource_destructor(index)).unwrap(),
1168 );
1169 if self.compiler.emit_debug_checks {
1170 self.builder
1171 .ins()
1172 .trapz(dtor_func_ref, TRAP_INTERNAL_ASSERT);
1173 }
1174 let func_addr = self.builder.ins().load(
1175 pointer_type,
1176 trusted,
1177 dtor_func_ref,
1178 i32::from(self.offsets.ptr.vm_func_ref_wasm_call()),
1179 );
1180 let callee_vmctx = self.builder.ins().load(
1181 pointer_type,
1182 trusted,
1183 dtor_func_ref,
1184 i32::from(self.offsets.ptr.vm_func_ref_vmctx()),
1185 );
1186
1187 let sig = crate::wasm_call_signature(
1188 self.isa,
1189 &self.types[self.signature].unwrap_func(),
1190 &self.compiler.tunables,
1191 );
1192 let sig_ref = self.builder.import_signature(sig);
1193
1194 self.builder.ins().call_indirect(
1200 sig_ref,
1201 func_addr,
1202 &[callee_vmctx, caller_vmctx, rep],
1203 );
1204 }
1205 self.builder.ins().jump(return_block, &[]);
1206 self.builder.seal_block(run_destructor_block);
1207
1208 self.builder.switch_to_block(return_block);
1209 self.builder.seal_block(return_block);
1210 self.abi_store_results(&[]);
1211 }
1212
1213 fn load_optional_memory(
1214 &mut self,
1215 vmctx: ir::Value,
1216 memory: Option<RuntimeMemoryIndex>,
1217 ) -> ir::Value {
1218 match memory {
1219 Some(idx) => self.load_memory(vmctx, idx),
1220 None => self.builder.ins().iconst(self.isa.pointer_type(), 0),
1221 }
1222 }
1223
1224 fn load_memory(&mut self, vmctx: ir::Value, memory: RuntimeMemoryIndex) -> ir::Value {
1225 self.builder.ins().load(
1226 self.isa.pointer_type(),
1227 MemFlags::trusted(),
1228 vmctx,
1229 i32::try_from(self.offsets.runtime_memory(memory)).unwrap(),
1230 )
1231 }
1232
1233 fn load_callback(
1234 &mut self,
1235 vmctx: ir::Value,
1236 callback: Option<RuntimeCallbackIndex>,
1237 ) -> ir::Value {
1238 let pointer_type = self.isa.pointer_type();
1239 match callback {
1240 Some(idx) => self.builder.ins().load(
1241 pointer_type,
1242 MemFlags::trusted(),
1243 vmctx,
1244 i32::try_from(self.offsets.runtime_callback(idx)).unwrap(),
1245 ),
1246 None => self.builder.ins().iconst(pointer_type, 0),
1247 }
1248 }
1249
1250 fn load_post_return(
1251 &mut self,
1252 vmctx: ir::Value,
1253 post_return: Option<RuntimePostReturnIndex>,
1254 ) -> ir::Value {
1255 let pointer_type = self.isa.pointer_type();
1256 match post_return {
1257 Some(idx) => self.builder.ins().load(
1258 pointer_type,
1259 MemFlags::trusted(),
1260 vmctx,
1261 i32::try_from(self.offsets.runtime_post_return(idx)).unwrap(),
1262 ),
1263 None => self.builder.ins().iconst(pointer_type, 0),
1264 }
1265 }
1266
1267 fn load_libcall(
1272 &mut self,
1273 vmctx: ir::Value,
1274 index: ComponentBuiltinFunctionIndex,
1275 ) -> ir::Value {
1276 let pointer_type = self.isa.pointer_type();
1277 let builtins_array = self.builder.ins().load(
1280 pointer_type,
1281 MemFlags::trusted().with_readonly(),
1282 vmctx,
1283 i32::try_from(self.offsets.builtins()).unwrap(),
1284 );
1285 self.builder.ins().load(
1287 pointer_type,
1288 MemFlags::trusted().with_readonly(),
1289 builtins_array,
1290 i32::try_from(index.index() * u32::from(self.offsets.ptr.size())).unwrap(),
1291 )
1292 }
1293
1294 fn abi_load_params(&mut self) -> Vec<ir::Value> {
1295 let mut block0_params = self.builder.func.dfg.block_params(self.block0).to_vec();
1296 match self.abi {
1297 Abi::Wasm => block0_params,
1300
1301 Abi::Array => {
1304 let results = self.compiler.load_values_from_array(
1305 self.types[self.signature].unwrap_func().params(),
1306 &mut self.builder,
1307 block0_params[2],
1308 block0_params[3],
1309 );
1310 block0_params.truncate(2);
1311 block0_params.extend(results);
1312 block0_params
1313 }
1314 }
1315 }
1316
1317 fn abi_store_results(&mut self, results: &[ir::Value]) {
1318 match self.abi {
1319 Abi::Wasm => {
1321 self.builder.ins().return_(results);
1322 }
1323
1324 Abi::Array => {
1328 let block0_params = self.builder.func.dfg.block_params(self.block0);
1329 let (ptr, len) = (block0_params[2], block0_params[3]);
1330 self.compiler.store_values_to_array(
1331 &mut self.builder,
1332 self.types[self.signature].unwrap_func().returns(),
1333 results,
1334 ptr,
1335 len,
1336 );
1337 let true_value = self.builder.ins().iconst(ir::types::I8, 1);
1338 self.builder.ins().return_(&[true_value]);
1339 }
1340 }
1341 }
1342
1343 fn raise_if_host_trapped(&mut self, succeeded: ir::Value) {
1344 let caller_vmctx = self.builder.func.dfg.block_params(self.block0)[1];
1345 self.compiler
1346 .raise_if_host_trapped(&mut self.builder, caller_vmctx, succeeded);
1347 }
1348
1349 fn raise_if_transcode_trapped(&mut self, amount_copied: ir::Value) {
1350 let pointer_type = self.isa.pointer_type();
1351 let minus_one = self.builder.ins().iconst(pointer_type, -1);
1352 let succeeded = self
1353 .builder
1354 .ins()
1355 .icmp(IntCC::NotEqual, amount_copied, minus_one);
1356 self.raise_if_host_trapped(succeeded);
1357 }
1358
1359 fn raise_if_negative_one_and_truncate(&mut self, ret: ir::Value) -> ir::Value {
1360 let ret = self.raise_if_negative_one(ret);
1361 self.builder.ins().ireduce(ir::types::I32, ret)
1362 }
1363
1364 fn raise_if_negative_one(&mut self, ret: ir::Value) -> ir::Value {
1365 let result_ty = self.builder.func.dfg.value_type(ret);
1366 let minus_one = self.builder.ins().iconst(result_ty, -1);
1367 let succeeded = self.builder.ins().icmp(IntCC::NotEqual, ret, minus_one);
1368 self.raise_if_host_trapped(succeeded);
1369 ret
1370 }
1371
1372 fn call_libcall(
1373 &mut self,
1374 vmctx: ir::Value,
1375 get_libcall: GetLibcallFn,
1376 args: &[ir::Value],
1377 ) -> ir::Inst {
1378 let (host_sig, index) = get_libcall(self.isa, &mut self.builder.func);
1379 let host_fn = self.load_libcall(vmctx, index);
1380 self.compiler
1381 .call_indirect_host(&mut self.builder, index, host_sig, host_fn, args)
1382 }
1383}
1384
1385impl ComponentCompiler for Compiler {
1386 fn compile_trampoline(
1387 &self,
1388 component: &ComponentTranslation,
1389 types: &ComponentTypesBuilder,
1390 key: FuncKey,
1391 abi: Abi,
1392 tunables: &Tunables,
1393 symbol: &str,
1394 ) -> Result<CompiledFunctionBody> {
1395 let (abi2, trampoline_index) = key.unwrap_component_trampoline();
1396 debug_assert_eq!(abi, abi2);
1397
1398 match abi {
1399 Abi::Wasm => {}
1401
1402 Abi::Array => {
1405 let offsets =
1406 VMComponentOffsets::new(self.isa.pointer_bytes(), &component.component);
1407 return Ok(self.array_to_wasm_trampoline(
1408 key,
1409 FuncKey::ComponentTrampoline(Abi::Wasm, trampoline_index),
1410 types.module_types_builder(),
1411 component.component.trampolines[trampoline_index],
1412 symbol,
1413 offsets.vm_store_context(),
1414 wasmtime_environ::component::VMCOMPONENT_MAGIC,
1415 )?);
1416 }
1417 }
1418
1419 let mut compiler = self.function_compiler();
1420 let mut c = TrampolineCompiler::new(
1421 self,
1422 &mut compiler,
1423 &component.component,
1424 types,
1425 trampoline_index,
1426 abi,
1427 tunables,
1428 );
1429
1430 let vmctx = c.builder.block_params(c.block0)[0];
1436 let pointer_type = self.isa.pointer_type();
1437 self.debug_assert_vmctx_kind(
1438 &mut c.builder,
1439 vmctx,
1440 wasmtime_environ::component::VMCOMPONENT_MAGIC,
1441 );
1442 if let Abi::Wasm = abi {
1443 let vm_store_context = c.builder.ins().load(
1444 pointer_type,
1445 MemFlags::trusted(),
1446 vmctx,
1447 i32::try_from(c.offsets.vm_store_context()).unwrap(),
1448 );
1449 super::save_last_wasm_exit_fp_and_pc(
1450 &mut c.builder,
1451 pointer_type,
1452 &c.offsets.ptr,
1453 vm_store_context,
1454 );
1455 }
1456
1457 c.translate(&component.trampolines[trampoline_index]);
1458 c.builder.finalize();
1459 compiler.cx.abi = Some(abi);
1460
1461 Ok(CompiledFunctionBody {
1462 code: super::box_dyn_any_compiler_context(Some(compiler.cx)),
1463 needs_gc_heap: false,
1464 })
1465 }
1466}
1467
1468impl TrampolineCompiler<'_> {
1469 fn translate_transcode(
1470 &mut self,
1471 op: Transcode,
1472 from: RuntimeMemoryIndex,
1473 from64: bool,
1474 to: RuntimeMemoryIndex,
1475 to64: bool,
1476 ) {
1477 let pointer_type = self.isa.pointer_type();
1478 let vmctx = self.builder.func.dfg.block_params(self.block0)[0];
1479
1480 let get_libcall = match op {
1484 Transcode::Copy(FixedEncoding::Utf8) => host::utf8_to_utf8,
1485 Transcode::Copy(FixedEncoding::Utf16) => host::utf16_to_utf16,
1486 Transcode::Copy(FixedEncoding::Latin1) => host::latin1_to_latin1,
1487 Transcode::Latin1ToUtf16 => host::latin1_to_utf16,
1488 Transcode::Latin1ToUtf8 => host::latin1_to_utf8,
1489 Transcode::Utf16ToCompactProbablyUtf16 => host::utf16_to_compact_probably_utf16,
1490 Transcode::Utf16ToCompactUtf16 => host::utf16_to_compact_utf16,
1491 Transcode::Utf16ToLatin1 => host::utf16_to_latin1,
1492 Transcode::Utf16ToUtf8 => host::utf16_to_utf8,
1493 Transcode::Utf8ToCompactUtf16 => host::utf8_to_compact_utf16,
1494 Transcode::Utf8ToLatin1 => host::utf8_to_latin1,
1495 Transcode::Utf8ToUtf16 => host::utf8_to_utf16,
1496 };
1497
1498 let from_base = self.load_runtime_memory_base(vmctx, from);
1500 let to_base = self.load_runtime_memory_base(vmctx, to);
1501
1502 let mut args = Vec::new();
1503 args.push(vmctx);
1504
1505 let uses_retptr = match op {
1506 Transcode::Utf16ToUtf8
1507 | Transcode::Latin1ToUtf8
1508 | Transcode::Utf8ToLatin1
1509 | Transcode::Utf16ToLatin1 => true,
1510 _ => false,
1511 };
1512
1513 match op {
1517 Transcode::Copy(_)
1518 | Transcode::Latin1ToUtf16
1519 | Transcode::Utf16ToCompactProbablyUtf16
1520 | Transcode::Utf8ToLatin1
1521 | Transcode::Utf16ToLatin1
1522 | Transcode::Utf8ToUtf16 => {
1523 args.push(self.ptr_param(0, from64, from_base));
1524 args.push(self.len_param(1, from64));
1525 args.push(self.ptr_param(2, to64, to_base));
1526 }
1527
1528 Transcode::Utf16ToUtf8 | Transcode::Latin1ToUtf8 => {
1529 args.push(self.ptr_param(0, from64, from_base));
1530 args.push(self.len_param(1, from64));
1531 args.push(self.ptr_param(2, to64, to_base));
1532 args.push(self.len_param(3, to64));
1533 }
1534
1535 Transcode::Utf8ToCompactUtf16 | Transcode::Utf16ToCompactUtf16 => {
1536 args.push(self.ptr_param(0, from64, from_base));
1537 args.push(self.len_param(1, from64));
1538 args.push(self.ptr_param(2, to64, to_base));
1539 args.push(self.len_param(3, to64));
1540 args.push(self.len_param(4, to64));
1541 }
1542 };
1543 if uses_retptr {
1544 let slot = self
1545 .builder
1546 .func
1547 .create_sized_stack_slot(ir::StackSlotData::new(
1548 ir::StackSlotKind::ExplicitSlot,
1549 pointer_type.bytes(),
1550 0,
1551 ));
1552 args.push(self.builder.ins().stack_addr(pointer_type, slot, 0));
1553 }
1554 let call = self.call_libcall(vmctx, get_libcall, &args);
1555 let mut results = self.builder.func.dfg.inst_results(call).to_vec();
1556 if uses_retptr {
1557 results.push(self.builder.ins().load(
1558 pointer_type,
1559 ir::MemFlags::trusted(),
1560 *args.last().unwrap(),
1561 0,
1562 ));
1563 }
1564 let mut raw_results = Vec::new();
1565
1566 match op {
1569 Transcode::Copy(_) | Transcode::Latin1ToUtf16 => {
1570 self.raise_if_host_trapped(results[0]);
1571 }
1572
1573 Transcode::Utf8ToUtf16
1574 | Transcode::Utf16ToCompactProbablyUtf16
1575 | Transcode::Utf8ToCompactUtf16
1576 | Transcode::Utf16ToCompactUtf16 => {
1577 self.raise_if_transcode_trapped(results[0]);
1578 raw_results.push(self.cast_from_pointer(results[0], to64));
1579 }
1580
1581 Transcode::Latin1ToUtf8
1582 | Transcode::Utf16ToUtf8
1583 | Transcode::Utf8ToLatin1
1584 | Transcode::Utf16ToLatin1 => {
1585 self.raise_if_transcode_trapped(results[0]);
1586 raw_results.push(self.cast_from_pointer(results[0], from64));
1587 raw_results.push(self.cast_from_pointer(results[1], to64));
1588 }
1589 };
1590
1591 self.builder.ins().return_(&raw_results);
1592 }
1593
1594 fn len_param(&mut self, param: usize, is64: bool) -> ir::Value {
1596 let val = self.builder.func.dfg.block_params(self.block0)[2 + param];
1597 self.cast_to_pointer(val, is64)
1598 }
1599
1600 fn ptr_param(&mut self, param: usize, is64: bool, base: ir::Value) -> ir::Value {
1607 let val = self.len_param(param, is64);
1608 self.builder.ins().iadd(base, val)
1609 }
1610
1611 fn cast_to_pointer(&mut self, val: ir::Value, is64: bool) -> ir::Value {
1614 let pointer_type = self.isa.pointer_type();
1615 let host64 = pointer_type == ir::types::I64;
1616 if is64 == host64 {
1617 val
1618 } else if !is64 {
1619 assert!(host64);
1620 self.builder.ins().uextend(pointer_type, val)
1621 } else {
1622 assert!(!host64);
1623 self.builder.ins().ireduce(pointer_type, val)
1624 }
1625 }
1626
1627 fn cast_from_pointer(&mut self, val: ir::Value, is64: bool) -> ir::Value {
1629 let host64 = self.isa.pointer_type() == ir::types::I64;
1630 if is64 == host64 {
1631 val
1632 } else if !is64 {
1633 assert!(host64);
1634 self.builder.ins().ireduce(ir::types::I32, val)
1635 } else {
1636 assert!(!host64);
1637 self.builder.ins().uextend(ir::types::I64, val)
1638 }
1639 }
1640
1641 fn load_runtime_memory_base(&mut self, vmctx: ir::Value, mem: RuntimeMemoryIndex) -> ir::Value {
1642 let pointer_type = self.isa.pointer_type();
1643 let from_vmmemory_definition = self.load_memory(vmctx, mem);
1644 self.builder.ins().load(
1645 pointer_type,
1646 MemFlags::trusted(),
1647 from_vmmemory_definition,
1648 i32::from(self.offsets.ptr.vmmemory_definition_base()),
1649 )
1650 }
1651}
1652
1653mod host {
1659 use cranelift_codegen::ir::{self, AbiParam};
1660 use cranelift_codegen::isa::{CallConv, TargetIsa};
1661 use wasmtime_environ::component::ComponentBuiltinFunctionIndex;
1662
1663 macro_rules! define {
1664 (
1665 $(
1666 $( #[$attr:meta] )*
1667 $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
1668 )*
1669 ) => {
1670 $(
1671 pub(super) fn $name(isa: &dyn TargetIsa, func: &mut ir::Function) -> (ir::SigRef, ComponentBuiltinFunctionIndex) {
1672 let pointer_type = isa.pointer_type();
1673 let sig = build_sig(
1674 isa,
1675 func,
1676 &[$( define!(@ty pointer_type $param) ),*],
1677 &[$( define!(@ty pointer_type $result) ),*],
1678 );
1679
1680 return (sig, ComponentBuiltinFunctionIndex::$name())
1681 }
1682 )*
1683 };
1684
1685 (@ty $ptr:ident size) => ($ptr);
1686 (@ty $ptr:ident ptr_u8) => ($ptr);
1687 (@ty $ptr:ident ptr_u16) => ($ptr);
1688 (@ty $ptr:ident ptr_size) => ($ptr);
1689 (@ty $ptr:ident bool) => (ir::types::I8);
1690 (@ty $ptr:ident u8) => (ir::types::I8);
1691 (@ty $ptr:ident u32) => (ir::types::I32);
1692 (@ty $ptr:ident u64) => (ir::types::I64);
1693 (@ty $ptr:ident vmctx) => ($ptr);
1694 }
1695
1696 wasmtime_environ::foreach_builtin_component_function!(define);
1697
1698 fn build_sig(
1699 isa: &dyn TargetIsa,
1700 func: &mut ir::Function,
1701 params: &[ir::Type],
1702 returns: &[ir::Type],
1703 ) -> ir::SigRef {
1704 let mut sig = ir::Signature {
1705 params: params.iter().map(|ty| AbiParam::new(*ty)).collect(),
1706 returns: returns.iter().map(|ty| AbiParam::new(*ty)).collect(),
1707 call_conv: CallConv::triple_default(isa.triple()),
1708 };
1709
1710 let extension = isa.default_argument_extension();
1714 for arg in sig.params.iter_mut().chain(sig.returns.iter_mut()) {
1715 if arg.value_type.is_int() {
1716 arg.extension = extension;
1717 }
1718 }
1719 func.import_signature(sig)
1720 }
1721}