mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Implement InternalEvent::Breakpoint in the llvm backend.
Enable now-working metering unit tests when run with the llvm backend.
This commit is contained in:
parent
bd3be45fcd
commit
536f9813dc
@ -1,9 +1,10 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <exception>
|
|
||||||
|
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@ -77,6 +78,19 @@ struct UserException : UncatchableException
|
|||||||
box_any_t error_data;
|
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
|
struct WasmTrap : UncatchableException
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -166,6 +180,8 @@ struct WasmModule
|
|||||||
|
|
||||||
extern "C"
|
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)
|
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);
|
*module_out = new WasmModule(mem_ptr, mem_size, callbacks);
|
||||||
@ -192,6 +208,12 @@ extern "C"
|
|||||||
throw UserException(data, vtable);
|
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(
|
bool invoke_trampoline(
|
||||||
trampoline_t trampoline,
|
trampoline_t trampoline,
|
||||||
void *ctx,
|
void *ctx,
|
||||||
@ -217,6 +239,10 @@ extern "C"
|
|||||||
*user_error = e.error_data;
|
*user_error = e.error_data;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
catch (const BreakpointException &e) {
|
||||||
|
callback_trampoline(user_error, (void *)e.callback);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
catch (const WasmException &e)
|
catch (const WasmException &e)
|
||||||
{
|
{
|
||||||
*trap_out = WasmTrap::Type::Unknown;
|
*trap_out = WasmTrap::Type::Unknown;
|
||||||
|
@ -39,7 +39,8 @@ extern "C" {
|
|||||||
fn module_delete(module: *mut LLVMModule);
|
fn module_delete(module: *mut LLVMModule);
|
||||||
fn get_func_symbol(module: *mut LLVMModule, name: *const c_char) -> *const vm::Func;
|
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,
|
/// This should be the same as spliting up the fat pointer into two arguments,
|
||||||
/// but this is cleaner, I think?
|
/// 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.memory.size.static.local") => vmcalls::local_static_memory_size as _,
|
||||||
|
|
||||||
fn_name!("vm.exception.trap") => throw_trap as _,
|
fn_name!("vm.exception.trap") => throw_trap as _,
|
||||||
|
fn_name!("vm.breakpoint") => throw_breakpoint as _,
|
||||||
|
|
||||||
_ => ptr::null(),
|
_ => ptr::null(),
|
||||||
}
|
}
|
||||||
|
@ -496,6 +496,21 @@ pub struct CodegenError {
|
|||||||
pub message: String,
|
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 {
|
pub struct LLVMModuleCodeGenerator {
|
||||||
context: Option<Context>,
|
context: Option<Context>,
|
||||||
builder: Option<Builder>,
|
builder: Option<Builder>,
|
||||||
@ -612,7 +627,14 @@ impl FunctionCodeGenerator<CodegenError> for LLVMFunctionCodeGenerator {
|
|||||||
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {
|
InternalEvent::FunctionBegin(_) | InternalEvent::FunctionEnd => {
|
||||||
return Ok(());
|
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(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
InternalEvent::GetInternal(idx) => {
|
InternalEvent::GetInternal(idx) => {
|
||||||
|
@ -147,6 +147,7 @@ pub struct Intrinsics {
|
|||||||
pub memory_size_shared_import: FunctionValue,
|
pub memory_size_shared_import: FunctionValue,
|
||||||
|
|
||||||
pub throw_trap: FunctionValue,
|
pub throw_trap: FunctionValue,
|
||||||
|
pub throw_breakpoint: FunctionValue,
|
||||||
|
|
||||||
pub ctx_ptr_ty: PointerType,
|
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);
|
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);
|
let ret_i1_take_i1_i1 = i1_ty.fn_type(&[i1_ty_basic, i1_ty_basic], false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
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),
|
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),
|
void_ty.fn_type(&[i32_ty_basic], false),
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
|
throw_breakpoint: module.add_function(
|
||||||
|
"vm.breakpoint",
|
||||||
|
void_ty.fn_type(&[i64_ty_basic], false),
|
||||||
|
None,
|
||||||
|
),
|
||||||
ctx_ptr_ty,
|
ctx_ptr_ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ pub fn set_points_used_ctx(ctx: &mut Ctx, value: u64) {
|
|||||||
ctx.set_internal(&INTERNAL_FIELD, value);
|
ctx.set_internal(&INTERNAL_FIELD, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(test, feature = "singlepass"))]
|
#[cfg(all(test, any(feature = "singlepass", feature = "llvm")))]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use wabt::wat2wasm;
|
use wabt::wat2wasm;
|
||||||
|
Loading…
Reference in New Issue
Block a user