2019-03-01 23:48:43 +00:00
|
|
|
use crate::intrinsics::Intrinsics;
|
2019-03-01 02:26:47 +00:00
|
|
|
use inkwell::{
|
|
|
|
builder::Builder,
|
|
|
|
context::Context,
|
|
|
|
module::{Linkage, Module},
|
|
|
|
passes::PassManager,
|
|
|
|
types::{BasicType, BasicTypeEnum, FunctionType, PointerType},
|
|
|
|
values::{BasicValue, FunctionValue, PhiValue, PointerValue},
|
|
|
|
AddressSpace, FloatPredicate, IntPredicate,
|
|
|
|
};
|
|
|
|
use wasmer_runtime_core::{
|
|
|
|
module::ModuleInfo,
|
2019-03-01 23:48:43 +00:00
|
|
|
structures::{SliceMap, TypedIndex},
|
|
|
|
types::{FuncSig, SigIndex, Type},
|
2019-03-01 02:26:47 +00:00
|
|
|
};
|
|
|
|
|
2019-03-01 23:48:43 +00:00
|
|
|
pub fn generate_trampolines(
|
|
|
|
info: &ModuleInfo,
|
|
|
|
signatures: &SliceMap<SigIndex, FunctionType>,
|
|
|
|
module: &Module,
|
|
|
|
context: &Context,
|
|
|
|
builder: &Builder,
|
|
|
|
intrinsics: &Intrinsics,
|
|
|
|
) {
|
2019-03-01 02:26:47 +00:00
|
|
|
for (sig_index, sig) in info.signatures.iter() {
|
2019-03-01 23:48:43 +00:00
|
|
|
let func_type = signatures[sig_index];
|
|
|
|
|
|
|
|
let trampoline_sig = intrinsics.void_ty.fn_type(
|
|
|
|
&[
|
|
|
|
intrinsics.ctx_ptr_ty.as_basic_type_enum(), // vmctx ptr
|
|
|
|
func_type
|
|
|
|
.ptr_type(AddressSpace::Generic)
|
|
|
|
.as_basic_type_enum(), // func ptr
|
|
|
|
intrinsics.i64_ptr_ty.as_basic_type_enum(), // args ptr
|
|
|
|
intrinsics.i64_ptr_ty.as_basic_type_enum(), // returns ptr
|
|
|
|
],
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
|
|
|
|
let trampoline_func = module.add_function(
|
|
|
|
&format!("trmp{}", sig_index.index()),
|
|
|
|
trampoline_sig,
|
|
|
|
Some(Linkage::External),
|
|
|
|
);
|
2019-03-01 02:26:47 +00:00
|
|
|
|
2019-03-01 23:48:43 +00:00
|
|
|
generate_trampoline(
|
|
|
|
trampoline_func,
|
|
|
|
func_type,
|
|
|
|
sig,
|
|
|
|
context,
|
|
|
|
builder,
|
|
|
|
intrinsics,
|
|
|
|
);
|
2019-03-01 02:26:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-01 23:48:43 +00:00
|
|
|
fn generate_trampoline(
|
|
|
|
trampoline_func: FunctionValue,
|
|
|
|
sig_type: FunctionType,
|
|
|
|
func_sig: &FuncSig,
|
|
|
|
context: &Context,
|
|
|
|
builder: &Builder,
|
|
|
|
intrinsics: &Intrinsics,
|
|
|
|
) {
|
|
|
|
let entry_block = context.append_basic_block(&trampoline_func, "entry");
|
|
|
|
builder.position_at_end(&entry_block);
|
|
|
|
|
|
|
|
let (vmctx_ptr, func_ptr, args_ptr, returns_ptr) = match trampoline_func.get_params().as_slice()
|
|
|
|
{
|
|
|
|
&[vmctx_ptr, func_ptr, args_ptr, returns_ptr] => (
|
|
|
|
vmctx_ptr,
|
|
|
|
func_ptr.into_pointer_value(),
|
|
|
|
args_ptr.into_pointer_value(),
|
|
|
|
returns_ptr.into_pointer_value(),
|
|
|
|
),
|
|
|
|
_ => unimplemented!(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let cast_ptr_ty = |wasmer_ty| match wasmer_ty {
|
|
|
|
Type::I32 => intrinsics.i32_ptr_ty,
|
|
|
|
Type::I64 => intrinsics.i64_ptr_ty,
|
|
|
|
Type::F32 => intrinsics.f32_ptr_ty,
|
|
|
|
Type::F64 => intrinsics.f64_ptr_ty,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1);
|
|
|
|
args_vec.push(vmctx_ptr);
|
|
|
|
|
|
|
|
for (i, param_ty) in func_sig.params().iter().enumerate() {
|
|
|
|
let index = intrinsics.i32_ty.const_int(i as _, false);
|
|
|
|
let item_pointer = unsafe { builder.build_in_bounds_gep(args_ptr, &[index], "arg_ptr") };
|
2019-03-01 02:26:47 +00:00
|
|
|
|
2019-03-01 23:48:43 +00:00
|
|
|
let casted_pointer_type = cast_ptr_ty(*param_ty);
|
2019-03-01 02:26:47 +00:00
|
|
|
|
2019-03-01 23:48:43 +00:00
|
|
|
let typed_item_pointer =
|
|
|
|
builder.build_pointer_cast(item_pointer, casted_pointer_type, "typed_arg_pointer");
|
|
|
|
|
|
|
|
let arg = builder.build_load(typed_item_pointer, "arg");
|
|
|
|
args_vec.push(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
let call_site = builder.build_call(func_ptr, &args_vec, "call");
|
|
|
|
|
|
|
|
match func_sig.returns() {
|
|
|
|
&[] => {}
|
|
|
|
&[one_ret] => {
|
|
|
|
let ret_ptr_type = cast_ptr_ty(one_ret);
|
|
|
|
|
|
|
|
let typed_ret_ptr =
|
|
|
|
builder.build_pointer_cast(returns_ptr, ret_ptr_type, "typed_ret_ptr");
|
|
|
|
builder.build_store(
|
|
|
|
typed_ret_ptr,
|
|
|
|
call_site.try_as_basic_value().left().unwrap(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => unimplemented!("multi-value returns"),
|
|
|
|
}
|
|
|
|
|
|
|
|
builder.build_return(None);
|
|
|
|
}
|