MCPcopy Create free account
hub / github.com/bytecodealliance/wasmtime / make_trampoline

Function make_trampoline

cranelift/filetests/src/function_runner.rs:545–617  ·  view source on GitHub ↗

Build the Cranelift IR for moving the memory-allocated [DataValue]s to their correct location (e.g. register, stack) prior to calling a [CompiledFunction]. The [Function] returned by [make_trampoline] is compiled to a [Trampoline]. Note that this uses the [TargetIsa]'s default calling convention so we must also check that the [CompiledFunction] has the same calling convention (see [TestFileCompile

(name: UserFuncName, signature: &ir::Signature, isa: &dyn TargetIsa)

Source from the content-addressed store, hash-verified

543/// calling convention so we must also check that the [CompiledFunction] has the same calling
544/// convention (see [TestFileCompiler::compile]).
545fn make_trampoline(name: UserFuncName, signature: &ir::Signature, isa: &dyn TargetIsa) -> Function {
546 // Create the trampoline signature: (callee_address: pointer, values_vec: pointer) -> ()
547 let pointer_type = isa.pointer_type();
548 let mut wrapper_sig = ir::Signature::new(isa.frontend_config().default_call_conv);
549 wrapper_sig.params.push(ir::AbiParam::new(pointer_type)); // Add the `callee_address` parameter.
550 wrapper_sig.params.push(ir::AbiParam::new(pointer_type)); // Add the `values_vec` parameter.
551
552 let mut func = ir::Function::with_name_signature(name, wrapper_sig);
553
554 // The trampoline has a single block filled with loads, one call to callee_address, and some loads.
555 let mut builder_context = FunctionBuilderContext::new();
556 let mut builder = FunctionBuilder::new(&mut func, &mut builder_context);
557 let block0 = builder.create_block();
558 builder.append_block_params_for_function_params(block0);
559 builder.switch_to_block(block0);
560 builder.seal_block(block0);
561
562 // Extract the incoming SSA values.
563 let (callee_value, values_vec_ptr_val) = {
564 let params = builder.func.dfg.block_params(block0);
565 (params[0], params[1])
566 };
567
568 // Load the argument values out of `values_vec`.
569 let callee_args = signature
570 .params
571 .iter()
572 .enumerate()
573 .map(|(i, param)| {
574 // We always store vector types in little-endian byte order as DataValue.
575 let mut flags = ir::MemFlagsData::trusted();
576 if param.value_type.is_vector() {
577 flags.set_endianness(ir::Endianness::Little);
578 }
579
580 // Load the value.
581 builder.ins().load(
582 param.value_type,
583 flags,
584 values_vec_ptr_val,
585 (i * UnboxedValues::SLOT_SIZE) as i32,
586 )
587 })
588 .collect::<Vec<_>>();
589
590 // Call the passed function.
591 let new_sig = builder.import_signature(signature.clone());
592 let call = builder
593 .ins()
594 .call_indirect(new_sig, callee_value, &callee_args);
595
596 // Store the return values into `values_vec`.
597 let results = builder.func.dfg.inst_results(call).to_vec();
598 for ((i, value), param) in results.iter().enumerate().zip(&signature.returns) {
599 // We always store vector types in little-endian byte order as DataValue.
600 let mut flags = ir::MemFlagsData::trusted();
601 if param.value_type.is_vector() {
602 flags.set_endianness(ir::Endianness::Little);

Callers 2

trampolinesFunction · 0.85

Calls 15

frontend_configMethod · 0.80
create_blockMethod · 0.80
switch_to_blockMethod · 0.80
set_endiannessMethod · 0.80
call_indirectMethod · 0.80
newFunction · 0.50
pointer_typeMethod · 0.45
pushMethod · 0.45
seal_blockMethod · 0.45
block_paramsMethod · 0.45
mapMethod · 0.45

Tested by 1

trampolinesFunction · 0.68