Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement InternalEvent::Breakpoint in the llvm backend. #618

Merged
merged 2 commits into from
Aug 1, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions lib/llvm-backend/cpp/object_loader.hh
Original file line number Diff line number Diff line change
@@ -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
{
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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;
Expand All @@ -233,4 +259,4 @@ extern "C"
{
return module->get_func(llvm::StringRef(name));
}
}
}
4 changes: 3 additions & 1 deletion lib/llvm-backend/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down Expand Up @@ -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(),
}
Expand Down
24 changes: 23 additions & 1 deletion lib/llvm-backend/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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) => {
Expand Down
7 changes: 6 additions & 1 deletion lib/llvm-backend/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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,
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/middleware-common/src/metering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down