Add preliminary support for throwing and catching uncatchable exceptions.

Additional info:
- WebAssembly "traps" are uncatchable, but are still caught by the trampoline caller.
This commit is contained in:
Lachlan Sneff
2019-03-02 12:57:35 -08:00
parent 5760f6006a
commit 9a90689b93
5 changed files with 120 additions and 11 deletions

View File

@ -71,6 +71,16 @@ extern "C" {
) -> LLVMResult;
fn module_delete(module: *mut LLVMModule);
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
fn throw_unreachable_exception();
fn throw_incorrect_call_indirect_signature();
// invoke_trampoline(trampoline_t trampoline, void* ctx, void* func, void* params, void* results)
fn invoke_trampoline(
trampoline: unsafe extern "C" fn(*mut vm::Ctx, *const vm::Func, *const u64, *mut u64),
vmctx_ptr: *mut vm::Ctx,
func_ptr: *const vm::Func,
params: *const u64,
results: *mut u64,
);
}
fn get_callbacks() -> Callbacks {
@ -162,6 +172,11 @@ fn get_callbacks() -> Callbacks {
fn_name!("vm.memory.size.dynamic.local") => vmcalls::local_dynamic_memory_size as _,
fn_name!("vm.memory.grow.static.local") => vmcalls::local_static_memory_grow as _,
fn_name!("vm.memory.size.static.local") => vmcalls::local_static_memory_size as _,
fn_name!("vm.exception.throw.unreachable") => throw_unreachable_exception as _,
fn_name!("vm.exception.throw.incorrect-call_indirect_signature") => {
throw_incorrect_call_indirect_signature as _
}
_ => ptr::null(),
}
}
@ -343,7 +358,8 @@ impl ProtectedCaller for LLVMProtectedCaller {
// Here we go.
unsafe {
trampoline(
invoke_trampoline(
trampoline,
vmctx_ptr,
func_ptr,
param_vec.as_ptr(),

View File

@ -539,6 +539,9 @@ fn parse_function(
// Emit an unreachable instruction.
// If llvm cannot prove that this is never touched,
// it will emit a `ud2` instruction on x86_64 arches.
builder.build_call(intrinsics.throw_unreachable, &[], "throw");
ctx.build_trap();
builder.build_unreachable();
@ -731,13 +734,12 @@ fn parse_function(
)
};
// let sigindices_equal = builder.build_int_compare(
// IntPredicate::EQ,
// expected_dynamic_sigindex,
// found_dynamic_sigindex,
// "sigindices_equal",
// );
let sigindices_equal = intrinsics.i1_ty.const_int(1, false);
let sigindices_equal = builder.build_int_compare(
IntPredicate::EQ,
expected_dynamic_sigindex,
found_dynamic_sigindex,
"sigindices_equal",
);
// Tell llvm that `expected_dynamic_sigindex` should equal `found_dynamic_sigindex`.
let sigindices_equal = builder
@ -764,7 +766,11 @@ fn parse_function(
);
builder.position_at_end(&sigindices_notequal_block);
ctx.build_trap();
builder.build_call(
intrinsics.throw_incorrect_call_indirect_signature,
&[],
"throw",
);
builder.build_unreachable();
builder.position_at_end(&continue_block);

View File

@ -105,6 +105,9 @@ pub struct Intrinsics {
pub memory_size_static_import: FunctionValue,
pub memory_size_shared_import: FunctionValue,
pub throw_unreachable: FunctionValue,
pub throw_incorrect_call_indirect_signature: FunctionValue,
ctx_ty: StructType,
pub ctx_ptr_ty: PointerType,
}
@ -344,7 +347,16 @@ impl Intrinsics {
ret_i32_take_ctx_i32,
None,
),
throw_unreachable: module.add_function(
"vm.exception.throw.unreachable",
void_ty.fn_type(&[], false),
None,
),
throw_incorrect_call_indirect_signature: module.add_function(
"vm.exception.throw.incorrect-call_indirect_signature",
void_ty.fn_type(&[], false),
None,
),
ctx_ty,
ctx_ptr_ty,
}