mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-22 05:01:33 +00:00
Update Emscripten API layout; expose inner parts to to C API; add test
This commit is contained in:
@ -325,6 +325,61 @@ impl<'a> EmscriptenData<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the global constructors for C++ and set up the emscripten environment.
|
||||||
|
///
|
||||||
|
/// Note that this function does not completely set up Emscripten to be called.
|
||||||
|
/// before calling this function, please initialize `Ctx::data` with a pointer
|
||||||
|
/// to [`EmscriptenData`].
|
||||||
|
pub fn set_up_emscripten(instance: &mut Instance) -> CallResult<()> {
|
||||||
|
// ATINIT
|
||||||
|
// (used by C++)
|
||||||
|
if let Ok(_func) = instance.dyn_func("globalCtors") {
|
||||||
|
instance.call("globalCtors", &[])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(_func) = instance.dyn_func("___emscripten_environ_constructor") {
|
||||||
|
instance.call("___emscripten_environ_constructor", &[])?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call the main function in emscripten, assumes that the emscripten state is
|
||||||
|
/// set up.
|
||||||
|
///
|
||||||
|
/// If you don't want to set it up yourself, consider using [`run_emscripten_instance`].
|
||||||
|
pub fn emscripten_call_main(instance: &mut Instance, path: &str, args: &[&str]) -> CallResult<()> {
|
||||||
|
let (func_name, main_func) = match instance.dyn_func("_main") {
|
||||||
|
Ok(func) => Ok(("_main", func)),
|
||||||
|
Err(_e) => match instance.dyn_func("main") {
|
||||||
|
Ok(func) => Ok(("main", func)),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
},
|
||||||
|
}?;
|
||||||
|
let num_params = main_func.signature().params().len();
|
||||||
|
let _result = match num_params {
|
||||||
|
2 => {
|
||||||
|
let mut new_args = vec![path];
|
||||||
|
new_args.extend(args);
|
||||||
|
let (argc, argv) = store_module_arguments(instance.context_mut(), new_args);
|
||||||
|
instance.call(
|
||||||
|
func_name,
|
||||||
|
&[Value::I32(argc as i32), Value::I32(argv as i32)],
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
0 => {
|
||||||
|
instance.call(func_name, &[])?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(CallError::Resolve(ResolveError::ExportWrongType {
|
||||||
|
name: "main".to_string(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Top level function to execute emscripten
|
||||||
pub fn run_emscripten_instance(
|
pub fn run_emscripten_instance(
|
||||||
_module: &Module,
|
_module: &Module,
|
||||||
instance: &mut Instance,
|
instance: &mut Instance,
|
||||||
@ -338,15 +393,7 @@ pub fn run_emscripten_instance(
|
|||||||
let data_ptr = &mut data as *mut _ as *mut c_void;
|
let data_ptr = &mut data as *mut _ as *mut c_void;
|
||||||
instance.context_mut().data = data_ptr;
|
instance.context_mut().data = data_ptr;
|
||||||
|
|
||||||
// ATINIT
|
set_up_emscripten(instance)?;
|
||||||
// (used by C++)
|
|
||||||
if let Ok(_func) = instance.dyn_func("globalCtors") {
|
|
||||||
instance.call("globalCtors", &[])?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(_func) = instance.dyn_func("___emscripten_environ_constructor") {
|
|
||||||
instance.call("___emscripten_environ_constructor", &[])?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// println!("running emscripten instance");
|
// println!("running emscripten instance");
|
||||||
|
|
||||||
@ -356,33 +403,7 @@ pub fn run_emscripten_instance(
|
|||||||
//let (argc, argv) = store_module_arguments(instance.context_mut(), args);
|
//let (argc, argv) = store_module_arguments(instance.context_mut(), args);
|
||||||
instance.call(&ep, &[Value::I32(arg as i32)])?;
|
instance.call(&ep, &[Value::I32(arg as i32)])?;
|
||||||
} else {
|
} else {
|
||||||
let (func_name, main_func) = match instance.dyn_func("_main") {
|
emscripten_call_main(instance, path, &args)?;
|
||||||
Ok(func) => Ok(("_main", func)),
|
|
||||||
Err(_e) => match instance.dyn_func("main") {
|
|
||||||
Ok(func) => Ok(("main", func)),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
},
|
|
||||||
}?;
|
|
||||||
let num_params = main_func.signature().params().len();
|
|
||||||
let _result = match num_params {
|
|
||||||
2 => {
|
|
||||||
let mut new_args = vec![path];
|
|
||||||
new_args.extend(args);
|
|
||||||
let (argc, argv) = store_module_arguments(instance.context_mut(), new_args);
|
|
||||||
instance.call(
|
|
||||||
func_name,
|
|
||||||
&[Value::I32(argc as i32), Value::I32(argv as i32)],
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
0 => {
|
|
||||||
instance.call(func_name, &[])?;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(CallError::Resolve(ResolveError::ExportWrongType {
|
|
||||||
name: "main".to_string(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO atexit for emscripten
|
// TODO atexit for emscripten
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
//! Functions and types for dealing with Emscripten imports
|
//! Functions and types for dealing with Emscripten imports
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::module::wasmer_module_t;
|
use crate::{get_slice_checked, instance::wasmer_instance_t, module::wasmer_module_t};
|
||||||
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use wasmer_emscripten::EmscriptenGlobals;
|
use wasmer_emscripten::EmscriptenGlobals;
|
||||||
use wasmer_runtime::Module;
|
use wasmer_runtime::{Instance, Module};
|
||||||
|
|
||||||
/// Type used to construct an import_object_t with Emscripten imports.
|
/// Type used to construct an import_object_t with Emscripten imports.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -40,9 +41,88 @@ pub unsafe extern "C" fn wasmer_emscripten_destroy_emscripten_globals(
|
|||||||
let _ = Box::from_raw(globals);
|
let _ = Box::from_raw(globals);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute global constructors (required if the module is compiled from C++)
|
||||||
|
/// and sets up the internal environment.
|
||||||
|
///
|
||||||
|
/// This function sets the data pointer in the same way that
|
||||||
|
/// [`wasmer_instance_context_data_set`] does.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasmer_emscripten_set_up_emscripten(
|
||||||
|
instance: *mut wasmer_instance_t,
|
||||||
|
globals: *mut wasmer_emscripten_globals_t,
|
||||||
|
) -> wasmer_result_t {
|
||||||
|
if globals.is_null() || instance.is_null() {
|
||||||
|
return wasmer_result_t::WASMER_ERROR;
|
||||||
|
}
|
||||||
|
let instance = &mut *(instance as *mut Instance);
|
||||||
|
instance.context_mut().data = globals as *mut c_void;
|
||||||
|
match wasmer_emscripten::set_up_emscripten(instance) {
|
||||||
|
Ok(_) => wasmer_result_t::WASMER_OK,
|
||||||
|
Err(e) => {
|
||||||
|
update_last_error(e);
|
||||||
|
wasmer_result_t::WASMER_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience function for setting up arguments and calling the Emscripten
|
||||||
|
/// main function.
|
||||||
|
///
|
||||||
|
/// WARNING:
|
||||||
|
///
|
||||||
|
/// Do not call this function on untrusted code when operating without
|
||||||
|
/// additional sandboxing in place.
|
||||||
|
/// Emscripten has access to many host system calls and therefore may do very
|
||||||
|
/// bad things.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn wasmer_emscripten_call_main(
|
||||||
|
instance: *mut wasmer_instance_t,
|
||||||
|
args: *const wasmer_byte_array,
|
||||||
|
args_len: c_uint,
|
||||||
|
) -> wasmer_result_t {
|
||||||
|
if instance.is_null() || args.is_null() {
|
||||||
|
return wasmer_result_t::WASMER_ERROR;
|
||||||
|
}
|
||||||
|
let instance = &mut *(instance as *mut Instance);
|
||||||
|
|
||||||
|
let arg_list = get_slice_checked(args, args_len as usize);
|
||||||
|
let arg_process_result: Result<Vec<&str>, _> =
|
||||||
|
arg_list.iter().map(|arg| arg.as_str()).collect();
|
||||||
|
let arg_vec = match arg_process_result.as_ref() {
|
||||||
|
Ok(arg_vec) => arg_vec,
|
||||||
|
Err(err) => {
|
||||||
|
update_last_error(*err);
|
||||||
|
return wasmer_result_t::WASMER_ERROR;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let prog_name = if let Some(prog_name) = arg_vec.first() {
|
||||||
|
prog_name
|
||||||
|
} else {
|
||||||
|
update_last_error(CApiError {
|
||||||
|
msg: "First argument (program name) is required to execute Emscripten's main function"
|
||||||
|
.to_string(),
|
||||||
|
});
|
||||||
|
return wasmer_result_t::WASMER_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
match wasmer_emscripten::emscripten_call_main(instance, prog_name, &arg_vec[1..]) {
|
||||||
|
Ok(_) => wasmer_result_t::WASMER_OK,
|
||||||
|
Err(e) => {
|
||||||
|
update_last_error(e);
|
||||||
|
wasmer_result_t::WASMER_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a `wasmer_import_object_t` with Emscripten imports, use
|
/// Create a `wasmer_import_object_t` with Emscripten imports, use
|
||||||
/// `wasmer_emscripten_get_emscripten_globals` to get a
|
/// `wasmer_emscripten_get_emscripten_globals` to get a
|
||||||
/// `wasmer_emscripten_globals_t` from a `wasmer_module_t`.
|
/// `wasmer_emscripten_globals_t` from a `wasmer_module_t`.
|
||||||
|
///
|
||||||
|
/// WARNING:
|
||||||
|
///1
|
||||||
|
/// This `import_object_t` contains thin-wrappers around host system calls.
|
||||||
|
/// Do not use this to execute untrusted code without additional sandboxing.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasmer_emscripten_generate_import_object(
|
pub unsafe extern "C" fn wasmer_emscripten_generate_import_object(
|
||||||
globals: *mut wasmer_emscripten_globals_t,
|
globals: *mut wasmer_emscripten_globals_t,
|
||||||
|
1
lib/runtime-c-api/tests/.gitignore
vendored
1
lib/runtime-c-api/tests/.gitignore
vendored
@ -27,3 +27,4 @@ test-module-serialize
|
|||||||
test-tables
|
test-tables
|
||||||
test-validate
|
test-validate
|
||||||
test-wasi-import-object
|
test-wasi-import-object
|
||||||
|
test-emscripten-import-object
|
@ -22,6 +22,11 @@ if (DEFINED WASI_TESTS)
|
|||||||
add_executable(test-wasi-import-object test-wasi-import-object.c)
|
add_executable(test-wasi-import-object test-wasi-import-object.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED EMSCRIPTEN_TESTS)
|
||||||
|
add_executable(test-emscripten-import-object test-emscripten-import-object.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
find_library(
|
find_library(
|
||||||
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so wasmer_runtime_c_api.dll
|
WASMER_LIB NAMES libwasmer_runtime_c_api.dylib libwasmer_runtime_c_api.so wasmer_runtime_c_api.dll
|
||||||
PATHS ${CMAKE_SOURCE_DIR}/../../../target/release/
|
PATHS ${CMAKE_SOURCE_DIR}/../../../target/release/
|
||||||
@ -74,6 +79,12 @@ if (DEFINED WASI_TESTS)
|
|||||||
add_test(test-wasi-import-object test-wasi-import-object)
|
add_test(test-wasi-import-object test-wasi-import-object)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (DEFINED EMSCRIPTEN_TESTS)
|
||||||
|
target_link_libraries(test-emscripten-import-object general ${WASMER_LIB})
|
||||||
|
target_compile_options(test-emscripten-import-object PRIVATE ${COMPILER_OPTIONS})
|
||||||
|
add_test(test-emscripten-import-object test-emscripten-import-object)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(test-instantiate general ${WASMER_LIB})
|
target_link_libraries(test-instantiate general ${WASMER_LIB})
|
||||||
target_compile_options(test-instantiate PRIVATE ${COMPILER_OPTIONS})
|
target_compile_options(test-instantiate PRIVATE ${COMPILER_OPTIONS})
|
||||||
add_test(test-instantiate test-instantiate)
|
add_test(test-instantiate test-instantiate)
|
||||||
|
10
lib/runtime-c-api/tests/assets/emscripten_hello_world.c
Normal file
10
lib/runtime-c-api/tests/assets/emscripten_hello_world.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
printf("Hello, world\n");
|
||||||
|
for ( int i = 0; i < argc; ++i ) {
|
||||||
|
printf("Arg %d: '%s'\n", i, argv[i]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
BIN
lib/runtime-c-api/tests/assets/emscripten_hello_world.wasm
Normal file
BIN
lib/runtime-c-api/tests/assets/emscripten_hello_world.wasm
Normal file
Binary file not shown.
@ -8,8 +8,10 @@ fn test_c_api() {
|
|||||||
".",
|
".",
|
||||||
#[cfg(feature = "wasi")]
|
#[cfg(feature = "wasi")]
|
||||||
"-DWASI_TESTS=ON",
|
"-DWASI_TESTS=ON",
|
||||||
|
#[cfg(feature = "emscripten")]
|
||||||
|
"-DEMSCRIPTEN_TESTS=ON",
|
||||||
];
|
];
|
||||||
// we use -f so it doesn't fail if the fiel doesn't exist
|
// we use -f so it doesn't fail if the file doesn't exist
|
||||||
run_command("rm", project_tests_dir, vec!["-f", "CMakeCache.txt"]);
|
run_command("rm", project_tests_dir, vec!["-f", "CMakeCache.txt"]);
|
||||||
run_command("cmake", project_tests_dir, cmake_args);
|
run_command("cmake", project_tests_dir, cmake_args);
|
||||||
run_command("make", project_tests_dir, vec!["-Wdev", "-Werror=dev"]);
|
run_command("make", project_tests_dir, vec!["-Wdev", "-Werror=dev"]);
|
||||||
|
235
lib/runtime-c-api/tests/test-emscripten-import-object.c
Normal file
235
lib/runtime-c-api/tests/test-emscripten-import-object.c
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "../wasmer.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static bool host_print_called = false;
|
||||||
|
|
||||||
|
// Host function that will be imported into the Web Assembly Instance
|
||||||
|
void host_print(const wasmer_instance_context_t *ctx, int32_t ptr, int32_t len)
|
||||||
|
{
|
||||||
|
host_print_called = true;
|
||||||
|
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);
|
||||||
|
printf("%.*s", len, mem_bytes + ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the last_error API to retrieve error messages
|
||||||
|
void print_wasmer_error()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to print byte array to stdout
|
||||||
|
void print_byte_array(wasmer_byte_array *arr) {
|
||||||
|
for (int i = 0; i < arr->bytes_len; ++i) {
|
||||||
|
putchar(arr->bytes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Create a new func to hold the parameter and signature
|
||||||
|
// of our `host_print` host function
|
||||||
|
wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32};
|
||||||
|
wasmer_value_tag returns_sig[] = {};
|
||||||
|
wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) host_print, params_sig, 2, returns_sig, 0);
|
||||||
|
|
||||||
|
// Create module name for our imports
|
||||||
|
// represented in bytes for UTF-8 compatability
|
||||||
|
const 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);
|
||||||
|
|
||||||
|
// Define a function import
|
||||||
|
const char *import_name = "host_print";
|
||||||
|
wasmer_byte_array import_name_bytes;
|
||||||
|
import_name_bytes.bytes = (const uint8_t *) import_name;
|
||||||
|
import_name_bytes.bytes_len = strlen(import_name);
|
||||||
|
wasmer_import_t func_import;
|
||||||
|
func_import.module_name = module_name_bytes;
|
||||||
|
func_import.import_name = import_name_bytes;
|
||||||
|
func_import.tag = WASM_FUNCTION;
|
||||||
|
func_import.value.func = func;
|
||||||
|
|
||||||
|
// Define a memory import
|
||||||
|
const char *import_memory_name = "memory";
|
||||||
|
wasmer_byte_array import_memory_name_bytes;
|
||||||
|
import_memory_name_bytes.bytes = (const uint8_t *) import_memory_name;
|
||||||
|
import_memory_name_bytes.bytes_len = strlen(import_memory_name);
|
||||||
|
wasmer_import_t memory_import;
|
||||||
|
memory_import.module_name = module_name_bytes;
|
||||||
|
memory_import.import_name = import_memory_name_bytes;
|
||||||
|
memory_import.tag = WASM_MEMORY;
|
||||||
|
wasmer_memory_t *memory = NULL;
|
||||||
|
wasmer_limits_t descriptor;
|
||||||
|
descriptor.min = 256;
|
||||||
|
wasmer_limit_option_t max;
|
||||||
|
max.has_some = true;
|
||||||
|
max.some = 256;
|
||||||
|
descriptor.max = max;
|
||||||
|
wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor);
|
||||||
|
if (memory_result != WASMER_OK)
|
||||||
|
{
|
||||||
|
print_wasmer_error();
|
||||||
|
}
|
||||||
|
memory_import.value.memory = memory;
|
||||||
|
|
||||||
|
// Define a global import
|
||||||
|
const char *import_global_name = "__memory_base";
|
||||||
|
wasmer_byte_array import_global_name_bytes;
|
||||||
|
import_global_name_bytes.bytes = (const uint8_t *) import_global_name;
|
||||||
|
import_global_name_bytes.bytes_len = strlen(import_global_name);
|
||||||
|
wasmer_import_t global_import;
|
||||||
|
global_import.module_name = module_name_bytes;
|
||||||
|
global_import.import_name = import_global_name_bytes;
|
||||||
|
global_import.tag = WASM_GLOBAL;
|
||||||
|
wasmer_value_t val;
|
||||||
|
val.tag = WASM_I32;
|
||||||
|
val.value.I32 = 1024;
|
||||||
|
wasmer_global_t *global = wasmer_global_new(val, false);
|
||||||
|
global_import.value.global = global;
|
||||||
|
|
||||||
|
// Define a table import
|
||||||
|
const char *import_table_name = "table";
|
||||||
|
wasmer_byte_array import_table_name_bytes;
|
||||||
|
import_table_name_bytes.bytes = (const uint8_t *) import_table_name;
|
||||||
|
import_table_name_bytes.bytes_len = strlen(import_table_name);
|
||||||
|
wasmer_import_t table_import;
|
||||||
|
table_import.module_name = module_name_bytes;
|
||||||
|
table_import.import_name = import_table_name_bytes;
|
||||||
|
table_import.tag = WASM_TABLE;
|
||||||
|
wasmer_table_t *table = NULL;
|
||||||
|
wasmer_limits_t table_descriptor;
|
||||||
|
table_descriptor.min = 256;
|
||||||
|
wasmer_limit_option_t table_max;
|
||||||
|
table_max.has_some = true;
|
||||||
|
table_max.some = 256;
|
||||||
|
table_descriptor.max = table_max;
|
||||||
|
wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor);
|
||||||
|
if (table_result != WASMER_OK)
|
||||||
|
{
|
||||||
|
print_wasmer_error();
|
||||||
|
}
|
||||||
|
table_import.value.table = table;
|
||||||
|
|
||||||
|
|
||||||
|
// Create arbitrary arguments for our program
|
||||||
|
|
||||||
|
|
||||||
|
// Read the Wasm file bytes.
|
||||||
|
FILE *file = fopen("assets/emscripten_hello_world.wasm", "r");
|
||||||
|
assert(file);
|
||||||
|
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);
|
||||||
|
|
||||||
|
wasmer_module_t *module = NULL;
|
||||||
|
// Compile the WebAssembly module
|
||||||
|
wasmer_result_t compile_result = wasmer_compile(&module, bytes, len);
|
||||||
|
printf("Compile result: %d\n", compile_result);
|
||||||
|
|
||||||
|
if (compile_result != WASMER_OK)
|
||||||
|
{
|
||||||
|
print_wasmer_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(compile_result == WASMER_OK);
|
||||||
|
|
||||||
|
// Set up data for Emscripten
|
||||||
|
wasmer_emscripten_globals_t *emscripten_globals = wasmer_emscripten_get_emscripten_globals(module);
|
||||||
|
|
||||||
|
if (!emscripten_globals)
|
||||||
|
{
|
||||||
|
print_wasmer_error();
|
||||||
|
}
|
||||||
|
assert(emscripten_globals);
|
||||||
|
|
||||||
|
// Create the Emscripten import object
|
||||||
|
wasmer_import_object_t *import_object =
|
||||||
|
wasmer_emscripten_generate_import_object(emscripten_globals);
|
||||||
|
|
||||||
|
// Create our imports
|
||||||
|
wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import};
|
||||||
|
int imports_len = sizeof(imports) / sizeof(imports[0]);
|
||||||
|
// Add our imports to the import object
|
||||||
|
wasmer_import_object_extend(import_object, imports, imports_len);
|
||||||
|
|
||||||
|
// Instantiatoe the module with our import_object
|
||||||
|
wasmer_instance_t *instance = NULL;
|
||||||
|
wasmer_result_t instantiate_result = wasmer_module_import_instantiate(&instance, module, import_object);
|
||||||
|
printf("Instantiate result: %d\n", instantiate_result);
|
||||||
|
|
||||||
|
if (instantiate_result != WASMER_OK)
|
||||||
|
{
|
||||||
|
print_wasmer_error();
|
||||||
|
}
|
||||||
|
assert(instantiate_result == WASMER_OK);
|
||||||
|
|
||||||
|
// Set up emscripten to be called
|
||||||
|
wasmer_result_t setup_result = wasmer_emscripten_set_up_emscripten(instance, emscripten_globals);
|
||||||
|
|
||||||
|
if (setup_result != WASMER_OK)
|
||||||
|
{
|
||||||
|
print_wasmer_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *emscripten_prog_name = "emscripten_test_program";
|
||||||
|
const char *emscripten_first_arg = "--help";
|
||||||
|
wasmer_byte_array args[] = {
|
||||||
|
{ .bytes = (const uint8_t *) emscripten_prog_name,
|
||||||
|
.bytes_len = strlen(emscripten_prog_name) },
|
||||||
|
{ .bytes = (const uint8_t *) emscripten_first_arg,
|
||||||
|
.bytes_len = strlen(emscripten_first_arg) }
|
||||||
|
};
|
||||||
|
int emscripten_argc = sizeof(args) / sizeof(args[0]);
|
||||||
|
|
||||||
|
wasmer_result_t main_result = wasmer_emscripten_call_main(instance, args, emscripten_argc);
|
||||||
|
|
||||||
|
printf("Main result: %d\n", main_result);
|
||||||
|
assert(main_result == WASMER_OK);
|
||||||
|
|
||||||
|
|
||||||
|
wasmer_import_object_iter_t *func_iter = wasmer_import_object_iterate_functions(import_object);
|
||||||
|
|
||||||
|
puts("Functions in import object:");
|
||||||
|
while ( !wasmer_import_object_iter_at_end(func_iter) ) {
|
||||||
|
wasmer_import_t import;
|
||||||
|
wasmer_result_t result = wasmer_import_object_iter_next(func_iter, &import);
|
||||||
|
assert(result == WASMER_OK);
|
||||||
|
|
||||||
|
print_byte_array(&import.module_name);
|
||||||
|
putchar(' ');
|
||||||
|
print_byte_array(&import.import_name);
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
assert(import.tag == WASM_FUNCTION);
|
||||||
|
assert(import.value.func);
|
||||||
|
wasmer_import_object_imports_destroy(&import, 1);
|
||||||
|
}
|
||||||
|
wasmer_import_object_iter_destroy(func_iter);
|
||||||
|
|
||||||
|
// Use *_destroy methods to cleanup as specified in the header documentation
|
||||||
|
wasmer_emscripten_destroy_emscripten_globals(emscripten_globals);
|
||||||
|
wasmer_import_func_destroy(func);
|
||||||
|
wasmer_global_destroy(global);
|
||||||
|
wasmer_memory_destroy(memory);
|
||||||
|
wasmer_table_destroy(table);
|
||||||
|
wasmer_instance_destroy(instance);
|
||||||
|
wasmer_import_object_destroy(import_object);
|
||||||
|
wasmer_module_destroy(module);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define WASMER_EMSCRIPTEN_ENABLED
|
||||||
#endif // WASMER_H_MACROS
|
#endif // WASMER_H_MACROS
|
||||||
|
|
||||||
|
|
||||||
@ -74,6 +75,15 @@ typedef struct {
|
|||||||
|
|
||||||
} wasmer_module_t;
|
} wasmer_module_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
} wasmer_instance_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const uint8_t *bytes;
|
||||||
|
uint32_t bytes_len;
|
||||||
|
} wasmer_byte_array;
|
||||||
|
|
||||||
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
||||||
/**
|
/**
|
||||||
* Type used to construct an import_object_t with Emscripten imports.
|
* Type used to construct an import_object_t with Emscripten imports.
|
||||||
@ -94,11 +104,6 @@ typedef struct {
|
|||||||
|
|
||||||
} wasmer_export_descriptor_t;
|
} wasmer_export_descriptor_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const uint8_t *bytes;
|
|
||||||
uint32_t bytes_len;
|
|
||||||
} wasmer_byte_array;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opaque pointer to `NamedExportDescriptors`.
|
* Opaque pointer to `NamedExportDescriptors`.
|
||||||
*/
|
*/
|
||||||
@ -191,10 +196,6 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
} wasmer_instance_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
} wasmer_instance_context_t;
|
} wasmer_instance_context_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -256,6 +257,23 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
|
|||||||
uint8_t *wasm_bytes,
|
uint8_t *wasm_bytes,
|
||||||
uint32_t wasm_bytes_len);
|
uint32_t wasm_bytes_len);
|
||||||
|
|
||||||
|
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
||||||
|
/**
|
||||||
|
* Convenience function for setting up arguments and calling the Emscripten
|
||||||
|
* main function.
|
||||||
|
*
|
||||||
|
* WARNING:
|
||||||
|
*
|
||||||
|
* Do not call this function on untrusted code when operating without
|
||||||
|
* additional sandboxing in place.
|
||||||
|
* Emscripten has access to many host system calls and therefore may do very
|
||||||
|
* bad things.
|
||||||
|
*/
|
||||||
|
wasmer_result_t wasmer_emscripten_call_main(wasmer_instance_t *instance,
|
||||||
|
const wasmer_byte_array *args,
|
||||||
|
unsigned int args_len);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
||||||
/**
|
/**
|
||||||
* Destroy `wasmer_emscrpten_globals_t` created by
|
* Destroy `wasmer_emscrpten_globals_t` created by
|
||||||
@ -269,6 +287,11 @@ void wasmer_emscripten_destroy_emscripten_globals(wasmer_emscripten_globals_t *g
|
|||||||
* Create a `wasmer_import_object_t` with Emscripten imports, use
|
* Create a `wasmer_import_object_t` with Emscripten imports, use
|
||||||
* `wasmer_emscripten_get_emscripten_globals` to get a
|
* `wasmer_emscripten_get_emscripten_globals` to get a
|
||||||
* `wasmer_emscripten_globals_t` from a `wasmer_module_t`.
|
* `wasmer_emscripten_globals_t` from a `wasmer_module_t`.
|
||||||
|
*
|
||||||
|
* WARNING:
|
||||||
|
*1
|
||||||
|
* This `import_object_t` contains thin-wrappers around host system calls.
|
||||||
|
* Do not use this to execute untrusted code without additional sandboxing.
|
||||||
*/
|
*/
|
||||||
wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscripten_globals_t *globals);
|
wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscripten_globals_t *globals);
|
||||||
#endif
|
#endif
|
||||||
@ -280,6 +303,18 @@ wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscript
|
|||||||
wasmer_emscripten_globals_t *wasmer_emscripten_get_emscripten_globals(const wasmer_module_t *module);
|
wasmer_emscripten_globals_t *wasmer_emscripten_get_emscripten_globals(const wasmer_module_t *module);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
||||||
|
/**
|
||||||
|
* Execute global constructors (required if the module is compiled from C++)
|
||||||
|
* and sets up the internal environment.
|
||||||
|
*
|
||||||
|
* This function sets the data pointer in the same way that
|
||||||
|
* [`wasmer_instance_context_data_set`] does.
|
||||||
|
*/
|
||||||
|
wasmer_result_t wasmer_emscripten_set_up_emscripten(wasmer_instance_t *instance,
|
||||||
|
wasmer_emscripten_globals_t *globals);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets export descriptor kind
|
* Gets export descriptor kind
|
||||||
*/
|
*/
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define WASMER_EMSCRIPTEN_ENABLED
|
||||||
#endif // WASMER_H_MACROS
|
#endif // WASMER_H_MACROS
|
||||||
|
|
||||||
|
|
||||||
@ -61,6 +62,15 @@ struct wasmer_module_t {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wasmer_instance_t {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wasmer_byte_array {
|
||||||
|
const uint8_t *bytes;
|
||||||
|
uint32_t bytes_len;
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
||||||
/// Type used to construct an import_object_t with Emscripten imports.
|
/// Type used to construct an import_object_t with Emscripten imports.
|
||||||
struct wasmer_emscripten_globals_t {
|
struct wasmer_emscripten_globals_t {
|
||||||
@ -77,11 +87,6 @@ struct wasmer_export_descriptor_t {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wasmer_byte_array {
|
|
||||||
const uint8_t *bytes;
|
|
||||||
uint32_t bytes_len;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Opaque pointer to `NamedExportDescriptors`.
|
/// Opaque pointer to `NamedExportDescriptors`.
|
||||||
struct wasmer_export_descriptors_t {
|
struct wasmer_export_descriptors_t {
|
||||||
|
|
||||||
@ -162,10 +167,6 @@ struct wasmer_import_object_iter_t {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wasmer_instance_t {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wasmer_instance_context_t {
|
struct wasmer_instance_context_t {
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -223,6 +224,21 @@ wasmer_result_t wasmer_compile(wasmer_module_t **module,
|
|||||||
uint8_t *wasm_bytes,
|
uint8_t *wasm_bytes,
|
||||||
uint32_t wasm_bytes_len);
|
uint32_t wasm_bytes_len);
|
||||||
|
|
||||||
|
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
||||||
|
/// Convenience function for setting up arguments and calling the Emscripten
|
||||||
|
/// main function.
|
||||||
|
///
|
||||||
|
/// WARNING:
|
||||||
|
///
|
||||||
|
/// Do not call this function on untrusted code when operating without
|
||||||
|
/// additional sandboxing in place.
|
||||||
|
/// Emscripten has access to many host system calls and therefore may do very
|
||||||
|
/// bad things.
|
||||||
|
wasmer_result_t wasmer_emscripten_call_main(wasmer_instance_t *instance,
|
||||||
|
const wasmer_byte_array *args,
|
||||||
|
unsigned int args_len);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
||||||
/// Destroy `wasmer_emscrpten_globals_t` created by
|
/// Destroy `wasmer_emscrpten_globals_t` created by
|
||||||
/// `wasmer_emscripten_get_emscripten_globals`.
|
/// `wasmer_emscripten_get_emscripten_globals`.
|
||||||
@ -233,6 +249,11 @@ void wasmer_emscripten_destroy_emscripten_globals(wasmer_emscripten_globals_t *g
|
|||||||
/// Create a `wasmer_import_object_t` with Emscripten imports, use
|
/// Create a `wasmer_import_object_t` with Emscripten imports, use
|
||||||
/// `wasmer_emscripten_get_emscripten_globals` to get a
|
/// `wasmer_emscripten_get_emscripten_globals` to get a
|
||||||
/// `wasmer_emscripten_globals_t` from a `wasmer_module_t`.
|
/// `wasmer_emscripten_globals_t` from a `wasmer_module_t`.
|
||||||
|
///
|
||||||
|
/// WARNING:
|
||||||
|
///1
|
||||||
|
/// This `import_object_t` contains thin-wrappers around host system calls.
|
||||||
|
/// Do not use this to execute untrusted code without additional sandboxing.
|
||||||
wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscripten_globals_t *globals);
|
wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscripten_globals_t *globals);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -241,6 +262,16 @@ wasmer_import_object_t *wasmer_emscripten_generate_import_object(wasmer_emscript
|
|||||||
wasmer_emscripten_globals_t *wasmer_emscripten_get_emscripten_globals(const wasmer_module_t *module);
|
wasmer_emscripten_globals_t *wasmer_emscripten_get_emscripten_globals(const wasmer_module_t *module);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WASMER_EMSCRIPTEN_ENABLED)
|
||||||
|
/// Execute global constructors (required if the module is compiled from C++)
|
||||||
|
/// and sets up the internal environment.
|
||||||
|
///
|
||||||
|
/// This function sets the data pointer in the same way that
|
||||||
|
/// [`wasmer_instance_context_data_set`] does.
|
||||||
|
wasmer_result_t wasmer_emscripten_set_up_emscripten(wasmer_instance_t *instance,
|
||||||
|
wasmer_emscripten_globals_t *globals);
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Gets export descriptor kind
|
/// Gets export descriptor kind
|
||||||
wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_);
|
wasmer_import_export_kind wasmer_export_descriptor_kind(wasmer_export_descriptor_t *export_);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user