mirror of
https://github.com/fluencelabs/wasmer
synced 2025-05-13 11:01:19 +00:00
Merge branch 'master' into feature/clif-cgapi
This commit is contained in:
commit
ac3fafae9a
@ -6,6 +6,10 @@ Blocks of changes will separated by version increments.
|
|||||||
|
|
||||||
## **[Unreleased]**
|
## **[Unreleased]**
|
||||||
|
|
||||||
|
- [#442](https://github.com/wasmerio/wasmer/pull/442) Misc. WASI FS fixes and implement readdir
|
||||||
|
- [#440](https://github.com/wasmerio/wasmer/pull/440) Fix type mismatch between `wasmer_instance_call` and `wasmer_export_func_*_arity` functions in the runtime C API.
|
||||||
|
- [#269](https://github.com/wasmerio/wasmer/pull/269) Add better runtime docs
|
||||||
|
- [#432](https://github.com/wasmerio/wasmer/pull/432) Fix returned value of `wasmer_last_error_message` in the runtime C API
|
||||||
- [#429](https://github.com/wasmerio/wasmer/pull/429) Get wasi::path_filestat_get working for some programs; misc. minor WASI FS improvements
|
- [#429](https://github.com/wasmerio/wasmer/pull/429) Get wasi::path_filestat_get working for some programs; misc. minor WASI FS improvements
|
||||||
- [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits
|
- [#413](https://github.com/wasmerio/wasmer/pull/413) Update LLVM backend to use new parser codegen traits
|
||||||
|
|
||||||
|
2
Makefile
2
Makefile
@ -49,11 +49,13 @@ test:
|
|||||||
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
# cargo test --all --exclude wasmer-emscripten -- --test-threads=1 $(runargs)
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
cargo test --manifest-path lib/spectests/Cargo.toml --features clif
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
cargo test --manifest-path lib/spectests/Cargo.toml --features llvm
|
||||||
|
cargo test --manifest-path lib/runtime/Cargo.toml --features llvm
|
||||||
cargo build -p wasmer-runtime-c-api
|
cargo build -p wasmer-runtime-c-api
|
||||||
cargo test -p wasmer-runtime-c-api -- --nocapture
|
cargo test -p wasmer-runtime-c-api -- --nocapture
|
||||||
|
|
||||||
test-singlepass:
|
test-singlepass:
|
||||||
cargo test --manifest-path lib/spectests/Cargo.toml --features singlepass
|
cargo test --manifest-path lib/spectests/Cargo.toml --features singlepass
|
||||||
|
cargo test --manifest-path lib/runtime/Cargo.toml --features singlepass
|
||||||
|
|
||||||
test-emscripten-llvm:
|
test-emscripten-llvm:
|
||||||
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
|
cargo test --manifest-path lib/emscripten/Cargo.toml --features llvm -- --test-threads=1 $(runargs)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
mod cache;
|
mod cache;
|
||||||
mod code;
|
mod code;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
|
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
|
||||||
//! accesses that occur when runniing webassembly.
|
//! accesses that occur when running WebAssembly.
|
||||||
//!
|
//!
|
||||||
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
||||||
//!
|
//!
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate wasmer_runtime_core;
|
extern crate wasmer_runtime_core;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
#![cfg_attr(nightly, feature(unwind_attributes))]
|
#![cfg_attr(nightly, feature(unwind_attributes))]
|
||||||
|
|
||||||
mod backend;
|
mod backend;
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
pub mod call_trace;
|
pub mod call_trace;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Errors.
|
//! Read runtime errors.
|
||||||
|
|
||||||
use libc::{c_char, c_int};
|
use libc::{c_char, c_int};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@ -61,20 +61,20 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let last_error = match take_last_error() {
|
let error_message = match take_last_error() {
|
||||||
Some(err) => err,
|
Some(err) => err.to_string(),
|
||||||
None => return 0,
|
None => return 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let error_message = last_error.to_string();
|
let length = length as usize;
|
||||||
|
|
||||||
let buffer = slice::from_raw_parts_mut(buffer as *mut u8, length as usize);
|
if error_message.len() >= length {
|
||||||
|
// buffer is too small to hold the error message
|
||||||
if error_message.len() >= buffer.len() {
|
|
||||||
// buffer to small for err message
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let buffer = slice::from_raw_parts_mut(buffer as *mut u8, length);
|
||||||
|
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(
|
||||||
error_message.as_ptr(),
|
error_message.as_ptr(),
|
||||||
buffer.as_mut_ptr(),
|
buffer.as_mut_ptr(),
|
||||||
@ -85,7 +85,7 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length:
|
|||||||
// accidentally read into garbage.
|
// accidentally read into garbage.
|
||||||
buffer[error_message.len()] = 0;
|
buffer[error_message.len()] = 0;
|
||||||
|
|
||||||
error_message.len() as c_int
|
error_message.len() as c_int + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
//! Wasm exports.
|
//! Create, read, destroy export definitions (function, global, memory
|
||||||
|
//! and table) on an instance.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{update_last_error, CApiError},
|
error::{update_last_error, CApiError},
|
||||||
@ -221,7 +222,7 @@ pub unsafe extern "C" fn wasmer_export_func_params_arity(
|
|||||||
pub unsafe extern "C" fn wasmer_export_func_params(
|
pub unsafe extern "C" fn wasmer_export_func_params(
|
||||||
func: *const wasmer_export_func_t,
|
func: *const wasmer_export_func_t,
|
||||||
params: *mut wasmer_value_tag,
|
params: *mut wasmer_value_tag,
|
||||||
params_len: c_int,
|
params_len: uint32_t,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
let named_export = &*(func as *const NamedExport);
|
let named_export = &*(func as *const NamedExport);
|
||||||
let export = &named_export.export;
|
let export = &named_export.export;
|
||||||
@ -251,7 +252,7 @@ pub unsafe extern "C" fn wasmer_export_func_params(
|
|||||||
pub unsafe extern "C" fn wasmer_export_func_returns(
|
pub unsafe extern "C" fn wasmer_export_func_returns(
|
||||||
func: *const wasmer_export_func_t,
|
func: *const wasmer_export_func_t,
|
||||||
returns: *mut wasmer_value_tag,
|
returns: *mut wasmer_value_tag,
|
||||||
returns_len: c_int,
|
returns_len: uint32_t,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
let named_export = &*(func as *const NamedExport);
|
let named_export = &*(func as *const NamedExport);
|
||||||
let export = &named_export.export;
|
let export = &named_export.export;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Wasm global.
|
//! Create, set, get and destroy global variables of an instance.
|
||||||
|
|
||||||
use crate::value::{wasmer_value_t, wasmer_value_tag};
|
use crate::value::{wasmer_value_t, wasmer_value_tag};
|
||||||
use wasmer_runtime::Global;
|
use wasmer_runtime::Global;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
//! Wasm imports.
|
//! Create, read, destroy import definitions (function, global, memory
|
||||||
|
//! and table) on an instance.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{update_last_error, CApiError},
|
error::{update_last_error, CApiError},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Wasm instance.
|
//! Instantiate a module, call functions, and read exports.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{update_last_error, CApiError},
|
error::{update_last_error, CApiError},
|
||||||
@ -125,9 +125,9 @@ pub unsafe extern "C" fn wasmer_instance_call(
|
|||||||
instance: *mut wasmer_instance_t,
|
instance: *mut wasmer_instance_t,
|
||||||
name: *const c_char,
|
name: *const c_char,
|
||||||
params: *const wasmer_value_t,
|
params: *const wasmer_value_t,
|
||||||
params_len: c_int,
|
params_len: uint32_t,
|
||||||
results: *mut wasmer_value_t,
|
results: *mut wasmer_value_t,
|
||||||
results_len: c_int,
|
results_len: uint32_t,
|
||||||
) -> wasmer_result_t {
|
) -> wasmer_result_t {
|
||||||
if instance.is_null() {
|
if instance.is_null() {
|
||||||
update_last_error(CApiError {
|
update_last_error(CApiError {
|
||||||
|
@ -1,4 +1,86 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
//! # Wasmer Runtime C API
|
||||||
|
//!
|
||||||
|
//! Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully
|
||||||
|
//! compatible with Emscripten, Rust and Go. [Learn
|
||||||
|
//! more](https://github.com/wasmerio/wasmer).
|
||||||
|
//!
|
||||||
|
//! This crate exposes a C and C++ API for the Wasmer runtime.
|
||||||
|
//!
|
||||||
|
//! # Usage
|
||||||
|
//!
|
||||||
|
//! The C and C++ header files can be found in the source tree of this
|
||||||
|
//! crate, respectively [`wasmer.h`][wasmer_h] and
|
||||||
|
//! [`wasmer.hh`][wasmer_hh]. They are automatically generated, and always
|
||||||
|
//! up-to-date in this repository.
|
||||||
|
//!
|
||||||
|
//! Here is a simple example to use the C API:
|
||||||
|
//!
|
||||||
|
//! ```c
|
||||||
|
//! #include <stdio.h>
|
||||||
|
//! #include "wasmer.h"
|
||||||
|
//! #include <assert.h>
|
||||||
|
//! #include <stdint.h>
|
||||||
|
//!
|
||||||
|
//! int main()
|
||||||
|
//! {
|
||||||
|
//! // Read the Wasm file bytes.
|
||||||
|
//! FILE *file = fopen("sum.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);
|
||||||
|
//!
|
||||||
|
//! // Prepare the imports.
|
||||||
|
//! wasmer_import_t imports[] = {};
|
||||||
|
//!
|
||||||
|
//! // Instantiate!
|
||||||
|
//! wasmer_instance_t *instance = NULL;
|
||||||
|
//! wasmer_result_t instantiation_result = wasmer_instantiate(&instance, bytes, len, imports, 0);
|
||||||
|
//!
|
||||||
|
//! assert(instantiation_result == WASMER_OK);
|
||||||
|
//!
|
||||||
|
//! // Let's call a function.
|
||||||
|
//! // Start by preparing the arguments.
|
||||||
|
//!
|
||||||
|
//! // Value of argument #1 is `7i32`.
|
||||||
|
//! wasmer_value_t argument_one;
|
||||||
|
//! argument_one.tag = WASM_I32;
|
||||||
|
//! argument_one.value.I32 = 7;
|
||||||
|
//!
|
||||||
|
//! // Value of argument #2 is `8i32`.
|
||||||
|
//! wasmer_value_t argument_two;
|
||||||
|
//! argument_two.tag = WASM_I32;
|
||||||
|
//! argument_two.value.I32 = 8;
|
||||||
|
//!
|
||||||
|
//! // Prepare the arguments.
|
||||||
|
//! wasmer_value_t arguments[] = {argument_one, argument_two};
|
||||||
|
//!
|
||||||
|
//! // Prepare the return value.
|
||||||
|
//! wasmer_value_t result_one;
|
||||||
|
//! wasmer_value_t results[] = {result_one};
|
||||||
|
//!
|
||||||
|
//! // Call the `sum` function with the prepared arguments and the return value.
|
||||||
|
//! wasmer_result_t call_result = wasmer_instance_call(instance, "sum", arguments, 2, results, 1);
|
||||||
|
//!
|
||||||
|
//! // Let's display the result.
|
||||||
|
//! printf("Call result: %d\n", call_result);
|
||||||
|
//! printf("Result: %d\n", results[0].value.I32);
|
||||||
|
//!
|
||||||
|
//! // `sum(7, 8) == 15`.
|
||||||
|
//! assert(results[0].value.I32 == 15);
|
||||||
|
//! assert(call_result == WASMER_OK);
|
||||||
|
//!
|
||||||
|
//! wasmer_instance_destroy(instance);
|
||||||
|
//!
|
||||||
|
//! return 0;
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! [wasmer_h]: ./wasmer.h
|
||||||
|
//! [wasmer_hh]: ./wasmer.hh
|
||||||
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
extern crate wasmer_runtime;
|
extern crate wasmer_runtime;
|
||||||
extern crate wasmer_runtime_core;
|
extern crate wasmer_runtime_core;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Wasm memory.o
|
//! Create, read, write, grow, destroy memory of an instance.
|
||||||
|
|
||||||
use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t};
|
use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t};
|
||||||
use libc::{uint32_t, uint8_t};
|
use libc::{uint32_t, uint8_t};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Wasm module.
|
//! Compile, validate, instantiate, serialize, and destroy modules.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{update_last_error, CApiError},
|
error::{update_last_error, CApiError},
|
||||||
@ -247,7 +247,7 @@ pub unsafe extern "C" fn wasmer_module_deserialize(
|
|||||||
let serialized_module: &[u8] = &*(serialized_module as *const &[u8]);
|
let serialized_module: &[u8] = &*(serialized_module as *const &[u8]);
|
||||||
|
|
||||||
match Artifact::deserialize(serialized_module) {
|
match Artifact::deserialize(serialized_module) {
|
||||||
Ok(artifact) => match load_cache_with(artifact, default_compiler()) {
|
Ok(artifact) => match load_cache_with(artifact, &default_compiler()) {
|
||||||
Ok(deserialized_module) => {
|
Ok(deserialized_module) => {
|
||||||
*module = Box::into_raw(Box::new(deserialized_module)) as _;
|
*module = Box::into_raw(Box::new(deserialized_module)) as _;
|
||||||
wasmer_result_t::WASMER_OK
|
wasmer_result_t::WASMER_OK
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Wasm tables.
|
//! Create, grow, destroy tables of an instance.
|
||||||
|
|
||||||
use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t};
|
use crate::{error::update_last_error, wasmer_limits_t, wasmer_result_t};
|
||||||
use libc::uint32_t;
|
use libc::uint32_t;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Wasm values.
|
//! Create and map Rust to WebAssembly values.
|
||||||
|
|
||||||
use libc::{int32_t, int64_t};
|
use libc::{int32_t, int64_t};
|
||||||
use wasmer_runtime::Value;
|
use wasmer_runtime::Value;
|
||||||
|
@ -60,7 +60,6 @@ int main()
|
|||||||
assert(returns_sig[0] == WASM_I32);
|
assert(returns_sig[0] == WASM_I32);
|
||||||
free(returns_sig);
|
free(returns_sig);
|
||||||
|
|
||||||
|
|
||||||
wasmer_value_t param_one;
|
wasmer_value_t param_one;
|
||||||
param_one.tag = WASM_I32;
|
param_one.tag = WASM_I32;
|
||||||
param_one.value.I32 = 7;
|
param_one.value.I32 = 7;
|
||||||
@ -71,7 +70,7 @@ int main()
|
|||||||
wasmer_value_t result_one;
|
wasmer_value_t result_one;
|
||||||
wasmer_value_t results[] = {result_one};
|
wasmer_value_t results[] = {result_one};
|
||||||
|
|
||||||
wasmer_result_t call_result = wasmer_export_func_call(func, params, 2, results, 1);
|
wasmer_result_t call_result = wasmer_export_func_call(func, params, params_arity, results, returns_arity);
|
||||||
printf("Call result: %d\n", call_result);
|
printf("Call result: %d\n", call_result);
|
||||||
printf("Result: %d\n", results[0].value.I32);
|
printf("Result: %d\n", results[0].value.I32);
|
||||||
assert(results[0].value.I32 == 15);
|
assert(results[0].value.I32 == 15);
|
||||||
|
@ -46,7 +46,8 @@ int main()
|
|||||||
int error_len = wasmer_last_error_length();
|
int error_len = wasmer_last_error_length();
|
||||||
printf("Error len: `%d`\n", error_len);
|
printf("Error len: `%d`\n", error_len);
|
||||||
char *error_str = malloc(error_len);
|
char *error_str = malloc(error_len);
|
||||||
wasmer_last_error_message(error_str, error_len);
|
int error_result = wasmer_last_error_message(error_str, error_len);
|
||||||
|
assert(error_len == error_result);
|
||||||
printf("Error str: `%s`\n", error_str);
|
printf("Error str: `%s`\n", error_str);
|
||||||
assert(0 == strcmp(error_str, "Call error: Parameters of type [I32] did not match signature [I32, I32] -> [I32]"));
|
assert(0 == strcmp(error_str, "Call error: Parameters of type [I32] did not match signature [I32, I32] -> [I32]"));
|
||||||
free(error_str);
|
free(error_str);
|
||||||
|
@ -197,7 +197,7 @@ wasmer_result_t wasmer_export_func_call(const wasmer_export_func_t *func,
|
|||||||
*/
|
*/
|
||||||
wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func,
|
wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func,
|
||||||
wasmer_value_tag *params,
|
wasmer_value_tag *params,
|
||||||
int params_len);
|
uint32_t params_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the result parameter to the arity of the params of the wasmer_export_func_t
|
* Sets the result parameter to the arity of the params of the wasmer_export_func_t
|
||||||
@ -215,7 +215,7 @@ wasmer_result_t wasmer_export_func_params_arity(const wasmer_export_func_t *func
|
|||||||
*/
|
*/
|
||||||
wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func,
|
wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func,
|
||||||
wasmer_value_tag *returns,
|
wasmer_value_tag *returns,
|
||||||
int returns_len);
|
uint32_t returns_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the result parameter to the arity of the returns of the wasmer_export_func_t
|
* Sets the result parameter to the arity of the returns of the wasmer_export_func_t
|
||||||
@ -390,9 +390,9 @@ wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *fun
|
|||||||
wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance,
|
wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance,
|
||||||
const char *name,
|
const char *name,
|
||||||
const wasmer_value_t *params,
|
const wasmer_value_t *params,
|
||||||
int params_len,
|
uint32_t params_len,
|
||||||
wasmer_value_t *results,
|
wasmer_value_t *results,
|
||||||
int results_len);
|
uint32_t results_len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `data` field within the context.
|
* Gets the `data` field within the context.
|
||||||
|
@ -178,7 +178,7 @@ wasmer_result_t wasmer_export_func_call(const wasmer_export_func_t *func,
|
|||||||
/// and `wasmer_last_error_message` to get an error message.
|
/// and `wasmer_last_error_message` to get an error message.
|
||||||
wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func,
|
wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func,
|
||||||
wasmer_value_tag *params,
|
wasmer_value_tag *params,
|
||||||
int params_len);
|
uint32_t params_len);
|
||||||
|
|
||||||
/// Sets the result parameter to the arity of the params of the wasmer_export_func_t
|
/// Sets the result parameter to the arity of the params of the wasmer_export_func_t
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
@ -192,7 +192,7 @@ wasmer_result_t wasmer_export_func_params_arity(const wasmer_export_func_t *func
|
|||||||
/// and `wasmer_last_error_message` to get an error message.
|
/// and `wasmer_last_error_message` to get an error message.
|
||||||
wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func,
|
wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func,
|
||||||
wasmer_value_tag *returns,
|
wasmer_value_tag *returns,
|
||||||
int returns_len);
|
uint32_t returns_len);
|
||||||
|
|
||||||
/// Sets the result parameter to the arity of the returns of the wasmer_export_func_t
|
/// Sets the result parameter to the arity of the returns of the wasmer_export_func_t
|
||||||
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
/// Returns `wasmer_result_t::WASMER_OK` upon success.
|
||||||
@ -313,9 +313,9 @@ wasmer_result_t wasmer_import_func_returns_arity(const wasmer_import_func_t *fun
|
|||||||
wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance,
|
wasmer_result_t wasmer_instance_call(wasmer_instance_t *instance,
|
||||||
const char *name,
|
const char *name,
|
||||||
const wasmer_value_t *params,
|
const wasmer_value_t *params,
|
||||||
int params_len,
|
uint32_t params_len,
|
||||||
wasmer_value_t *results,
|
wasmer_value_t *results,
|
||||||
int results_len);
|
uint32_t results_len);
|
||||||
|
|
||||||
/// Gets the `data` field within the context.
|
/// Gets the `data` field within the context.
|
||||||
void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx);
|
void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx);
|
||||||
|
@ -17,30 +17,31 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
|
/// The `LocalBacking` "owns" the memory used by all the local resources of an Instance.
|
||||||
|
/// That is, local memories, tables, and globals (as well as some additional
|
||||||
|
/// data for the virtual call machinery).
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LocalBacking {
|
pub struct LocalBacking {
|
||||||
|
/// This is a map from the local resource index to actual memory,
|
||||||
|
/// table, and globals.
|
||||||
pub(crate) memories: BoxedMap<LocalMemoryIndex, Memory>,
|
pub(crate) memories: BoxedMap<LocalMemoryIndex, Memory>,
|
||||||
pub(crate) tables: BoxedMap<LocalTableIndex, Table>,
|
pub(crate) tables: BoxedMap<LocalTableIndex, Table>,
|
||||||
pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>,
|
pub(crate) globals: BoxedMap<LocalGlobalIndex, Global>,
|
||||||
|
|
||||||
|
/// This own the memory containing the pointers to the local memories.
|
||||||
|
/// While simplifying implementation, this adds indirection and may hurt
|
||||||
|
/// performance, especially on cache-starved systems.
|
||||||
pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory>,
|
pub(crate) vm_memories: BoxedMap<LocalMemoryIndex, *mut vm::LocalMemory>,
|
||||||
pub(crate) vm_tables: BoxedMap<LocalTableIndex, *mut vm::LocalTable>,
|
pub(crate) vm_tables: BoxedMap<LocalTableIndex, *mut vm::LocalTable>,
|
||||||
pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal>,
|
pub(crate) vm_globals: BoxedMap<LocalGlobalIndex, *mut vm::LocalGlobal>,
|
||||||
|
|
||||||
|
/// The dynamic sigindices are used to efficiently support caching and
|
||||||
|
/// the `call_indirect` wasm instruction. This field (and local_functions
|
||||||
|
/// as well) are subject to change.
|
||||||
pub(crate) dynamic_sigindices: BoxedMap<SigIndex, vm::SigId>,
|
pub(crate) dynamic_sigindices: BoxedMap<SigIndex, vm::SigId>,
|
||||||
pub(crate) local_functions: BoxedMap<LocalFuncIndex, *const vm::Func>,
|
pub(crate) local_functions: BoxedMap<LocalFuncIndex, *const vm::Func>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl LocalBacking {
|
|
||||||
// pub fn memory(&mut self, local_memory_index: LocalMemoryIndex) -> &mut Memory {
|
|
||||||
// &mut self.memories[local_memory_index]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn table(&mut self, local_table_index: LocalTableIndex) -> &mut TableBacking {
|
|
||||||
// &mut self.tables[local_table_index]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl LocalBacking {
|
impl LocalBacking {
|
||||||
pub(crate) fn new(module: &ModuleInner, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
|
pub(crate) fn new(module: &ModuleInner, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
|
||||||
let mut memories = Self::generate_memories(module);
|
let mut memories = Self::generate_memories(module);
|
||||||
@ -102,6 +103,9 @@ impl LocalBacking {
|
|||||||
memories.into_boxed_map()
|
memories.into_boxed_map()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initialize each locally-defined memory in the Module.
|
||||||
|
///
|
||||||
|
/// This involves copying in the data initializers.
|
||||||
fn finalize_memories(
|
fn finalize_memories(
|
||||||
module: &ModuleInner,
|
module: &ModuleInner,
|
||||||
imports: &ImportBacking,
|
imports: &ImportBacking,
|
||||||
@ -174,6 +178,9 @@ impl LocalBacking {
|
|||||||
tables.into_boxed_map()
|
tables.into_boxed_map()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This initializes all of the locally-defined tables in the Module, e.g.
|
||||||
|
/// putting all the table elements (function pointers)
|
||||||
|
/// in the right places.
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
fn finalize_tables(
|
fn finalize_tables(
|
||||||
module: &ModuleInner,
|
module: &ModuleInner,
|
||||||
|
@ -35,7 +35,6 @@ impl fmt::Debug for InternalEvent {
|
|||||||
InternalEvent::Breakpoint(_) => write!(f, "Breakpoint"),
|
InternalEvent::Breakpoint(_) => write!(f, "Breakpoint"),
|
||||||
InternalEvent::SetInternal(_) => write!(f, "SetInternal"),
|
InternalEvent::SetInternal(_) => write!(f, "SetInternal"),
|
||||||
InternalEvent::GetInternal(_) => write!(f, "GetInternal"),
|
InternalEvent::GetInternal(_) => write!(f, "GetInternal"),
|
||||||
_ => panic!("unknown event"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ pub type ResolveResult<T> = std::result::Result<T, ResolveError>;
|
|||||||
pub type ParseResult<T> = std::result::Result<T, ParseError>;
|
pub type ParseResult<T> = std::result::Result<T, ParseError>;
|
||||||
|
|
||||||
/// This is returned when the chosen compiler is unable to
|
/// This is returned when the chosen compiler is unable to
|
||||||
/// successfully compile the provided webassembly module into
|
/// successfully compile the provided WebAssembly module into
|
||||||
/// a `Module`.
|
/// a `Module`.
|
||||||
///
|
///
|
||||||
/// Comparing two `CompileError`s always evaluates to false.
|
/// Comparing two `CompileError`s always evaluates to false.
|
||||||
@ -114,7 +114,7 @@ impl std::fmt::Display for LinkError {
|
|||||||
impl std::error::Error for LinkError {}
|
impl std::error::Error for LinkError {}
|
||||||
|
|
||||||
/// This is the error type returned when calling
|
/// This is the error type returned when calling
|
||||||
/// a webassembly function.
|
/// a WebAssembly function.
|
||||||
///
|
///
|
||||||
/// The main way to do this is `Instance.call`.
|
/// The main way to do this is `Instance.call`.
|
||||||
///
|
///
|
||||||
@ -270,7 +270,7 @@ impl std::error::Error for CreationError {}
|
|||||||
|
|
||||||
/// The amalgamation of all errors that can occur
|
/// The amalgamation of all errors that can occur
|
||||||
/// during the compilation, instantiation, or execution
|
/// during the compilation, instantiation, or execution
|
||||||
/// of a webassembly module.
|
/// of a WebAssembly module.
|
||||||
///
|
///
|
||||||
/// Comparing two `Error`s always evaluates to false.
|
/// Comparing two `Error`s always evaluates to false.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -262,7 +262,7 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call an exported webassembly function given the export name.
|
/// Call an exported WebAssembly function given the export name.
|
||||||
/// Pass arguments by wrapping each one in the [`Value`] enum.
|
/// Pass arguments by wrapping each one in the [`Value`] enum.
|
||||||
/// The returned values are also each wrapped in a [`Value`].
|
/// The returned values are also each wrapped in a [`Value`].
|
||||||
///
|
///
|
||||||
@ -270,7 +270,7 @@ impl Instance {
|
|||||||
///
|
///
|
||||||
/// # Note:
|
/// # Note:
|
||||||
/// This returns `CallResult<Vec<Value>>` in order to support
|
/// This returns `CallResult<Vec<Value>>` in order to support
|
||||||
/// the future multi-value returns webassembly feature.
|
/// the future multi-value returns WebAssembly feature.
|
||||||
///
|
///
|
||||||
/// # Usage:
|
/// # Usage:
|
||||||
/// ```
|
/// ```
|
||||||
@ -601,7 +601,7 @@ pub struct DynFunc<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DynFunc<'a> {
|
impl<'a> DynFunc<'a> {
|
||||||
/// Call an exported webassembly function safely.
|
/// Call an exported WebAssembly function safely.
|
||||||
///
|
///
|
||||||
/// Pass arguments by wrapping each one in the [`Value`] enum.
|
/// Pass arguments by wrapping each one in the [`Value`] enum.
|
||||||
/// The returned values are also each wrapped in a [`Value`].
|
/// The returned values are also each wrapped in a [`Value`].
|
||||||
@ -610,7 +610,7 @@ impl<'a> DynFunc<'a> {
|
|||||||
///
|
///
|
||||||
/// # Note:
|
/// # Note:
|
||||||
/// This returns `CallResult<Vec<Value>>` in order to support
|
/// This returns `CallResult<Vec<Value>>` in order to support
|
||||||
/// the future multi-value returns webassembly feature.
|
/// the future multi-value returns WebAssembly feature.
|
||||||
///
|
///
|
||||||
/// # Usage:
|
/// # Usage:
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
#![cfg_attr(nightly, feature(unwind_attributes))]
|
#![cfg_attr(nightly, feature(unwind_attributes))]
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||||||
/// This is an internal-only api.
|
/// This is an internal-only api.
|
||||||
///
|
///
|
||||||
/// A static memory allocates 6GB of *virtual* memory when created
|
/// A static memory allocates 6GB of *virtual* memory when created
|
||||||
/// in order to allow the webassembly module to contain no bounds-checks.
|
/// in order to allow the WebAssembly module to contain no bounds-checks.
|
||||||
///
|
///
|
||||||
/// Additionally, static memories stay at a single virtual address, so there is no need
|
/// Additionally, static memories stay at a single virtual address, so there is no need
|
||||||
/// to reload its address on each use.
|
/// to reload its address on each use.
|
||||||
|
@ -23,10 +23,18 @@ struct GlobalSigRegistry {
|
|||||||
sig_assoc: Map<SigIndex, Arc<FuncSig>>,
|
sig_assoc: Map<SigIndex, Arc<FuncSig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The `SigRegistry` represents a process-global map of function signatures
|
||||||
|
/// to signature indexes and vice versa (the map goes both ways).
|
||||||
|
///
|
||||||
|
/// This exists for two reasons:
|
||||||
|
/// 1. The `call_indirect` wasm instruction can compare two signature indices
|
||||||
|
/// to do signature validation very quickly.
|
||||||
|
/// 2. To intern function signatures, which may be expensive to create.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SigRegistry;
|
pub struct SigRegistry;
|
||||||
|
|
||||||
impl SigRegistry {
|
impl SigRegistry {
|
||||||
|
/// Map a `FuncSig` to a global `SigIndex`.
|
||||||
pub fn lookup_sig_index<Sig>(&self, func_sig: Sig) -> SigIndex
|
pub fn lookup_sig_index<Sig>(&self, func_sig: Sig) -> SigIndex
|
||||||
where
|
where
|
||||||
Sig: Into<Arc<FuncSig>>,
|
Sig: Into<Arc<FuncSig>>,
|
||||||
@ -45,11 +53,15 @@ impl SigRegistry {
|
|||||||
sig_index
|
sig_index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map a global `SigIndex` to an interned `FuncSig`.
|
||||||
pub fn lookup_signature(&self, sig_index: SigIndex) -> Arc<FuncSig> {
|
pub fn lookup_signature(&self, sig_index: SigIndex) -> Arc<FuncSig> {
|
||||||
let global = (*GLOBAL_SIG_REGISTRY).read();
|
let global = (*GLOBAL_SIG_REGISTRY).read();
|
||||||
Arc::clone(&global.sig_assoc[sig_index])
|
Arc::clone(&global.sig_assoc[sig_index])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a function signature with the global signature registry.
|
||||||
|
///
|
||||||
|
/// This will return an interned `FuncSig`.
|
||||||
pub fn lookup_signature_ref(&self, func_sig: &FuncSig) -> Arc<FuncSig> {
|
pub fn lookup_signature_ref(&self, func_sig: &FuncSig) -> Arc<FuncSig> {
|
||||||
let mut global = (*GLOBAL_SIG_REGISTRY).write();
|
let mut global = (*GLOBAL_SIG_REGISTRY).write();
|
||||||
let global = &mut *global;
|
let global = &mut *global;
|
||||||
|
@ -247,7 +247,7 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
|
|||||||
type CStruct = S1<A>;
|
type CStruct = S1<A>;
|
||||||
type RetArray = [u64; 1];
|
type RetArray = [u64; 1];
|
||||||
fn from_ret_array(array: Self::RetArray) -> Self {
|
fn from_ret_array(array: Self::RetArray) -> Self {
|
||||||
(WasmExternType::from_native(NativeWasmType::from_bits(
|
(WasmExternType::from_native(NativeWasmType::from_binary(
|
||||||
array[0],
|
array[0],
|
||||||
)),)
|
)),)
|
||||||
}
|
}
|
||||||
@ -274,7 +274,7 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
|
|||||||
ctx: *mut Ctx,
|
ctx: *mut Ctx,
|
||||||
) -> Result<Rets, RuntimeError> {
|
) -> Result<Rets, RuntimeError> {
|
||||||
let (a,) = self;
|
let (a,) = self;
|
||||||
let args = [a.to_native().to_bits()];
|
let args = [a.to_native().to_binary()];
|
||||||
let mut rets = Rets::empty_ret_array();
|
let mut rets = Rets::empty_ret_array();
|
||||||
let mut trap = WasmTrapInfo::Unknown;
|
let mut trap = WasmTrapInfo::Unknown;
|
||||||
let mut user_error = None;
|
let mut user_error = None;
|
||||||
@ -322,7 +322,7 @@ macro_rules! impl_traits {
|
|||||||
fn from_ret_array(array: Self::RetArray) -> Self {
|
fn from_ret_array(array: Self::RetArray) -> Self {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let [ $( $x ),* ] = array;
|
let [ $( $x ),* ] = array;
|
||||||
( $( WasmExternType::from_native(NativeWasmType::from_bits($x)) ),* )
|
( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
|
||||||
}
|
}
|
||||||
fn empty_ret_array() -> Self::RetArray {
|
fn empty_ret_array() -> Self::RetArray {
|
||||||
[0; count_idents!( $( $x ),* )]
|
[0; count_idents!( $( $x ),* )]
|
||||||
@ -344,7 +344,7 @@ macro_rules! impl_traits {
|
|||||||
unsafe fn call<Rets: WasmTypeList>(self, f: NonNull<vm::Func>, wasm: Wasm, ctx: *mut Ctx) -> Result<Rets, RuntimeError> {
|
unsafe fn call<Rets: WasmTypeList>(self, f: NonNull<vm::Func>, wasm: Wasm, ctx: *mut Ctx) -> Result<Rets, RuntimeError> {
|
||||||
#[allow(unused_parens)]
|
#[allow(unused_parens)]
|
||||||
let ( $( $x ),* ) = self;
|
let ( $( $x ),* ) = self;
|
||||||
let args = [ $( $x.to_native().to_bits() ),* ];
|
let args = [ $( $x.to_native().to_binary()),* ];
|
||||||
let mut rets = Rets::empty_ret_array();
|
let mut rets = Rets::empty_ret_array();
|
||||||
let mut trap = WasmTrapInfo::Unknown;
|
let mut trap = WasmTrapInfo::Unknown;
|
||||||
let mut user_error = None;
|
let mut user_error = None;
|
||||||
|
@ -76,44 +76,44 @@ where
|
|||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
const TYPE: Type;
|
const TYPE: Type;
|
||||||
fn from_bits(bits: u64) -> Self;
|
fn from_binary(bits: u64) -> Self;
|
||||||
fn to_bits(self) -> u64;
|
fn to_binary(self) -> u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl NativeWasmType for i32 {
|
unsafe impl NativeWasmType for i32 {
|
||||||
const TYPE: Type = Type::I32;
|
const TYPE: Type = Type::I32;
|
||||||
fn from_bits(bits: u64) -> Self {
|
fn from_binary(bits: u64) -> Self {
|
||||||
bits as _
|
bits as _
|
||||||
}
|
}
|
||||||
fn to_bits(self) -> u64 {
|
fn to_binary(self) -> u64 {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe impl NativeWasmType for i64 {
|
unsafe impl NativeWasmType for i64 {
|
||||||
const TYPE: Type = Type::I64;
|
const TYPE: Type = Type::I64;
|
||||||
fn from_bits(bits: u64) -> Self {
|
fn from_binary(bits: u64) -> Self {
|
||||||
bits as _
|
bits as _
|
||||||
}
|
}
|
||||||
fn to_bits(self) -> u64 {
|
fn to_binary(self) -> u64 {
|
||||||
self as _
|
self as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe impl NativeWasmType for f32 {
|
unsafe impl NativeWasmType for f32 {
|
||||||
const TYPE: Type = Type::F32;
|
const TYPE: Type = Type::F32;
|
||||||
fn from_bits(bits: u64) -> Self {
|
fn from_binary(bits: u64) -> Self {
|
||||||
bits as _
|
f32::from_bits(bits as u32)
|
||||||
}
|
}
|
||||||
fn to_bits(self) -> u64 {
|
fn to_binary(self) -> u64 {
|
||||||
self as _
|
self.to_bits() as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe impl NativeWasmType for f64 {
|
unsafe impl NativeWasmType for f64 {
|
||||||
const TYPE: Type = Type::F64;
|
const TYPE: Type = Type::F64;
|
||||||
fn from_bits(bits: u64) -> Self {
|
fn from_binary(bits: u64) -> Self {
|
||||||
bits as _
|
f64::from_bits(bits)
|
||||||
}
|
}
|
||||||
fn to_bits(self) -> u64 {
|
fn to_binary(self) -> u64 {
|
||||||
self as _
|
self.to_bits()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,3 +516,58 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::types::NativeWasmType;
|
||||||
|
use crate::types::WasmExternType;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_native_types_round_trip() {
|
||||||
|
assert_eq!(
|
||||||
|
42i32,
|
||||||
|
i32::from_native(i32::from_binary((42i32).to_native().to_binary()))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
-42i32,
|
||||||
|
i32::from_native(i32::from_binary((-42i32).to_native().to_binary()))
|
||||||
|
);
|
||||||
|
|
||||||
|
use std::i64;
|
||||||
|
let xi64 = i64::MAX;
|
||||||
|
assert_eq!(
|
||||||
|
xi64,
|
||||||
|
i64::from_native(i64::from_binary((xi64).to_native().to_binary()))
|
||||||
|
);
|
||||||
|
let yi64 = i64::MIN;
|
||||||
|
assert_eq!(
|
||||||
|
yi64,
|
||||||
|
i64::from_native(i64::from_binary((yi64).to_native().to_binary()))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
16.5f32,
|
||||||
|
f32::from_native(f32::from_binary((16.5f32).to_native().to_binary()))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
-16.5f32,
|
||||||
|
f32::from_native(f32::from_binary((-16.5f32).to_native().to_binary()))
|
||||||
|
);
|
||||||
|
|
||||||
|
use std::f64;
|
||||||
|
let xf64: f64 = f64::MAX;
|
||||||
|
assert_eq!(
|
||||||
|
xf64,
|
||||||
|
f64::from_native(f64::from_binary((xf64).to_native().to_binary()))
|
||||||
|
);
|
||||||
|
|
||||||
|
let yf64: f64 = f64::MIN;
|
||||||
|
assert_eq!(
|
||||||
|
yf64,
|
||||||
|
f64::from_native(f64::from_binary((yf64).to_native().to_binary()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -11,7 +11,16 @@ use hashbrown::HashMap;
|
|||||||
|
|
||||||
/// The context of the currently running WebAssembly instance.
|
/// The context of the currently running WebAssembly instance.
|
||||||
///
|
///
|
||||||
|
/// This is implicitly passed to every WebAssembly function.
|
||||||
|
/// Since this is per-instance, each field has a statically
|
||||||
|
/// (as in after compiling the wasm) known size, so no
|
||||||
|
/// runtime checks are necessary.
|
||||||
///
|
///
|
||||||
|
/// While the runtime currently just passes this around
|
||||||
|
/// as the first, implicit parameter of every function,
|
||||||
|
/// it may someday be pinned to a register (especially
|
||||||
|
/// on arm, which has a ton of registers) to reduce
|
||||||
|
/// register shuffling.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Ctx {
|
pub struct Ctx {
|
||||||
@ -20,11 +29,25 @@ pub struct Ctx {
|
|||||||
|
|
||||||
pub(crate) local_functions: *const *const Func,
|
pub(crate) local_functions: *const *const Func,
|
||||||
|
|
||||||
|
/// These are pointers to things that are known to be owned
|
||||||
|
/// by the owning `Instance`.
|
||||||
local_backing: *mut LocalBacking,
|
local_backing: *mut LocalBacking,
|
||||||
import_backing: *mut ImportBacking,
|
import_backing: *mut ImportBacking,
|
||||||
pub module: *const ModuleInner,
|
pub module: *const ModuleInner,
|
||||||
|
|
||||||
|
//// This is intended to be user-supplied, per-instance
|
||||||
|
/// contextual data. There are currently some issue with it,
|
||||||
|
/// notably that it cannot be set before running the `start`
|
||||||
|
/// function in a WebAssembly module.
|
||||||
|
///
|
||||||
|
/// [#219](https://github.com/wasmerio/wasmer/pull/219) fixes that
|
||||||
|
/// issue, as well as allowing the user to have *per-function*
|
||||||
|
/// context, instead of just per-instance.
|
||||||
pub data: *mut c_void,
|
pub data: *mut c_void,
|
||||||
|
|
||||||
|
/// If there's a function set in this field, it gets called
|
||||||
|
/// when the context is destructed, e.g. when an `Instance`
|
||||||
|
/// is dropped.
|
||||||
pub data_finalizer: Option<fn(data: *mut c_void)>,
|
pub data_finalizer: Option<fn(data: *mut c_void)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,9 @@ impl Cache for FileSystemCache {
|
|||||||
let mmap = unsafe { Mmap::map(&file)? };
|
let mmap = unsafe { Mmap::map(&file)? };
|
||||||
|
|
||||||
let serialized_cache = Artifact::deserialize(&mmap[..])?;
|
let serialized_cache = Artifact::deserialize(&mmap[..])?;
|
||||||
unsafe { wasmer_runtime_core::load_cache_with(serialized_cache, super::default_compiler()) }
|
unsafe {
|
||||||
|
wasmer_runtime_core::load_cache_with(serialized_cache, &super::default_compiler())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), CacheError> {
|
fn store(&mut self, key: WasmHash, module: Module) -> Result<(), CacheError> {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
//! Wasmer-runtime is a library that makes embedding WebAssembly
|
//! Wasmer-runtime is a library that makes embedding WebAssembly
|
||||||
//! in your application easy, efficient, and safe.
|
//! in your application easy, efficient, and safe.
|
||||||
@ -131,7 +131,7 @@ use wasmer_runtime_core::backend::{Compiler, CompilerConfig};
|
|||||||
/// # Errors:
|
/// # Errors:
|
||||||
/// If the operation fails, the function returns `Err(error::CompileError::...)`.
|
/// If the operation fails, the function returns `Err(error::CompileError::...)`.
|
||||||
pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
|
pub fn compile(wasm: &[u8]) -> error::CompileResult<Module> {
|
||||||
wasmer_runtime_core::compile_with(&wasm[..], default_compiler())
|
wasmer_runtime_core::compile_with(&wasm[..], &default_compiler())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The same as `compile` but takes a `CompilerConfig` for the purpose of
|
/// The same as `compile` but takes a `CompilerConfig` for the purpose of
|
||||||
@ -140,7 +140,7 @@ pub fn compile_with_config(
|
|||||||
wasm: &[u8],
|
wasm: &[u8],
|
||||||
compiler_config: CompilerConfig,
|
compiler_config: CompilerConfig,
|
||||||
) -> error::CompileResult<Module> {
|
) -> error::CompileResult<Module> {
|
||||||
wasmer_runtime_core::compile_with_config(&wasm[..], default_compiler(), compiler_config)
|
wasmer_runtime_core::compile_with_config(&wasm[..], &default_compiler(), compiler_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The same as `compile_with_config` but takes a `Compiler` for the purpose of
|
/// The same as `compile_with_config` but takes a `Compiler` for the purpose of
|
||||||
@ -177,9 +177,7 @@ pub fn instantiate(wasm: &[u8], import_object: &ImportObject) -> error::Result<I
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a single instance of the default compiler to use.
|
/// Get a single instance of the default compiler to use.
|
||||||
pub fn default_compiler() -> &'static dyn Compiler {
|
pub fn default_compiler() -> impl Compiler {
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
#[cfg(feature = "llvm")]
|
#[cfg(feature = "llvm")]
|
||||||
use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler;
|
use wasmer_llvm_backend::LLVMCompiler as DefaultCompiler;
|
||||||
|
|
||||||
@ -189,11 +187,7 @@ pub fn default_compiler() -> &'static dyn Compiler {
|
|||||||
#[cfg(not(any(feature = "llvm", feature = "singlepass")))]
|
#[cfg(not(any(feature = "llvm", feature = "singlepass")))]
|
||||||
use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler;
|
use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler;
|
||||||
|
|
||||||
lazy_static! {
|
DefaultCompiler::new()
|
||||||
static ref DEFAULT_COMPILER: DefaultCompiler = { DefaultCompiler::new() };
|
|
||||||
}
|
|
||||||
|
|
||||||
&*DEFAULT_COMPILER as &dyn Compiler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current version of this crate
|
/// The current version of this crate
|
||||||
|
@ -212,10 +212,10 @@ impl RunnableModule for X64ExecutionContext {
|
|||||||
user_error: *mut Option<Box<dyn Any>>,
|
user_error: *mut Option<Box<dyn Any>>,
|
||||||
num_params_plus_one: Option<NonNull<c_void>>,
|
num_params_plus_one: Option<NonNull<c_void>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let rm: &Box<dyn RunnableModule> = &unsafe { &*(*ctx).module }.runnable_module;
|
let rm: &Box<dyn RunnableModule> = &(&*(*ctx).module).runnable_module;
|
||||||
let execution_context = unsafe {
|
let execution_context =
|
||||||
::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm)
|
::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm);
|
||||||
};
|
|
||||||
let args = ::std::slice::from_raw_parts(
|
let args = ::std::slice::from_raw_parts(
|
||||||
args,
|
args,
|
||||||
num_params_plus_one.unwrap().as_ptr() as usize - 1,
|
num_params_plus_one.unwrap().as_ptr() as usize - 1,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
#![feature(proc_macro_hygiene)]
|
#![feature(proc_macro_hygiene)]
|
||||||
|
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
|
//! Installing signal handlers allows us to handle traps and out-of-bounds memory
|
||||||
//! accesses that occur when runniing webassembly.
|
//! accesses that occur when runniing WebAssembly.
|
||||||
//!
|
//!
|
||||||
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622
|
||||||
//!
|
//!
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
@ -139,8 +139,10 @@ pub enum Kind {
|
|||||||
handle: WasiFile,
|
handle: WasiFile,
|
||||||
},
|
},
|
||||||
Dir {
|
Dir {
|
||||||
// TODO: wrap it like WasiFile
|
/// Parent directory
|
||||||
|
parent: Option<Inode>,
|
||||||
/// The path on the host system where the directory is located
|
/// The path on the host system where the directory is located
|
||||||
|
// TODO: wrap it like WasiFile
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
/// The entries of a directory are lazily filled.
|
/// The entries of a directory are lazily filled.
|
||||||
entries: HashMap<String, Inode>,
|
entries: HashMap<String, Inode>,
|
||||||
@ -196,6 +198,7 @@ impl WasiFs {
|
|||||||
let cur_dir_metadata = cur_dir.metadata().expect("Could not find directory");
|
let cur_dir_metadata = cur_dir.metadata().expect("Could not find directory");
|
||||||
let kind = if cur_dir_metadata.is_dir() {
|
let kind = if cur_dir_metadata.is_dir() {
|
||||||
Kind::Dir {
|
Kind::Dir {
|
||||||
|
parent: None,
|
||||||
path: cur_dir.clone(),
|
path: cur_dir.clone(),
|
||||||
entries: Default::default(),
|
entries: Default::default(),
|
||||||
}
|
}
|
||||||
@ -414,6 +417,32 @@ impl WasiFs {
|
|||||||
);
|
);
|
||||||
Ok(idx)
|
Ok(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_base_path_for_directory(&self, directory: Inode) -> Option<String> {
|
||||||
|
let mut path_segments = vec![];
|
||||||
|
let mut cur_inode = directory;
|
||||||
|
loop {
|
||||||
|
path_segments.push(self.inodes[cur_inode].name.clone());
|
||||||
|
|
||||||
|
if let Kind::Dir { parent, .. } = &self.inodes[cur_inode].kind {
|
||||||
|
if let Some(p_inode) = parent {
|
||||||
|
cur_inode = *p_inode;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
path_segments.reverse();
|
||||||
|
Some(
|
||||||
|
path_segments
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.fold(path_segments.first()?.clone(), |a, b| a + "/" + b),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -767,14 +767,74 @@ pub fn fd_readdir(
|
|||||||
) -> __wasi_errno_t {
|
) -> __wasi_errno_t {
|
||||||
debug!("wasi::fd_readdir");
|
debug!("wasi::fd_readdir");
|
||||||
let memory = ctx.memory(0);
|
let memory = ctx.memory(0);
|
||||||
|
let state = get_wasi_state(ctx);
|
||||||
|
// TODO: figure out how this is supposed to work;
|
||||||
|
// is it supposed to pack the buffer full every time until it can't? or do one at a time?
|
||||||
|
|
||||||
if let (Ok(buf_arr_cell), Ok(bufused_cell)) =
|
let buf_arr_cell = wasi_try!(buf.deref(memory, 0, buf_len));
|
||||||
(buf.deref(memory, 0, buf_len), bufused.deref(memory))
|
let bufused_cell = wasi_try!(bufused.deref(memory));
|
||||||
{
|
let working_dir = wasi_try!(state.fs.fd_map.get(&fd).ok_or(__WASI_EBADF));
|
||||||
unimplemented!("wasi::fd_readdir")
|
let mut cur_cookie = cookie;
|
||||||
|
let mut buf_idx = 0;
|
||||||
|
|
||||||
|
if let Kind::Dir { path, .. } = &state.fs.inodes[working_dir.inode].kind {
|
||||||
|
// we need to support multiple calls,
|
||||||
|
// simple and obviously correct implementation for now:
|
||||||
|
// maintain consistent order via lexacographic sorting
|
||||||
|
let mut entries = wasi_try!(wasi_try!(std::fs::read_dir(path).map_err(|_| __WASI_EIO))
|
||||||
|
.collect::<Result<Vec<std::fs::DirEntry>, _>>()
|
||||||
|
.map_err(|_| __WASI_EIO));
|
||||||
|
entries.sort_by(|a, b| a.file_name().cmp(&b.file_name()));
|
||||||
|
|
||||||
|
for entry in entries.iter().skip(cookie as usize) {
|
||||||
|
cur_cookie += 1;
|
||||||
|
let entry_path = entry.path();
|
||||||
|
let entry_path_str = entry_path.to_string_lossy();
|
||||||
|
let namlen = entry_path_str.len();
|
||||||
|
let dirent = __wasi_dirent_t {
|
||||||
|
d_next: cur_cookie,
|
||||||
|
d_ino: 0, // TODO: inode
|
||||||
|
d_namlen: namlen as u32,
|
||||||
|
d_type: {
|
||||||
|
let file_type = wasi_try!(entry.file_type().map_err(|_| __WASI_EIO));
|
||||||
|
// TODO: handle other file types
|
||||||
|
if file_type.is_dir() {
|
||||||
|
__WASI_FILETYPE_DIRECTORY
|
||||||
|
} else if file_type.is_file() {
|
||||||
|
__WASI_FILETYPE_REGULAR_FILE
|
||||||
|
} else if file_type.is_symlink() {
|
||||||
|
__WASI_FILETYPE_SYMBOLIC_LINK
|
||||||
} else {
|
} else {
|
||||||
__WASI_EFAULT
|
__WASI_FILETYPE_UNKNOWN
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let dirent_bytes = dirent_to_le_bytes(&dirent);
|
||||||
|
let upper_limit = std::cmp::min(
|
||||||
|
buf_len as usize - buf_idx,
|
||||||
|
std::mem::size_of::<__wasi_dirent_t>(),
|
||||||
|
);
|
||||||
|
for i in 0..upper_limit {
|
||||||
|
buf_arr_cell[i + buf_idx].set(dirent_bytes[i]);
|
||||||
|
}
|
||||||
|
buf_idx += upper_limit;
|
||||||
|
if upper_limit != std::mem::size_of::<__wasi_dirent_t>() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let upper_limit = std::cmp::min(buf_len as usize - buf_idx, namlen);
|
||||||
|
for (i, b) in entry_path_str.bytes().take(upper_limit).enumerate() {
|
||||||
|
buf_arr_cell[i + buf_idx].set(b);
|
||||||
|
}
|
||||||
|
buf_idx += upper_limit;
|
||||||
|
if upper_limit != namlen {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return __WASI_ENOTDIR;
|
||||||
|
}
|
||||||
|
bufused_cell.set(buf_idx as u32);
|
||||||
|
__WASI_ESUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### `fd_renumber()`
|
/// ### `fd_renumber()`
|
||||||
@ -788,15 +848,14 @@ pub fn fd_renumber(ctx: &mut Ctx, from: __wasi_fd_t, to: __wasi_fd_t) -> __wasi_
|
|||||||
debug!("wasi::fd_renumber: from={}, to={}", from, to);
|
debug!("wasi::fd_renumber: from={}, to={}", from, to);
|
||||||
let state = get_wasi_state(ctx);
|
let state = get_wasi_state(ctx);
|
||||||
let fd_entry = wasi_try!(state.fs.fd_map.get(&from).ok_or(__WASI_EBADF));
|
let fd_entry = wasi_try!(state.fs.fd_map.get(&from).ok_or(__WASI_EBADF));
|
||||||
|
let new_fd_entry = Fd {
|
||||||
state.fs.fd_map.insert(
|
|
||||||
to,
|
|
||||||
Fd {
|
|
||||||
// TODO: verify this is correct
|
// TODO: verify this is correct
|
||||||
rights: fd_entry.rights_inheriting,
|
rights: fd_entry.rights_inheriting,
|
||||||
..*fd_entry
|
..*fd_entry
|
||||||
},
|
};
|
||||||
);
|
|
||||||
|
state.fs.fd_map.insert(to, new_fd_entry);
|
||||||
|
state.fs.fd_map.remove(&from);
|
||||||
__WASI_ESUCCESS
|
__WASI_ESUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1025,7 +1084,7 @@ pub fn path_create_directory(
|
|||||||
wasi_try!(std::fs::create_dir(&path).map_err(|_| __WASI_EIO));
|
wasi_try!(std::fs::create_dir(&path).map_err(|_| __WASI_EIO));
|
||||||
|
|
||||||
let kind = Kind::Dir {
|
let kind = Kind::Dir {
|
||||||
//parent: Some(working_dir.inode),
|
parent: Some(working_dir.inode),
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
entries: Default::default(),
|
entries: Default::default(),
|
||||||
};
|
};
|
||||||
@ -1118,6 +1177,7 @@ pub fn path_filestat_get(
|
|||||||
return __WASI_ENOTDIR;
|
return __WASI_ENOTDIR;
|
||||||
}
|
}
|
||||||
let kind = Kind::Dir {
|
let kind = Kind::Dir {
|
||||||
|
parent: Some(inode),
|
||||||
path: std::path::PathBuf::from(&segment),
|
path: std::path::PathBuf::from(&segment),
|
||||||
entries: Default::default(),
|
entries: Default::default(),
|
||||||
};
|
};
|
||||||
@ -1177,6 +1237,7 @@ pub fn path_filestat_get(
|
|||||||
is_preopened: false, // is this correct?
|
is_preopened: false, // is this correct?
|
||||||
name: last_segment.clone(),
|
name: last_segment.clone(),
|
||||||
kind: Kind::Dir {
|
kind: Kind::Dir {
|
||||||
|
parent: Some(inode),
|
||||||
path: std::path::PathBuf::from(&last_segment),
|
path: std::path::PathBuf::from(&last_segment),
|
||||||
entries: Default::default(),
|
entries: Default::default(),
|
||||||
},
|
},
|
||||||
@ -1361,7 +1422,10 @@ pub fn path_open(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut cur_dir_inode = working_dir.inode;
|
let mut cur_dir_inode = working_dir.inode;
|
||||||
let mut cumulative_path = std::path::PathBuf::from(".");
|
let mut cumulative_path = std::path::PathBuf::from(wasi_try!(state
|
||||||
|
.fs
|
||||||
|
.get_base_path_for_directory(working_dir.inode)
|
||||||
|
.ok_or(__WASI_EIO)));
|
||||||
|
|
||||||
// traverse path
|
// traverse path
|
||||||
if path_vec.len() > 1 {
|
if path_vec.len() > 1 {
|
||||||
@ -1391,11 +1455,13 @@ pub fn path_open(
|
|||||||
};
|
};
|
||||||
// TODO: handle __WASI_O_TRUNC on directories
|
// TODO: handle __WASI_O_TRUNC on directories
|
||||||
|
|
||||||
|
dbg!(&cumulative_path);
|
||||||
// TODO: refactor and reuse
|
// TODO: refactor and reuse
|
||||||
let cur_file_metadata =
|
let cur_file_metadata =
|
||||||
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EINVAL));
|
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EINVAL));
|
||||||
let kind = if cur_file_metadata.is_dir() {
|
let kind = if cur_file_metadata.is_dir() {
|
||||||
Kind::Dir {
|
Kind::Dir {
|
||||||
|
parent: Some(cur_dir_inode),
|
||||||
path: cumulative_path.clone(),
|
path: cumulative_path.clone(),
|
||||||
entries: Default::default(),
|
entries: Default::default(),
|
||||||
}
|
}
|
||||||
@ -1457,41 +1523,57 @@ pub fn path_open(
|
|||||||
.fs
|
.fs
|
||||||
.create_fd(fs_rights_base, fs_rights_inheriting, fs_flags, child))
|
.create_fd(fs_rights_base, fs_rights_inheriting, fs_flags, child))
|
||||||
} else {
|
} else {
|
||||||
|
let file_metadata = wasi_try!(file_path.metadata().map_err(|_| __WASI_ENOENT));
|
||||||
// if entry does not exist in parent directory, try to lazily
|
// if entry does not exist in parent directory, try to lazily
|
||||||
// load it; possibly creating or truncating it if flags set
|
// load it; possibly creating or truncating it if flags set
|
||||||
|
let kind = if file_metadata.is_dir() {
|
||||||
|
// special dir logic
|
||||||
|
Kind::Dir {
|
||||||
|
parent: Some(cur_dir_inode),
|
||||||
|
path: file_path.clone(),
|
||||||
|
entries: Default::default(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// file is not a dir
|
||||||
let real_opened_file = {
|
let real_opened_file = {
|
||||||
let mut open_options = std::fs::OpenOptions::new();
|
let mut open_options = std::fs::OpenOptions::new();
|
||||||
let open_options = open_options.read(true).write(true);
|
let open_options = open_options.read(true).write(true);
|
||||||
let open_options = if o_flags & __WASI_O_CREAT != 0 {
|
let open_options = if o_flags & __WASI_O_CREAT != 0 {
|
||||||
debug!(
|
debug!(
|
||||||
"File {} may be created when opened if it does not exist",
|
"File {:?} may be created when opened if it does not exist",
|
||||||
&path_string
|
&file_path
|
||||||
);
|
);
|
||||||
open_options.create(true)
|
open_options.create(true)
|
||||||
} else {
|
} else {
|
||||||
open_options
|
open_options
|
||||||
};
|
};
|
||||||
let open_options = if o_flags & __WASI_O_TRUNC != 0 {
|
let open_options = if o_flags & __WASI_O_TRUNC != 0 {
|
||||||
debug!("File {} will be truncated when opened", &path_string);
|
debug!("File {:?} will be truncated when opened", &file_path);
|
||||||
open_options.truncate(true)
|
open_options.truncate(true)
|
||||||
} else {
|
} else {
|
||||||
open_options
|
open_options
|
||||||
};
|
};
|
||||||
let real_open_file =
|
debug!("Opening host file {:?}", &file_path);
|
||||||
wasi_try!(open_options.open(&file_path).map_err(|_| __WASI_EIO));
|
let real_open_file = wasi_try!(open_options.open(&file_path).map_err(|e| {
|
||||||
debug!("Opening host file {}", &path_string);
|
dbg!(e);
|
||||||
|
__WASI_EIO
|
||||||
|
}));
|
||||||
|
|
||||||
real_open_file
|
real_open_file
|
||||||
};
|
};
|
||||||
|
Kind::File {
|
||||||
|
handle: WasiFile::HostFile(real_opened_file),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// record lazily loaded or newly created fd
|
// record lazily loaded or newly created fd
|
||||||
let new_inode = state.fs.inodes.insert(InodeVal {
|
let new_inode = state.fs.inodes.insert(InodeVal {
|
||||||
stat: __wasi_filestat_t::default(),
|
stat: __wasi_filestat_t::default(),
|
||||||
is_preopened: false,
|
is_preopened: false,
|
||||||
name: file_name.clone(),
|
name: file_name.clone(),
|
||||||
kind: Kind::File {
|
kind,
|
||||||
handle: WasiFile::HostFile(real_opened_file),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// reborrow to insert entry
|
// reborrow to insert entry
|
||||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[working_dir.inode].kind {
|
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[working_dir.inode].kind {
|
||||||
entries.insert(file_name.clone(), new_inode);
|
entries.insert(file_name.clone(), new_inode);
|
||||||
|
@ -43,6 +43,31 @@ pub struct __wasi_dirent_t {
|
|||||||
pub d_type: __wasi_filetype_t,
|
pub d_type: __wasi_filetype_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl ValueType for __wasi_dirent_t {}
|
||||||
|
|
||||||
|
pub fn dirent_to_le_bytes(ent: &__wasi_dirent_t) -> Vec<u8> {
|
||||||
|
use std::mem::transmute;
|
||||||
|
let mut out = Vec::with_capacity(std::mem::size_of::<__wasi_dirent_t>());
|
||||||
|
let bytes: [u8; 8] = unsafe { transmute(ent.d_next.to_le()) };
|
||||||
|
for &b in &bytes {
|
||||||
|
out.push(b);
|
||||||
|
}
|
||||||
|
let bytes: [u8; 8] = unsafe { transmute(ent.d_ino.to_le()) };
|
||||||
|
for &b in &bytes {
|
||||||
|
out.push(b);
|
||||||
|
}
|
||||||
|
let bytes: [u8; 4] = unsafe { transmute(ent.d_namlen.to_le()) };
|
||||||
|
for &b in &bytes {
|
||||||
|
out.push(b);
|
||||||
|
}
|
||||||
|
out.push(ent.d_type);
|
||||||
|
out.push(0);
|
||||||
|
out.push(0);
|
||||||
|
out.push(0);
|
||||||
|
assert_eq!(out.len(), std::mem::size_of::<__wasi_dirent_t>());
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
pub type __wasi_errno_t = u16;
|
pub type __wasi_errno_t = u16;
|
||||||
pub const __WASI_ESUCCESS: u16 = 0;
|
pub const __WASI_ESUCCESS: u16 = 0;
|
||||||
pub const __WASI_E2BIG: u16 = 1;
|
pub const __WASI_E2BIG: u16 = 1;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod exception_handling;
|
mod exception_handling;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
extern crate structopt;
|
extern crate structopt;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(unused_imports, unused_variables)]
|
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate wasmer_runtime_core;
|
extern crate wasmer_runtime_core;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user