mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-12 22:05:33 +00:00
Merge #618
618: Implement InternalEvent::Breakpoint in the llvm backend. r=nlewycky a=nlewycky Enable now-working metering unit tests when run with the llvm backend. Co-authored-by: Nick Lewycky <nick@wasmer.io> Co-authored-by: nlewycky <nick@wasmer.io>
This commit is contained in:
commit
1138a048d8
@ -1,9 +1,10 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
|
||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@ -77,6 +78,19 @@ struct UserException : UncatchableException
|
||||
box_any_t error_data;
|
||||
};
|
||||
|
||||
struct BreakpointException : UncatchableException
|
||||
{
|
||||
public:
|
||||
BreakpointException(uintptr_t callback) : callback(callback) {}
|
||||
|
||||
virtual std::string description() const noexcept override
|
||||
{
|
||||
return "breakpoint exception";
|
||||
}
|
||||
|
||||
uintptr_t callback;
|
||||
};
|
||||
|
||||
struct WasmTrap : UncatchableException
|
||||
{
|
||||
public:
|
||||
@ -166,6 +180,8 @@ struct WasmModule
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void callback_trampoline(void *, void *);
|
||||
|
||||
result_t module_load(const uint8_t *mem_ptr, size_t mem_size, callbacks_t callbacks, WasmModule **module_out)
|
||||
{
|
||||
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
||||
@ -192,6 +208,12 @@ extern "C"
|
||||
throw UserException(data, vtable);
|
||||
}
|
||||
|
||||
// Throw a pointer that's assumed to be codegen::BreakpointHandler on the
|
||||
// rust side.
|
||||
[[noreturn]] void throw_breakpoint(uintptr_t callback) {
|
||||
throw BreakpointException(callback);
|
||||
}
|
||||
|
||||
bool invoke_trampoline(
|
||||
trampoline_t trampoline,
|
||||
void *ctx,
|
||||
@ -217,6 +239,10 @@ extern "C"
|
||||
*user_error = e.error_data;
|
||||
return false;
|
||||
}
|
||||
catch (const BreakpointException &e) {
|
||||
callback_trampoline(user_error, (void *)e.callback);
|
||||
return false;
|
||||
}
|
||||
catch (const WasmException &e)
|
||||
{
|
||||
*trap_out = WasmTrap::Type::Unknown;
|
||||
|
@ -39,7 +39,8 @@ extern "C" {
|
||||
fn module_delete(module: *mut LLVMModule);
|
||||
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
|
||||
|
||||
fn throw_trap(ty: i32);
|
||||
fn throw_trap(ty: i32) -> !;
|
||||
fn throw_breakpoint(ty: i64) -> !;
|
||||
|
||||
/// This should be the same as spliting up the fat pointer into two arguments,
|
||||
/// but this is cleaner, I think?
|
||||
@ -103,6 +104,7 @@ fn get_callbacks() -> Callbacks {
|
||||
fn_name!("vm.memory.size.static.local") => vmcalls::local_static_memory_size as _,
|
||||
|
||||
fn_name!("vm.exception.trap") => throw_trap as _,
|
||||
fn_name!("vm.breakpoint") => throw_breakpoint as _,
|
||||
|
||||
_ => ptr::null(),
|
||||
}
|
||||
|
@ -496,6 +496,21 @@ pub struct CodegenError {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
// This is only called by C++ code, the 'pub' + '#[no_mangle]' combination
|
||||
// prevents unused function elimination.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn callback_trampoline(
|
||||
b: *mut Option<Box<dyn std::any::Any>>,
|
||||
callback: *mut BreakpointHandler,
|
||||
) {
|
||||
let callback = Box::from_raw(callback);
|
||||
let result: Result<(), Box<dyn std::any::Any>> = callback(BreakpointInfo { fault: None });
|
||||
match result {
|
||||
Ok(()) => *b = None,
|
||||
Err(e) => *b = Some(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LLVMModuleCodeGenerator {
|
||||
context: Option<Context>,
|
||||
builder: Option<Builder>,
|
||||
@ -612,7 +627,14 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
||||
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {
|
||||
return Ok(());
|
||||
}
|
||||
InternalEvent::Breakpoint(_callback) => {
|
||||
InternalEvent::Breakpoint(callback) => {
|
||||
let raw = Box::into_raw(Box::new(callback)) as u64;
|
||||
let callback = intrinsics.i64_ty.const_int(raw, false);
|
||||
builder.build_call(
|
||||
intrinsics.throw_breakpoint,
|
||||
&[callback.as_basic_value_enum()],
|
||||
"",
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
InternalEvent::GetInternal(idx) => {
|
||||
|
@ -147,6 +147,7 @@ pub struct Intrinsics {
|
||||
pub memory_size_shared_import: FunctionValue,
|
||||
|
||||
pub throw_trap: FunctionValue,
|
||||
pub throw_breakpoint: FunctionValue,
|
||||
|
||||
pub ctx_ptr_ty: PointerType,
|
||||
}
|
||||
@ -309,7 +310,6 @@ impl Intrinsics {
|
||||
i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false);
|
||||
|
||||
let ret_i1_take_i1_i1 = i1_ty.fn_type(&[i1_ty_basic, i1_ty_basic], false);
|
||||
|
||||
Self {
|
||||
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
||||
ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
|
||||
@ -525,6 +525,11 @@ impl Intrinsics {
|
||||
void_ty.fn_type(&[i32_ty_basic], false),
|
||||
None,
|
||||
),
|
||||
throw_breakpoint: module.add_function(
|
||||
"vm.breakpoint",
|
||||
void_ty.fn_type(&[i64_ty_basic], false),
|
||||
None,
|
||||
),
|
||||
ctx_ptr_ty,
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ pub fn set_points_used_ctx(ctx: &mut Ctx, value: u64) {
|
||||
ctx.set_internal(&INTERNAL_FIELD, value);
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "singlepass"))]
|
||||
#[cfg(all(test, any(feature = "singlepass", feature = "llvm")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use wabt::wat2wasm;
|
||||
|
Loading…
Reference in New Issue
Block a user