diff --git a/.travis.yml b/.travis.yml index 395c3a7399d4..ef7ab74114e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ os: - osx language: rust rust: - - 1.32.0 + - 1.34.0 - beta - nightly matrix: diff --git a/Cargo.toml b/Cargo.toml index 0f3dddf96983..90202005d1d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,12 @@ wabt = "0.7" libc = "0.2.50" errno = "0.2.4" +[target.'cfg(unix)'.dependencies] +wasmtime-wasi-c = { path = "wasmtime-wasi-c" } + +[target.'cfg(windows)'.dependencies] +winapi = "0.3" + [workspace] [features] diff --git a/README.md b/README.md index 1259d4ce70db..0ccd29568624 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ utility or as a library embedded in a larger application. [![Travis Status](https://travis-ci.org/CraneStation/wasmtime.svg?branch=master)](https://travis-ci.org/CraneStation/wasmtime) [![Appveyor Status](https://ci.appveyor.com/api/projects/status/vxvpt2plriy5s0mc?svg=true)](https://ci.appveyor.com/project/CraneStation/cranelift) [![Gitter chat](https://badges.gitter.im/CraneStation/CraneStation.svg)](https://gitter.im/CraneStation/Lobby) -![Minimum rustc 1.32](https://img.shields.io/badge/rustc-1.32+-green.svg) +![Minimum rustc 1.34](https://img.shields.io/badge/rustc-1.34+-green.svg) Wasmtime passes the WebAssembly spec testsuite, and supports a new system API proposal called [WebAssembly System Interface], or WASI. diff --git a/src/wasmtime.rs b/src/wasmtime.rs index b50c8d5c2447..3994da605989 100644 --- a/src/wasmtime.rs +++ b/src/wasmtime.rs @@ -37,11 +37,10 @@ use cranelift_codegen::settings; use cranelift_codegen::settings::Configurable; use cranelift_native; use docopt::Docopt; -use errno::errno; use file_per_thread_logger; use pretty_env_logger; use std::error::Error; -use std::ffi::{CString, OsStr}; +use std::ffi::OsStr; use std::fs::File; use std::io; use std::io::prelude::*; @@ -53,6 +52,9 @@ use wasmtime_jit::{ActionOutcome, Context}; use wasmtime_wasi::instantiate_wasi; use wasmtime_wast::instantiate_spectest; +#[cfg(unix)] +use wasmtime_wasi_c::instantiate_wasi_c; + static LOG_FILENAME_PREFIX: &str = "wasmtime.dbg."; const USAGE: &str = " @@ -63,8 +65,8 @@ including calling the start function if one is present. Additional functions given with --invoke are then called. Usage: - wasmtime [-odg] [--preload=...] [--env=...] [--dir=...] [--mapdir=...] [...] - wasmtime [-odg] [--preload=...] [--env=...] [--dir=...] [--mapdir=...] --invoke= [...] + wasmtime [-odg] [--wasi-common] [--preload=...] [--env=...] [--dir=...] [--mapdir=...] [...] + wasmtime [-odg] [--wasi-common] [--preload=...] [--env=...] [--dir=...] [--mapdir=...] --invoke= [...] wasmtime --help | --version Options: @@ -72,6 +74,7 @@ Options: -o, --optimize runs optimization passes on the translated functions -g generate debug information -d, --debug enable debug output on stderr/stdout + --wasi-common enable the wasi-common implementation of WASI --preload= load an additional wasm module before loading the main module --env= pass an environment variable (\"key=value\") to the program --dir= grant access to the given host directory @@ -93,6 +96,7 @@ struct Args { flag_env: Vec, flag_dir: Vec, flag_mapdir: Vec, + flag_wasi_common: bool, } fn read_to_end(path: PathBuf) -> Result, io::Error> { @@ -114,22 +118,42 @@ fn read_wasm(path: PathBuf) -> Result, String> { }) } -fn compute_preopen_dirs(flag_dir: &[String], flag_mapdir: &[String]) -> Vec<(String, libc::c_int)> { +fn preopen_dir>(path: P) -> io::Result { + #[cfg(windows)] + { + use std::fs::OpenOptions; + use std::os::windows::fs::OpenOptionsExt; + use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS; + + // To open a directory using CreateFile2, specify the + // FILE_FLAG_BACKUP_SEMANTICS flag as part of dwFileFlags... + // cf. https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfile2 + OpenOptions::new() + .create(false) + .write(true) + .read(true) + .attributes(FILE_FLAG_BACKUP_SEMANTICS) + .open(path) + } + #[cfg(unix)] + { + File::open(path) + } + #[cfg(not(any(windows, unix)))] + { + unimplemented!("this OS is currently not supported by Wasmtime") + } +} + +fn compute_preopen_dirs(flag_dir: &[String], flag_mapdir: &[String]) -> Vec<(String, File)> { let mut preopen_dirs = Vec::new(); for dir in flag_dir { - let fd = unsafe { - libc::open( - CString::new(dir.as_bytes()).unwrap().as_ptr(), - libc::O_RDONLY | libc::O_DIRECTORY, - ) - }; - if fd < 0 { - println!("error while pre-opening directory {}: {}", dir, errno()); + let preopen_dir = preopen_dir(dir).unwrap_or_else(|err| { + println!("error while pre-opening directory {}: {}", dir, err); exit(1); - } - - preopen_dirs.push((dir.clone(), fd)); + }); + preopen_dirs.push((dir.clone(), preopen_dir)); } for mapdir in flag_mapdir { @@ -139,18 +163,11 @@ fn compute_preopen_dirs(flag_dir: &[String], flag_mapdir: &[String]) -> Vec<(Str exit(1); } let (key, value) = (parts[0], parts[1]); - let fd = unsafe { - libc::open( - CString::new(value.as_bytes()).unwrap().as_ptr(), - libc::O_RDONLY | libc::O_DIRECTORY, - ) - }; - if fd < 0 { - println!("error while pre-opening directory {}: {}", value, errno()); + let preopen_dir = preopen_dir(value).unwrap_or_else(|err| { + println!("error while pre-opening directory {}: {}", value, err); exit(1); - } - - preopen_dirs.push((key.to_string(), fd)); + }); + preopen_dirs.push((key.to_string(), preopen_dir)); } preopen_dirs @@ -243,20 +260,22 @@ fn main() { let preopen_dirs = compute_preopen_dirs(&args.flag_dir, &args.flag_mapdir); let argv = compute_argv(&args.arg_file, &args.arg_arg); let environ = compute_environ(&args.flag_env); - context.name_instance( - "wasi_unstable".to_owned(), + + let wasi = if args.flag_wasi_common { instantiate_wasi("", global_exports, &preopen_dirs, &argv, &environ) - .expect("instantiating wasi"), - ); + } else { + #[cfg(unix)] + { + instantiate_wasi_c("", global_exports, &preopen_dirs, &argv, &environ) + } + #[cfg(not(unix))] + { + unimplemented!("wasmtime-wasi-c requires a *nix") + } + } + .expect("instantiating wasi"); - // FIXME: Also recognize "env", for compatibility with clang/llvm 8.0. And use - // "__wasi_" prefixes for compatibility with prototype reference-sysroot. - let global_exports = context.get_global_exports(); - context.name_instance( - "env".to_owned(), - instantiate_wasi("__wasi_", global_exports, &preopen_dirs, &argv, &environ) - .expect("instantiating wasi"), - ); + context.name_instance("wasi_unstable".to_owned(), wasi); // Enable/disable producing of debug info. context.set_debug_info(args.flag_g); diff --git a/wasmtime-wasi-c/Cargo.toml b/wasmtime-wasi-c/Cargo.toml new file mode 100644 index 000000000000..9952b4942c6a --- /dev/null +++ b/wasmtime-wasi-c/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "wasmtime-wasi-c" +version = "0.0.0" +authors = ["The Cranelift Project Developers"] +publish = false +description = "WASI API support for Wasmtime" +categories = ["wasm"] +repository = "https://github.com/CraneStation/wasmtime" +license = "Apache-2.0 WITH LLVM-exception" +readme = "README.md" + +[dependencies] +wasmtime-runtime = { path = "../wasmtime-runtime" } +wasmtime-environ = { path = "../wasmtime-environ" } +wasmtime-jit = { path = "../wasmtime-jit" } +cranelift-codegen = "0.30.0" +cranelift-entity = "0.30.0" +cranelift-wasm = "0.30.0" +target-lexicon = "0.3.0" +cast = { version = "0.2.2", default-features = false } +log = { version = "0.4.6", default-features = false } +libc = "0.2.50" + +[build-dependencies] +cmake = "0.1.35" +bindgen = "0.49.0" + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "CraneStation/wasmtime" } diff --git a/wasmtime-wasi-c/LICENSE b/wasmtime-wasi-c/LICENSE new file mode 100644 index 000000000000..f9d81955f4bc --- /dev/null +++ b/wasmtime-wasi-c/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/wasmtime-wasi-c/README.md b/wasmtime-wasi-c/README.md new file mode 100644 index 000000000000..56585967b457 --- /dev/null +++ b/wasmtime-wasi-c/README.md @@ -0,0 +1,8 @@ +This is the `wasmtime-wasi-c` crate, which implements the +WebAssembly System Interface (WASI) API in C. + +WASI is greatly inspired by and directly derived from [CloudABI]. +It differs in that it has aspirations to expand to a greater +scope, and to better support the needs of WebAssembly engines. + +[CloudABI]: https://cloudabi.org/ diff --git a/wasmtime-wasi-c/build.rs b/wasmtime-wasi-c/build.rs new file mode 100644 index 000000000000..ed070ea88b4a --- /dev/null +++ b/wasmtime-wasi-c/build.rs @@ -0,0 +1,36 @@ +extern crate bindgen; +extern crate cmake; + +use cmake::Config; +use std::env; +use std::path::PathBuf; + +fn main() { + let dst = Config::new("sandboxed-system-primitives").build(); + + println!("cargo:rustc-link-search=native={}", dst.display()); + println!("cargo:rustc-link-lib=static=SandboxedSystemPrimitives"); + + let bindings_builder = bindgen::Builder::default() + .header("sandboxed-system-primitives/include/wasmtime_ssp.h") + .header("sandboxed-system-primitives/src/posix.h") + .whitelist_function("wasmtime_ssp_.*") + .whitelist_function("fd_table_init") + .whitelist_function("fd_table_insert_existing") + .whitelist_function("fd_prestats_init") + .whitelist_function("fd_prestats_insert") + .whitelist_function("argv_environ_init") + .whitelist_type("__wasi_.*") + .whitelist_type("fd_table") + .whitelist_type("fd_prestats") + .whitelist_type("argv_environ_values") + .whitelist_var("__WASI_.*"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + + bindings_builder + .generate() + .expect("Unable to generate bindings") + .write_to_file(out_path.join("wasmtime_ssp.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/wasmtime-wasi-c/js-polyfill/WASI-small.png b/wasmtime-wasi-c/js-polyfill/WASI-small.png new file mode 100644 index 000000000000..ef55a0bf6df4 Binary files /dev/null and b/wasmtime-wasi-c/js-polyfill/WASI-small.png differ diff --git a/wasmtime-wasi-c/js-polyfill/build.sh b/wasmtime-wasi-c/js-polyfill/build.sh new file mode 100755 index 000000000000..f87e97377699 --- /dev/null +++ b/wasmtime-wasi-c/js-polyfill/build.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail + +EMCC=emcc + +# TODO: Remove the clang include once Emscripten supports + +"$EMCC" ../sandboxed-system-primitives/src/*.c \ + -DWASMTIME_SSP_WASI_API \ + -DWASMTIME_SSP_STATIC_CURFDS \ + -I../sandboxed-system-primitives/include \ + -Iclang \ + --shell-file shell.html \ + polyfill.c \ + -s WARN_ON_UNDEFINED_SYMBOLS=0 \ + -s EXPORTED_FUNCTIONS="['_main', '_handleFiles', '___wasi_args_get', '___wasi_args_sizes_get', '___wasi_clock_res_get', '___wasi_clock_time_get', '___wasi_environ_get', '___wasi_environ_sizes_get', '___wasi_fd_prestat_get', '___wasi_fd_prestat_dir_name', '___wasi_fd_close', '___wasi_fd_datasync', '___wasi_fd_pread', '___wasi_fd_pwrite', '___wasi_fd_read', '___wasi_fd_renumber', '___wasi_fd_seek', '___wasi_fd_tell', '___wasi_fd_fdstat_get', '___wasi_fd_fdstat_set_flags', '___wasi_fd_fdstat_set_rights', '___wasi_fd_sync', '___wasi_fd_write', '___wasi_fd_advise', '___wasi_fd_allocate', '___wasi_path_create_directory', '___wasi_path_link', '___wasi_path_open', '___wasi_fd_readdir', '___wasi_path_readlink', '___wasi_path_rename', '___wasi_fd_filestat_get', '___wasi_fd_filestat_set_times', '___wasi_fd_filestat_set_size', '___wasi_path_filestat_get', '___wasi_path_filestat_set_times', '___wasi_path_symlink', '___wasi_path_unlink_file', '___wasi_path_remove_directory', '___wasi_poll_oneoff', '___wasi_proc_exit', '___wasi_proc_raise', '___wasi_random_get', '___wasi_sched_yield', '___wasi_sock_recv', '___wasi_sock_send', '___wasi_sock_shutdown']" \ + --pre-js wasi.js \ + -o polyfill.html diff --git a/wasmtime-wasi-c/js-polyfill/clang/stdatomic.h b/wasmtime-wasi-c/js-polyfill/clang/stdatomic.h new file mode 100644 index 000000000000..b4845a74e494 --- /dev/null +++ b/wasmtime-wasi-c/js-polyfill/clang/stdatomic.h @@ -0,0 +1,190 @@ +/*===---- stdatomic.h - Standard header for atomic types and operations -----=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __CLANG_STDATOMIC_H +#define __CLANG_STDATOMIC_H + +/* If we're hosted, fall back to the system's stdatomic.h. FreeBSD, for + * example, already has a Clang-compatible stdatomic.h header. + */ +#if __STDC_HOSTED__ && __has_include_next() +# include_next +#else + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* 7.17.1 Introduction */ + +#define ATOMIC_BOOL_LOCK_FREE __CLANG_ATOMIC_BOOL_LOCK_FREE +#define ATOMIC_CHAR_LOCK_FREE __CLANG_ATOMIC_CHAR_LOCK_FREE +#define ATOMIC_CHAR16_T_LOCK_FREE __CLANG_ATOMIC_CHAR16_T_LOCK_FREE +#define ATOMIC_CHAR32_T_LOCK_FREE __CLANG_ATOMIC_CHAR32_T_LOCK_FREE +#define ATOMIC_WCHAR_T_LOCK_FREE __CLANG_ATOMIC_WCHAR_T_LOCK_FREE +#define ATOMIC_SHORT_LOCK_FREE __CLANG_ATOMIC_SHORT_LOCK_FREE +#define ATOMIC_INT_LOCK_FREE __CLANG_ATOMIC_INT_LOCK_FREE +#define ATOMIC_LONG_LOCK_FREE __CLANG_ATOMIC_LONG_LOCK_FREE +#define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE +#define ATOMIC_POINTER_LOCK_FREE __CLANG_ATOMIC_POINTER_LOCK_FREE + +/* 7.17.2 Initialization */ + +#define ATOMIC_VAR_INIT(value) (value) +#define atomic_init __c11_atomic_init + +/* 7.17.3 Order and consistency */ + +typedef enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +} memory_order; + +#define kill_dependency(y) (y) + +/* 7.17.4 Fences */ + +/* These should be provided by the libc implementation. */ +void atomic_thread_fence(memory_order); +void atomic_signal_fence(memory_order); + +#define atomic_thread_fence(order) __c11_atomic_thread_fence(order) +#define atomic_signal_fence(order) __c11_atomic_signal_fence(order) + +/* 7.17.5 Lock-free property */ + +#define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj))) + +/* 7.17.6 Atomic integer types */ + +#ifdef __cplusplus +typedef _Atomic(bool) atomic_bool; +#else +typedef _Atomic(_Bool) atomic_bool; +#endif +typedef _Atomic(char) atomic_char; +typedef _Atomic(signed char) atomic_schar; +typedef _Atomic(unsigned char) atomic_uchar; +typedef _Atomic(short) atomic_short; +typedef _Atomic(unsigned short) atomic_ushort; +typedef _Atomic(int) atomic_int; +typedef _Atomic(unsigned int) atomic_uint; +typedef _Atomic(long) atomic_long; +typedef _Atomic(unsigned long) atomic_ulong; +typedef _Atomic(long long) atomic_llong; +typedef _Atomic(unsigned long long) atomic_ullong; +typedef _Atomic(uint_least16_t) atomic_char16_t; +typedef _Atomic(uint_least32_t) atomic_char32_t; +typedef _Atomic(wchar_t) atomic_wchar_t; +typedef _Atomic(int_least8_t) atomic_int_least8_t; +typedef _Atomic(uint_least8_t) atomic_uint_least8_t; +typedef _Atomic(int_least16_t) atomic_int_least16_t; +typedef _Atomic(uint_least16_t) atomic_uint_least16_t; +typedef _Atomic(int_least32_t) atomic_int_least32_t; +typedef _Atomic(uint_least32_t) atomic_uint_least32_t; +typedef _Atomic(int_least64_t) atomic_int_least64_t; +typedef _Atomic(uint_least64_t) atomic_uint_least64_t; +typedef _Atomic(int_fast8_t) atomic_int_fast8_t; +typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t; +typedef _Atomic(int_fast16_t) atomic_int_fast16_t; +typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t; +typedef _Atomic(int_fast32_t) atomic_int_fast32_t; +typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t; +typedef _Atomic(int_fast64_t) atomic_int_fast64_t; +typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t; +typedef _Atomic(intptr_t) atomic_intptr_t; +typedef _Atomic(uintptr_t) atomic_uintptr_t; +typedef _Atomic(size_t) atomic_size_t; +typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; +typedef _Atomic(intmax_t) atomic_intmax_t; +typedef _Atomic(uintmax_t) atomic_uintmax_t; + +/* 7.17.7 Operations on atomic types */ + +#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __c11_atomic_store + +#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __c11_atomic_load + +#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __c11_atomic_exchange + +#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + +#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + +#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __c11_atomic_fetch_add + +#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + +#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __c11_atomic_fetch_or + +#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + +#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __c11_atomic_fetch_and + +/* 7.17.8 Atomic flag type and operations */ + +typedef struct atomic_flag { atomic_bool _Value; } atomic_flag; + +#define ATOMIC_FLAG_INIT { 0 } + +/* These should be provided by the libc implementation. */ +#ifdef __cplusplus +bool atomic_flag_test_and_set(volatile atomic_flag *); +bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); +#else +_Bool atomic_flag_test_and_set(volatile atomic_flag *); +_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); +#endif +void atomic_flag_clear(volatile atomic_flag *); +void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order); + +#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST) +#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order) + +#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST) +#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order) + +#ifdef __cplusplus +} +#endif + +#endif /* __STDC_HOSTED__ */ +#endif /* __CLANG_STDATOMIC_H */ + diff --git a/wasmtime-wasi-c/js-polyfill/polyfill.c b/wasmtime-wasi-c/js-polyfill/polyfill.c new file mode 100644 index 000000000000..d4c63cebf27c --- /dev/null +++ b/wasmtime-wasi-c/js-polyfill/polyfill.c @@ -0,0 +1,45 @@ +#include +#include "wasmtime_ssp.h" +#include "../src/posix.h" + +static __thread struct fd_table curfds_pointee; + +int main(int argc, char *argv[]) { + return 0; +} + +void handleFiles(void) { + struct fd_table *curfds = &curfds_pointee; + + fd_table_init(curfds); + + // Prepopulate curfds with stdin, stdout, and stderr file descriptors. + if (!fd_table_insert_existing(curfds, 0, 0)) + __builtin_trap(); + if (!fd_table_insert_existing(curfds, 1, 1)) + __builtin_trap(); + if (!fd_table_insert_existing(curfds, 2, 2)) + __builtin_trap(); + + EM_ASM(" \ + const imports = { wasi_unstable: WASIPolyfill }; \ + let file = document.getElementById('input').files[0]; \ + let file_with_mime_type = file.slice(0, file.size, 'application/wasm'); \ + let response = new Response(file_with_mime_type); \ + wasi_instantiateStreaming(response, imports) \ + .then(obj => { \ + setInstance(obj.instance); \ + try { \ + obj.instance.exports._start(); \ + } catch (e) { \ + if (e instanceof WASIExit) { \ + handleWASIExit(e); \ + } else { \ + } \ + } \ + }) \ + .catch(error => { \ + console.log('error! ' + error); \ + }); \ + "); +} diff --git a/wasmtime-wasi-c/js-polyfill/shell.html b/wasmtime-wasi-c/js-polyfill/shell.html new file mode 100644 index 000000000000..f44eda52ca03 --- /dev/null +++ b/wasmtime-wasi-c/js-polyfill/shell.html @@ -0,0 +1,88 @@ + + + + + + + WASI Web Polyfill + + + +
WASI
+
Downloading...
+
+ +
+ WASI logo + +
+ + + {{{ SCRIPT }}} + + diff --git a/wasmtime-wasi-c/js-polyfill/wasi.js b/wasmtime-wasi-c/js-polyfill/wasi.js new file mode 100644 index 000000000000..a30412f88675 --- /dev/null +++ b/wasmtime-wasi-c/js-polyfill/wasi.js @@ -0,0 +1,497 @@ +// To implement `proc_exit`, we define a custom exception object +// that we can throw to unwind the stack and carry the exit value. +function WASIExit(return_value, message, fileName, lineNumber) { + let instance = new Error(message, fileName, lineNumber); + instance.return_value = return_value; + Object.setPrototypeOf(instance, Object.getPrototypeOf(this)); + if (Error.captureStackTrace) { + Error.captureStackTrace(instance, WASIExit); + } + return instance; +} + +WASIExit.prototype = Object.create(Error.prototype, { + constructor: { + value: Error, + enumerable: false, + writable: true, + configurable: true + } +}); + +if (Object.setPrototypeOf) { + Object.setPrototypeOf(WASIExit, Error); +} else { + WASIExit.__proto__ = Error; +} + +function handleWASIExit(e) { + if (e.return_value != 0) { + console.log('program exited with non-zero exit status ' + e.return_value); + } +} + +// Safari doesn't have instantiateStreaming +function wasi_instantiateStreaming(response, imports) { + if (WebAssembly && WebAssembly.instantiateStreaming) { + return WebAssembly.instantiateStreaming(response, imports); + } + return response.arrayBuffer() + .then(function(buffer) { + return WebAssembly.instantiate(buffer, imports); + }); +} + +// The current guest wasm instance. +var currentInstance; + +// There are two heaps in play, the guest heap, which belongs to the WASI-using +// program, and the host heap, which belongs to the Emscripten-compiled polyfill +// library. The following declare support for the guest heap in a similar manner +// to Emscripten's heap. + +var GUEST_HEAP, +/** @type {ArrayBuffer} */ + GUEST_buffer, +/** @type {Int8Array} */ + GUEST_HEAP8, +/** @type {Uint8Array} */ + GUEST_HEAPU8, +/** @type {Int16Array} */ + GUEST_HEAP16, +/** @type {Uint16Array} */ + GUEST_HEAPU16, +/** @type {Int32Array} */ + GUEST_HEAP32, +/** @type {Uint32Array} */ + GUEST_HEAPU32, +/** @type {Float32Array} */ + GUEST_HEAPF32, +/** @type {Float64Array} */ + GUEST_HEAPF64; + +function setInstance(instance) { + currentInstance = instance; + updateGuestBuffer(); +} + +/// We call updateGuestBuffer any time the guest's memory may have changed, +/// such as when creating a new instance, or after calling _malloc. +function updateGuestBuffer() { + var buf = currentInstance.exports.memory.buffer; + Module['GUEST_buffer'] = GUEST_buffer = buf; + Module['GUEST_HEAP8'] = GUEST_HEAP8 = new Int8Array(GUEST_buffer); + Module['GUEST_HEAP16'] = GUEST_HEAP16 = new Int16Array(GUEST_buffer); + Module['GUEST_HEAP32'] = GUEST_HEAP32 = new Int32Array(GUEST_buffer); + Module['GUEST_HEAPU8'] = GUEST_HEAPU8 = new Uint8Array(GUEST_buffer); + Module['GUEST_HEAPU16'] = GUEST_HEAPU16 = new Uint16Array(GUEST_buffer); + Module['GUEST_HEAPU32'] = GUEST_HEAPU32 = new Uint32Array(GUEST_buffer); + Module['GUEST_HEAPF32'] = GUEST_HEAPF32 = new Float32Array(GUEST_buffer); + Module['GUEST_HEAPF64'] = GUEST_HEAPF64 = new Float64Array(GUEST_buffer); +} + +function copyin_bytes(src, len) { + let dst = _malloc(len); + updateGuestBuffer(); + + for (let i = 0; i < len; ++i) { + HEAP8[dst + i] = GUEST_HEAP8[src + i]; + } + return dst; +} + +function copyout_bytes(dst, src, len) { + updateGuestBuffer(); + + for (let i = 0; i < len; ++i) { + GUEST_HEAP8[dst + i] = HEAP8[src + i]; + } + _free(src); +} + +function copyout_i32(dst, src) { + updateGuestBuffer(); + + GUEST_HEAP32[dst>>2] = HEAP32[src>>2]; + _free(src); +} + +function copyout_i64(dst, src) { + updateGuestBuffer(); + + GUEST_HEAP32[dst>>2] = HEAP32[src>>2]; + GUEST_HEAP32[(dst + 4)>>2] = HEAP32[(src + 4)>>2]; + _free(src); +} + +function translate_ciovs(iovs, iovs_len) { + host_iovs = _malloc(8 * iovs_len); + updateGuestBuffer(); + + for (let i = 0; i < iovs_len; ++i) { + let ptr = GUEST_HEAP32[(iovs + i * 8 + 0) >> 2]; + let len = GUEST_HEAP32[(iovs + i * 8 + 4) >> 2]; + let buf = copyin_bytes(ptr, len); + HEAP32[(host_iovs + i * 8 + 0)>>2] = buf; + HEAP32[(host_iovs + i * 8 + 4)>>2] = len; + } + return host_iovs; +} + +function free_ciovs(host_iovs, iovs_len) { + for (let i = 0; i < iovs_len; ++i) { + let buf = HEAP32[(host_iovs + i * 8 + 0) >> 2]; + _free(buf); + } + _free(host_iovs); +} + +function translate_iovs(iovs, iovs_len) { + host_iovs = _malloc(8 * iovs_len); + updateGuestBuffer(); + + for (let i = 0; i < iovs_len; ++i) { + let len = GUEST_HEAP32[(iovs + i * 8 + 4) >> 2]; + let buf = _malloc(len); + updateGuestBuffer(); + HEAP32[(host_iovs + i * 8 + 0)>>2] = buf; + HEAP32[(host_iovs + i * 8 + 4)>>2] = len; + } + return host_iovs; +} + +function free_iovs(host_iovs, iovs_len, iovs) { + updateGuestBuffer(); + for (let i = 0; i < iovs_len; ++i) { + let buf = HEAP32[(host_iovs + i * 8 + 0) >> 2]; + let len = HEAP32[(host_iovs + i * 8 + 4) >> 2]; + let ptr = GUEST_HEAP32[(iovs + i * 8 + 0) >> 2]; + copyout_bytes(ptr, buf, len); + } + _free(host_iovs); +} + +var WASIPolyfill = { + +args_get: function(argv, argv_buf) { + return 0; +}, + +args_sizes_get: function(argc, argv_buf_size) { + updateGuestBuffer(); + + // TODO: Implement command-line arguments. + GUEST_HEAP32[(argc) >> 2] = 0; + GUEST_HEAP32[(argv_buf_size) >> 2] = 0; + return 0; +}, + +clock_res_get: function(clock_id, resolution) { + let host_resolution = _malloc(8); + let ret = ___wasi_clock_res_get(clock_id, host_resolution); + copyout_i64(resolution, host_resolution); + return ret; +}, + +clock_time_get: function(clock_id, precision, time) { + let host_time = _malloc(8); + let ret = ___wasi_clock_time_get(clock_id, precision, host_time); + copyout_i64(time, host_time); + return ret; +}, + +environ_get: function(environ, environ_buf) { + return 0; +}, + +environ_sizes_get: function(environ_size, environ_buf_size) { + updateGuestBuffer(); + + // TODO: Implement environment variables. + GUEST_HEAP32[(environ_size) >> 2] = 0; + GUEST_HEAP32[(environ_buf_size) >> 2] = 0; + return 0; +}, + +fd_prestat_get: function(fd, buf) { + let host_buf = _malloc(8); // sizeof __wasi_prestat_t + let ret = ___wasi_fd_prestat_get(fd, host_buf); + copyout_bytes(buf, host_buf, 8); + return ret; +}, + +fd_prestat_dir_name: function(fd, path, path_len) { + let host_buf = _malloc(path_len); + let ret = ___wasi_fd_prestat_get(fd, host_buf, path_len); + copyout_bytes(buf, host_buf, path_len); + return ret; +}, + +fd_close: function(fd) { + return ___wasi_fd_close(fd); +}, + +fd_datasync: function(fd) { + return ___wasi_fd_datasync(fd); +}, + +fd_pread: function(fd, iovs, iovs_len, offset, nread) { + let host_iovs = translate_iovs(iovs, iovs_len); + let host_nread = _malloc(4); + let ret = ___wasi_fd_pread(fd, host_iovs, iovs_len, offset, host_nread); + copyout_i32(nread, host_nread); + free_iovs(host_iovs, iovs_len, iovs); + return ret; +}, + +fd_pwrite: function(fd, iovs, iovs_len, offset, nwritten) { + let host_iovs = translate_ciovs(iovs, iovs_len); + let host_nwritten = _malloc(4); + let ret = ___wasi_fd_pwrite(fd, host_iovs, iovs_len, offset, host_nwritten); + copyout_i32(nwritten, host_nwritten); + free_ciovs(host_iovs, iovs_len); + return ret; +}, + +fd_read: function(fd, iovs, iovs_len, nread) { + let host_iovs = translate_iovs(iovs, iovs_len); + let host_nread = _malloc(4); + let ret = ___wasi_fd_read(fd, host_iovs, iovs_len, host_nread); + copyout_i32(nread, host_nread); + free_iovs(host_iovs, iovs_len, iovs); + return ret; +}, + +fd_renumber: function(from, to) { + return ___wasi_fd_renumber(from, to); +}, + +fd_seek: function(fd, offset, whence, newoffset) { + let host_newoffset = _malloc(8); + let ret = ___wasi_fd_seek(fd, offset, whence, host_newoffset); + copyout_i64(newoffset, host_newoffset); + return ret; +}, + +fd_tell: function(fd, newoffset) { + let host_newoffset = _malloc(8); + let ret = ___wasi_fd_seek(fd, host_newoffset); + copyout_i64(newoffset, host_newoffset); + return ret; +}, + +fd_fdstat_get: function(fd, buf) { + let host_buf = _malloc(24); // sizeof __wasi_fdstat_t + let ret = ___wasi_fd_fdstat_get(fd, host_buf); + copyout_bytes(buf, host_buf, 24); + return ret; +}, + +fd_fdstat_set_flags: function(fd, flags) { + return ___wasi_fd_fdstat_set_flags(fd, flags); +}, + +fd_fdstat_set_rights: function(fd, fs_rights_base, fs_rights_inheriting) { + return ___wasi_fd_fdstat_set_rights(fd, fs_rights_base, fs_rights_inheriting); +}, + +fd_sync: function(fd) { + return ___wasi_fd_sync(fd); +}, + +fd_write: function(fd, iovs, iovs_len, nwritten) { + let host_iovs = translate_ciovs(iovs, iovs_len); + let host_nwritten = _malloc(4); + let ret = ___wasi_fd_write(fd, host_iovs, iovs_len, host_nwritten); + copyout_i32(nwritten, host_nwritten); + free_ciovs(host_iovs, iovs_len); + return ret; +}, + +fd_advise: function(fd, offset, len, advice) { + return ___wasi_fd_advise(fd, offset, len, advice); +}, + +fd_allocate: function(fd, offset, len) { + return ___wasi_fd_allocate(fd, offset, len); +}, + +path_create_directory: function(fd, path, path_len) { + let host_path = copyin_bytes(path, path_len); + let ret = ___wasi_path_create_directory(fd, host_path, path_len); + _free(host_path); + return ret; +}, + +path_link: function(fd0, path0, path_len0, fd1, path1, path_len1) { + let host_path0 = copyin_bytes(path0, path_len0); + let host_path1 = copyin_bytes(path1, path_len1); + let ret = ___wasi_path_link(fd, host_path0, path_len0, fd1, host_path1, path1_len); + _free(host_path1); + _free(host_path0); + return ret; +}, + +path_open: function(dirfd, dirflags, path, path_len, oflags, fs_rights_base, fs_rights_inheriting, fs_flags, fd) { + let host_path = copyin_bytes(path, path_len); + let host_fd = _malloc(4); + let ret = ___wasi_path_open(dirfd, dirflags, host_path, path_len, oflags, fs_rights_base, fs_rights_inheriting, fs_flags, host_fd); + copyout_i32(fd, host_fd); + _free(host_path); + return ret; +}, + +fd_readdir: function(fd, buf, buf_len, cookie, buf_used) { + let host_buf = _malloc(buf_len); + let host_buf_used = _malloc(4); + let ret = ___wasi_fd_readdir(fd, buf, buf_len, cookie, host_buf_used); + copyout_i32(buf_used, host_buf_used); + copyout_bytes(buf, host_buf, buf_len); + return ret; +}, + +path_readlink: function(fd, path, path_len, buf, buf_len, buf_used) { + let host_path = copyin_bytes(path, path_len); + let host_buf = _malloc(buf_len); + let host_buf_used = _malloc(4); + let ret = ___wasi_path_readlink(fd, path, path_len, buf, buf_len, host_buf_used); + copyout_i32(buf_used, host_buf_used); + copyout_bytes(buf, host_buf, buf_len); + _free(host_path); + return ret; +}, + +path_rename: function(fd0, path0, path_len0, fd1, path1, path_len1) { + let host_path0 = copyin_bytes(path0, path_len0); + let host_path1 = copyin_bytes(path1, path_len1); + let ret = ___wasi_path_rename(fd, host_path0, path_len0, fd1, host_path1, path1_len); + _free(host_path1); + _free(host_path0); + return ret; +}, + +fd_filestat_get: function(fd, buf) { + let host_buf = _malloc(56); // sizeof __wasi_filestat_t + let ret = ___wasi_fd_filestat_get(host_buf); + copyout_bytes(buf, host_buf, 56); + return ret; +}, + +fd_filestat_set_size: function(fd, size) { + return ___wasi_fd_filestat_set_size(fd, size); +}, + +fd_filestat_set_times: function(fd, st_atim, st_mtim, fstflags) { + return ___wasi_fd_filestat_set_times(fd, st_atim, st_mtim, fstflags); +}, + +path_filestat_get: function(fd, path, path_len, buf) { + let host_path = copyin_bytes(path, path_len); + let host_buf = _malloc(56); // sizeof __wasi_filestat_t + let ret = ___wasi_path_filestat_get(fd, host_path, path_len, host_buf); + copyout_bytes(buf, host_buf, 56); + _free(host_path); + return ret; +}, + +path_filestat_set_times: function(fd, path, path_len, st_atim, st_mtim, flags) { + let host_path = copyin_bytes(path, path_len); + let ret = ___wasi_path_filestat_set_times(fd, host_path, st_atim, st_mtim, fstflags); + _free(host_path); + return ret; +}, + +path_symlink: function(path0, path_len0, fd, path1, path_len1) { + let host_path0 = copyin_bytes(path0, path0_len); + let host_path1 = copyin_bytes(path1, path1_len); + let ret = ___wasi_path_symlink(host_path0, path_len0, fd, host_path1, path_len1); + _free(host_path1); + _free(host_path0); + return ret; +}, + +path_unlink_file: function(fd, path, path_len, flags) { + let host_path = copyin_bytes(path, path_len); + let ret = ___wasi_path_unlink_file(fd, host_path, path_len, flags); + _free(host_path); + return ret; +}, + +path_remove_directory: function(fd, path, path_len, flags) { + let host_path = copyin_bytes(path, path_len); + let ret = ___wasi_path_remove_directory(fd, host_path, path_len, flags); + _free(host_path); + return ret; +}, + +poll_oneoff: function(in_, out, nsubscriptions, nevents) { + let host_in = copyin_bytes(in_, nsubscriptions * 56); // sizeof __wasi_subscription_t + let host_out = _malloc(nsubscriptions * 32); // sizeof __wasi_event_t + let host_nevents = _malloc(4); + let ret = ___wasi_poll_oneoff(host_in, host_out, host_nevents); + copyout_bytes(out, host_out, nsubscriptions * 32); + copyout_i32(nevents, host_nevents); + _free(host_in); + return ret; +}, + +proc_exit: function(rval) { + let message; + if (rval == 0) { + message = "success"; + } else { + message = "error code " + rval; + } + throw new WASIExit(rval, message); +}, + +proc_raise: function(sig) { + if (sig == 18 || // SIGSTOP + sig == 19 || // SIGTSTP + sig == 20 || // SIGTTIN + sig == 21 || // SIGTTOU + sig == 22 || // SIGURG + sig == 16 || // SIGCHLD + sig == 13) // SIGPIPE + { + return 0; + } + + let message = "raised signal " + sig; + throw new WASIExit(128 + sig, message); +}, + +random_get: function(buf, buf_len) { + let host_buf = _malloc(buf_len); + let ret = ___wasi_random_get(host_buf, buf_len); + copyout_bytes(buf, host_buf, buf_len); + return ret; +}, + +sched_yield: function() { + return ___wasi_sched_yield(); +}, + +sock_recv: function(sock, ri_data, ri_data_len, ri_flags, ro_datalen, ro_flags) { + let host_ri_data = translate_iovs(ri_data, ri_data_len); + let host_ro_datalen = _malloc(4); + let ret = ___wasi_sock_recv(sock, host_ri_data, ri_data_len, ri_flags, host_ro_data, ro_flags); + copyout_i32(ro_datalen, host_ro_datalen); + free_iovs(host_ri_data, ri_data_len, ri_data); + return ret; +}, + +sock_send: function(sock, si_data, si_data_len, si_flags, so_datalen) { + let host_si_data = translate_ciovs(si_data, si_data_len); + let host_so_datalen = _malloc(4); + let ret = ___wasi_sock_send(sock, host_si_data, si_data_len, si_flags, host_so_datalen); + copyout_i32(so_datalen, host_so_datalen); + free_ciovs(host_si_data, si_data_len); + return ret; +}, + +sock_shutdown: function(sock, how) { + return ___wasi_sock_shutdown(sock, how); +} + +}; diff --git a/wasmtime-wasi/sandboxed-system-primitives/CMakeLists.txt b/wasmtime-wasi-c/sandboxed-system-primitives/CMakeLists.txt similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/CMakeLists.txt rename to wasmtime-wasi-c/sandboxed-system-primitives/CMakeLists.txt diff --git a/wasmtime-wasi/sandboxed-system-primitives/LICENSE b/wasmtime-wasi-c/sandboxed-system-primitives/LICENSE similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/LICENSE rename to wasmtime-wasi-c/sandboxed-system-primitives/LICENSE diff --git a/wasmtime-wasi/sandboxed-system-primitives/README.md b/wasmtime-wasi-c/sandboxed-system-primitives/README.md similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/README.md rename to wasmtime-wasi-c/sandboxed-system-primitives/README.md diff --git a/wasmtime-wasi/sandboxed-system-primitives/include/LICENSE b/wasmtime-wasi-c/sandboxed-system-primitives/include/LICENSE similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/include/LICENSE rename to wasmtime-wasi-c/sandboxed-system-primitives/include/LICENSE diff --git a/wasmtime-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/wasmtime-wasi-c/sandboxed-system-primitives/include/wasmtime_ssp.h similarity index 97% rename from wasmtime-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h rename to wasmtime-wasi-c/sandboxed-system-primitives/include/wasmtime_ssp.h index ff46aa235df7..6a0d348c4fe2 100644 --- a/wasmtime-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/wasmtime-wasi-c/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -497,6 +497,23 @@ __wasi_errno_t wasmtime_ssp_environ_sizes_get( size_t *environ_buf_size ) WASMTIME_SSP_SYSCALL_NAME(environ_sizes_get) __attribute__((__warn_unused_result__)); +__wasi_errno_t wasmtime_ssp_fd_prestat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd, + __wasi_prestat_t *buf +) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_prestat_dir_name( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd, + char *path, + size_t path_len +) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_dir_name) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasmtime_ssp_fd_close( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, @@ -793,6 +810,10 @@ __wasi_errno_t wasmtime_ssp_poll_oneoff( size_t *nevents ) WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) __attribute__((__warn_unused_result__)); +_Noreturn void wasmtime_ssp_proc_exit( + __wasi_exitcode_t rval +) WASMTIME_SSP_SYSCALL_NAME(proc_exit); + __wasi_errno_t wasmtime_ssp_proc_raise( __wasi_signal_t sig ) WASMTIME_SSP_SYSCALL_NAME(proc_raise) __attribute__((__warn_unused_result__)); @@ -833,6 +854,9 @@ __wasi_errno_t wasmtime_ssp_sock_shutdown( __wasi_sdflags_t how ) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__)); +__wasi_errno_t wasmtime_ssp_sched_yield(void) + WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__)); + #ifdef __cplusplus } #endif diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/LICENSE b/wasmtime-wasi-c/sandboxed-system-primitives/src/LICENSE similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/LICENSE rename to wasmtime-wasi-c/sandboxed-system-primitives/src/LICENSE diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/README.md b/wasmtime-wasi-c/sandboxed-system-primitives/src/README.md similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/README.md rename to wasmtime-wasi-c/sandboxed-system-primitives/src/README.md diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/config.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/config.h similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/config.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/config.h diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/locking.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/locking.h similarity index 96% rename from wasmtime-wasi/sandboxed-system-primitives/src/locking.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/locking.h index 3c606235ebb3..0efb788ed5e4 100644 --- a/wasmtime-wasi/sandboxed-system-primitives/src/locking.h +++ b/wasmtime-wasi-c/sandboxed-system-primitives/src/locking.h @@ -83,21 +83,21 @@ struct LOCKABLE rwlock { pthread_rwlock_t object; }; -void rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock) { +static inline void rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock) { pthread_rwlock_init(&lock->object, NULL); } -void rwlock_rdlock(struct rwlock *lock) +static inline void rwlock_rdlock(struct rwlock *lock) LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS { pthread_rwlock_rdlock(&lock->object); } -void rwlock_wrlock(struct rwlock *lock) +static inline void rwlock_wrlock(struct rwlock *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS { pthread_rwlock_wrlock(&lock->object); } -void rwlock_unlock(struct rwlock *lock) +static inline void rwlock_unlock(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS { pthread_rwlock_unlock(&lock->object); } diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/numeric_limits.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/numeric_limits.h similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/numeric_limits.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/numeric_limits.h diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/posix.c b/wasmtime-wasi-c/sandboxed-system-primitives/src/posix.c similarity index 97% rename from wasmtime-wasi/sandboxed-system-primitives/src/posix.c rename to wasmtime-wasi-c/sandboxed-system-primitives/src/posix.c index 1aa533f3b56b..daf135fe8b57 100644 --- a/wasmtime-wasi/sandboxed-system-primitives/src/posix.c +++ b/wasmtime-wasi-c/sandboxed-system-primitives/src/posix.c @@ -46,9 +46,6 @@ #include "rights.h" #include "str.h" -// static_assert is not defined in older compilers. -#ifdef static_assert - // struct iovec must have the same layout as __wasi_iovec_t. static_assert(offsetof(struct iovec, iov_base) == offsetof(__wasi_iovec_t, buf), @@ -81,8 +78,6 @@ static_assert(sizeof(((struct iovec *)0)->iov_len) == static_assert(sizeof(struct iovec) == sizeof(__wasi_ciovec_t), "Size mismatch"); -#endif - #if defined(WASMTIME_SSP_STATIC_CURFDS) static __thread struct fd_table *curfds; static __thread struct fd_prestats *prestats; @@ -248,6 +243,10 @@ __wasi_errno_t wasmtime_ssp_clock_time_get( return 0; } +struct fd_prestat { + const char *dir; +}; + void fd_prestats_init( struct fd_prestats *pt ) { @@ -279,10 +278,8 @@ static bool fd_prestats_grow( return false; // Mark all new file descriptors as unused. - for (size_t i = pt->size; i < size; ++i) { - prestats[i].dir_name = NULL; - prestats[i].dir_name_len = 0; - } + for (size_t i = pt->size; i < size; ++i) + prestats[i].dir = NULL; pt->prestats = prestats; pt->size = size; } @@ -302,8 +299,7 @@ bool fd_prestats_insert( return false; } - pt->prestats[fd].dir_name = strdup(dir); - pt->prestats[fd].dir_name_len = strlen(dir); + pt->prestats[fd].dir = strdup(dir); rwlock_unlock(&pt->lock); return true; } @@ -318,7 +314,7 @@ static __wasi_errno_t fd_prestats_get_entry( if (fd >= pt->size) return __WASI_EBADF; struct fd_prestat *prestat = &pt->prestats[fd]; - if (prestat->dir_name == NULL) + if (prestat->dir == NULL) return __WASI_EBADF; *ret = prestat; @@ -657,6 +653,59 @@ static __wasi_errno_t fd_table_insert_fd( return fd_table_insert(ft, fo, rights_base, rights_inheriting, out); } +__wasi_errno_t wasmtime_ssp_fd_prestat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd, + __wasi_prestat_t *buf +) { + rwlock_rdlock(&prestats->lock); + struct fd_prestat *prestat; + __wasi_errno_t error = fd_prestats_get_entry(prestats, fd, &prestat); + if (error != 0) { + rwlock_unlock(&prestats->lock); + return error; + } + + *buf = (__wasi_prestat_t) { + .pr_type = __WASI_PREOPENTYPE_DIR, + }; + + buf->u.dir.pr_name_len = strlen(prestat->dir); + + rwlock_unlock(&prestats->lock); + + return 0; +} + +__wasi_errno_t wasmtime_ssp_fd_prestat_dir_name( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd, + char *path, + size_t path_len +) { + rwlock_rdlock(&prestats->lock); + struct fd_prestat *prestat; + __wasi_errno_t error = fd_prestats_get_entry(prestats, fd, &prestat); + if (error != 0) { + rwlock_unlock(&prestats->lock); + return error; + } + if (path_len != strlen(prestat->dir)) { + rwlock_unlock(&prestats->lock); + return EINVAL; + } + + memcpy(path, prestat->dir, path_len); + + rwlock_unlock(&prestats->lock); + + return 0; +} + __wasi_errno_t wasmtime_ssp_fd_close( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct fd_table *curfds, @@ -2003,13 +2052,7 @@ static void convert_timestamp( in /= 1000000000; // Clamp to the maximum in case it would overflow our system's time_t. - time_t time_max; - switch (sizeof(time_t)) { - case sizeof(int32_t): time_max = INT32_MAX; - case sizeof(int64_t): time_max = INT64_MAX; - default: assert(0 && "Unrecognized time_t type"); - } - out->tv_sec = in < time_max ? in : time_max; + out->tv_sec = in < NUMERIC_MAX(time_t) ? in : NUMERIC_MAX(time_t); } // Converts the provided timestamps and flags to a set of arguments for @@ -2486,6 +2529,12 @@ __wasi_errno_t wasmtime_ssp_poll_oneoff( return error; } +void wasmtime_ssp_proc_exit( + __wasi_exitcode_t rval +) { + _Exit(rval); +} + __wasi_errno_t wasmtime_ssp_proc_raise( __wasi_signal_t sig ) { @@ -2640,6 +2689,12 @@ __wasi_errno_t wasmtime_ssp_sock_shutdown( return 0; } +__wasi_errno_t wasmtime_ssp_sched_yield(void) { + if (sched_yield() < 0) + return convert_errno(errno); + return 0; +} + __wasi_errno_t wasmtime_ssp_args_get( #if !defined(WASMTIME_SSP_STATIC_CURFDS) struct argv_environ_values *argv_environ, @@ -2650,6 +2705,7 @@ __wasi_errno_t wasmtime_ssp_args_get( for (size_t i = 0; i < argv_environ->argc; ++i) { argv[i] = argv_buf + (argv_environ->argv[i] - argv_environ->argv_buf); } + argv[argv_environ->argc] = NULL; memcpy(argv_buf, argv_environ->argv_buf, argv_environ->argv_buf_size); return __WASI_ESUCCESS; } @@ -2676,6 +2732,7 @@ __wasi_errno_t wasmtime_ssp_environ_get( for (size_t i = 0; i < argv_environ->environ_count; ++i) { environ[i] = environ_buf + (argv_environ->environ[i] - argv_environ->environ_buf); } + environ[argv_environ->environ_count] = NULL; memcpy(environ_buf, argv_environ->environ_buf, argv_environ->environ_buf_size); return __WASI_ESUCCESS; } diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/posix.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/posix.h similarity index 95% rename from wasmtime-wasi/sandboxed-system-primitives/src/posix.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/posix.h index 6eb7011f7abc..6711c9b2e37f 100644 --- a/wasmtime-wasi/sandboxed-system-primitives/src/posix.h +++ b/wasmtime-wasi-c/sandboxed-system-primitives/src/posix.h @@ -18,13 +18,9 @@ #include "locking.h" struct fd_entry; +struct fd_prestat; struct syscalls; -struct fd_prestat { - const char *dir_name; - size_t dir_name_len; -}; - struct fd_table { struct rwlock lock; struct fd_entry *entries; diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/queue.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/queue.h similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/queue.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/queue.h diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/random.c b/wasmtime-wasi-c/sandboxed-system-primitives/src/random.c similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/random.c rename to wasmtime-wasi-c/sandboxed-system-primitives/src/random.c diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/random.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/random.h similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/random.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/random.h diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/refcount.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/refcount.h similarity index 80% rename from wasmtime-wasi/sandboxed-system-primitives/src/refcount.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/refcount.h index a259104c1080..51752bc9b1e3 100644 --- a/wasmtime-wasi/sandboxed-system-primitives/src/refcount.h +++ b/wasmtime-wasi-c/sandboxed-system-primitives/src/refcount.h @@ -13,20 +13,14 @@ #define REFCOUNT_H #include -#if !defined(__GNUC__) #include -#endif #include #include "locking.h" // Simple reference counter. struct LOCKABLE refcount { -#if defined(__GNUC__) - unsigned count; -#else atomic_uint count; -#endif }; #define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS @@ -34,30 +28,18 @@ struct LOCKABLE refcount { // Initialize the reference counter. static void refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r) { -#if defined(__GNUC__) - __atomic_store_n(&r->count, count, __ATOMIC_SEQ_CST); -#else atomic_init(&r->count, count); -#endif } // Increment the reference counter. static inline void refcount_acquire(struct refcount *r) PRODUCES(*r) { -#if defined(__GNUC__) - __atomic_fetch_add(&r->count, 1, __ATOMIC_ACQUIRE); -#else atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire); -#endif } // Decrement the reference counter, returning whether the reference // dropped to zero. static inline bool refcount_release(struct refcount *r) CONSUMES(*r) { -#if defined(__GNUC__) - int old = __atomic_fetch_sub(&r->count, 1, __ATOMIC_RELEASE); -#else int old = atomic_fetch_sub_explicit(&r->count, 1, memory_order_release); -#endif assert(old != 0 && "Reference count becoming negative"); return old == 1; } diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/rights.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/rights.h similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/rights.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/rights.h diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/signals.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/signals.h similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/signals.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/signals.h diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/str.c b/wasmtime-wasi-c/sandboxed-system-primitives/src/str.c similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/str.c rename to wasmtime-wasi-c/sandboxed-system-primitives/src/str.c diff --git a/wasmtime-wasi/sandboxed-system-primitives/src/str.h b/wasmtime-wasi-c/sandboxed-system-primitives/src/str.h similarity index 100% rename from wasmtime-wasi/sandboxed-system-primitives/src/str.h rename to wasmtime-wasi-c/sandboxed-system-primitives/src/str.h diff --git a/wasmtime-wasi-c/src/host.rs b/wasmtime-wasi-c/src/host.rs new file mode 100644 index 000000000000..918ea92f5eef --- /dev/null +++ b/wasmtime-wasi-c/src/host.rs @@ -0,0 +1,6 @@ +#![allow(non_camel_case_types, dead_code)] + +include!(concat!(env!("OUT_DIR"), "/wasmtime_ssp.rs")); + +pub type char = ::std::os::raw::c_char; +pub type void = ::std::os::raw::c_void; diff --git a/wasmtime-wasi-c/src/instantiate.rs b/wasmtime-wasi-c/src/instantiate.rs new file mode 100644 index 000000000000..991aaaa50a22 --- /dev/null +++ b/wasmtime-wasi-c/src/instantiate.rs @@ -0,0 +1,205 @@ +use crate::host::{ + argv_environ_init, argv_environ_values, fd_prestats, fd_prestats_init, fd_prestats_insert, + fd_table, fd_table_init, fd_table_insert_existing, +}; +use cranelift_codegen::ir::types; +use cranelift_codegen::{ir, isa}; +use cranelift_entity::PrimaryMap; +use cranelift_wasm::DefinedFuncIndex; +use std::cell::RefCell; +use std::collections::HashMap; +use std::ffi::CString; +use std::fs::File; +use std::mem; +use std::os::unix::io::AsRawFd; +use std::rc::Rc; +use syscalls; +use target_lexicon::HOST; +use wasmtime_environ::{translate_signature, Export, Module}; +use wasmtime_runtime::{Imports, InstanceHandle, InstantiationError, VMFunctionBody}; + +pub(crate) struct WASIState { + pub curfds: Box, + pub prestats: Box, + pub argv_environ: Box, +} + +/// Return an instance implementing the "wasi" interface. +pub fn instantiate_wasi_c( + prefix: &str, + global_exports: Rc>>>, + preopened_dirs: &[(String, File)], + argv: &[String], + environ: &[(String, String)], +) -> Result { + let pointer_type = types::Type::triple_pointer_type(&HOST); + let mut module = Module::new(); + let mut finished_functions: PrimaryMap = + PrimaryMap::new(); + let call_conv = isa::CallConv::triple_default(&HOST); + + macro_rules! signature { + ($name:ident) => {{ + let sig = module.signatures.push(translate_signature( + ir::Signature { + params: syscalls::$name::params() + .into_iter() + .map(ir::AbiParam::new) + .collect(), + returns: syscalls::$name::results() + .into_iter() + .map(ir::AbiParam::new) + .collect(), + call_conv, + }, + pointer_type, + )); + let func = module.functions.push(sig); + module.exports.insert( + prefix.to_owned() + stringify!($name), + Export::Function(func), + ); + finished_functions.push(syscalls::$name::SHIM as *const VMFunctionBody); + }}; + } + + signature!(args_get); + signature!(args_sizes_get); + signature!(clock_res_get); + signature!(clock_time_get); + signature!(environ_get); + signature!(environ_sizes_get); + signature!(fd_prestat_get); + signature!(fd_prestat_dir_name); + signature!(fd_close); + signature!(fd_datasync); + signature!(fd_pread); + signature!(fd_pwrite); + signature!(fd_read); + signature!(fd_renumber); + signature!(fd_seek); + signature!(fd_tell); + signature!(fd_fdstat_get); + signature!(fd_fdstat_set_flags); + signature!(fd_fdstat_set_rights); + signature!(fd_sync); + signature!(fd_write); + signature!(fd_advise); + signature!(fd_allocate); + signature!(path_create_directory); + signature!(path_link); + signature!(path_open); + signature!(fd_readdir); + signature!(path_readlink); + signature!(path_rename); + signature!(fd_filestat_get); + signature!(fd_filestat_set_times); + signature!(fd_filestat_set_size); + signature!(path_filestat_get); + signature!(path_filestat_set_times); + signature!(path_symlink); + signature!(path_unlink_file); + signature!(path_remove_directory); + signature!(poll_oneoff); + signature!(proc_exit); + signature!(proc_raise); + signature!(random_get); + signature!(sched_yield); + signature!(sock_recv); + signature!(sock_send); + signature!(sock_shutdown); + + let imports = Imports::none(); + let data_initializers = Vec::new(); + let signatures = PrimaryMap::new(); + let mut curfds = Box::new(unsafe { mem::zeroed::() }); + let mut prestats = Box::new(unsafe { mem::zeroed::() }); + let mut argv_environ = Box::new(unsafe { mem::zeroed::() }); + + unsafe { + let argv_environ: &mut argv_environ_values = &mut *argv_environ; + let (argv_offsets, argv_buf, environ_offsets, environ_buf) = + allocate_argv_environ(argv, environ); + argv_environ_init( + argv_environ, + argv_offsets.as_ptr(), + argv_offsets.len(), + argv_buf.as_ptr(), + argv_buf.len(), + environ_offsets.as_ptr(), + environ_offsets.len(), + environ_buf.as_ptr(), + environ_buf.len(), + ); + + let curfds: *mut fd_table = &mut *curfds; + fd_table_init(curfds); + + let prestats: *mut fd_prestats = &mut *prestats; + fd_prestats_init(prestats); + + // Prepopulate curfds with stdin, stdout, and stderr file descriptors. + assert!(fd_table_insert_existing(curfds, 0, 0)); + assert!(fd_table_insert_existing(curfds, 1, 1)); + assert!(fd_table_insert_existing(curfds, 2, 2)); + + let mut wasm_fd = 3; + for (dir, file) in preopened_dirs { + assert!(fd_table_insert_existing(curfds, wasm_fd, file.as_raw_fd())); + assert!(fd_prestats_insert( + prestats, + CString::new(dir.as_str()).unwrap().as_ptr(), + wasm_fd, + )); + wasm_fd += 1; + } + } + + let host_state = WASIState { + curfds, + prestats, + argv_environ, + }; + + InstanceHandle::new( + Rc::new(module), + global_exports, + finished_functions.into_boxed_slice(), + imports, + &data_initializers, + signatures.into_boxed_slice(), + None, + Box::new(host_state), + ) +} + +fn allocate_argv_environ( + argv: &[String], + environ: &[(String, String)], +) -> (Vec, Vec, Vec, Vec) { + let mut argv_offsets = Vec::new(); + let mut argv_buf = Vec::new(); + let mut environ_offsets = Vec::new(); + let mut environ_buf = Vec::new(); + + for arg in argv { + argv_offsets.push(argv_buf.len()); + for c in arg.bytes() { + argv_buf.push(c as libc::c_char); + } + argv_buf.push('\0' as libc::c_char); + } + for (key, value) in environ { + environ_offsets.push(environ_buf.len()); + for c in key.bytes() { + environ_buf.push(c as libc::c_char); + } + environ_buf.push('=' as libc::c_char); + for c in value.bytes() { + environ_buf.push(c as libc::c_char); + } + environ_buf.push('\0' as libc::c_char); + } + + (argv_offsets, argv_buf, environ_offsets, environ_buf) +} diff --git a/wasmtime-wasi-c/src/lib.rs b/wasmtime-wasi-c/src/lib.rs new file mode 100644 index 000000000000..712ee83b9c60 --- /dev/null +++ b/wasmtime-wasi-c/src/lib.rs @@ -0,0 +1,18 @@ +extern crate cast; +extern crate cranelift_codegen; +extern crate cranelift_entity; +extern crate cranelift_wasm; +extern crate target_lexicon; +extern crate wasmtime_environ; +extern crate wasmtime_jit; +extern crate wasmtime_runtime; +#[macro_use] +extern crate log; + +mod host; +mod instantiate; +mod syscalls; +mod translate; +mod wasm32; + +pub use instantiate::instantiate_wasi_c; diff --git a/wasmtime-wasi-c/src/syscalls.rs b/wasmtime-wasi-c/src/syscalls.rs new file mode 100644 index 000000000000..687e1a6f76a9 --- /dev/null +++ b/wasmtime-wasi-c/src/syscalls.rs @@ -0,0 +1,1557 @@ +use crate::host::{argv_environ_values, fd_prestats, fd_table}; +use crate::instantiate::WASIState; +use cranelift_codegen::ir::types::{Type, I32, I64}; +use host; +use std::{mem, ptr, slice, str}; +use translate::*; +use wasm32; +use wasmtime_runtime::VMContext; + +fn str_for_trace<'str>(ptr: *const i8, len: usize) -> Result<&'str str, str::Utf8Error> { + str::from_utf8(unsafe { slice::from_raw_parts(ptr as *const u8, len) }) +} + +fn return_encoded_errno(e: host::__wasi_errno_t) -> wasm32::__wasi_errno_t { + let errno = encode_errno(e); + trace!(" -> errno={}", wasm32::strerror(errno)); + errno +} + +unsafe fn get_curfds(vmctx: *mut VMContext) -> *mut fd_table { + (&mut *(&mut *vmctx) + .host_state() + .downcast_mut::() + .unwrap() + .curfds) as *mut fd_table +} + +unsafe fn get_prestats(vmctx: *mut VMContext) -> *mut fd_prestats { + (&mut *(&mut *vmctx) + .host_state() + .downcast_mut::() + .unwrap() + .prestats) as *mut fd_prestats +} + +unsafe fn get_argv_environ(vmctx: *mut VMContext) -> *mut argv_environ_values { + (&mut *(&mut *vmctx) + .host_state() + .downcast_mut::() + .unwrap() + .argv_environ) as *mut argv_environ_values +} + +pub trait AbiRet { + type Abi; + fn convert(self) -> Self::Abi; + fn codegen_tys() -> Vec; +} + +pub trait AbiParam { + type Abi; + fn convert(arg: Self::Abi) -> Self; + fn codegen_ty() -> Type; +} + +macro_rules! cast32 { + ($($i:ident)*) => ($( + impl AbiRet for $i { + type Abi = i32; + + fn convert(self) -> Self::Abi { + self as i32 + } + + fn codegen_tys() -> Vec { vec![I32] } + } + + impl AbiParam for $i { + type Abi = i32; + + fn convert(param: i32) -> Self { + param as $i + } + + fn codegen_ty() -> Type { I32 } + } + )*) +} + +macro_rules! cast64 { + ($($i:ident)*) => ($( + impl AbiRet for $i { + type Abi = i64; + + fn convert(self) -> Self::Abi { + self as i64 + } + + fn codegen_tys() -> Vec { vec![I64] } + } + + impl AbiParam for $i { + type Abi = i64; + + fn convert(param: i64) -> Self { + param as $i + } + + fn codegen_ty() -> Type { I64 } + } + )*) +} + +cast32!(i8 i16 i32 u8 u16 u32); +cast64!(i64 u64); + +impl AbiRet for () { + type Abi = (); + fn convert(self) {} + fn codegen_tys() -> Vec { + Vec::new() + } +} + +macro_rules! syscalls { + ($(pub unsafe extern "C" fn $name:ident($ctx:ident: *mut VMContext $(, $arg:ident: $ty:ty)*,) -> $ret:ty { + $($body:tt)* + })*) => ($( + pub mod $name { + use super::*; + + /// Returns the codegen types of all the parameters to the shim + /// generated + pub fn params() -> Vec { + vec![$(<$ty as AbiParam>::codegen_ty()),*] + } + + /// Returns the codegen types of all the results of the shim + /// generated + pub fn results() -> Vec { + <$ret as AbiRet>::codegen_tys() + } + + /// The actual function pointer to the shim for a syscall. + /// + /// NB: ideally we'd expose `shim` below, but it seems like there's + /// a compiler bug which prvents that from being cast to a `usize`. + pub static SHIM: unsafe extern "C" fn( + *mut VMContext, + $(<$ty as AbiParam>::Abi),* + ) -> <$ret as AbiRet>::Abi = shim; + + unsafe extern "C" fn shim( + $ctx: *mut VMContext, + $($arg: <$ty as AbiParam>::Abi,)* + ) -> <$ret as AbiRet>::Abi { + let r = super::$name($ctx, $(<$ty as AbiParam>::convert($arg),)*); + <$ret as AbiRet>::convert(r) + } + } + + pub unsafe extern "C" fn $name($ctx: *mut VMContext, $($arg: $ty,)*) -> $ret { + $($body)* + } + )*) +} + +syscalls! { + + pub unsafe extern "C" fn args_get( + vmctx: *mut VMContext, + argv: wasm32::uintptr_t, + argv_buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "args_get(argv={:#x?}, argv_buf={:#x?})", + argv, + argv_buf, + ); + + let vmctx = &mut *vmctx; + let argv_environ = get_argv_environ(vmctx); + let argc = match cast::u32((*argv_environ).argc) { + Ok(argc) => argc, + Err(_) => return wasm32::__WASI_ENOMEM, + }; + let argv_buf_size = match cast::u32((*argv_environ).argv_buf_size) { + Ok(argc) => argc, + Err(_) => return wasm32::__WASI_ENOMEM, + }; + + let (host_argv_buf, _argv_buf_size) = match decode_char_slice(vmctx, argv_buf, argv_buf_size) { + Ok((argv_buf, argv_buf_size)) => (argv_buf, argv_buf_size), + Err(e) => return return_encoded_errno(e), + }; + // Add 1 so that we can add an extra NULL pointer at the end. + let (argv, _argc) = match decode_charstar_slice(vmctx, argv, argc + 1) { + Ok((argv, argc)) => (argv, argc), + Err(e) => return return_encoded_errno(e), + }; + let mut host_argv = Vec::new(); + host_argv.resize((*argv_environ).argc + 1, ptr::null_mut()); + + let e = host::wasmtime_ssp_args_get(argv_environ, host_argv.as_mut_ptr(), host_argv_buf); + + encode_charstar_slice(argv, host_argv, argv_buf, host_argv_buf); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn args_sizes_get( + vmctx: *mut VMContext, + argc: wasm32::uintptr_t, + argv_buf_size: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "args_sizes_get(argc={:#x?}, argv_buf_size={:#x?})", + argc, + argv_buf_size, + ); + + let vmctx = &mut *vmctx; + let mut host_argc = 0; + if let Err(e) = decode_usize_byref(vmctx, argc) { + return return_encoded_errno(e); + } + let mut host_argv_buf_size = 0; + if let Err(e) = decode_usize_byref(vmctx, argv_buf_size) { + return return_encoded_errno(e); + } + + let vmctx = &mut *vmctx; + let argv_environ = get_argv_environ(vmctx); + + let e = host::wasmtime_ssp_args_sizes_get(argv_environ, &mut host_argc, &mut host_argv_buf_size); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *argc={:?}", host_argc); + encode_usize_byref(vmctx, argc, host_argc); + + trace!(" | *argv_buf_size={:?}", host_argv_buf_size); + encode_usize_byref(vmctx, argv_buf_size, host_argv_buf_size); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn clock_res_get( + vmctx: *mut VMContext, + clock_id: wasm32::__wasi_clockid_t, + resolution: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "clock_res_get(clock_id={:?}, resolution={:#x?})", + clock_id, + resolution, + ); + + let vmctx = &mut *vmctx; + let clock_id = decode_clockid(clock_id); + let mut host_resolution = 0; + if let Err(e) = decode_timestamp_byref(vmctx, resolution) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_clock_res_get(clock_id, &mut host_resolution); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *resolution={:?}", host_resolution); + encode_timestamp_byref(vmctx, resolution, host_resolution); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn clock_time_get( + vmctx: *mut VMContext, + clock_id: wasm32::__wasi_clockid_t, + precision: wasm32::__wasi_timestamp_t, + time: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "clock_time_get(clock_id={:?}, precision={:?}, time={:#x?})", + clock_id, + precision, + time, + ); + + let vmctx = &mut *vmctx; + let clock_id = decode_clockid(clock_id); + let precision = decode_timestamp(precision); + let mut host_time = 0; + if let Err(e) = decode_timestamp_byref(vmctx, time) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_clock_time_get(clock_id, precision, &mut host_time); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *time={:?}", host_time); + encode_timestamp_byref(vmctx, time, host_time); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn environ_get( + vmctx: *mut VMContext, + environ: wasm32::uintptr_t, + environ_buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "environ_get(environ={:#x?}, environ_buf={:#x?})", + environ, + environ_buf, + ); + + let vmctx = &mut *vmctx; + let argv_environ = get_argv_environ(vmctx); + let environ_count = match cast::u32((*argv_environ).environ_count) { + Ok(host_environ_count) => host_environ_count, + Err(_) => return wasm32::__WASI_ENOMEM, + }; + let environ_buf_size = match cast::u32((*argv_environ).environ_buf_size) { + Ok(host_environ_buf_size) => host_environ_buf_size, + Err(_) => return wasm32::__WASI_ENOMEM, + }; + + let (host_environ_buf, _environ_buf_len) = match decode_char_slice(vmctx, environ_buf, environ_buf_size) { + Ok((environ_buf, environ_buf_len)) => (environ_buf, environ_buf_len), + Err(e) => return return_encoded_errno(e), + }; + // Add 1 so that we can add an extra NULL pointer at the end. + let (environ, _environ_count) = match decode_charstar_slice(vmctx, environ, environ_count + 1) { + Ok((environ, environ_count)) => (environ, environ_count), + Err(e) => return return_encoded_errno(e), + }; + let mut host_environ = Vec::new(); + host_environ.resize((*argv_environ).environ_count + 1, ptr::null_mut()); + + let e = host::wasmtime_ssp_environ_get(argv_environ, host_environ.as_mut_ptr(), host_environ_buf); + + encode_charstar_slice(environ, host_environ, environ_buf, host_environ_buf); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn environ_sizes_get( + vmctx: *mut VMContext, + environ_count: wasm32::uintptr_t, + environ_buf_size: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "environ_sizes_get(environ_count={:#x?}, environ_buf_size={:#x?})", + environ_count, + environ_buf_size, + ); + + let vmctx = &mut *vmctx; + let mut host_environ_count = 0; + if let Err(e) = decode_usize_byref(vmctx, environ_count) { + return return_encoded_errno(e); + } + let mut host_environ_buf_size = 0; + if let Err(e) = decode_usize_byref(vmctx, environ_buf_size) { + return return_encoded_errno(e); + } + + let vmctx = &mut *vmctx; + let argv_environ = get_argv_environ(vmctx); + + let e = host::wasmtime_ssp_environ_sizes_get(argv_environ, &mut host_environ_count, &mut host_environ_buf_size); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *environ_count={:?}", host_environ_count); + encode_usize_byref(vmctx, environ_count, host_environ_count); + + trace!(" | *environ_buf_size={:?}", host_environ_buf_size); + encode_usize_byref(vmctx, environ_buf_size, host_environ_buf_size); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_prestat_get( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_prestat_get(fd={:?}, buf={:#x?})", fd, buf); + + let vmctx = &mut *vmctx; + let prestats = get_prestats(vmctx); + let fd = decode_fd(fd); + let mut host_buf = std::mem::zeroed(); + if let Err(e) = decode_prestat_byref(vmctx, buf) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_prestat_get(prestats, fd, &mut host_buf); + + encode_prestat_byref(vmctx, buf, host_buf); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_prestat_dir_name( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + path: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_prestat_dir_name(fd={:?}, path={:#x?}, path_len={})", fd, path, path_len); + + let vmctx = &mut *vmctx; + let prestats = get_prestats(vmctx); + let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { + Ok((path, path_len)) => (path, path_len), + Err(e) => return return_encoded_errno(e), + }; + + trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + + let e = host::wasmtime_ssp_fd_prestat_dir_name(prestats, fd, path, path_len); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_close( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_close(fd={:?})", fd); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let prestats = get_prestats(vmctx); + let fd = decode_fd(fd); + + let e = host::wasmtime_ssp_fd_close(curfds, prestats, fd); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_datasync( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_datasync(fd={:?})", fd); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + + let e = host::wasmtime_ssp_fd_datasync(curfds, fd); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_pread( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + iovs: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + offset: wasm32::__wasi_filesize_t, + nread: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_pread(fd={:?}, iovs={:#x?}, iovs_len={:?}, offset={}, nread={:#x?})", + fd, + iovs, + iovs_len, + offset, + nread + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let iovs = match decode_iovec_slice(vmctx, iovs, iovs_len) { + Ok(iovs) => iovs, + Err(e) => return return_encoded_errno(e), + }; + let offset = decode_filesize(offset); + let mut host_nread = 0; + if let Err(e) = decode_usize_byref(vmctx, nread) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_pread( + curfds, + fd, + iovs.as_ptr(), + iovs.len(), + offset, + &mut host_nread, + ); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *nread={:?}", host_nread); + encode_usize_byref(vmctx, nread, host_nread); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_pwrite( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + iovs: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + offset: wasm32::__wasi_filesize_t, + nwritten: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_pwrite(fd={:?}, iovs={:#x?}, iovs_len={:?}, offset={}, nwritten={:#x?})", + fd, + iovs, + iovs_len, + offset, + nwritten + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let iovs = match decode_ciovec_slice(vmctx, iovs, iovs_len) { + Ok(iovs) => iovs, + Err(e) => return return_encoded_errno(e), + }; + let offset = decode_filesize(offset); + let mut host_nwritten = 0; + if let Err(e) = decode_usize_byref(vmctx, nwritten) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_pwrite( + curfds, + fd, + iovs.as_ptr(), + iovs.len(), + offset, + &mut host_nwritten, + ); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *nwritten={:?}", host_nwritten); + encode_usize_byref(vmctx, nwritten, host_nwritten); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_read( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + iovs: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nread: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_read(fd={:?}, iovs={:#x?}, iovs_len={:?}, nread={:#x?})", + fd, + iovs, + iovs_len, + nread + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let iovs = match decode_iovec_slice(vmctx, iovs, iovs_len) { + Ok(iovs) => iovs, + Err(e) => return return_encoded_errno(e), + }; + let mut host_nread = 0; + if let Err(e) = decode_usize_byref(vmctx, nread) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_read(curfds, fd, iovs.as_ptr(), iovs.len(), &mut host_nread); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *nread={:?}", host_nread); + encode_usize_byref(vmctx, nread, host_nread); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_renumber( + vmctx: *mut VMContext, + from: wasm32::__wasi_fd_t, + to: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_renumber(from={:?}, to={:?})", from, to); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let prestats = get_prestats(vmctx); + let from = decode_fd(from); + let to = decode_fd(to); + + let e = host::wasmtime_ssp_fd_renumber(curfds, prestats, from, to); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_seek( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filedelta_t, + whence: wasm32::__wasi_whence_t, + newoffset: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_seek(fd={:?}, offset={:?}, whence={}, newoffset={:#x?})", + fd, + offset, + wasm32::whence_to_str(whence), + newoffset + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let offset = decode_filedelta(offset); + let whence = decode_whence(whence); + let mut host_newoffset = 0; + if let Err(e) = decode_filesize_byref(vmctx, newoffset) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_seek(curfds, fd, offset, whence, &mut host_newoffset); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *newoffset={:?}", host_newoffset); + encode_filesize_byref(vmctx, newoffset, host_newoffset); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_tell( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + newoffset: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let mut host_newoffset = 0; + if let Err(e) = decode_filesize_byref(vmctx, newoffset) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_tell(curfds, fd, &mut host_newoffset); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *newoffset={:?}", host_newoffset); + encode_filesize_byref(vmctx, newoffset, host_newoffset); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_fdstat_get( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_fdstat_get(fd={:?}, buf={:#x?})", fd, buf); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let mut host_buf = std::mem::zeroed(); + if let Err(e) = decode_fdstat_byref(vmctx, buf) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_fdstat_get(curfds, fd, &mut host_buf); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *buf={:?}", host_buf); + encode_fdstat_byref(vmctx, buf, host_buf); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_fdstat_set_flags( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + flags: wasm32::__wasi_fdflags_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_fdstat_set_flags(fd={:?}, flags={:#x?})", + fd, + flags + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let flags = decode_fdflags(flags); + + let e = host::wasmtime_ssp_fd_fdstat_set_flags(curfds, fd, flags); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_fdstat_set_rights( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_fdstat_set_rights(fd={:?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?})", + fd, + fs_rights_base, + fs_rights_inheriting + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let fs_rights_base = decode_rights(fs_rights_base); + let fs_rights_inheriting = decode_rights(fs_rights_inheriting); + + let e = host::wasmtime_ssp_fd_fdstat_set_rights(curfds, fd, fs_rights_base, fs_rights_inheriting); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_sync( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_sync(fd={:?})", fd); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + + let e = host::wasmtime_ssp_fd_sync(curfds, fd); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_write( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + iovs: wasm32::uintptr_t, + iovs_len: wasm32::size_t, + nwritten: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_write(fd={:?}, iovs={:#x?}, iovs_len={:?}, nwritten={:#x?})", + fd, + iovs, + iovs_len, + nwritten + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let iovs = match decode_ciovec_slice(vmctx, iovs, iovs_len) { + Ok(iovs) => iovs, + Err(e) => return return_encoded_errno(e), + }; + let mut host_nwritten = 0; + if let Err(e) = decode_usize_byref(vmctx, nwritten) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_write(curfds, fd, iovs.as_ptr(), iovs.len(), &mut host_nwritten); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *nwritten={:?}", host_nwritten); + encode_usize_byref(vmctx, nwritten, host_nwritten); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_advise( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filesize_t, + len: wasm32::__wasi_filesize_t, + advice: wasm32::__wasi_advice_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_advise(fd={:?}, offset={}, len={}, advice={:?})", + fd, + offset, + len, + advice + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let offset = decode_filesize(offset); + let len = decode_filesize(len); + let advice = decode_advice(advice); + + let e = host::wasmtime_ssp_fd_advise(curfds, fd, offset, len, advice); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_allocate( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + offset: wasm32::__wasi_filesize_t, + len: wasm32::__wasi_filesize_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let offset = decode_filesize(offset); + let len = decode_filesize(len); + + let e = host::wasmtime_ssp_fd_allocate(curfds, fd, offset, len); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_create_directory( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + path: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_create_directory(fd={:?}, path={:#x?}, path_len={})", + fd, + path, + path_len, + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { + Ok((path, path_len)) => (path, path_len), + Err(e) => return return_encoded_errno(e), + }; + + trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + + let e = host::wasmtime_ssp_path_create_directory(curfds, fd, path, path_len); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_link( + vmctx: *mut VMContext, + fd0: wasm32::__wasi_fd_t, + flags0: wasm32::__wasi_lookupflags_t, + path0: wasm32::uintptr_t, + path_len0: wasm32::size_t, + fd1: wasm32::__wasi_fd_t, + path1: wasm32::uintptr_t, + path_len1: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_link(fd0={:?}, flags0={:?}, path0={:#x?}, path_len0={}, fd1={:?}, path1={:#x?}, path_len1={})", + fd0, + flags0, + path0, + path_len0, + fd1, + path1, + path_len1 + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd0 = decode_fd(fd0); + let flags0 = decode_lookupflags(flags0); + let (path0, path_len0) = match decode_char_slice(vmctx, path0, path_len0) { + Ok((path0, path_len0)) => (path0, path_len0), + Err(e) => return return_encoded_errno(e), + }; + let fd1 = decode_fd(fd1); + let (path1, path_len1) = match decode_char_slice(vmctx, path1, path_len1) { + Ok((path1, path_len1)) => (path1, path_len1), + Err(e) => return return_encoded_errno(e), + }; + + trace!(" | (path0,path_len0)={:?}", str_for_trace(path0, path_len0)); + trace!(" | (path1,path_len1)={:?}", str_for_trace(path1, path_len1)); + + let e = + host::wasmtime_ssp_path_link(curfds, fd0, flags0, path0, path_len0, fd1, path1, path_len1); + + return_encoded_errno(e) + } + + // TODO: When multi-value happens, switch to that instead of passing + // the `fd` by reference? + pub unsafe extern "C" fn path_open( + vmctx: *mut VMContext, + dirfd: wasm32::__wasi_fd_t, + dirflags: wasm32::__wasi_lookupflags_t, + path: wasm32::uintptr_t, + path_len: wasm32::size_t, + oflags: wasm32::__wasi_oflags_t, + fs_rights_base: wasm32::__wasi_rights_t, + fs_rights_inheriting: wasm32::__wasi_rights_t, + fs_flags: wasm32::__wasi_fdflags_t, + fd: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_open(dirfd={:?}, dirflags={:?}, path={:#x?}, path_len={:?}, oflags={:#x?}, fs_rights_base={:#x?}, fs_rights_inheriting={:#x?}, fs_flags={:#x?}, fd={:#x?})", + dirfd, + dirflags, + path, + path_len, + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let dirfd = decode_fd(dirfd); + let dirflags = decode_lookupflags(dirflags); + let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { + Ok((path, path_len)) => (path, path_len), + Err(e) => return return_encoded_errno(e), + }; + let oflags = decode_oflags(oflags); + let fs_rights_base = decode_rights(fs_rights_base); + let fs_rights_inheriting = decode_rights(fs_rights_inheriting); + let fs_flags = decode_fdflags(fs_flags); + let mut host_fd = wasm32::__wasi_fd_t::max_value(); + if let Err(e) = decode_fd_byref(vmctx, fd) { + return return_encoded_errno(e); + } + + trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + + let e = host::wasmtime_ssp_path_open( + curfds, + dirfd, + dirflags, + path, + path_len, + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + &mut host_fd, + ); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *fd={:?}", host_fd); + encode_fd_byref(vmctx, fd, host_fd); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_readdir( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + buf: wasm32::uintptr_t, + buf_len: wasm32::size_t, + cookie: wasm32::__wasi_dircookie_t, + buf_used: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_readdir(fd={:?}, buf={:#x?}, buf_len={}, cookie={:#x?}, buf_used={:#x?})", + fd, + buf, + buf_len, + cookie, + buf_used, + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let (buf, buf_len) = match decode_char_slice(vmctx, buf, buf_len) { + Ok((buf, buf_len)) => (buf, buf_len), + Err(e) => return return_encoded_errno(e), + }; + let cookie = decode_dircookie(cookie); + let mut host_buf_used = 0; + if let Err(e) = decode_usize_byref(vmctx, buf_used) { + return return_encoded_errno(e); + } + + trace!(" | (buf,buf_len)={:?}", str_for_trace(buf, buf_len)); + + let e = host::wasmtime_ssp_fd_readdir( + curfds, + fd, + buf as *mut host::void, + buf_len, + cookie, + &mut host_buf_used, + ); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *buf_used={:?}", host_buf_used); + encode_usize_byref(vmctx, buf_used, host_buf_used); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_readlink( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + path: wasm32::uintptr_t, + path_len: wasm32::size_t, + buf: wasm32::uintptr_t, + buf_len: wasm32::size_t, + buf_used: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_readlink(fd={:?}, path={:#x?}, path_len={:?}, buf={:#x?}, buf_len={}, buf_used={:#x?})", + fd, + path, + path_len, + buf, + buf_len, + buf_used, + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { + Ok((path, path_len)) => (path, path_len), + Err(e) => return return_encoded_errno(e), + }; + let (buf, buf_len) = match decode_char_slice(vmctx, buf, buf_len) { + Ok((buf, buf_len)) => (buf, buf_len), + Err(e) => return return_encoded_errno(e), + }; + let mut host_buf_used = 0; + if let Err(e) = decode_usize_byref(vmctx, buf_used) { + return return_encoded_errno(e); + } + + trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + + let e = host::wasmtime_ssp_path_readlink( + curfds, + fd, + path, + path_len, + buf, + buf_len, + &mut host_buf_used, + ); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | (buf,*buf_used)={:?}", str_for_trace(buf, host_buf_used)); + trace!(" | *buf_used={:?}", host_buf_used); + encode_usize_byref(vmctx, buf_used, host_buf_used); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_rename( + vmctx: *mut VMContext, + fd0: wasm32::__wasi_fd_t, + path0: wasm32::uintptr_t, + path_len0: wasm32::size_t, + fd1: wasm32::__wasi_fd_t, + path1: wasm32::uintptr_t, + path_len1: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_rename(fd0={:?}, path0={:#x?}, path_len0={:?}, fd1={:?}, path1={:#x?}, path_len1={:?})", + fd0, + path0, + path_len0, + fd1, + path1, + path_len1, + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd0 = decode_fd(fd0); + let (path0, path_len0) = match decode_char_slice(vmctx, path0, path_len0) { + Ok((path0, path_len0)) => (path0, path_len0), + Err(e) => return return_encoded_errno(e), + }; + let fd1 = decode_fd(fd1); + let (path1, path_len1) = match decode_char_slice(vmctx, path1, path_len1) { + Ok((path1, path_len1)) => (path1, path_len1), + Err(e) => return return_encoded_errno(e), + }; + + trace!(" | (path0,path_len0)={:?}", str_for_trace(path0, path_len0)); + trace!(" | (path1,path_len1)={:?}", str_for_trace(path1, path_len1)); + + let e = host::wasmtime_ssp_path_rename(curfds, fd0, path0, path_len0, fd1, path1, path_len1); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_filestat_get( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!("fd_filestat_get(fd={:?}, buf={:#x?})", fd, buf); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let mut host_buf = std::mem::zeroed(); + if let Err(e) = decode_filestat_byref(vmctx, buf) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_fd_filestat_get(curfds, fd, &mut host_buf); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *buf={:?}", host_buf); + encode_filestat_byref(vmctx, buf, host_buf); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_filestat_set_times( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + st_atim: wasm32::__wasi_timestamp_t, + st_mtim: wasm32::__wasi_timestamp_t, + fstflags: wasm32::__wasi_fstflags_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_filestat_set_times(fd={:?}, st_atim={}, st_mtim={}, fstflags={:#x?})", + fd, + st_atim, st_mtim, + fstflags + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let st_atim = decode_timestamp(st_atim); + let st_mtim = decode_timestamp(st_mtim); + let fstflags = decode_fstflags(fstflags); + + let e = host::wasmtime_ssp_fd_filestat_set_times(curfds, fd, st_atim, st_mtim, fstflags); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn fd_filestat_set_size( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + size: wasm32::__wasi_filesize_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "fd_filestat_set_size(fd={:?}, size={})", + fd, + size + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let size = decode_filesize(size); + + let e = host::wasmtime_ssp_fd_filestat_set_size(curfds, fd, size); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_filestat_get( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + flags: wasm32::__wasi_lookupflags_t, + path: wasm32::uintptr_t, + path_len: wasm32::size_t, + buf: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_filestat_get(fd={:?}, flags={:?}, path={:#x?}, path_len={}, buf={:#x?})", + fd, + flags, + path, + path_len, + buf + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let flags = decode_lookupflags(flags); + let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { + Ok((path, path_len)) => (path, path_len), + Err(e) => return return_encoded_errno(e), + }; + let mut host_buf = std::mem::zeroed(); + if let Err(e) = decode_filestat_byref(vmctx, buf) { + return return_encoded_errno(e); + } + + trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + + let e = host::wasmtime_ssp_path_filestat_get(curfds, fd, flags, path, path_len, &mut host_buf); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *buf={:?}", host_buf); + encode_filestat_byref(vmctx, buf, host_buf); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_filestat_set_times( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + flags: wasm32::__wasi_lookupflags_t, + path: wasm32::uintptr_t, + path_len: wasm32::size_t, + st_atim: wasm32::__wasi_timestamp_t, + st_mtim: wasm32::__wasi_timestamp_t, + fstflags: wasm32::__wasi_fstflags_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_filestat_set_times(fd={:?}, flags={:?}, path={:#x?}, path_len={}, st_atim={}, st_mtim={}, fstflags={:#x?})", + fd, + flags, + path, + path_len, + st_atim, st_mtim, + fstflags + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let flags = decode_lookupflags(flags); + let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { + Ok((path, path_len)) => (path, path_len), + Err(e) => return return_encoded_errno(e), + }; + let st_atim = decode_timestamp(st_atim); + let st_mtim = decode_timestamp(st_mtim); + let fstflags = decode_fstflags(fstflags); + + trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + + let e = host::wasmtime_ssp_path_filestat_set_times(curfds, fd, flags, path, path_len, st_atim, st_mtim, fstflags); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_symlink( + vmctx: *mut VMContext, + path0: wasm32::uintptr_t, + path_len0: wasm32::size_t, + fd: wasm32::__wasi_fd_t, + path1: wasm32::uintptr_t, + path_len1: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_symlink(path0={:#x?}, path_len0={}, fd={:?}, path1={:#x?}, path_len1={})", + path0, + path_len0, + fd, + path1, + path_len1 + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let (path0, path_len0) = match decode_char_slice(vmctx, path0, path_len0) { + Ok((path0, path_len0)) => (path0, path_len0), + Err(e) => return return_encoded_errno(e), + }; + let fd = decode_fd(fd); + let (path1, path_len1) = match decode_char_slice(vmctx, path1, path_len1) { + Ok((path1, path_len1)) => (path1, path_len1), + Err(e) => return return_encoded_errno(e), + }; + + trace!(" | (path0,path_len0)={:?}", str_for_trace(path0, path_len0)); + trace!(" | (path1,path_len1)={:?}", str_for_trace(path1, path_len1)); + + let e = host::wasmtime_ssp_path_symlink(curfds, path0, path_len0, fd, path1, path_len1); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_unlink_file( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + path: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_unlink_file(fd={:?}, path={:#x?}, path_len={})", + fd, + path, + path_len + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { + Ok((path, path_len)) => (path, path_len), + Err(e) => return return_encoded_errno(e), + }; + + trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + + let e = host::wasmtime_ssp_path_unlink_file(curfds, fd, path, path_len); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn path_remove_directory( + vmctx: *mut VMContext, + fd: wasm32::__wasi_fd_t, + path: wasm32::uintptr_t, + path_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "path_remove_directory(fd={:?}, path={:#x?}, path_len={})", + fd, + path, + path_len + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let fd = decode_fd(fd); + let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { + Ok((path, path_len)) => (path, path_len), + Err(e) => return return_encoded_errno(e), + }; + + trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + + let e = host::wasmtime_ssp_path_remove_directory(curfds, fd, path, path_len); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn poll_oneoff( + vmctx: *mut VMContext, + in_: wasm32::uintptr_t, + out: wasm32::uintptr_t, + nsubscriptions: wasm32::size_t, + nevents: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "poll_oneoff(in={:#x?}, out={:#x?}, nsubscriptions={}, nevents={:#x?})", + in_, + out, + nsubscriptions, + nevents, + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let in_ = match decode_subscription_slice(vmctx, in_, nsubscriptions) { + Ok(in_) => in_, + Err(e) => return return_encoded_errno(e), + }; + let (out, out_len) = match decode_event_slice(vmctx, out, nsubscriptions) { + Ok((out, out_len)) => (out, out_len), + Err(e) => return return_encoded_errno(e), + }; + let mut host_out = Vec::new(); + host_out.resize(out_len, mem::zeroed()); + let mut host_nevents = 0; + if let Err(e) = decode_usize_byref(vmctx, nevents) { + return return_encoded_errno(e); + } + + assert!(in_.len() == host_out.len()); + + let e = host::wasmtime_ssp_poll_oneoff( + curfds, + in_.as_ptr(), + host_out.as_mut_ptr(), + in_.len(), + &mut host_nevents, + ); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *nevents={:?}", host_nevents); + encode_usize_byref(vmctx, nevents, host_nevents); + + host_out.truncate(host_nevents); + if log_enabled!(log::Level::Trace) { + for (index, _event) in host_out.iter().enumerate() { + // TODO: Format the output for tracing. + trace!(" | *out[{}]=...", index); + } + } + encode_event_slice(out, host_out); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn proc_exit(_vmctx: *mut VMContext, rval: u32,) -> () { + trace!("proc_exit(rval={:?})", rval); + + let rval = decode_exitcode(rval); + + // TODO: Rather than call __wasi_proc_exit here, we should trigger a + // stack unwind similar to a trap. + host::wasmtime_ssp_proc_exit(rval); + } + + pub unsafe extern "C" fn proc_raise( + _vmctx: *mut VMContext, + _sig: wasm32::__wasi_signal_t, + ) -> wasm32::__wasi_errno_t { + unimplemented!("__wasi_proc_raise"); + } + + pub unsafe extern "C" fn random_get( + vmctx: *mut VMContext, + buf: wasm32::uintptr_t, + buf_len: wasm32::size_t, + ) -> wasm32::__wasi_errno_t { + trace!("random_get(buf={:#x?}, buf_len={:?})", buf, buf_len); + + let vmctx = &mut *vmctx; + let (buf, buf_len) = match decode_char_slice(vmctx, buf, buf_len) { + Ok((buf, buf_len)) => (buf, buf_len), + Err(e) => return return_encoded_errno(e), + }; + + let e = host::wasmtime_ssp_random_get(buf as *mut host::void, buf_len); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn sched_yield(_vmctx: *mut VMContext,) -> wasm32::__wasi_errno_t { + let e = host::wasmtime_ssp_sched_yield(); + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn sock_recv( + vmctx: *mut VMContext, + sock: wasm32::__wasi_fd_t, + ri_data: wasm32::uintptr_t, + ri_data_len: wasm32::size_t, + ri_flags: wasm32::__wasi_riflags_t, + ro_datalen: wasm32::uintptr_t, + ro_flags: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "sock_recv(sock={:?}, ri_data={:#x?}, ri_data_len={}, ri_flags={:#x?}, ro_datalen={:#x?}, ro_flags={:#x?})", + sock, + ri_data, ri_data_len, ri_flags, + ro_datalen, ro_flags + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let sock = decode_fd(sock); + let ri_data = match decode_iovec_slice(vmctx, ri_data, ri_data_len) { + Ok(ri_data) => ri_data, + Err(e) => return return_encoded_errno(e), + }; + let ri_flags = decode_riflags(ri_flags); + let mut host_ro_datalen = 0; + if let Err(e) = decode_usize_byref(vmctx, ro_datalen) { + return return_encoded_errno(e); + } + let mut host_ro_flags = 0; + if let Err(e) = decode_roflags_byref(vmctx, ro_flags) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_sock_recv(curfds, sock, ri_data.as_ptr(), ri_data.len(), ri_flags, + &mut host_ro_datalen, &mut host_ro_flags); + + if u32::from(e) == host::__WASI_ESUCCESS { + // TODO: Format the output for tracing. + trace!(" | *ro_datalen={}", host_ro_datalen); + trace!(" | *ro_flags={}", host_ro_flags); + encode_usize_byref(vmctx, ro_datalen, host_ro_datalen); + encode_roflags_byref(vmctx, ro_flags, host_ro_flags); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn sock_send( + vmctx: *mut VMContext, + sock: wasm32::__wasi_fd_t, + si_data: wasm32::uintptr_t, + si_data_len: wasm32::size_t, + si_flags: wasm32::__wasi_siflags_t, + so_datalen: wasm32::uintptr_t, + ) -> wasm32::__wasi_errno_t { + trace!( + "sock_send(sock={:?}, si_data={:#x?}, si_data_len={}, si_flags={:#x?}, so_datalen={:#x?})", + sock, + si_data, si_data_len, si_flags, so_datalen, + ); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let sock = decode_fd(sock); + let si_data = match decode_ciovec_slice(vmctx, si_data, si_data_len) { + Ok(si_data) => si_data, + Err(e) => return return_encoded_errno(e), + }; + let si_flags = decode_siflags(si_flags); + let mut host_so_datalen = 0; + if let Err(e) = decode_usize_byref(vmctx, so_datalen) { + return return_encoded_errno(e); + } + + let e = host::wasmtime_ssp_sock_send(curfds, sock, si_data.as_ptr(), si_data.len(), si_flags, &mut host_so_datalen); + + if u32::from(e) == host::__WASI_ESUCCESS { + trace!(" | *so_datalen={:?}", host_so_datalen); + encode_usize_byref(vmctx, so_datalen, host_so_datalen); + } + + return_encoded_errno(e) + } + + pub unsafe extern "C" fn sock_shutdown( + vmctx: *mut VMContext, + sock: wasm32::__wasi_fd_t, + how: wasm32::__wasi_sdflags_t, + ) -> wasm32::__wasi_errno_t { + trace!("sock_shutdown(sock={:?}, how={:?})", sock, how); + + let vmctx = &mut *vmctx; + let curfds = get_curfds(vmctx); + let sock = decode_fd(sock); + let how = decode_sdflags(how); + + let e = host::wasmtime_ssp_sock_shutdown(curfds, sock, how); + + return_encoded_errno(e) + } +} diff --git a/wasmtime-wasi/src/translate.rs b/wasmtime-wasi-c/src/translate.rs similarity index 100% rename from wasmtime-wasi/src/translate.rs rename to wasmtime-wasi-c/src/translate.rs diff --git a/wasmtime-wasi/src/wasm32.rs b/wasmtime-wasi-c/src/wasm32.rs similarity index 100% rename from wasmtime-wasi/src/wasm32.rs rename to wasmtime-wasi-c/src/wasm32.rs diff --git a/wasmtime-wasi/Cargo.toml b/wasmtime-wasi/Cargo.toml index 7b4161cd1f70..511dc505bd0e 100644 --- a/wasmtime-wasi/Cargo.toml +++ b/wasmtime-wasi/Cargo.toml @@ -13,18 +13,12 @@ readme = "README.md" wasmtime-runtime = { path = "../wasmtime-runtime" } wasmtime-environ = { path = "../wasmtime-environ" } wasmtime-jit = { path = "../wasmtime-jit" } +wasi-common = { git = "https://github.com/CraneStation/wasi-common" } cranelift-codegen = "0.30.0" cranelift-entity = "0.30.0" cranelift-wasm = "0.30.0" target-lexicon = "0.3.0" -cast = { version = "0.2.2", default-features = false } log = { version = "0.4.6", default-features = false } -libc = "0.2.50" -errno = "0.2.4" - -[build-dependencies] -cmake = "0.1.35" -bindgen = "0.49.0" [badges] maintenance = { status = "experimental" } diff --git a/wasmtime-wasi/README.md b/wasmtime-wasi/README.md index 4ee92fc9a85c..7f2eaad27fa3 100644 --- a/wasmtime-wasi/README.md +++ b/wasmtime-wasi/README.md @@ -1,5 +1,5 @@ This is the `wasmtime-wasi` crate, which implements the -WebAssembly System Interface (WASI) API. +WebAssembly System Interface (WASI) API in Rust. WASI is greatly inspired by and directly derived from [CloudABI]. It differs in that it has aspirations to expand to a greater diff --git a/wasmtime-wasi/build.rs b/wasmtime-wasi/build.rs deleted file mode 100644 index 4145068a572d..000000000000 --- a/wasmtime-wasi/build.rs +++ /dev/null @@ -1,118 +0,0 @@ -extern crate bindgen; -extern crate cmake; - -use cmake::Config; -use std::env; -use std::path::PathBuf; - -fn main() { - let dst = Config::new("sandboxed-system-primitives") - .cflag("-std=gnu99") - .build(); - - println!("cargo:rustc-link-search=native={}", dst.display()); - println!("cargo:rustc-link-lib=static=SandboxedSystemPrimitives"); - - let bindings_builder = bindgen::Builder::default() - .header("sandboxed-system-primitives/include/wasmtime_ssp.h") - .header("sandboxed-system-primitives/src/posix.h") - .whitelist_function("wasmtime_ssp_.*") - .whitelist_function("fd_table_init") - .whitelist_function("fd_table_insert_existing") - .whitelist_function("fd_prestats_init") - .whitelist_function("fd_prestats_insert") - .whitelist_function("argv_environ_init") - .whitelist_function("rwlock_.*") - .whitelist_type("__wasi_.*") - .whitelist_type("fd_table") - .whitelist_type("fd_prestat") - .whitelist_type("fd_prestats") - .whitelist_type("argv_environ_values") - .whitelist_var("__WASI_.*") - .blacklist_item("__WASI_ESUCCESS") - .blacklist_item("__WASI_E2BIG") - .blacklist_item("__WASI_EACCES") - .blacklist_item("__WASI_EADDRINUSE") - .blacklist_item("__WASI_EADDRNOTAVAIL") - .blacklist_item("__WASI_EAFNOSUPPORT") - .blacklist_item("__WASI_EAGAIN") - .blacklist_item("__WASI_EALREADY") - .blacklist_item("__WASI_EBADF") - .blacklist_item("__WASI_EBADMSG") - .blacklist_item("__WASI_EBUSY") - .blacklist_item("__WASI_ECANCELED") - .blacklist_item("__WASI_ECHILD") - .blacklist_item("__WASI_ECONNABORTED") - .blacklist_item("__WASI_ECONNREFUSED") - .blacklist_item("__WASI_ECONNRESET") - .blacklist_item("__WASI_EDEADLK") - .blacklist_item("__WASI_EDESTADDRREQ") - .blacklist_item("__WASI_EDOM") - .blacklist_item("__WASI_EDQUOT") - .blacklist_item("__WASI_EEXIST") - .blacklist_item("__WASI_EFAULT") - .blacklist_item("__WASI_EFBIG") - .blacklist_item("__WASI_EHOSTUNREACH") - .blacklist_item("__WASI_EIDRM") - .blacklist_item("__WASI_EILSEQ") - .blacklist_item("__WASI_EINPROGRESS") - .blacklist_item("__WASI_EINTR") - .blacklist_item("__WASI_EINVAL") - .blacklist_item("__WASI_EIO") - .blacklist_item("__WASI_EISCONN") - .blacklist_item("__WASI_EISDIR") - .blacklist_item("__WASI_ELOOP") - .blacklist_item("__WASI_EMFILE") - .blacklist_item("__WASI_EMLINK") - .blacklist_item("__WASI_EMSGSIZE") - .blacklist_item("__WASI_EMULTIHOP") - .blacklist_item("__WASI_ENAMETOOLONG") - .blacklist_item("__WASI_ENETDOWN") - .blacklist_item("__WASI_ENETRESET") - .blacklist_item("__WASI_ENETUNREACH") - .blacklist_item("__WASI_ENFILE") - .blacklist_item("__WASI_ENOBUFS") - .blacklist_item("__WASI_ENODEV") - .blacklist_item("__WASI_ENOENT") - .blacklist_item("__WASI_ENOEXEC") - .blacklist_item("__WASI_ENOLCK") - .blacklist_item("__WASI_ENOLINK") - .blacklist_item("__WASI_ENOMEM") - .blacklist_item("__WASI_ENOMSG") - .blacklist_item("__WASI_ENOPROTOOPT") - .blacklist_item("__WASI_ENOSPC") - .blacklist_item("__WASI_ENOSYS") - .blacklist_item("__WASI_ENOTCONN") - .blacklist_item("__WASI_ENOTDIR") - .blacklist_item("__WASI_ENOTEMPTY") - .blacklist_item("__WASI_ENOTRECOVERABLE") - .blacklist_item("__WASI_ENOTSOCK") - .blacklist_item("__WASI_ENOTSUP") - .blacklist_item("__WASI_ENOTTY") - .blacklist_item("__WASI_ENXIO") - .blacklist_item("__WASI_EOVERFLOW") - .blacklist_item("__WASI_EOWNERDEAD") - .blacklist_item("__WASI_EPERM") - .blacklist_item("__WASI_EPIPE") - .blacklist_item("__WASI_EPROTO") - .blacklist_item("__WASI_EPROTONOSUPPORT") - .blacklist_item("__WASI_EPROTOTYPE") - .blacklist_item("__WASI_ERANGE") - .blacklist_item("__WASI_EROFS") - .blacklist_item("__WASI_ESPIPE") - .blacklist_item("__WASI_ESRCH") - .blacklist_item("__WASI_ESTALE") - .blacklist_item("__WASI_ETIMEDOUT") - .blacklist_item("__WASI_ETXTBSY") - .blacklist_item("__WASI_EXDEV") - .blacklist_item("__WASI_ENOTCAPABLE") - .blacklist_item("__WASI_PREOPENTYPE_DIR"); - - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - - bindings_builder - .generate() - .expect("Unable to generate bindings") - .write_to_file(out_path.join("wasmtime_ssp.rs")) - .expect("Couldn't write bindings!"); -} diff --git a/wasmtime-wasi/src/host.rs b/wasmtime-wasi/src/host.rs deleted file mode 100644 index afd01bc1637d..000000000000 --- a/wasmtime-wasi/src/host.rs +++ /dev/null @@ -1,88 +0,0 @@ -#![allow(non_camel_case_types, dead_code)] - -include!(concat!(env!("OUT_DIR"), "/wasmtime_ssp.rs")); - -pub type char = ::std::os::raw::c_char; -pub type void = ::std::os::raw::c_void; -// pub type __wasi_errno_t = u16; - -pub const __WASI_ESUCCESS: __wasi_errno_t = 0; -pub const __WASI_E2BIG: __wasi_errno_t = 1; -pub const __WASI_EACCES: __wasi_errno_t = 2; -pub const __WASI_EADDRINUSE: __wasi_errno_t = 3; -pub const __WASI_EADDRNOTAVAIL: __wasi_errno_t = 4; -pub const __WASI_EAFNOSUPPORT: __wasi_errno_t = 5; -pub const __WASI_EAGAIN: __wasi_errno_t = 6; -pub const __WASI_EALREADY: __wasi_errno_t = 7; -pub const __WASI_EBADF: __wasi_errno_t = 8; -pub const __WASI_EBADMSG: __wasi_errno_t = 9; -pub const __WASI_EBUSY: __wasi_errno_t = 10; -pub const __WASI_ECANCELED: __wasi_errno_t = 11; -pub const __WASI_ECHILD: __wasi_errno_t = 12; -pub const __WASI_ECONNABORTED: __wasi_errno_t = 13; -pub const __WASI_ECONNREFUSED: __wasi_errno_t = 14; -pub const __WASI_ECONNRESET: __wasi_errno_t = 15; -pub const __WASI_EDEADLK: __wasi_errno_t = 16; -pub const __WASI_EDESTADDRREQ: __wasi_errno_t = 17; -pub const __WASI_EDOM: __wasi_errno_t = 18; -pub const __WASI_EDQUOT: __wasi_errno_t = 19; -pub const __WASI_EEXIST: __wasi_errno_t = 20; -pub const __WASI_EFAULT: __wasi_errno_t = 21; -pub const __WASI_EFBIG: __wasi_errno_t = 22; -pub const __WASI_EHOSTUNREACH: __wasi_errno_t = 23; -pub const __WASI_EIDRM: __wasi_errno_t = 24; -pub const __WASI_EILSEQ: __wasi_errno_t = 25; -pub const __WASI_EINPROGRESS: __wasi_errno_t = 26; -pub const __WASI_EINTR: __wasi_errno_t = 27; -pub const __WASI_EINVAL: __wasi_errno_t = 28; -pub const __WASI_EIO: __wasi_errno_t = 29; -pub const __WASI_EISCONN: __wasi_errno_t = 30; -pub const __WASI_EISDIR: __wasi_errno_t = 31; -pub const __WASI_ELOOP: __wasi_errno_t = 32; -pub const __WASI_EMFILE: __wasi_errno_t = 33; -pub const __WASI_EMLINK: __wasi_errno_t = 34; -pub const __WASI_EMSGSIZE: __wasi_errno_t = 35; -pub const __WASI_EMULTIHOP: __wasi_errno_t = 36; -pub const __WASI_ENAMETOOLONG: __wasi_errno_t = 37; -pub const __WASI_ENETDOWN: __wasi_errno_t = 38; -pub const __WASI_ENETRESET: __wasi_errno_t = 39; -pub const __WASI_ENETUNREACH: __wasi_errno_t = 40; -pub const __WASI_ENFILE: __wasi_errno_t = 41; -pub const __WASI_ENOBUFS: __wasi_errno_t = 42; -pub const __WASI_ENODEV: __wasi_errno_t = 43; -pub const __WASI_ENOENT: __wasi_errno_t = 44; -pub const __WASI_ENOEXEC: __wasi_errno_t = 45; -pub const __WASI_ENOLCK: __wasi_errno_t = 46; -pub const __WASI_ENOLINK: __wasi_errno_t = 47; -pub const __WASI_ENOMEM: __wasi_errno_t = 48; -pub const __WASI_ENOMSG: __wasi_errno_t = 49; -pub const __WASI_ENOPROTOOPT: __wasi_errno_t = 50; -pub const __WASI_ENOSPC: __wasi_errno_t = 51; -pub const __WASI_ENOSYS: __wasi_errno_t = 52; -pub const __WASI_ENOTCONN: __wasi_errno_t = 53; -pub const __WASI_ENOTDIR: __wasi_errno_t = 54; -pub const __WASI_ENOTEMPTY: __wasi_errno_t = 55; -pub const __WASI_ENOTRECOVERABLE: __wasi_errno_t = 56; -pub const __WASI_ENOTSOCK: __wasi_errno_t = 57; -pub const __WASI_ENOTSUP: __wasi_errno_t = 58; -pub const __WASI_ENOTTY: __wasi_errno_t = 59; -pub const __WASI_ENXIO: __wasi_errno_t = 60; -pub const __WASI_EOVERFLOW: __wasi_errno_t = 61; -pub const __WASI_EOWNERDEAD: __wasi_errno_t = 62; -pub const __WASI_EPERM: __wasi_errno_t = 63; -pub const __WASI_EPIPE: __wasi_errno_t = 64; -pub const __WASI_EPROTO: __wasi_errno_t = 65; -pub const __WASI_EPROTONOSUPPORT: __wasi_errno_t = 66; -pub const __WASI_EPROTOTYPE: __wasi_errno_t = 67; -pub const __WASI_ERANGE: __wasi_errno_t = 68; -pub const __WASI_EROFS: __wasi_errno_t = 69; -pub const __WASI_ESPIPE: __wasi_errno_t = 70; -pub const __WASI_ESRCH: __wasi_errno_t = 71; -pub const __WASI_ESTALE: __wasi_errno_t = 72; -pub const __WASI_ETIMEDOUT: __wasi_errno_t = 73; -pub const __WASI_ETXTBSY: __wasi_errno_t = 74; -pub const __WASI_EXDEV: __wasi_errno_t = 75; -pub const __WASI_ENOTCAPABLE: __wasi_errno_t = 76; - -// pub type __wasi_preopentype_t = u8; -pub const __WASI_PREOPENTYPE_DIR: __wasi_preopentype_t = 0; diff --git a/wasmtime-wasi/src/host_impls.rs b/wasmtime-wasi/src/host_impls.rs deleted file mode 100644 index e545c834f76d..000000000000 --- a/wasmtime-wasi/src/host_impls.rs +++ /dev/null @@ -1,183 +0,0 @@ -use super::host; -use super::wasm32; -use errno::{errno, Errno}; - -/// Convert POSIX error code to host's WASI error code -fn convert_errno(error: Errno) -> host::__wasi_errno_t { - #[allow(unreachable_patterns)] - match error.into() { - libc::E2BIG => host::__WASI_E2BIG, - libc::EACCES => host::__WASI_EACCES, - libc::EADDRINUSE => host::__WASI_EADDRINUSE, - libc::EADDRNOTAVAIL => host::__WASI_EADDRNOTAVAIL, - libc::EAFNOSUPPORT => host::__WASI_EAFNOSUPPORT, - libc::EAGAIN | libc::EWOULDBLOCK => host::__WASI_EAGAIN, - libc::EALREADY => host::__WASI_EALREADY, - libc::EBADF => host::__WASI_EBADF, - libc::EBADMSG => host::__WASI_EBADMSG, - libc::EBUSY => host::__WASI_EBUSY, - libc::ECANCELED => host::__WASI_ECANCELED, - libc::ECHILD => host::__WASI_ECHILD, - libc::ECONNABORTED => host::__WASI_ECONNABORTED, - libc::ECONNREFUSED => host::__WASI_ECONNREFUSED, - libc::ECONNRESET => host::__WASI_ECONNRESET, - libc::EDEADLK => host::__WASI_EDEADLK, - libc::EDESTADDRREQ => host::__WASI_EDESTADDRREQ, - libc::EDOM => host::__WASI_EDOM, - libc::EDQUOT => host::__WASI_EDQUOT, - libc::EEXIST => host::__WASI_EEXIST, - libc::EFAULT => host::__WASI_EFAULT, - libc::EFBIG => host::__WASI_EFBIG, - libc::EHOSTUNREACH => host::__WASI_EHOSTUNREACH, - libc::EIDRM => host::__WASI_EIDRM, - libc::EILSEQ => host::__WASI_EILSEQ, - libc::EINPROGRESS => host::__WASI_EINPROGRESS, - libc::EINTR => host::__WASI_EINTR, - libc::EINVAL => host::__WASI_EINVAL, - libc::EIO => host::__WASI_EIO, - libc::EISCONN => host::__WASI_EISCONN, - libc::EISDIR => host::__WASI_EISDIR, - libc::ELOOP => host::__WASI_ELOOP, - libc::EMFILE => host::__WASI_EMFILE, - libc::EMLINK => host::__WASI_EMLINK, - libc::EMSGSIZE => host::__WASI_EMSGSIZE, - libc::EMULTIHOP => host::__WASI_EMULTIHOP, - libc::ENAMETOOLONG => host::__WASI_ENAMETOOLONG, - libc::ENETDOWN => host::__WASI_ENETDOWN, - libc::ENETRESET => host::__WASI_ENETRESET, - libc::ENETUNREACH => host::__WASI_ENETUNREACH, - libc::ENFILE => host::__WASI_ENFILE, - libc::ENOBUFS => host::__WASI_ENOBUFS, - libc::ENODEV => host::__WASI_ENODEV, - libc::ENOENT => host::__WASI_ENOENT, - libc::ENOEXEC => host::__WASI_ENOEXEC, - libc::ENOLCK => host::__WASI_ENOLCK, - libc::ENOLINK => host::__WASI_ENOLINK, - libc::ENOMEM => host::__WASI_ENOMEM, - libc::ENOMSG => host::__WASI_ENOMSG, - libc::ENOPROTOOPT => host::__WASI_ENOPROTOOPT, - libc::ENOSPC => host::__WASI_ENOSPC, - libc::ENOSYS => host::__WASI_ENOSYS, - // TODO: verify if this is correct - #[cfg(target_os = "freebsd")] - libc::ENOTCAPABLE => host::__WASI_ENOTCAPABLE, - libc::ENOTCONN => host::__WASI_ENOTCONN, - libc::ENOTDIR => host::__WASI_ENOTDIR, - libc::ENOTEMPTY => host::__WASI_ENOTEMPTY, - libc::ENOTRECOVERABLE => host::__WASI_ENOTRECOVERABLE, - libc::ENOTSOCK => host::__WASI_ENOTSOCK, - libc::ENOTSUP | libc::EOPNOTSUPP => host::__WASI_ENOTSUP, - libc::ENOTTY => host::__WASI_ENOTTY, - libc::ENXIO => host::__WASI_ENXIO, - libc::EOVERFLOW => host::__WASI_EOVERFLOW, - libc::EOWNERDEAD => host::__WASI_EOWNERDEAD, - libc::EPERM => host::__WASI_EPERM, - libc::EPIPE => host::__WASI_EPIPE, - libc::EPROTO => host::__WASI_EPROTO, - libc::EPROTONOSUPPORT => host::__WASI_EPROTONOSUPPORT, - libc::EPROTOTYPE => host::__WASI_EPROTOTYPE, - libc::ERANGE => host::__WASI_ERANGE, - libc::EROFS => host::__WASI_EROFS, - libc::ESPIPE => host::__WASI_ESPIPE, - libc::ESRCH => host::__WASI_ESRCH, - libc::ESTALE => host::__WASI_ESTALE, - libc::ETIMEDOUT => host::__WASI_ETIMEDOUT, - libc::ETXTBSY => host::__WASI_ETXTBSY, - libc::EXDEV => host::__WASI_EXDEV, - _ => host::__WASI_ENOSYS, - } -} - -fn fd_prestats_get_entry( - pt: &host::fd_prestats, - fd: host::__wasi_fd_t, -) -> Option<&host::fd_prestat> { - // Test for file descriptor existence - if fd as usize >= pt.size { - return None; - } - - let prestat = unsafe { &*pt.prestats.add(fd as usize) }; - if prestat.dir_name == ::std::ptr::null() { - return None; - } - - Some(prestat) -} - -macro_rules! rwlock_rdlock { - ($prestats:expr) => { - unsafe { - host::rwlock_rdlock(&mut (*$prestats).lock as *mut host::rwlock); - } - }; -} - -macro_rules! rwlock_unlock { - ($prestats:expr) => { - unsafe { - host::rwlock_unlock(&mut (*$prestats).lock as *mut host::rwlock); - } - }; -} - -pub fn wasmtime_ssp_proc_exit(rval: wasm32::__wasi_exitcode_t) { - ::std::process::exit(rval as i32) -} - -pub fn wasmtime_ssp_fd_prestat_get( - prestats: &mut host::fd_prestats, - fd: host::__wasi_fd_t, - buf: &mut host::__wasi_prestat_t, -) -> host::__wasi_errno_t { - rwlock_rdlock!(prestats); - - let ret_code = if let Some(prestat) = fd_prestats_get_entry(prestats, fd) { - buf.pr_type = host::__WASI_PREOPENTYPE_DIR; - unsafe { - buf.u.dir.pr_name_len = prestat.dir_name_len; - } - host::__WASI_ESUCCESS - } else { - host::__WASI_EBADF - }; - - rwlock_unlock!(prestats); - - ret_code -} - -pub fn wasmtime_ssp_fd_prestat_dir_name( - prestats: &mut host::fd_prestats, - fd: host::__wasi_fd_t, - path: &mut [host::char], -) -> host::__wasi_errno_t { - rwlock_rdlock!(prestats); - - let ret_code = if let Some(prestat) = fd_prestats_get_entry(prestats, fd) { - if path.len() != prestat.dir_name_len { - host::__WASI_EINVAL - } else { - path.copy_from_slice(unsafe { - ::std::slice::from_raw_parts(prestat.dir_name, prestat.dir_name_len) - }); - host::__WASI_ESUCCESS - } - } else { - host::__WASI_EBADF - }; - - rwlock_unlock!(prestats); - - ret_code -} - -pub fn wasmtime_ssp_sched_yield() -> host::__wasi_errno_t { - unsafe { - if libc::sched_yield() < 0 { - return convert_errno(errno()); - } - } - - host::__WASI_ESUCCESS -} diff --git a/wasmtime-wasi/src/instantiate.rs b/wasmtime-wasi/src/instantiate.rs index 9a550784764f..ec189642d319 100644 --- a/wasmtime-wasi/src/instantiate.rs +++ b/wasmtime-wasi/src/instantiate.rs @@ -1,32 +1,22 @@ -use crate::host::{ - argv_environ_init, argv_environ_values, fd_prestats, fd_prestats_init, fd_prestats_insert, - fd_table, fd_table_init, fd_table_insert_existing, -}; use cranelift_codegen::ir::types; use cranelift_codegen::{ir, isa}; use cranelift_entity::PrimaryMap; use cranelift_wasm::DefinedFuncIndex; use std::cell::RefCell; use std::collections::HashMap; -use std::ffi::CString; -use std::mem; +use std::fs::File; use std::rc::Rc; use syscalls; use target_lexicon::HOST; +use wasi_common::WasiCtxBuilder; use wasmtime_environ::{translate_signature, Export, Module}; use wasmtime_runtime::{Imports, InstanceHandle, InstantiationError, VMFunctionBody}; -pub(crate) struct WASIState { - pub curfds: Box, - pub prestats: Box, - pub argv_environ: Box, -} - /// Return an instance implementing the "wasi" interface. pub fn instantiate_wasi( prefix: &str, global_exports: Rc>>>, - preopened_dirs: &[(String, libc::c_int)], + preopened_dirs: &[(String, File)], argv: &[String], environ: &[(String, String)], ) -> Result { @@ -110,54 +100,29 @@ pub fn instantiate_wasi( let imports = Imports::none(); let data_initializers = Vec::new(); let signatures = PrimaryMap::new(); - let mut curfds = Box::new(unsafe { mem::zeroed::() }); - let mut prestats = Box::new(unsafe { mem::zeroed::() }); - let mut argv_environ = Box::new(unsafe { mem::zeroed::() }); - - unsafe { - let argv_environ: &mut argv_environ_values = &mut *argv_environ; - let (argv_offsets, argv_buf, environ_offsets, environ_buf) = - allocate_argv_environ(argv, environ); - argv_environ_init( - argv_environ, - argv_offsets.as_ptr(), - argv_offsets.len(), - argv_buf.as_ptr(), - argv_buf.len(), - environ_offsets.as_ptr(), - environ_offsets.len(), - environ_buf.as_ptr(), - environ_buf.len(), - ); - let curfds: *mut fd_table = &mut *curfds; - fd_table_init(curfds); + let args: Vec<&str> = argv.iter().map(AsRef::as_ref).collect(); + let mut wasi_ctx_builder = WasiCtxBuilder::new().args(&args).inherit_stdio(); - let prestats: *mut fd_prestats = &mut *prestats; - fd_prestats_init(prestats); - - // Prepopulate curfds with stdin, stdout, and stderr file descriptors. - assert!(fd_table_insert_existing(curfds, 0, 0)); - assert!(fd_table_insert_existing(curfds, 1, 1)); - assert!(fd_table_insert_existing(curfds, 2, 2)); + for (k, v) in environ { + wasi_ctx_builder = wasi_ctx_builder.env(k, v); + } - let mut wasm_fd = 3; - for (dir, fd) in preopened_dirs { - assert!(fd_table_insert_existing(curfds, wasm_fd, *fd)); - assert!(fd_prestats_insert( - prestats, - CString::new(dir.as_str()).unwrap().as_ptr(), - wasm_fd, - )); - wasm_fd += 1; - } + for (dir, f) in preopened_dirs { + wasi_ctx_builder = wasi_ctx_builder.preopened_dir( + f.try_clone().map_err(|err| { + InstantiationError::Resource(format!( + "couldn't clone an instance handle to pre-opened dir: {}", + err + )) + })?, + dir, + ); } - let host_state = WASIState { - curfds, - prestats, - argv_environ, - }; + let wasi_ctx = wasi_ctx_builder.build().map_err(|err| { + InstantiationError::Resource(format!("couldn't assemble WASI context object: {}", err)) + })?; InstanceHandle::new( Rc::new(module), @@ -167,37 +132,6 @@ pub fn instantiate_wasi( &data_initializers, signatures.into_boxed_slice(), None, - Box::new(host_state), + Box::new(wasi_ctx), ) } - -fn allocate_argv_environ( - argv: &[String], - environ: &[(String, String)], -) -> (Vec, Vec, Vec, Vec) { - let mut argv_offsets = Vec::new(); - let mut argv_buf = Vec::new(); - let mut environ_offsets = Vec::new(); - let mut environ_buf = Vec::new(); - - for arg in argv { - argv_offsets.push(argv_buf.len()); - for c in arg.bytes() { - argv_buf.push(c as libc::c_char); - } - argv_buf.push('\0' as libc::c_char); - } - for (key, value) in environ { - environ_offsets.push(environ_buf.len()); - for c in key.bytes() { - environ_buf.push(c as libc::c_char); - } - environ_buf.push('=' as libc::c_char); - for c in value.bytes() { - environ_buf.push(c as libc::c_char); - } - environ_buf.push('\0' as libc::c_char); - } - - (argv_offsets, argv_buf, environ_offsets, environ_buf) -} diff --git a/wasmtime-wasi/src/lib.rs b/wasmtime-wasi/src/lib.rs index d38f1d155b2f..52978224fed9 100644 --- a/wasmtime-wasi/src/lib.rs +++ b/wasmtime-wasi/src/lib.rs @@ -1,4 +1,3 @@ -extern crate cast; extern crate cranelift_codegen; extern crate cranelift_entity; extern crate cranelift_wasm; @@ -8,13 +7,9 @@ extern crate wasmtime_jit; extern crate wasmtime_runtime; #[macro_use] extern crate log; -extern crate errno; +extern crate wasi_common; -mod host; -mod host_impls; mod instantiate; mod syscalls; -mod translate; -mod wasm32; pub use instantiate::instantiate_wasi; diff --git a/wasmtime-wasi/src/syscalls.rs b/wasmtime-wasi/src/syscalls.rs index 6bdf465d991a..c400b39917dd 100644 --- a/wasmtime-wasi/src/syscalls.rs +++ b/wasmtime-wasi/src/syscalls.rs @@ -1,45 +1,42 @@ -use crate::host::{argv_environ_values, fd_prestats, fd_table}; -use crate::instantiate::WASIState; use cranelift_codegen::ir::types::{Type, I32, I64}; -use host; -use host_impls; -use std::{mem, ptr, slice, str}; -use translate::*; -use wasm32; -use wasmtime_runtime::VMContext; - -fn str_for_trace<'str>(ptr: *const i8, len: usize) -> Result<&'str str, str::Utf8Error> { - str::from_utf8(unsafe { slice::from_raw_parts(ptr as *const u8, len) }) -} +use wasi_common::{host, hostcalls, memory, wasm32, WasiCtx}; +use wasmtime_runtime::{Export, VMContext}; fn return_encoded_errno(e: host::__wasi_errno_t) -> wasm32::__wasi_errno_t { - let errno = encode_errno(e); + let errno = memory::enc_errno(e); trace!(" -> errno={}", wasm32::strerror(errno)); errno } -unsafe fn get_curfds(vmctx: *mut VMContext) -> *mut fd_table { - (&mut *(&mut *vmctx) - .host_state() - .downcast_mut::() - .unwrap() - .curfds) as *mut fd_table -} - -unsafe fn get_prestats(vmctx: *mut VMContext) -> *mut fd_prestats { - (&mut *(&mut *vmctx) - .host_state() - .downcast_mut::() - .unwrap() - .prestats) as *mut fd_prestats +fn get_wasi_ctx(vmctx: &mut VMContext) -> Result<&mut WasiCtx, host::__wasi_errno_t> { + unsafe { + vmctx.host_state().downcast_mut::().ok_or_else(|| { + println!("!!! no host state named WasiCtx available"); + host::__WASI_EINVAL + }) + } } -unsafe fn get_argv_environ(vmctx: *mut VMContext) -> *mut argv_environ_values { - (&mut *(&mut *vmctx) - .host_state() - .downcast_mut::() - .unwrap() - .argv_environ) as *mut argv_environ_values +fn get_memory(vmctx: &mut VMContext) -> Result<&mut [u8], host::__wasi_errno_t> { + unsafe { + match vmctx.lookup_global_export("memory") { + Some(Export::Memory { + definition, + vmctx: _, + memory: _, + }) => Ok(std::slice::from_raw_parts_mut( + (*definition).base, + (*definition).current_length, + )), + x => { + println!( + "!!! no export named __wasi_memory, or the export isn't a mem: {:?}", + x + ); + Err(host::__WASI_EINVAL) + } + } + } } pub trait AbiRet { @@ -157,7 +154,6 @@ macro_rules! syscalls { } syscalls! { - pub unsafe extern "C" fn args_get( vmctx: *mut VMContext, argv: wasm32::uintptr_t, @@ -169,34 +165,17 @@ syscalls! { argv_buf, ); - let vmctx = &mut *vmctx; - let argv_environ = get_argv_environ(vmctx); - let argc = match cast::u32((*argv_environ).argc) { - Ok(argc) => argc, - Err(_) => return wasm32::__WASI_ENOMEM, - }; - let argv_buf_size = match cast::u32((*argv_environ).argv_buf_size) { - Ok(argc) => argc, - Err(_) => return wasm32::__WASI_ENOMEM, - }; - - let (host_argv_buf, _argv_buf_size) = match decode_char_slice(vmctx, argv_buf, argv_buf_size) { - Ok((argv_buf, argv_buf_size)) => (argv_buf, argv_buf_size), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - // Add 1 so that we can add an extra NULL pointer at the end. - let (argv, _argc) = match decode_charstar_slice(vmctx, argv, argc + 1) { - Ok((argv, argc)) => (argv, argc), + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - let mut host_argv = Vec::new(); - host_argv.resize((*argv_environ).argc + 1, ptr::null_mut()); - let e = host::wasmtime_ssp_args_get(argv_environ, host_argv.as_mut_ptr(), host_argv_buf); - - encode_charstar_slice(argv, host_argv, argv_buf, host_argv_buf); - - return_encoded_errno(e) + hostcalls::args_get(wasi_ctx, memory, argv, argv_buf) } pub unsafe extern "C" fn args_sizes_get( @@ -210,28 +189,17 @@ syscalls! { argv_buf_size, ); - let vmctx = &mut *vmctx; - let mut host_argc = 0; - if let Err(e) = decode_usize_byref(vmctx, argc) { - return return_encoded_errno(e); - } - let mut host_argv_buf_size = 0; - if let Err(e) = decode_usize_byref(vmctx, argv_buf_size) { - return return_encoded_errno(e); - } - - let vmctx = &mut *vmctx; - let argv_environ = get_argv_environ(vmctx); - - let e = host::wasmtime_ssp_args_sizes_get(argv_environ, &mut host_argc, &mut host_argv_buf_size); - - trace!(" | *argc={:?}", host_argc); - encode_usize_byref(vmctx, argc, host_argc); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - trace!(" | *argv_buf_size={:?}", host_argv_buf_size); - encode_usize_byref(vmctx, argv_buf_size, host_argv_buf_size); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::args_sizes_get(wasi_ctx, memory, argc, argv_buf_size) } pub unsafe extern "C" fn clock_res_get( @@ -245,19 +213,12 @@ syscalls! { resolution, ); - let vmctx = &mut *vmctx; - let clock_id = decode_clockid(clock_id); - let mut host_resolution = 0; - if let Err(e) = decode_timestamp_byref(vmctx, resolution) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_clock_res_get(clock_id, &mut host_resolution); - - trace!(" | *resolution={:?}", host_resolution); - encode_timestamp_byref(vmctx, resolution, host_resolution); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::clock_res_get(memory, clock_id, resolution) } pub unsafe extern "C" fn clock_time_get( @@ -273,20 +234,12 @@ syscalls! { time, ); - let vmctx = &mut *vmctx; - let clock_id = decode_clockid(clock_id); - let precision = decode_timestamp(precision); - let mut host_time = 0; - if let Err(e) = decode_timestamp_byref(vmctx, time) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_clock_time_get(clock_id, precision, &mut host_time); - - trace!(" | *time={:?}", host_time); - encode_timestamp_byref(vmctx, time, host_time); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::clock_time_get(memory, clock_id, precision, time) } pub unsafe extern "C" fn environ_get( @@ -300,34 +253,17 @@ syscalls! { environ_buf, ); - let vmctx = &mut *vmctx; - let argv_environ = get_argv_environ(vmctx); - let environ_count = match cast::u32((*argv_environ).environ_count) { - Ok(host_environ_count) => host_environ_count, - Err(_) => return wasm32::__WASI_ENOMEM, - }; - let environ_buf_size = match cast::u32((*argv_environ).environ_buf_size) { - Ok(host_environ_buf_size) => host_environ_buf_size, - Err(_) => return wasm32::__WASI_ENOMEM, - }; - - let (host_environ_buf, _environ_buf_len) = match decode_char_slice(vmctx, environ_buf, environ_buf_size) { - Ok((environ_buf, environ_buf_len)) => (environ_buf, environ_buf_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - // Add 1 so that we can add an extra NULL pointer at the end. - let (environ, _environ_count) = match decode_charstar_slice(vmctx, environ, environ_count + 1) { - Ok((environ, environ_count)) => (environ, environ_count), + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - let mut host_environ = Vec::new(); - host_environ.resize((*argv_environ).environ_count + 1, ptr::null_mut()); - - let e = host::wasmtime_ssp_environ_get(argv_environ, host_environ.as_mut_ptr(), host_environ_buf); - encode_charstar_slice(environ, host_environ, environ_buf, host_environ_buf); - - return_encoded_errno(e) + hostcalls::environ_get(wasi_ctx, memory, environ, environ_buf) } pub unsafe extern "C" fn environ_sizes_get( @@ -341,28 +277,17 @@ syscalls! { environ_buf_size, ); - let vmctx = &mut *vmctx; - let mut host_environ_count = 0; - if let Err(e) = decode_usize_byref(vmctx, environ_count) { - return return_encoded_errno(e); - } - let mut host_environ_buf_size = 0; - if let Err(e) = decode_usize_byref(vmctx, environ_buf_size) { - return return_encoded_errno(e); - } - - let vmctx = &mut *vmctx; - let argv_environ = get_argv_environ(vmctx); - - let e = host::wasmtime_ssp_environ_sizes_get(argv_environ, &mut host_environ_count, &mut host_environ_buf_size); - - trace!(" | *environ_count={:?}", host_environ_count); - encode_usize_byref(vmctx, environ_count, host_environ_count); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - trace!(" | *environ_buf_size={:?}", host_environ_buf_size); - encode_usize_byref(vmctx, environ_buf_size, host_environ_buf_size); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::environ_sizes_get(wasi_ctx, memory, environ_count, environ_buf_size) } pub unsafe extern "C" fn fd_prestat_get( @@ -372,19 +297,17 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_prestat_get(fd={:?}, buf={:#x?})", fd, buf); - let vmctx = &mut *vmctx; - let prestats = get_prestats(vmctx); - let fd = decode_fd(fd); - let mut host_buf = std::mem::zeroed(); - if let Err(e) = decode_prestat_byref(vmctx, buf) { - return return_encoded_errno(e); - } - - let e = host_impls::wasmtime_ssp_fd_prestat_get(&mut *prestats, fd, &mut host_buf); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - encode_prestat_byref(vmctx, buf, host_buf); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_prestat_get(wasi_ctx, memory, fd, buf) } pub unsafe extern "C" fn fd_prestat_dir_name( @@ -395,22 +318,17 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_prestat_dir_name(fd={:?}, path={:#x?}, path_len={})", fd, path, path_len); - let vmctx = &mut *vmctx; - let prestats = get_prestats(vmctx); - let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { - Ok((path, path_len)) => (path, path_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); - - let e = host_impls::wasmtime_ssp_fd_prestat_dir_name( - &mut *prestats, - fd, - ::std::slice::from_raw_parts_mut(path, path_len), - ); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_prestat_dir_name(wasi_ctx, memory, fd, path, path_len) } pub unsafe extern "C" fn fd_close( @@ -419,14 +337,12 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_close(fd={:?})", fd); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let prestats = get_prestats(vmctx); - let fd = decode_fd(fd); - - let e = host::wasmtime_ssp_fd_close(curfds, prestats, fd); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_close(wasi_ctx, fd) } pub unsafe extern "C" fn fd_datasync( @@ -435,13 +351,12 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_datasync(fd={:?})", fd); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - - let e = host::wasmtime_ssp_fd_datasync(curfds, fd); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_datasync(wasi_ctx, fd) } pub unsafe extern "C" fn fd_pread( @@ -461,32 +376,25 @@ syscalls! { nread ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let iovs = match decode_iovec_slice(vmctx, iovs, iovs_len) { - Ok(iovs) => iovs, + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - let offset = decode_filesize(offset); - let mut host_nread = 0; - if let Err(e) = decode_usize_byref(vmctx, nread) { - return return_encoded_errno(e); - } - let e = host::wasmtime_ssp_fd_pread( - curfds, + hostcalls::fd_pread( + wasi_ctx, + memory, fd, - iovs.as_ptr(), - iovs.len(), + iovs, + iovs_len, offset, - &mut host_nread, - ); - - trace!(" | *nread={:?}", host_nread); - encode_usize_byref(vmctx, nread, host_nread); - - return_encoded_errno(e) + nread + ) } pub unsafe extern "C" fn fd_pwrite( @@ -506,32 +414,25 @@ syscalls! { nwritten ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let iovs = match decode_ciovec_slice(vmctx, iovs, iovs_len) { - Ok(iovs) => iovs, + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - let offset = decode_filesize(offset); - let mut host_nwritten = 0; - if let Err(e) = decode_usize_byref(vmctx, nwritten) { - return return_encoded_errno(e); - } - let e = host::wasmtime_ssp_fd_pwrite( - curfds, + hostcalls::fd_pwrite( + wasi_ctx, + memory, fd, - iovs.as_ptr(), - iovs.len(), + iovs, + iovs_len, offset, - &mut host_nwritten, - ); - - trace!(" | *nwritten={:?}", host_nwritten); - encode_usize_byref(vmctx, nwritten, host_nwritten); - - return_encoded_errno(e) + nwritten + ) } pub unsafe extern "C" fn fd_read( @@ -549,24 +450,17 @@ syscalls! { nread ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let iovs = match decode_iovec_slice(vmctx, iovs, iovs_len) { - Ok(iovs) => iovs, + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let mut host_nread = 0; - if let Err(e) = decode_usize_byref(vmctx, nread) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_fd_read(curfds, fd, iovs.as_ptr(), iovs.len(), &mut host_nread); - trace!(" | *nread={:?}", host_nread); - encode_usize_byref(vmctx, nread, host_nread); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_read(wasi_ctx, memory, fd, iovs, iovs_len, nread) } pub unsafe extern "C" fn fd_renumber( @@ -576,15 +470,12 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_renumber(from={:?}, to={:?})", from, to); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let prestats = get_prestats(vmctx); - let from = decode_fd(from); - let to = decode_fd(to); - - let e = host::wasmtime_ssp_fd_renumber(curfds, prestats, from, to); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_renumber(wasi_ctx, from, to) } pub unsafe extern "C" fn fd_seek( @@ -602,22 +493,17 @@ syscalls! { newoffset ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let offset = decode_filedelta(offset); - let whence = decode_whence(whence); - let mut host_newoffset = 0; - if let Err(e) = decode_filesize_byref(vmctx, newoffset) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_fd_seek(curfds, fd, offset, whence, &mut host_newoffset); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - trace!(" | *newoffset={:?}", host_newoffset); - encode_filesize_byref(vmctx, newoffset, host_newoffset); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_seek(wasi_ctx, memory, fd, offset, whence, newoffset) } pub unsafe extern "C" fn fd_tell( @@ -627,20 +513,17 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_tell(fd={:?}, newoffset={:#x?})", fd, newoffset); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let mut host_newoffset = 0; - if let Err(e) = decode_filesize_byref(vmctx, newoffset) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_fd_tell(curfds, fd, &mut host_newoffset); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - trace!(" | *newoffset={:?}", host_newoffset); - encode_filesize_byref(vmctx, newoffset, host_newoffset); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_tell(wasi_ctx, memory, fd, newoffset) } pub unsafe extern "C" fn fd_fdstat_get( @@ -650,20 +533,17 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_fdstat_get(fd={:?}, buf={:#x?})", fd, buf); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let mut host_buf = std::mem::zeroed(); - if let Err(e) = decode_fdstat_byref(vmctx, buf) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_fd_fdstat_get(curfds, fd, &mut host_buf); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - trace!(" | *buf={:?}", host_buf); - encode_fdstat_byref(vmctx, buf, host_buf); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_fdstat_get(wasi_ctx, memory, fd, buf) } pub unsafe extern "C" fn fd_fdstat_set_flags( @@ -677,14 +557,12 @@ syscalls! { flags ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let flags = decode_fdflags(flags); - - let e = host::wasmtime_ssp_fd_fdstat_set_flags(curfds, fd, flags); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_fdstat_set_flags(wasi_ctx, fd, flags) } pub unsafe extern "C" fn fd_fdstat_set_rights( @@ -700,15 +578,17 @@ syscalls! { fs_rights_inheriting ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let fs_rights_base = decode_rights(fs_rights_base); - let fs_rights_inheriting = decode_rights(fs_rights_inheriting); - - let e = host::wasmtime_ssp_fd_fdstat_set_rights(curfds, fd, fs_rights_base, fs_rights_inheriting); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_fdstat_set_rights( + wasi_ctx, + fd, + fs_rights_base, + fs_rights_inheriting + ) } pub unsafe extern "C" fn fd_sync( @@ -717,13 +597,12 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_sync(fd={:?})", fd); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - - let e = host::wasmtime_ssp_fd_sync(curfds, fd); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_sync(wasi_ctx, fd) } pub unsafe extern "C" fn fd_write( @@ -741,24 +620,17 @@ syscalls! { nwritten ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let iovs = match decode_ciovec_slice(vmctx, iovs, iovs_len) { - Ok(iovs) => iovs, + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let mut host_nwritten = 0; - if let Err(e) = decode_usize_byref(vmctx, nwritten) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_fd_write(curfds, fd, iovs.as_ptr(), iovs.len(), &mut host_nwritten); - trace!(" | *nwritten={:?}", host_nwritten); - encode_usize_byref(vmctx, nwritten, host_nwritten); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_write(wasi_ctx, memory, fd, iovs, iovs_len, nwritten) } pub unsafe extern "C" fn fd_advise( @@ -776,16 +648,12 @@ syscalls! { advice ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let offset = decode_filesize(offset); - let len = decode_filesize(len); - let advice = decode_advice(advice); - - let e = host::wasmtime_ssp_fd_advise(curfds, fd, offset, len, advice); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_advise(wasi_ctx, fd, offset, len, advice) } pub unsafe extern "C" fn fd_allocate( @@ -796,15 +664,12 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_allocate(fd={:?}, offset={}, len={})", fd, offset, len); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let offset = decode_filesize(offset); - let len = decode_filesize(len); - - let e = host::wasmtime_ssp_fd_allocate(curfds, fd, offset, len); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_allocate(wasi_ctx, fd, offset, len) } pub unsafe extern "C" fn path_create_directory( @@ -820,19 +685,17 @@ syscalls! { path_len, ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { - Ok((path, path_len)) => (path, path_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); - - let e = host::wasmtime_ssp_path_create_directory(curfds, fd, path, path_len); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::path_create_directory(wasi_ctx, memory, fd, path, path_len) } pub unsafe extern "C" fn path_link( @@ -856,27 +719,27 @@ syscalls! { path_len1 ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd0 = decode_fd(fd0); - let flags0 = decode_lookupflags(flags0); - let (path0, path_len0) = match decode_char_slice(vmctx, path0, path_len0) { - Ok((path0, path_len0)) => (path0, path_len0), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let fd1 = decode_fd(fd1); - let (path1, path_len1) = match decode_char_slice(vmctx, path1, path_len1) { - Ok((path1, path_len1)) => (path1, path_len1), + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - trace!(" | (path0,path_len0)={:?}", str_for_trace(path0, path_len0)); - trace!(" | (path1,path_len1)={:?}", str_for_trace(path1, path_len1)); - - let e = - host::wasmtime_ssp_path_link(curfds, fd0, flags0, path0, path_len0, fd1, path1, path_len1); - - return_encoded_errno(e) + hostcalls::path_link( + wasi_ctx, + memory, + fd0, + flags0, + path0, + path_len0, + fd1, + path1, + path_len1 + ) } // TODO: When multi-value happens, switch to that instead of passing @@ -906,27 +769,19 @@ syscalls! { fd ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let dirfd = decode_fd(dirfd); - let dirflags = decode_lookupflags(dirflags); - let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { - Ok((path, path_len)) => (path, path_len), - Err(e) => return return_encoded_errno(e), - }; - let oflags = decode_oflags(oflags); - let fs_rights_base = decode_rights(fs_rights_base); - let fs_rights_inheriting = decode_rights(fs_rights_inheriting); - let fs_flags = decode_fdflags(fs_flags); - let mut host_fd = wasm32::__wasi_fd_t::max_value(); - if let Err(e) = decode_fd_byref(vmctx, fd) { - return return_encoded_errno(e); - } + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - let e = host::wasmtime_ssp_path_open( - curfds, + hostcalls::path_open( + wasi_ctx, + memory, dirfd, dirflags, path, @@ -935,13 +790,8 @@ syscalls! { fs_rights_base, fs_rights_inheriting, fs_flags, - &mut host_fd, - ); - - trace!(" | *fd={:?}", host_fd); - encode_fd_byref(vmctx, fd, host_fd); - - return_encoded_errno(e) + fd + ) } pub unsafe extern "C" fn fd_readdir( @@ -961,34 +811,25 @@ syscalls! { buf_used, ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let (buf, buf_len) = match decode_char_slice(vmctx, buf, buf_len) { - Ok((buf, buf_len)) => (buf, buf_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let cookie = decode_dircookie(cookie); - let mut host_buf_used = 0; - if let Err(e) = decode_usize_byref(vmctx, buf_used) { - return return_encoded_errno(e); - } - trace!(" | (buf,buf_len)={:?}", str_for_trace(buf, buf_len)); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - let e = host::wasmtime_ssp_fd_readdir( - curfds, + hostcalls::fd_readdir( + wasi_ctx, + memory, fd, - buf as *mut host::void, + buf, buf_len, cookie, - &mut host_buf_used, - ); - - trace!(" | *buf_used={:?}", host_buf_used); - encode_usize_byref(vmctx, buf_used, host_buf_used); - - return_encoded_errno(e) + buf_used + ) } pub unsafe extern "C" fn path_readlink( @@ -1010,39 +851,26 @@ syscalls! { buf_used, ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { - Ok((path, path_len)) => (path, path_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let (buf, buf_len) = match decode_char_slice(vmctx, buf, buf_len) { - Ok((buf, buf_len)) => (buf, buf_len), + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - let mut host_buf_used = 0; - if let Err(e) = decode_usize_byref(vmctx, buf_used) { - return return_encoded_errno(e); - } - trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); - - let e = host::wasmtime_ssp_path_readlink( - curfds, + hostcalls::path_readlink( + wasi_ctx, + memory, fd, path, path_len, buf, buf_len, - &mut host_buf_used, - ); - - trace!(" | *buf_used={:?}", host_buf_used); - trace!(" | (buf,*buf_used)={:?}", str_for_trace(buf, host_buf_used)); - encode_usize_byref(vmctx, buf_used, host_buf_used); - - return_encoded_errno(e) + buf_used + ) } pub unsafe extern "C" fn path_rename( @@ -1064,25 +892,26 @@ syscalls! { path_len1, ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd0 = decode_fd(fd0); - let (path0, path_len0) = match decode_char_slice(vmctx, path0, path_len0) { - Ok((path0, path_len0)) => (path0, path_len0), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let fd1 = decode_fd(fd1); - let (path1, path_len1) = match decode_char_slice(vmctx, path1, path_len1) { - Ok((path1, path_len1)) => (path1, path_len1), + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - trace!(" | (path0,path_len0)={:?}", str_for_trace(path0, path_len0)); - trace!(" | (path1,path_len1)={:?}", str_for_trace(path1, path_len1)); - - let e = host::wasmtime_ssp_path_rename(curfds, fd0, path0, path_len0, fd1, path1, path_len1); - - return_encoded_errno(e) + hostcalls::path_rename( + wasi_ctx, + memory, + fd0, + path0, + path_len0, + fd1, + path1, + path_len1 + ) } pub unsafe extern "C" fn fd_filestat_get( @@ -1092,20 +921,17 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("fd_filestat_get(fd={:?}, buf={:#x?})", fd, buf); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let mut host_buf = std::mem::zeroed(); - if let Err(e) = decode_filestat_byref(vmctx, buf) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_fd_filestat_get(curfds, fd, &mut host_buf); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - trace!(" | *buf={:?}", host_buf); - encode_filestat_byref(vmctx, buf, host_buf); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_filestat_get(wasi_ctx, memory, fd, buf) } pub unsafe extern "C" fn fd_filestat_set_times( @@ -1122,16 +948,12 @@ syscalls! { fstflags ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let st_atim = decode_timestamp(st_atim); - let st_mtim = decode_timestamp(st_mtim); - let fstflags = decode_fstflags(fstflags); - - let e = host::wasmtime_ssp_fd_filestat_set_times(curfds, fd, st_atim, st_mtim, fstflags); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_filestat_set_times(wasi_ctx, fd, st_atim, st_mtim, fstflags) } pub unsafe extern "C" fn fd_filestat_set_size( @@ -1145,14 +967,12 @@ syscalls! { size ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let size = decode_filesize(size); - - let e = host::wasmtime_ssp_fd_filestat_set_size(curfds, fd, size); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::fd_filestat_set_size(wasi_ctx, fd, size) } pub unsafe extern "C" fn path_filestat_get( @@ -1172,27 +992,17 @@ syscalls! { buf ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let flags = decode_lookupflags(flags); - let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { - Ok((path, path_len)) => (path, path_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let mut host_buf = std::mem::zeroed(); - if let Err(e) = decode_filestat_byref(vmctx, buf) { - return return_encoded_errno(e); - } - - trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); - let e = host::wasmtime_ssp_path_filestat_get(curfds, fd, flags, path, path_len, &mut host_buf); - - trace!(" | *buf={:?}", host_buf); - encode_filestat_byref(vmctx, buf, host_buf); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::path_filestat_get(wasi_ctx, memory, fd, flags, path, path_len, buf) } pub unsafe extern "C" fn path_filestat_set_times( @@ -1215,23 +1025,27 @@ syscalls! { fstflags ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let flags = decode_lookupflags(flags); - let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { - Ok((path, path_len)) => (path, path_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let st_atim = decode_timestamp(st_atim); - let st_mtim = decode_timestamp(st_mtim); - let fstflags = decode_fstflags(fstflags); - - trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); - let e = host::wasmtime_ssp_path_filestat_set_times(curfds, fd, flags, path, path_len, st_atim, st_mtim, fstflags); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::path_filestat_set_times( + wasi_ctx, + memory, + fd, + flags, + path, + path_len, + st_atim, + st_mtim, + fstflags + ) } pub unsafe extern "C" fn path_symlink( @@ -1251,24 +1065,25 @@ syscalls! { path_len1 ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let (path0, path_len0) = match decode_char_slice(vmctx, path0, path_len0) { - Ok((path0, path_len0)) => (path0, path_len0), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let fd = decode_fd(fd); - let (path1, path_len1) = match decode_char_slice(vmctx, path1, path_len1) { - Ok((path1, path_len1)) => (path1, path_len1), + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - trace!(" | (path0,path_len0)={:?}", str_for_trace(path0, path_len0)); - trace!(" | (path1,path_len1)={:?}", str_for_trace(path1, path_len1)); - - let e = host::wasmtime_ssp_path_symlink(curfds, path0, path_len0, fd, path1, path_len1); - - return_encoded_errno(e) + hostcalls::path_symlink( + wasi_ctx, + memory, + path0, + path_len0, + fd, + path1, + path_len1 + ) } pub unsafe extern "C" fn path_unlink_file( @@ -1284,19 +1099,17 @@ syscalls! { path_len ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { - Ok((path, path_len)) => (path, path_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); - - let e = host::wasmtime_ssp_path_unlink_file(curfds, fd, path, path_len); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::path_unlink_file(wasi_ctx, memory, fd, path, path_len) } pub unsafe extern "C" fn path_remove_directory( @@ -1312,19 +1125,17 @@ syscalls! { path_len ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let fd = decode_fd(fd); - let (path, path_len) = match decode_char_slice(vmctx, path, path_len) { - Ok((path, path_len)) => (path, path_len), + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - trace!(" | (path,path_len)={:?}", str_for_trace(path, path_len)); - - let e = host::wasmtime_ssp_path_remove_directory(curfds, fd, path, path_len); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::path_remove_directory(wasi_ctx, memory, fd, path, path_len) } pub unsafe extern "C" fn poll_oneoff( @@ -1342,63 +1153,37 @@ syscalls! { nevents, ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let in_ = match decode_subscription_slice(vmctx, in_, nsubscriptions) { - Ok(in_) => in_, + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - let (out, out_len) = match decode_event_slice(vmctx, out, nsubscriptions) { - Ok((out, out_len)) => (out, out_len), - Err(e) => return return_encoded_errno(e), - }; - let mut host_out = Vec::new(); - host_out.resize(out_len, mem::zeroed()); - let mut host_nevents = 0; - if let Err(e) = decode_usize_byref(vmctx, nevents) { - return return_encoded_errno(e); - } - - assert!(in_.len() == host_out.len()); - let e = host::wasmtime_ssp_poll_oneoff( - curfds, - in_.as_ptr(), - host_out.as_mut_ptr(), - in_.len(), - &mut host_nevents, - ); - - trace!(" | *nevents={:?}", host_nevents); - encode_usize_byref(vmctx, nevents, host_nevents); - - host_out.truncate(host_nevents); - if log_enabled!(log::Level::Trace) { - for (index, _event) in host_out.iter().enumerate() { - // TODO: Format the output for tracing. - trace!(" | *out[{}]=...", index); - } - } - encode_event_slice(out, host_out); - - return_encoded_errno(e) + hostcalls::poll_oneoff(memory, in_, out, nsubscriptions, nevents) } pub unsafe extern "C" fn proc_exit(_vmctx: *mut VMContext, rval: u32,) -> () { trace!("proc_exit(rval={:?})", rval); - let rval = decode_exitcode(rval); - - // TODO: Rather than call __wasi_proc_exit here, we should trigger a - // stack unwind similar to a trap. - host_impls::wasmtime_ssp_proc_exit(rval); + hostcalls::proc_exit(rval) } pub unsafe extern "C" fn proc_raise( - _vmctx: *mut VMContext, - _sig: wasm32::__wasi_signal_t, + vmctx: *mut VMContext, + sig: wasm32::__wasi_signal_t, ) -> wasm32::__wasi_errno_t { - unimplemented!("__wasi_proc_raise"); + trace!("proc_raise(sig={:?})", sig); + + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; + + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; + + hostcalls::proc_raise(wasi_ctx, memory, sig) } pub unsafe extern "C" fn random_get( @@ -1408,21 +1193,18 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("random_get(buf={:#x?}, buf_len={:?})", buf, buf_len); - let vmctx = &mut *vmctx; - let (buf, buf_len) = match decode_char_slice(vmctx, buf, buf_len) { - Ok((buf, buf_len)) => (buf, buf_len), + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, Err(e) => return return_encoded_errno(e), }; - let e = host::wasmtime_ssp_random_get(buf as *mut host::void, buf_len); - - return_encoded_errno(e) + hostcalls::random_get(memory, buf, buf_len) } pub unsafe extern "C" fn sched_yield(_vmctx: *mut VMContext,) -> wasm32::__wasi_errno_t { - let e = host_impls::wasmtime_ssp_sched_yield(); + trace!("sched_yield(void)"); - return_encoded_errno(e) + hostcalls::sched_yield() } pub unsafe extern "C" fn sock_recv( @@ -1441,33 +1223,26 @@ syscalls! { ro_datalen, ro_flags ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let sock = decode_fd(sock); - let ri_data = match decode_iovec_slice(vmctx, ri_data, ri_data_len) { - Ok(ri_data) => ri_data, + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let ri_flags = decode_riflags(ri_flags); - let mut host_ro_datalen = 0; - if let Err(e) = decode_usize_byref(vmctx, ro_datalen) { - return return_encoded_errno(e); - } - let mut host_ro_flags = 0; - if let Err(e) = decode_roflags_byref(vmctx, ro_flags) { - return return_encoded_errno(e); - } - let e = host::wasmtime_ssp_sock_recv(curfds, sock, ri_data.as_ptr(), ri_data.len(), ri_flags, - &mut host_ro_datalen, &mut host_ro_flags); - - // TODO: Format the output for tracing. - trace!(" | *ro_datalen={}", host_ro_datalen); - trace!(" | *ro_flags={}", host_ro_flags); - encode_usize_byref(vmctx, ro_datalen, host_ro_datalen); - encode_roflags_byref(vmctx, ro_flags, host_ro_flags); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::sock_recv( + wasi_ctx, + memory, + sock, + ri_data, + ri_data_len, + ri_flags, + ro_datalen, + ro_flags + ) } pub unsafe extern "C" fn sock_send( @@ -1484,25 +1259,25 @@ syscalls! { si_data, si_data_len, si_flags, so_datalen, ); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let sock = decode_fd(sock); - let si_data = match decode_ciovec_slice(vmctx, si_data, si_data_len) { - Ok(si_data) => si_data, + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, Err(e) => return return_encoded_errno(e), }; - let si_flags = decode_siflags(si_flags); - let mut host_so_datalen = 0; - if let Err(e) = decode_usize_byref(vmctx, so_datalen) { - return return_encoded_errno(e); - } - - let e = host::wasmtime_ssp_sock_send(curfds, sock, si_data.as_ptr(), si_data.len(), si_flags, &mut host_so_datalen); - trace!(" | *so_datalen={:?}", host_so_datalen); - encode_usize_byref(vmctx, so_datalen, host_so_datalen); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::sock_send( + wasi_ctx, + memory, + sock, + si_data, + si_data_len, + si_flags, + so_datalen + ) } pub unsafe extern "C" fn sock_shutdown( @@ -1512,13 +1287,16 @@ syscalls! { ) -> wasm32::__wasi_errno_t { trace!("sock_shutdown(sock={:?}, how={:?})", sock, how); - let vmctx = &mut *vmctx; - let curfds = get_curfds(vmctx); - let sock = decode_fd(sock); - let how = decode_sdflags(how); + let wasi_ctx = match get_wasi_ctx(&mut *vmctx) { + Ok(ctx) => ctx, + Err(e) => return return_encoded_errno(e), + }; - let e = host::wasmtime_ssp_sock_shutdown(curfds, sock, how); + let memory = match get_memory(&mut *vmctx) { + Ok(memory) => memory, + Err(e) => return return_encoded_errno(e), + }; - return_encoded_errno(e) + hostcalls::sock_shutdown(wasi_ctx, memory, sock, how) } }