mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 08:10:49 +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]**
|
||||
|
||||
- [#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
|
||||
- [#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 --manifest-path lib/spectests/Cargo.toml --features clif
|
||||
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 test -p wasmer-runtime-c-api -- --nocapture
|
||||
|
||||
test-singlepass:
|
||||
cargo test --manifest-path lib/spectests/Cargo.toml --features singlepass
|
||||
cargo test --manifest-path lib/runtime/Cargo.toml --features singlepass
|
||||
|
||||
test-emscripten-llvm:
|
||||
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 code;
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! 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
|
||||
//!
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![deny(unused_imports, unused_variables)]
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
#[macro_use]
|
||||
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))]
|
||||
|
||||
mod backend;
|
||||
|
@ -1,3 +1,3 @@
|
||||
#![deny(unused_imports, unused_variables)]
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
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"))]
|
||||
#[macro_use]
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Errors.
|
||||
//! Read runtime errors.
|
||||
|
||||
use libc::{c_char, c_int};
|
||||
use std::cell::RefCell;
|
||||
@ -61,20 +61,20 @@ pub unsafe extern "C" fn wasmer_last_error_message(buffer: *mut c_char, length:
|
||||
return -1;
|
||||
}
|
||||
|
||||
let last_error = match take_last_error() {
|
||||
Some(err) => err,
|
||||
let error_message = match take_last_error() {
|
||||
Some(err) => err.to_string(),
|
||||
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() >= buffer.len() {
|
||||
// buffer to small for err message
|
||||
if error_message.len() >= length {
|
||||
// buffer is too small to hold the error message
|
||||
return -1;
|
||||
}
|
||||
|
||||
let buffer = slice::from_raw_parts_mut(buffer as *mut u8, length);
|
||||
|
||||
ptr::copy_nonoverlapping(
|
||||
error_message.as_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.
|
||||
buffer[error_message.len()] = 0;
|
||||
|
||||
error_message.len() as c_int
|
||||
error_message.len() as c_int + 1
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1,4 +1,5 @@
|
||||
//! Wasm exports.
|
||||
//! Create, read, destroy export definitions (function, global, memory
|
||||
//! and table) on an instance.
|
||||
|
||||
use crate::{
|
||||
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(
|
||||
func: *const wasmer_export_func_t,
|
||||
params: *mut wasmer_value_tag,
|
||||
params_len: c_int,
|
||||
params_len: uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let named_export = &*(func as *const NamedExport);
|
||||
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(
|
||||
func: *const wasmer_export_func_t,
|
||||
returns: *mut wasmer_value_tag,
|
||||
returns_len: c_int,
|
||||
returns_len: uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
let named_export = &*(func as *const NamedExport);
|
||||
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 wasmer_runtime::Global;
|
||||
|
@ -1,4 +1,5 @@
|
||||
//! Wasm imports.
|
||||
//! Create, read, destroy import definitions (function, global, memory
|
||||
//! and table) on an instance.
|
||||
|
||||
use crate::{
|
||||
error::{update_last_error, CApiError},
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Wasm instance.
|
||||
//! Instantiate a module, call functions, and read exports.
|
||||
|
||||
use crate::{
|
||||
error::{update_last_error, CApiError},
|
||||
@ -125,9 +125,9 @@ pub unsafe extern "C" fn wasmer_instance_call(
|
||||
instance: *mut wasmer_instance_t,
|
||||
name: *const c_char,
|
||||
params: *const wasmer_value_t,
|
||||
params_len: c_int,
|
||||
params_len: uint32_t,
|
||||
results: *mut wasmer_value_t,
|
||||
results_len: c_int,
|
||||
results_len: uint32_t,
|
||||
) -> wasmer_result_t {
|
||||
if instance.is_null() {
|
||||
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_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 libc::{uint32_t, uint8_t};
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Wasm module.
|
||||
//! Compile, validate, instantiate, serialize, and destroy modules.
|
||||
|
||||
use crate::{
|
||||
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]);
|
||||
|
||||
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) => {
|
||||
*module = Box::into_raw(Box::new(deserialized_module)) as _;
|
||||
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 libc::uint32_t;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Wasm values.
|
||||
//! Create and map Rust to WebAssembly values.
|
||||
|
||||
use libc::{int32_t, int64_t};
|
||||
use wasmer_runtime::Value;
|
||||
|
@ -60,7 +60,6 @@ int main()
|
||||
assert(returns_sig[0] == WASM_I32);
|
||||
free(returns_sig);
|
||||
|
||||
|
||||
wasmer_value_t param_one;
|
||||
param_one.tag = WASM_I32;
|
||||
param_one.value.I32 = 7;
|
||||
@ -71,7 +70,7 @@ int main()
|
||||
wasmer_value_t 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("Result: %d\n", results[0].value.I32);
|
||||
assert(results[0].value.I32 == 15);
|
||||
|
@ -46,7 +46,8 @@ int main()
|
||||
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);
|
||||
int error_result = wasmer_last_error_message(error_str, error_len);
|
||||
assert(error_len == error_result);
|
||||
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]"));
|
||||
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_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
|
||||
@ -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_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
|
||||
@ -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,
|
||||
const char *name,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
uint32_t params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
uint32_t results_len);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
wasmer_result_t wasmer_export_func_params(const wasmer_export_func_t *func,
|
||||
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
|
||||
/// 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.
|
||||
wasmer_result_t wasmer_export_func_returns(const wasmer_export_func_t *func,
|
||||
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
|
||||
/// 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,
|
||||
const char *name,
|
||||
const wasmer_value_t *params,
|
||||
int params_len,
|
||||
uint32_t params_len,
|
||||
wasmer_value_t *results,
|
||||
int results_len);
|
||||
uint32_t results_len);
|
||||
|
||||
/// Gets the `data` field within the context.
|
||||
void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx);
|
||||
|
@ -17,30 +17,31 @@ use crate::{
|
||||
};
|
||||
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)]
|
||||
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) tables: BoxedMap<LocalTableIndex, Table>,
|
||||
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_tables: BoxedMap<LocalTableIndex, *mut vm::LocalTable>,
|
||||
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) 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 {
|
||||
pub(crate) fn new(module: &ModuleInner, imports: &ImportBacking, vmctx: *mut vm::Ctx) -> Self {
|
||||
let mut memories = Self::generate_memories(module);
|
||||
@ -102,6 +103,9 @@ impl LocalBacking {
|
||||
memories.into_boxed_map()
|
||||
}
|
||||
|
||||
/// Initialize each locally-defined memory in the Module.
|
||||
///
|
||||
/// This involves copying in the data initializers.
|
||||
fn finalize_memories(
|
||||
module: &ModuleInner,
|
||||
imports: &ImportBacking,
|
||||
@ -174,6 +178,9 @@ impl LocalBacking {
|
||||
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)]
|
||||
fn finalize_tables(
|
||||
module: &ModuleInner,
|
||||
|
@ -35,7 +35,6 @@ impl fmt::Debug for InternalEvent {
|
||||
InternalEvent::Breakpoint(_) => write!(f, "Breakpoint"),
|
||||
InternalEvent::SetInternal(_) => write!(f, "SetInternal"),
|
||||
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>;
|
||||
|
||||
/// 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`.
|
||||
///
|
||||
/// Comparing two `CompileError`s always evaluates to false.
|
||||
@ -114,7 +114,7 @@ impl std::fmt::Display for LinkError {
|
||||
impl std::error::Error for LinkError {}
|
||||
|
||||
/// This is the error type returned when calling
|
||||
/// a webassembly function.
|
||||
/// a WebAssembly function.
|
||||
///
|
||||
/// 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
|
||||
/// during the compilation, instantiation, or execution
|
||||
/// of a webassembly module.
|
||||
/// of a WebAssembly module.
|
||||
///
|
||||
/// Comparing two `Error`s always evaluates to false.
|
||||
#[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.
|
||||
/// The returned values are also each wrapped in a [`Value`].
|
||||
///
|
||||
@ -270,7 +270,7 @@ impl Instance {
|
||||
///
|
||||
/// # Note:
|
||||
/// This returns `CallResult<Vec<Value>>` in order to support
|
||||
/// the future multi-value returns webassembly feature.
|
||||
/// the future multi-value returns WebAssembly feature.
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```
|
||||
@ -601,7 +601,7 @@ pub struct 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.
|
||||
/// The returned values are also each wrapped in a [`Value`].
|
||||
@ -610,7 +610,7 @@ impl<'a> DynFunc<'a> {
|
||||
///
|
||||
/// # Note:
|
||||
/// This returns `CallResult<Vec<Value>>` in order to support
|
||||
/// the future multi-value returns webassembly feature.
|
||||
/// the future multi-value returns WebAssembly feature.
|
||||
///
|
||||
/// # 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(test)]
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
/// This is an internal-only api.
|
||||
///
|
||||
/// 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
|
||||
/// to reload its address on each use.
|
||||
|
@ -23,10 +23,18 @@ struct GlobalSigRegistry {
|
||||
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)]
|
||||
pub struct SigRegistry;
|
||||
|
||||
impl SigRegistry {
|
||||
/// Map a `FuncSig` to a global `SigIndex`.
|
||||
pub fn lookup_sig_index<Sig>(&self, func_sig: Sig) -> SigIndex
|
||||
where
|
||||
Sig: Into<Arc<FuncSig>>,
|
||||
@ -45,11 +53,15 @@ impl SigRegistry {
|
||||
sig_index
|
||||
}
|
||||
|
||||
/// Map a global `SigIndex` to an interned `FuncSig`.
|
||||
pub fn lookup_signature(&self, sig_index: SigIndex) -> Arc<FuncSig> {
|
||||
let global = (*GLOBAL_SIG_REGISTRY).read();
|
||||
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> {
|
||||
let mut global = (*GLOBAL_SIG_REGISTRY).write();
|
||||
let global = &mut *global;
|
||||
|
@ -247,7 +247,7 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
|
||||
type CStruct = S1<A>;
|
||||
type RetArray = [u64; 1];
|
||||
fn from_ret_array(array: Self::RetArray) -> Self {
|
||||
(WasmExternType::from_native(NativeWasmType::from_bits(
|
||||
(WasmExternType::from_native(NativeWasmType::from_binary(
|
||||
array[0],
|
||||
)),)
|
||||
}
|
||||
@ -274,7 +274,7 @@ impl<A: WasmExternType> WasmTypeList for (A,) {
|
||||
ctx: *mut Ctx,
|
||||
) -> Result<Rets, RuntimeError> {
|
||||
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 trap = WasmTrapInfo::Unknown;
|
||||
let mut user_error = None;
|
||||
@ -322,7 +322,7 @@ macro_rules! impl_traits {
|
||||
fn from_ret_array(array: Self::RetArray) -> Self {
|
||||
#[allow(non_snake_case)]
|
||||
let [ $( $x ),* ] = array;
|
||||
( $( WasmExternType::from_native(NativeWasmType::from_bits($x)) ),* )
|
||||
( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* )
|
||||
}
|
||||
fn empty_ret_array() -> Self::RetArray {
|
||||
[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> {
|
||||
#[allow(unused_parens)]
|
||||
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 trap = WasmTrapInfo::Unknown;
|
||||
let mut user_error = None;
|
||||
|
@ -76,44 +76,44 @@ where
|
||||
Self: Sized,
|
||||
{
|
||||
const TYPE: Type;
|
||||
fn from_bits(bits: u64) -> Self;
|
||||
fn to_bits(self) -> u64;
|
||||
fn from_binary(bits: u64) -> Self;
|
||||
fn to_binary(self) -> u64;
|
||||
}
|
||||
|
||||
unsafe impl NativeWasmType for i32 {
|
||||
const TYPE: Type = Type::I32;
|
||||
fn from_bits(bits: u64) -> Self {
|
||||
fn from_binary(bits: u64) -> Self {
|
||||
bits as _
|
||||
}
|
||||
fn to_bits(self) -> u64 {
|
||||
fn to_binary(self) -> u64 {
|
||||
self as _
|
||||
}
|
||||
}
|
||||
unsafe impl NativeWasmType for i64 {
|
||||
const TYPE: Type = Type::I64;
|
||||
fn from_bits(bits: u64) -> Self {
|
||||
fn from_binary(bits: u64) -> Self {
|
||||
bits as _
|
||||
}
|
||||
fn to_bits(self) -> u64 {
|
||||
fn to_binary(self) -> u64 {
|
||||
self as _
|
||||
}
|
||||
}
|
||||
unsafe impl NativeWasmType for f32 {
|
||||
const TYPE: Type = Type::F32;
|
||||
fn from_bits(bits: u64) -> Self {
|
||||
bits as _
|
||||
fn from_binary(bits: u64) -> Self {
|
||||
f32::from_bits(bits as u32)
|
||||
}
|
||||
fn to_bits(self) -> u64 {
|
||||
self as _
|
||||
fn to_binary(self) -> u64 {
|
||||
self.to_bits() as _
|
||||
}
|
||||
}
|
||||
unsafe impl NativeWasmType for f64 {
|
||||
const TYPE: Type = Type::F64;
|
||||
fn from_bits(bits: u64) -> Self {
|
||||
bits as _
|
||||
fn from_binary(bits: u64) -> Self {
|
||||
f64::from_bits(bits)
|
||||
}
|
||||
fn to_bits(self) -> u64 {
|
||||
self as _
|
||||
fn to_binary(self) -> u64 {
|
||||
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.
|
||||
///
|
||||
/// 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)]
|
||||
#[repr(C)]
|
||||
pub struct Ctx {
|
||||
@ -20,11 +29,25 @@ pub struct Ctx {
|
||||
|
||||
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,
|
||||
import_backing: *mut ImportBacking,
|
||||
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,
|
||||
|
||||
/// 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)>,
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,9 @@ impl Cache for FileSystemCache {
|
||||
let mmap = unsafe { Mmap::map(&file)? };
|
||||
|
||||
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> {
|
||||
|
@ -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
|
||||
//! in your application easy, efficient, and safe.
|
||||
@ -131,7 +131,7 @@ use wasmer_runtime_core::backend::{Compiler, CompilerConfig};
|
||||
/// # Errors:
|
||||
/// If the operation fails, the function returns `Err(error::CompileError::...)`.
|
||||
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
|
||||
@ -140,7 +140,7 @@ pub fn compile_with_config(
|
||||
wasm: &[u8],
|
||||
compiler_config: CompilerConfig,
|
||||
) -> 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
|
||||
@ -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.
|
||||
pub fn default_compiler() -> &'static dyn Compiler {
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub fn default_compiler() -> impl Compiler {
|
||||
#[cfg(feature = "llvm")]
|
||||
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")))]
|
||||
use wasmer_clif_backend::CraneliftCompiler as DefaultCompiler;
|
||||
|
||||
lazy_static! {
|
||||
static ref DEFAULT_COMPILER: DefaultCompiler = { DefaultCompiler::new() };
|
||||
}
|
||||
|
||||
&*DEFAULT_COMPILER as &dyn Compiler
|
||||
DefaultCompiler::new()
|
||||
}
|
||||
|
||||
/// The current version of this crate
|
||||
|
@ -212,10 +212,10 @@ impl RunnableModule for X64ExecutionContext {
|
||||
user_error: *mut Option<Box<dyn Any>>,
|
||||
num_params_plus_one: Option<NonNull<c_void>>,
|
||||
) -> bool {
|
||||
let rm: &Box<dyn RunnableModule> = &unsafe { &*(*ctx).module }.runnable_module;
|
||||
let execution_context = unsafe {
|
||||
::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm)
|
||||
};
|
||||
let rm: &Box<dyn RunnableModule> = &(&*(*ctx).module).runnable_module;
|
||||
let execution_context =
|
||||
::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm);
|
||||
|
||||
let args = ::std::slice::from_raw_parts(
|
||||
args,
|
||||
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)]
|
||||
|
||||
#[cfg(not(any(
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! 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
|
||||
//!
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![deny(unused_imports, unused_variables)]
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
@ -139,8 +139,10 @@ pub enum Kind {
|
||||
handle: WasiFile,
|
||||
},
|
||||
Dir {
|
||||
// TODO: wrap it like WasiFile
|
||||
/// Parent directory
|
||||
parent: Option<Inode>,
|
||||
/// The path on the host system where the directory is located
|
||||
// TODO: wrap it like WasiFile
|
||||
path: PathBuf,
|
||||
/// The entries of a directory are lazily filled.
|
||||
entries: HashMap<String, Inode>,
|
||||
@ -196,6 +198,7 @@ impl WasiFs {
|
||||
let cur_dir_metadata = cur_dir.metadata().expect("Could not find directory");
|
||||
let kind = if cur_dir_metadata.is_dir() {
|
||||
Kind::Dir {
|
||||
parent: None,
|
||||
path: cur_dir.clone(),
|
||||
entries: Default::default(),
|
||||
}
|
||||
@ -414,6 +417,32 @@ impl WasiFs {
|
||||
);
|
||||
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)]
|
||||
|
@ -767,14 +767,74 @@ pub fn fd_readdir(
|
||||
) -> __wasi_errno_t {
|
||||
debug!("wasi::fd_readdir");
|
||||
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)) =
|
||||
(buf.deref(memory, 0, buf_len), bufused.deref(memory))
|
||||
{
|
||||
unimplemented!("wasi::fd_readdir")
|
||||
let buf_arr_cell = wasi_try!(buf.deref(memory, 0, buf_len));
|
||||
let bufused_cell = wasi_try!(bufused.deref(memory));
|
||||
let working_dir = wasi_try!(state.fs.fd_map.get(&fd).ok_or(__WASI_EBADF));
|
||||
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 {
|
||||
__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 {
|
||||
__WASI_EFAULT
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
bufused_cell.set(buf_idx as u32);
|
||||
__WASI_ESUCCESS
|
||||
}
|
||||
|
||||
/// ### `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);
|
||||
let state = get_wasi_state(ctx);
|
||||
let fd_entry = wasi_try!(state.fs.fd_map.get(&from).ok_or(__WASI_EBADF));
|
||||
let new_fd_entry = Fd {
|
||||
// TODO: verify this is correct
|
||||
rights: fd_entry.rights_inheriting,
|
||||
..*fd_entry
|
||||
};
|
||||
|
||||
state.fs.fd_map.insert(
|
||||
to,
|
||||
Fd {
|
||||
// TODO: verify this is correct
|
||||
rights: fd_entry.rights_inheriting,
|
||||
..*fd_entry
|
||||
},
|
||||
);
|
||||
state.fs.fd_map.insert(to, new_fd_entry);
|
||||
state.fs.fd_map.remove(&from);
|
||||
__WASI_ESUCCESS
|
||||
}
|
||||
|
||||
@ -1025,7 +1084,7 @@ pub fn path_create_directory(
|
||||
wasi_try!(std::fs::create_dir(&path).map_err(|_| __WASI_EIO));
|
||||
|
||||
let kind = Kind::Dir {
|
||||
//parent: Some(working_dir.inode),
|
||||
parent: Some(working_dir.inode),
|
||||
path: path.clone(),
|
||||
entries: Default::default(),
|
||||
};
|
||||
@ -1118,6 +1177,7 @@ pub fn path_filestat_get(
|
||||
return __WASI_ENOTDIR;
|
||||
}
|
||||
let kind = Kind::Dir {
|
||||
parent: Some(inode),
|
||||
path: std::path::PathBuf::from(&segment),
|
||||
entries: Default::default(),
|
||||
};
|
||||
@ -1177,6 +1237,7 @@ pub fn path_filestat_get(
|
||||
is_preopened: false, // is this correct?
|
||||
name: last_segment.clone(),
|
||||
kind: Kind::Dir {
|
||||
parent: Some(inode),
|
||||
path: std::path::PathBuf::from(&last_segment),
|
||||
entries: Default::default(),
|
||||
},
|
||||
@ -1361,7 +1422,10 @@ pub fn path_open(
|
||||
}
|
||||
|
||||
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
|
||||
if path_vec.len() > 1 {
|
||||
@ -1391,11 +1455,13 @@ pub fn path_open(
|
||||
};
|
||||
// TODO: handle __WASI_O_TRUNC on directories
|
||||
|
||||
dbg!(&cumulative_path);
|
||||
// TODO: refactor and reuse
|
||||
let cur_file_metadata =
|
||||
wasi_try!(cumulative_path.metadata().map_err(|_| __WASI_EINVAL));
|
||||
let kind = if cur_file_metadata.is_dir() {
|
||||
Kind::Dir {
|
||||
parent: Some(cur_dir_inode),
|
||||
path: cumulative_path.clone(),
|
||||
entries: Default::default(),
|
||||
}
|
||||
@ -1457,41 +1523,57 @@ pub fn path_open(
|
||||
.fs
|
||||
.create_fd(fs_rights_base, fs_rights_inheriting, fs_flags, child))
|
||||
} else {
|
||||
let file_metadata = wasi_try!(file_path.metadata().map_err(|_| __WASI_ENOENT));
|
||||
// if entry does not exist in parent directory, try to lazily
|
||||
// load it; possibly creating or truncating it if flags set
|
||||
let real_opened_file = {
|
||||
let mut open_options = std::fs::OpenOptions::new();
|
||||
let open_options = open_options.read(true).write(true);
|
||||
let open_options = if o_flags & __WASI_O_CREAT != 0 {
|
||||
debug!(
|
||||
"File {} may be created when opened if it does not exist",
|
||||
&path_string
|
||||
);
|
||||
open_options.create(true)
|
||||
} else {
|
||||
open_options
|
||||
};
|
||||
let open_options = if o_flags & __WASI_O_TRUNC != 0 {
|
||||
debug!("File {} will be truncated when opened", &path_string);
|
||||
open_options.truncate(true)
|
||||
} else {
|
||||
open_options
|
||||
};
|
||||
let real_open_file =
|
||||
wasi_try!(open_options.open(&file_path).map_err(|_| __WASI_EIO));
|
||||
debug!("Opening host file {}", &path_string);
|
||||
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 mut open_options = std::fs::OpenOptions::new();
|
||||
let open_options = open_options.read(true).write(true);
|
||||
let open_options = if o_flags & __WASI_O_CREAT != 0 {
|
||||
debug!(
|
||||
"File {:?} may be created when opened if it does not exist",
|
||||
&file_path
|
||||
);
|
||||
open_options.create(true)
|
||||
} else {
|
||||
open_options
|
||||
};
|
||||
let open_options = if o_flags & __WASI_O_TRUNC != 0 {
|
||||
debug!("File {:?} will be truncated when opened", &file_path);
|
||||
open_options.truncate(true)
|
||||
} else {
|
||||
open_options
|
||||
};
|
||||
debug!("Opening host file {:?}", &file_path);
|
||||
let real_open_file = wasi_try!(open_options.open(&file_path).map_err(|e| {
|
||||
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
|
||||
let new_inode = state.fs.inodes.insert(InodeVal {
|
||||
stat: __wasi_filestat_t::default(),
|
||||
is_preopened: false,
|
||||
name: file_name.clone(),
|
||||
kind: Kind::File {
|
||||
handle: WasiFile::HostFile(real_opened_file),
|
||||
},
|
||||
kind,
|
||||
});
|
||||
|
||||
// reborrow to insert entry
|
||||
if let Kind::Dir { entries, .. } = &mut state.fs.inodes[working_dir.inode].kind {
|
||||
entries.insert(file_name.clone(), new_inode);
|
||||
|
@ -43,6 +43,31 @@ pub struct __wasi_dirent_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 const __WASI_ESUCCESS: u16 = 0;
|
||||
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)]
|
||||
mod exception_handling;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![deny(unused_imports, unused_variables)]
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
extern crate structopt;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![deny(unused_imports, unused_variables)]
|
||||
#![deny(unused_imports, unused_variables, unused_unsafe, unreachable_patterns)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate wasmer_runtime_core;
|
||||
|
Loading…
x
Reference in New Issue
Block a user