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

Added context trampoline into runtime #481

Merged
merged 11 commits into from
Jun 5, 2019
2 changes: 2 additions & 0 deletions lib/runtime-c-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub mod instance;
pub mod memory;
pub mod module;
pub mod table;
#[cfg(all(unix, target_arch = "x86_64"))]
pub mod trampoline;
pub mod value;

#[allow(non_camel_case_types)]
Expand Down
84 changes: 84 additions & 0 deletions lib/runtime-c-api/src/trampoline.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! Trampoline emitter for transforming function calls.

use std::ffi::c_void;
use std::mem;
use wasmer_runtime_core::trampoline::*;

#[repr(C)]
pub struct wasmer_trampoline_buffer_builder_t;

#[repr(C)]
pub struct wasmer_trampoline_buffer_t;

#[repr(C)]
pub struct wasmer_trampoline_callable_t;

/// Creates a new trampoline builder.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub extern "C" fn wasmer_trampoline_buffer_builder_new() -> *mut wasmer_trampoline_buffer_builder_t
losfair marked this conversation as resolved.
Show resolved Hide resolved
{
Box::into_raw(Box::new(TrampolineBufferBuilder::new())) as *mut _
}

/// Adds a context trampoline to the builder.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_trampoline_buffer_builder_add_context_trampoline(
builder: *mut wasmer_trampoline_buffer_builder_t,
func: *const wasmer_trampoline_callable_t,
ctx: *const c_void,
) -> usize {
let builder = &mut *(builder as *mut TrampolineBufferBuilder);
builder.add_context_trampoline(func as *const CallTarget, ctx as *const CallContext)
}

/// Adds a callinfo trampoline to the builder.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_trampoline_buffer_builder_add_callinfo_trampoline(
builder: *mut wasmer_trampoline_buffer_builder_t,
func: *const wasmer_trampoline_callable_t,
ctx: *const c_void,
num_params: u32,
) -> usize {
let builder = &mut *(builder as *mut TrampolineBufferBuilder);
builder.add_callinfo_trampoline(mem::transmute(func), ctx as *const CallContext, num_params)
}

/// Finalizes the trampoline builder into an executable buffer.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_trampoline_buffer_builder_build(
builder: *mut wasmer_trampoline_buffer_builder_t,
) -> *mut wasmer_trampoline_buffer_t {
let builder = Box::from_raw(builder as *mut TrampolineBufferBuilder);
Box::into_raw(Box::new(builder.build())) as *mut _
}

/// Destroys the trampoline buffer if not null.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_trampoline_buffer_destroy(buffer: *mut wasmer_trampoline_buffer_t) {
if !buffer.is_null() {
Box::from_raw(buffer);
}
}

/// Returns the callable pointer for the trampoline with index `idx`.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_trampoline_buffer_get_trampoline(
buffer: *const wasmer_trampoline_buffer_t,
idx: usize,
) -> *const wasmer_trampoline_callable_t {
let buffer = &*(buffer as *const TrampolineBuffer);
buffer.get_trampoline(idx) as _
}

/// Returns the context added by `add_context_trampoline`, from within the callee function.
#[no_mangle]
#[allow(clippy::cast_ptr_alignment)]
pub unsafe extern "C" fn wasmer_trampoline_get_context() -> *mut c_void {
get_context() as *const c_void as *mut c_void
}
132 changes: 132 additions & 0 deletions lib/runtime-c-api/tests/test-import-function-callinfo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include <stdio.h>
#include "../wasmer.h"
#include <assert.h>
#include <stdint.h>
#include <string.h>

static bool print_str_called = false;
static int memory_len = 0;
static int ptr_len = 0;
static char actual_str[14] = {};
static int actual_context_data_value = 0;

typedef struct {
int value;
} context_data;

struct print_str_context {
int call_count;
};

void print_str(struct print_str_context *local_context, uint64_t *args)
{
local_context->call_count++;

wasmer_instance_context_t *ctx = (void *) args[0];
int32_t ptr = args[1];
int32_t len = args[2];

const wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0);
uint32_t mem_len = wasmer_memory_length(memory);
uint8_t *mem_bytes = wasmer_memory_data(memory);
for (int32_t idx = 0; idx < len; idx++)
{
actual_str[idx] = mem_bytes[ptr + idx];
}
actual_str[13] = '\0';
printf("In print_str, memory len: %d, ptr_len: %d\n, str %s", mem_len, len, actual_str);
print_str_called = true;
memory_len = mem_len;
ptr_len = len;

actual_context_data_value = ((context_data *) wasmer_instance_context_data_get(ctx))->value;
}

int main()
{
wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32};
wasmer_value_tag returns_sig[] = {};
struct print_str_context local_context = {
.call_count = 0
};

printf("Creating trampoline buffer\n");
wasmer_trampoline_buffer_builder_t *tbb = wasmer_trampoline_buffer_builder_new();
unsigned long print_str_idx = wasmer_trampoline_buffer_builder_add_callinfo_trampoline(
tbb,
(wasmer_trampoline_callable_t *) print_str,
(void *) &local_context,
3
losfair marked this conversation as resolved.
Show resolved Hide resolved
);
wasmer_trampoline_buffer_t *tb = wasmer_trampoline_buffer_builder_build(tbb);
const wasmer_trampoline_callable_t *print_str_callable = wasmer_trampoline_buffer_get_trampoline(tb, print_str_idx);

printf("Creating new func\n");
wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) print_str_callable, params_sig, 2, returns_sig, 0);
wasmer_import_t import;

char *module_name = "env";
wasmer_byte_array module_name_bytes;
module_name_bytes.bytes = (const uint8_t *) module_name;
module_name_bytes.bytes_len = strlen(module_name);
char *import_name = "print_str";
wasmer_byte_array import_name_bytes;
import_name_bytes.bytes = (const uint8_t *) import_name;
import_name_bytes.bytes_len = strlen(import_name);

import.module_name = module_name_bytes;
import.import_name = import_name_bytes;
import.tag = WASM_FUNCTION;
import.value.func = func;
wasmer_import_t imports[] = {import};

// Read the wasm file bytes
FILE *file = fopen("assets/wasm_sample_app.wasm", "r");
fseek(file, 0, SEEK_END);
long len = ftell(file);
uint8_t *bytes = malloc(len);
fseek(file, 0, SEEK_SET);
fread(bytes, 1, len, file);
fclose(file);

printf("Instantiating\n");
wasmer_instance_t *instance = NULL;
wasmer_result_t compile_result = wasmer_instantiate(&instance, bytes, len, imports, 1);
printf("Compile result: %d\n", compile_result);

assert(compile_result == WASMER_OK);

context_data* context_data = malloc(sizeof(context_data));
int context_data_value = 42;
context_data->value = context_data_value;
wasmer_instance_context_data_set(instance, context_data);

wasmer_value_t params[] = {};
wasmer_value_t results[] = {};
wasmer_result_t call_result = wasmer_instance_call(instance, "hello_wasm", params, 0, results, 0);
printf("Call result: %d\n", call_result);

int error_len = wasmer_last_error_length();
printf("Error len: `%d`\n", error_len);
char *error_str = malloc(error_len);
wasmer_last_error_message(error_str, error_len);
printf("Error str: `%s`\n", error_str);

assert(call_result == WASMER_OK);

assert(print_str_called);
assert(memory_len == 17);
assert(ptr_len == 13);
assert(0 == strcmp(actual_str, "Hello, World!"));
assert(context_data_value == actual_context_data_value);
assert(local_context.call_count == 1);

printf("Destroying trampoline buffer\n");
wasmer_trampoline_buffer_destroy(tb);
printf("Destroying func\n");
wasmer_import_func_destroy(func);
printf("Destroy instance\n");
wasmer_instance_destroy(instance);
free(context_data);
return 0;
}
25 changes: 24 additions & 1 deletion lib/runtime-c-api/tests/test-import-function.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ typedef struct {
int value;
} context_data;

struct print_str_context {
int call_count;
};

void print_str(wasmer_instance_context_t *ctx, int32_t ptr, int32_t len)
losfair marked this conversation as resolved.
Show resolved Hide resolved
{
struct print_str_context *local_context = wasmer_trampoline_get_context();
local_context->call_count++;

const wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0);
uint32_t mem_len = wasmer_memory_length(memory);
uint8_t *mem_bytes = wasmer_memory_data(memory);
Expand All @@ -36,9 +43,22 @@ int main()
{
wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32};
wasmer_value_tag returns_sig[] = {};
struct print_str_context local_context = {
.call_count = 0
};

printf("Creating trampoline buffer\n");
wasmer_trampoline_buffer_builder_t *tbb = wasmer_trampoline_buffer_builder_new();
unsigned long print_str_idx = wasmer_trampoline_buffer_builder_add_context_trampoline(
tbb,
(wasmer_trampoline_callable_t *) print_str,
(void *) &local_context
);
wasmer_trampoline_buffer_t *tb = wasmer_trampoline_buffer_builder_build(tbb);
const wasmer_trampoline_callable_t *print_str_callable = wasmer_trampoline_buffer_get_trampoline(tb, print_str_idx);

printf("Creating new func\n");
wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) print_str, params_sig, 2, returns_sig, 0);
wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) print_str_callable, params_sig, 2, returns_sig, 0);
wasmer_import_t import;

char *module_name = "env";
Expand Down Expand Up @@ -95,7 +115,10 @@ int main()
assert(ptr_len == 13);
assert(0 == strcmp(actual_str, "Hello, World!"));
assert(context_data_value == actual_context_data_value);
assert(local_context.call_count == 1);

printf("Destroying trampoline buffer\n");
wasmer_trampoline_buffer_destroy(tb);
printf("Destroying func\n");
wasmer_import_func_destroy(func);
printf("Destroy instance\n");
Expand Down
53 changes: 53 additions & 0 deletions lib/runtime-c-api/wasmer.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ typedef struct {

} wasmer_serialized_module_t;

typedef struct {

} wasmer_trampoline_buffer_builder_t;

typedef struct {

} wasmer_trampoline_callable_t;

typedef struct {

} wasmer_trampoline_buffer_t;

/**
* Creates a new Module from the given wasm bytes.
* Returns `wasmer_result_t::WASMER_OK` upon success.
Expand Down Expand Up @@ -584,6 +596,47 @@ uint32_t wasmer_table_length(wasmer_table_t *table);
*/
wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits);

/**
* Adds a callinfo trampoline to the builder.
*/
uintptr_t wasmer_trampoline_buffer_builder_add_callinfo_trampoline(wasmer_trampoline_buffer_builder_t *builder,
const wasmer_trampoline_callable_t *func,
const void *ctx,
uint32_t num_params);

/**
* Adds a context trampoline to the builder.
*/
uintptr_t wasmer_trampoline_buffer_builder_add_context_trampoline(wasmer_trampoline_buffer_builder_t *builder,
const wasmer_trampoline_callable_t *func,
const void *ctx);

/**
* Finalizes the trampoline builder into an executable buffer.
*/
wasmer_trampoline_buffer_t *wasmer_trampoline_buffer_builder_build(wasmer_trampoline_buffer_builder_t *builder);

/**
* Creates a new trampoline builder.
*/
wasmer_trampoline_buffer_builder_t *wasmer_trampoline_buffer_builder_new(void);

/**
* Destroys the trampoline buffer if not null.
*/
void wasmer_trampoline_buffer_destroy(wasmer_trampoline_buffer_t *buffer);

/**
* Returns the callable pointer for the trampoline with index `idx`.
*/
const wasmer_trampoline_callable_t *wasmer_trampoline_buffer_get_trampoline(const wasmer_trampoline_buffer_t *buffer,
uintptr_t idx);

/**
* Returns the context added by `add_context_trampoline`, from within the callee function.
*/
void *wasmer_trampoline_get_context(void);

/**
* Returns true for valid wasm bytes and false for invalid bytes
*/
Expand Down
39 changes: 39 additions & 0 deletions lib/runtime-c-api/wasmer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ struct wasmer_serialized_module_t {

};

struct wasmer_trampoline_buffer_builder_t {

};

struct wasmer_trampoline_callable_t {

};

struct wasmer_trampoline_buffer_t {

};

extern "C" {

/// Creates a new Module from the given wasm bytes.
Expand Down Expand Up @@ -458,6 +470,33 @@ uint32_t wasmer_table_length(wasmer_table_t *table);
/// and `wasmer_last_error_message` to get an error message.
wasmer_result_t wasmer_table_new(wasmer_table_t **table, wasmer_limits_t limits);

/// Adds a callinfo trampoline to the builder.
uintptr_t wasmer_trampoline_buffer_builder_add_callinfo_trampoline(wasmer_trampoline_buffer_builder_t *builder,
const wasmer_trampoline_callable_t *func,
const void *ctx,
uint32_t num_params);

/// Adds a context trampoline to the builder.
uintptr_t wasmer_trampoline_buffer_builder_add_context_trampoline(wasmer_trampoline_buffer_builder_t *builder,
const wasmer_trampoline_callable_t *func,
const void *ctx);

/// Finalizes the trampoline builder into an executable buffer.
wasmer_trampoline_buffer_t *wasmer_trampoline_buffer_builder_build(wasmer_trampoline_buffer_builder_t *builder);

/// Creates a new trampoline builder.
wasmer_trampoline_buffer_builder_t *wasmer_trampoline_buffer_builder_new();

/// Destroys the trampoline buffer if not null.
void wasmer_trampoline_buffer_destroy(wasmer_trampoline_buffer_t *buffer);

/// Returns the callable pointer for the trampoline with index `idx`.
const wasmer_trampoline_callable_t *wasmer_trampoline_buffer_get_trampoline(const wasmer_trampoline_buffer_t *buffer,
uintptr_t idx);

/// Returns the context added by `add_context_trampoline`, from within the callee function.
void *wasmer_trampoline_get_context();

/// Returns true for valid wasm bytes and false for invalid bytes
bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len);

Expand Down
Loading