From 09b1228c3a2723c6ecb768b40a507688015a478f Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 4 Sep 2019 17:56:51 -0400 Subject: wasi: introduce initial WASI support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gus Caplan Co-authored-by: Daniel Bevenius Co-authored-by: Jiawen Geng Co-authored-by: Tobias Nießen Co-authored-by: Chengzhong Wu PR-URL: https://github.com/nodejs/node/pull/30258 Refs: https://github.com/nodejs/node/pull/27850 Reviewed-By: Anna Henningsen Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Guy Bedford Reviewed-By: Richard Lau Reviewed-By: Wyatt Preul Reviewed-By: Matteo Collina Reviewed-By: Tobias Nießen Reviewed-By: Jiawen Geng Reviewed-By: Chengzhong Wu Reviewed-By: Daniel Bevenius --- src/env-inl.h | 15 + src/env.h | 8 +- src/node_binding.cc | 1 + src/node_config.cc | 3 + src/node_options.cc | 4 + src/node_options.h | 1 + src/node_wasi.cc | 1802 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/node_wasi.h | 103 +++ 8 files changed, 1936 insertions(+), 1 deletion(-) create mode 100644 src/node_wasi.cc create mode 100644 src/node_wasi.h (limited to 'src') diff --git a/src/env-inl.h b/src/env-inl.h index d34bd03c7c..d75b4ea743 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -1102,6 +1102,21 @@ inline void Environment::SetProtoMethodNoSideEffect( t->SetClassName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility. } +inline void Environment::SetInstanceMethod(v8::Local that, + const char* name, + v8::FunctionCallback callback) { + v8::Local signature = v8::Signature::New(isolate(), that); + v8::Local t = + NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow, + v8::SideEffectType::kHasSideEffect); + // kInternalized strings are created in the old space. + const v8::NewStringType type = v8::NewStringType::kInternalized; + v8::Local name_string = + v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked(); + that->InstanceTemplate()->Set(name_string, t); + t->SetClassName(name_string); +} + void Environment::AddCleanupHook(void (*fn)(void*), void* arg) { auto insertion_info = cleanup_hooks_.emplace(CleanupHookCallback { fn, arg, cleanup_hook_counter_++ diff --git a/src/env.h b/src/env.h index c0c8ac0db4..c25a03ea1e 100644 --- a/src/env.h +++ b/src/env.h @@ -541,7 +541,8 @@ struct ContextInfo { #define DEBUG_CATEGORY_NAMES(V) \ NODE_ASYNC_PROVIDER_TYPES(V) \ V(INSPECTOR_SERVER) \ - V(INSPECTOR_PROFILER) + V(INSPECTOR_PROFILER) \ + V(WASI) enum class DebugCategory { #define V(name) name, @@ -1114,6 +1115,11 @@ class Environment : public MemoryRetainer { const char* name, v8::FunctionCallback callback); + inline void SetInstanceMethod(v8::Local that, + const char* name, + v8::FunctionCallback callback); + + // Safe variants denote the function has no side effects. inline void SetMethodNoSideEffect(v8::Local that, const char* name, diff --git a/src/node_binding.cc b/src/node_binding.cc index f57ddb54b6..82836585c5 100644 --- a/src/node_binding.cc +++ b/src/node_binding.cc @@ -85,6 +85,7 @@ V(util) \ V(uv) \ V(v8) \ + V(wasi) \ V(worker) \ V(zlib) diff --git a/src/node_config.cc b/src/node_config.cc index 92985dff2f..16050bdd5b 100644 --- a/src/node_config.cc +++ b/src/node_config.cc @@ -84,6 +84,9 @@ static void Initialize(Local target, READONLY_PROPERTY(target, "hasCachedBuiltins", v8::Boolean::New(isolate, native_module::has_code_cache)); + + if (env->options()->experimental_wasi) + READONLY_TRUE_PROPERTY(target, "experimentalWasi"); } // InitConfig } // namespace node diff --git a/src/node_options.cc b/src/node_options.cc index 0bc6730156..44b125775f 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -347,6 +347,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { &EnvironmentOptions::experimental_report, kAllowedInEnvironment); #endif // NODE_REPORT + AddOption("--experimental-wasi-unstable-preview0", + "experimental WASI support", + &EnvironmentOptions::experimental_wasi, + kAllowedInEnvironment); AddOption("--expose-internals", "", &EnvironmentOptions::expose_internals); AddOption("--frozen-intrinsics", "experimental frozen intrinsics support", diff --git a/src/node_options.h b/src/node_options.h index ce0cee5fe5..adc0ef783f 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -151,6 +151,7 @@ class EnvironmentOptions : public Options { #ifdef NODE_REPORT bool experimental_report = false; #endif // NODE_REPORT + bool experimental_wasi = false; std::string eval_string; bool print_eval = false; bool force_repl = false; diff --git a/src/node_wasi.cc b/src/node_wasi.cc new file mode 100644 index 0000000000..8de7f1fc1c --- /dev/null +++ b/src/node_wasi.cc @@ -0,0 +1,1802 @@ +#include "env-inl.h" +#include "base_object-inl.h" +#include "debug_utils.h" +#include "util-inl.h" +#include "node.h" +#include "uv.h" +#include "uvwasi.h" +#include "node_wasi.h" + +namespace node { +namespace wasi { + +static inline bool is_access_oob(size_t mem_size, + uint32_t offset, + uint32_t buf_size) { + return offset + buf_size > mem_size; +} + +template +inline void Debug(WASI* wasi, Args&&... args) { + Debug(wasi->env(), DebugCategory::WASI, std::forward(args)...); +} + +#define RETURN_IF_BAD_ARG_COUNT(args, expected) \ + do { \ + if ((args).Length() != (expected)) { \ + (args).GetReturnValue().Set(UVWASI_EINVAL); \ + return; \ + } \ + } while (0) + +#define CHECK_TO_TYPE_OR_RETURN(args, input, type, result) \ + do { \ + if (!(input)->Is##type()) { \ + (args).GetReturnValue().Set(UVWASI_EINVAL); \ + return; \ + } \ + (result) = (input).As()->Value(); \ + } while (0) + +#define UNWRAP_BIGINT_OR_RETURN(args, input, type, result) \ + do { \ + if (!(input)->IsBigInt()) { \ + (args).GetReturnValue().Set(UVWASI_EINVAL); \ + return; \ + } \ + Local js_value = (input).As(); \ + bool lossless; \ + (result) = js_value->type ## Value(&lossless); \ + } while (0) + +#define GET_BACKING_STORE_OR_RETURN(wasi, args, mem_ptr, mem_size) \ + do { \ + uvwasi_errno_t err = (wasi)->backingStore((mem_ptr), (mem_size)); \ + if (err != UVWASI_ESUCCESS) { \ + (args).GetReturnValue().Set(err); \ + return; \ + } \ + } while (0) + +#define CHECK_BOUNDS_OR_RETURN(args, mem_size, offset, buf_size) \ + do { \ + if (is_access_oob((mem_size), (offset), (buf_size))) { \ + (args).GetReturnValue().Set(UVWASI_EOVERFLOW); \ + return; \ + } \ + } while (0) + + +using v8::Array; +using v8::ArrayBuffer; +using v8::BackingStore; +using v8::BigInt; +using v8::Context; +using v8::FunctionCallbackInfo; +using v8::FunctionTemplate; +using v8::Local; +using v8::Object; +using v8::String; +using v8::Uint32; +using v8::Value; + + +WASI::WASI(Environment* env, + Local object, + uvwasi_options_t* options) : BaseObject(env, object) { + MakeWeak(); + CHECK_EQ(uvwasi_init(&uvw_, options), UVWASI_ESUCCESS); +} + + +WASI::~WASI() { + uvwasi_destroy(&uvw_); +} + + +void WASI::New(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + CHECK_EQ(args.Length(), 3); + CHECK(args[0]->IsArray()); + CHECK(args[1]->IsArray()); + CHECK(args[2]->IsArray()); + + Environment* env = Environment::GetCurrent(args); + Local context = env->context(); + Local argv = args[0].As(); + const uint32_t argc = argv->Length(); + uvwasi_options_t options; + + options.fd_table_size = 3; + options.argc = argc; + options.argv = argc == 0 ? nullptr : new char*[argc]; + + for (uint32_t i = 0; i < argc; i++) { + auto arg = argv->Get(context, i).ToLocalChecked(); + CHECK(arg->IsString()); + node::Utf8Value str(env->isolate(), arg); + options.argv[i] = strdup(*str); + CHECK_NOT_NULL(options.argv[i]); + } + + Local env_pairs = args[1].As(); + const uint32_t envc = env_pairs->Length(); + options.envp = new char*[envc + 1]; + for (uint32_t i = 0; i < envc; i++) { + auto pair = env_pairs->Get(context, i).ToLocalChecked(); + CHECK(pair->IsString()); + node::Utf8Value str(env->isolate(), pair); + options.envp[i] = strdup(*str); + CHECK_NOT_NULL(options.envp[i]); + } + options.envp[envc] = nullptr; + + Local preopens = args[2].As(); + CHECK_EQ(preopens->Length() % 2, 0); + options.preopenc = preopens->Length() / 2; + options.preopens = UncheckedCalloc(options.preopenc); + int index = 0; + for (uint32_t i = 0; i < preopens->Length(); i += 2) { + auto mapped = preopens->Get(context, i).ToLocalChecked(); + auto real = preopens->Get(context, i + 1).ToLocalChecked(); + CHECK(mapped->IsString()); + CHECK(real->IsString()); + node::Utf8Value mapped_path(env->isolate(), mapped); + node::Utf8Value real_path(env->isolate(), real); + options.preopens[index].mapped_path = strdup(*mapped_path); + options.preopens[index].real_path = strdup(*real_path); + index++; + } + + new WASI(env, args.This(), &options); + + if (options.argv != nullptr) { + for (uint32_t i = 0; i < argc; i++) + free(options.argv[i]); + delete[] options.argv; + } + + if (options.envp != nullptr) { + for (uint32_t i = 0; options.envp[i]; i++) + free(options.envp[i]); + delete[] options.envp; + } +} + + +void WASI::ArgsGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t argv_offset; + uint32_t argv_buf_offset; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, argv_offset); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, argv_buf_offset); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "args_get(%d, %d)\n", argv_offset, argv_buf_offset); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, + mem_size, + argv_buf_offset, + wasi->uvw_.argv_buf_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, argv_offset, wasi->uvw_.argc * 4); + std::vector argv(wasi->uvw_.argc); + char* argv_buf = &memory[argv_buf_offset]; + uvwasi_errno_t err = uvwasi_args_get(&wasi->uvw_, argv.data(), argv_buf); + + if (err == UVWASI_ESUCCESS) { + for (size_t i = 0; i < wasi->uvw_.argc; i++) { + uint32_t offset = argv_buf_offset + (argv[i] - argv[0]); + wasi->writeUInt32(memory, offset, argv_offset + (i * 4)); + } + } + + args.GetReturnValue().Set(err); +} + + +void WASI::ArgsSizesGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t argc_offset; + uint32_t argv_buf_offset; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, argc_offset); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, argv_buf_offset); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "args_sizes_get(%d, %d)\n", argc_offset, argv_buf_offset); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, argc_offset, 4); + CHECK_BOUNDS_OR_RETURN(args, mem_size, argv_buf_offset, 4); + size_t argc; + size_t argv_buf_size; + uvwasi_errno_t err = uvwasi_args_sizes_get(&wasi->uvw_, + &argc, + &argv_buf_size); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, argc, argc_offset); + wasi->writeUInt32(memory, argv_buf_size, argv_buf_offset); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::ClockResGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t clock_id; + uint32_t resolution_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, clock_id); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, resolution_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "clock_res_get(%d, %d)\n", clock_id, resolution_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, resolution_ptr, 8); + uvwasi_timestamp_t resolution; + uvwasi_errno_t err = uvwasi_clock_res_get(&wasi->uvw_, + clock_id, + &resolution); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt64(memory, resolution, resolution_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::ClockTimeGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t clock_id; + uint64_t precision; + uint32_t time_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, clock_id); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, precision); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, time_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "clock_time_get(%d, %d, %d)\n", clock_id, precision, time_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, time_ptr, 8); + uvwasi_timestamp_t time; + uvwasi_errno_t err = uvwasi_clock_time_get(&wasi->uvw_, + clock_id, + precision, + &time); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt64(memory, time, time_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::EnvironGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t environ_offset; + uint32_t environ_buf_offset; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, environ_offset); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, environ_buf_offset); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "environ_get(%d, %d)\n", environ_offset, environ_buf_offset); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, + mem_size, + environ_buf_offset, + wasi->uvw_.env_buf_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, environ_offset, wasi->uvw_.envc * 4); + std::vector environment(wasi->uvw_.envc); + char* environ_buf = &memory[environ_buf_offset]; + uvwasi_errno_t err = uvwasi_environ_get(&wasi->uvw_, + environment.data(), + environ_buf); + + if (err == UVWASI_ESUCCESS) { + for (size_t i = 0; i < wasi->uvw_.envc; i++) { + uint32_t offset = environ_buf_offset + (environment[i] - environment[0]); + wasi->writeUInt32(memory, offset, environ_offset + (i * 4)); + } + } + + args.GetReturnValue().Set(err); +} + + +void WASI::EnvironSizesGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t envc_offset; + uint32_t env_buf_offset; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, envc_offset); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, env_buf_offset); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "environ_sizes_get(%d, %d)\n", envc_offset, env_buf_offset); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, envc_offset, 4); + CHECK_BOUNDS_OR_RETURN(args, mem_size, env_buf_offset, 4); + size_t envc; + size_t env_buf_size; + uvwasi_errno_t err = uvwasi_environ_sizes_get(&wasi->uvw_, + &envc, + &env_buf_size); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, envc, envc_offset); + wasi->writeUInt32(memory, env_buf_size, env_buf_offset); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::FdAdvise(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t offset; + uint64_t len; + uint8_t advice; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, offset); + UNWRAP_BIGINT_OR_RETURN(args, args[2], Uint64, len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, advice); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_advise(%d, %d, %d, %d)\n", fd, offset, len, advice); + uvwasi_errno_t err = uvwasi_fd_advise(&wasi->uvw_, fd, offset, len, advice); + args.GetReturnValue().Set(err); +} + + +void WASI::FdAllocate(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t offset; + uint64_t len; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, offset); + UNWRAP_BIGINT_OR_RETURN(args, args[2], Uint64, len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_allocate(%d, %d, %d)\n", fd, offset, len); + uvwasi_errno_t err = uvwasi_fd_allocate(&wasi->uvw_, fd, offset, len); + args.GetReturnValue().Set(err); +} + + +void WASI::FdClose(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_close(%d)\n", fd); + uvwasi_errno_t err = uvwasi_fd_close(&wasi->uvw_, fd); + args.GetReturnValue().Set(err); +} + + +void WASI::FdDatasync(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_datasync(%d)\n", fd); + uvwasi_errno_t err = uvwasi_fd_datasync(&wasi->uvw_, fd); + args.GetReturnValue().Set(err); +} + + +void WASI::FdFdstatGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t buf; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_fdstat_get(%d, %d)\n", fd, buf); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf, 24); + uvwasi_fdstat_t stats; + uvwasi_errno_t err = uvwasi_fd_fdstat_get(&wasi->uvw_, fd, &stats); + + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt8(memory, stats.fs_filetype, buf); + wasi->writeUInt16(memory, stats.fs_flags, buf + 2); + wasi->writeUInt64(memory, stats.fs_rights_base, buf + 8); + wasi->writeUInt64(memory, stats.fs_rights_inheriting, buf + 16); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::FdFdstatSetFlags(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint16_t flags; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, flags); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_fdstat_set_flags(%d, %d)\n", fd, flags); + uvwasi_errno_t err = uvwasi_fd_fdstat_set_flags(&wasi->uvw_, fd, flags); + args.GetReturnValue().Set(err); +} + + +void WASI::FdFdstatSetRights(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t fs_rights_base; + uint64_t fs_rights_inheriting; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, fs_rights_base); + UNWRAP_BIGINT_OR_RETURN(args, args[2], Uint64, fs_rights_inheriting); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "fd_fdstat_set_rights(%d, %d, %d)\n", + fd, + fs_rights_base, + fs_rights_inheriting); + uvwasi_errno_t err = uvwasi_fd_fdstat_set_rights(&wasi->uvw_, + fd, + fs_rights_base, + fs_rights_inheriting); + args.GetReturnValue().Set(err); +} + + +void WASI::FdFilestatGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t buf; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_filestat_get(%d, %d)\n", fd, buf); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf, 56); + uvwasi_filestat_t stats; + uvwasi_errno_t err = uvwasi_fd_filestat_get(&wasi->uvw_, fd, &stats); + + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt64(memory, stats.st_dev, buf); + wasi->writeUInt64(memory, stats.st_ino, buf + 8); + wasi->writeUInt8(memory, stats.st_filetype, buf + 16); + wasi->writeUInt32(memory, stats.st_nlink, buf + 20); + wasi->writeUInt64(memory, stats.st_size, buf + 24); + wasi->writeUInt64(memory, stats.st_atim, buf + 32); + wasi->writeUInt64(memory, stats.st_mtim, buf + 40); + wasi->writeUInt64(memory, stats.st_ctim, buf + 48); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::FdFilestatSetSize(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t st_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, st_size); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_filestat_set_size(%d, %d)\n", fd, st_size); + uvwasi_errno_t err = uvwasi_fd_filestat_set_size(&wasi->uvw_, fd, st_size); + args.GetReturnValue().Set(err); +} + + +void WASI::FdFilestatSetTimes(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint64_t st_atim; + uint64_t st_mtim; + uint16_t fst_flags; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Uint64, st_atim); + UNWRAP_BIGINT_OR_RETURN(args, args[2], Uint64, st_mtim); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, fst_flags); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "fd_filestat_set_times(%d, %d, %d, %d)\n", + fd, + st_atim, + st_mtim, + fst_flags); + uvwasi_errno_t err = uvwasi_fd_filestat_set_times(&wasi->uvw_, + fd, + st_atim, + st_mtim, + fst_flags); + args.GetReturnValue().Set(err); +} + + +void WASI::FdPread(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t iovs_ptr; + uint32_t iovs_len; + uint64_t offset; + uint32_t nread_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, iovs_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, iovs_len); + UNWRAP_BIGINT_OR_RETURN(args, args[3], Uint64, offset); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, nread_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "uvwasi_fd_pread(%d, %d, %d, %d, %d)\n", + fd, + iovs_ptr, + iovs_len, + offset, + nread_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, iovs_ptr, iovs_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nread_ptr, 4); + uvwasi_iovec_t* iovs = UncheckedCalloc(iovs_len); + + if (iovs == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < iovs_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, iovs_ptr); + wasi->readUInt32(memory, &buf_len, iovs_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(iovs); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + iovs_ptr += 8; + iovs[i].buf = static_cast(&memory[buf_ptr]); + iovs[i].buf_len = buf_len; + } + + size_t nread; + uvwasi_errno_t err = uvwasi_fd_pread(&wasi->uvw_, + fd, + iovs, + iovs_len, + offset, + &nread); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, nread, nread_ptr); + + free(iovs); + args.GetReturnValue().Set(err); +} + + +void WASI::FdPrestatGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t buf; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_prestat_get(%d, %d)\n", fd, buf); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf, 8); + uvwasi_prestat_t prestat; + uvwasi_errno_t err = uvwasi_fd_prestat_get(&wasi->uvw_, fd, &prestat); + + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, prestat.pr_type, buf); + wasi->writeUInt32(memory, prestat.u.dir.pr_name_len, buf + 4); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::FdPrestatDirName(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_prestat_dir_name(%d, %d, %d)\n", fd, path_ptr, path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_fd_prestat_dir_name(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::FdPwrite(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t iovs_ptr; + uint32_t iovs_len; + uint64_t offset; + uint32_t nwritten_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, iovs_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, iovs_len); + UNWRAP_BIGINT_OR_RETURN(args, args[3], Uint64, offset); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, nwritten_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "uvwasi_fd_pwrite(%d, %d, %d, %d, %d)\n", + fd, + iovs_ptr, + iovs_len, + offset, + nwritten_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, iovs_ptr, iovs_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nwritten_ptr, 4); + uvwasi_ciovec_t* iovs = UncheckedCalloc(iovs_len); + + if (iovs == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < iovs_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, iovs_ptr); + wasi->readUInt32(memory, &buf_len, iovs_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(iovs); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + iovs_ptr += 8; + iovs[i].buf = static_cast(&memory[buf_ptr]); + iovs[i].buf_len = buf_len; + } + + size_t nwritten; + uvwasi_errno_t err = uvwasi_fd_pwrite(&wasi->uvw_, + fd, + iovs, + iovs_len, + offset, + &nwritten); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, nwritten, nwritten_ptr); + + free(iovs); + args.GetReturnValue().Set(err); +} + + +void WASI::FdRead(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t iovs_ptr; + uint32_t iovs_len; + uint32_t nread_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, iovs_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, iovs_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, nread_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_read(%d, %d, %d, %d)\n", fd, iovs_ptr, iovs_len, nread_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, iovs_ptr, iovs_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nread_ptr, 4); + uvwasi_iovec_t* iovs = UncheckedCalloc(iovs_len); + + if (iovs == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < iovs_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, iovs_ptr); + wasi->readUInt32(memory, &buf_len, iovs_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(iovs); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + iovs_ptr += 8; + iovs[i].buf = static_cast(&memory[buf_ptr]); + iovs[i].buf_len = buf_len; + } + + size_t nread; + uvwasi_errno_t err = uvwasi_fd_read(&wasi->uvw_, + fd, + iovs, + iovs_len, + &nread); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, nread, nread_ptr); + + free(iovs); + args.GetReturnValue().Set(err); +} + + +void WASI::FdReaddir(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t buf_ptr; + uint32_t buf_len; + uint64_t cookie; + uint32_t bufused_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, buf_len); + UNWRAP_BIGINT_OR_RETURN(args, args[3], Uint64, cookie); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, bufused_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "uvwasi_fd_readdir(%d, %d, %d, %d, %d)\n", + fd, + buf_ptr, + buf_len, + cookie, + bufused_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf_ptr, buf_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, bufused_ptr, 4); + size_t bufused; + uvwasi_errno_t err = uvwasi_fd_readdir(&wasi->uvw_, + fd, + &memory[buf_ptr], + buf_len, + cookie, + &bufused); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, bufused, bufused_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::FdRenumber(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t from; + uint32_t to; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, from); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, to); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_renumber(%d, %d)\n", from, to); + uvwasi_errno_t err = uvwasi_fd_renumber(&wasi->uvw_, from, to); + args.GetReturnValue().Set(err); +} + + +void WASI::FdSeek(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + int64_t offset; + uint8_t whence; + uint32_t newoffset_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + UNWRAP_BIGINT_OR_RETURN(args, args[1], Int64, offset); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, whence); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, newoffset_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_seek(%d, %d, %d, %d)\n", fd, offset, whence, newoffset_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, newoffset_ptr, 8); + uvwasi_filesize_t newoffset; + uvwasi_errno_t err = uvwasi_fd_seek(&wasi->uvw_, + fd, + offset, + whence, + &newoffset); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt64(memory, newoffset, newoffset_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::FdSync(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_sync(%d)\n", fd); + uvwasi_errno_t err = uvwasi_fd_sync(&wasi->uvw_, fd); + args.GetReturnValue().Set(err); +} + + +void WASI::FdTell(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t offset_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, offset_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "fd_tell(%d, %d)\n", fd, offset_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, offset_ptr, 8); + uvwasi_filesize_t offset; + uvwasi_errno_t err = uvwasi_fd_tell(&wasi->uvw_, fd, &offset); + + if (err == UVWASI_ESUCCESS) + wasi->writeUInt64(memory, offset, offset_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::FdWrite(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t iovs_ptr; + uint32_t iovs_len; + uint32_t nwritten_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, iovs_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, iovs_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, nwritten_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "fd_write(%d, %d, %d, %d)\n", + fd, + iovs_ptr, + iovs_len, + nwritten_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, iovs_ptr, iovs_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nwritten_ptr, 4); + uvwasi_ciovec_t* iovs = UncheckedCalloc(iovs_len); + + if (iovs == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < iovs_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, iovs_ptr); + wasi->readUInt32(memory, &buf_len, iovs_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(iovs); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + iovs_ptr += 8; + iovs[i].buf = static_cast(&memory[buf_ptr]); + iovs[i].buf_len = buf_len; + } + + size_t nwritten; + uvwasi_errno_t err = uvwasi_fd_write(&wasi->uvw_, + fd, + iovs, + iovs_len, + &nwritten); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, nwritten, nwritten_ptr); + + free(iovs); + args.GetReturnValue().Set(err); +} + + +void WASI::PathCreateDirectory(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "path_create_directory(%d, %d, %d)\n", fd, path_ptr, path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_path_create_directory(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathFilestatGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t flags; + uint32_t path_ptr; + uint32_t path_len; + uint32_t buf_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, flags); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, buf_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_filestat_get(%d, %d, %d, %d, %d)\n", + fd, + path_ptr, + path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf_ptr, 56); + uvwasi_filestat_t stats; + uvwasi_errno_t err = uvwasi_path_filestat_get(&wasi->uvw_, + fd, + flags, + &memory[path_ptr], + path_len, + &stats); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt64(memory, stats.st_dev, buf_ptr); + wasi->writeUInt64(memory, stats.st_ino, buf_ptr + 8); + wasi->writeUInt8(memory, stats.st_filetype, buf_ptr + 16); + wasi->writeUInt32(memory, stats.st_nlink, buf_ptr + 20); + wasi->writeUInt64(memory, stats.st_size, buf_ptr + 24); + wasi->writeUInt64(memory, stats.st_atim, buf_ptr + 32); + wasi->writeUInt64(memory, stats.st_mtim, buf_ptr + 40); + wasi->writeUInt64(memory, stats.st_ctim, buf_ptr + 48); + } + + args.GetReturnValue().Set(err); +} + + +void WASI::PathFilestatSetTimes(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t flags; + uint32_t path_ptr; + uint32_t path_len; + uint64_t st_atim; + uint64_t st_mtim; + uint16_t fst_flags; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 7); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, flags); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, path_len); + UNWRAP_BIGINT_OR_RETURN(args, args[4], Uint64, st_atim); + UNWRAP_BIGINT_OR_RETURN(args, args[5], Uint64, st_mtim); + CHECK_TO_TYPE_OR_RETURN(args, args[6], Uint32, fst_flags); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_filestat_set_times(%d, %d, %d, %d, %d, %d, %d)\n", + fd, + flags, + path_ptr, + path_len, + st_atim, + st_mtim, + fst_flags); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_path_filestat_set_times(&wasi->uvw_, + fd, + flags, + &memory[path_ptr], + path_len, + st_atim, + st_mtim, + fst_flags); + args.GetReturnValue().Set(err); +} + + +void WASI::PathLink(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t old_fd; + uint32_t old_flags; + uint32_t old_path_ptr; + uint32_t old_path_len; + uint32_t new_fd; + uint32_t new_path_ptr; + uint32_t new_path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 7); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, old_fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, old_flags); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, old_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, old_path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, new_fd); + CHECK_TO_TYPE_OR_RETURN(args, args[5], Uint32, new_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[6], Uint32, new_path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_link(%d, %d, %d, %d, %d, %d, %d)\n", + old_fd, + old_flags, + old_path_ptr, + old_path_len, + new_fd, + new_path_ptr, + new_path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, old_path_ptr, old_path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, new_path_ptr, new_path_len); + uvwasi_errno_t err = uvwasi_path_link(&wasi->uvw_, + old_fd, + old_flags, + &memory[old_path_ptr], + old_path_len, + new_fd, + &memory[new_path_ptr], + new_path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathOpen(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t dirfd; + uint32_t dirflags; + uint32_t path_ptr; + uint32_t path_len; + uint32_t o_flags; + uint64_t fs_rights_base; + uint64_t fs_rights_inheriting; + uint32_t fs_flags; + uint32_t fd_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 9); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, dirfd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, dirflags); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, o_flags); + UNWRAP_BIGINT_OR_RETURN(args, args[5], Uint64, fs_rights_base); + UNWRAP_BIGINT_OR_RETURN(args, args[6], Uint64, fs_rights_inheriting); + CHECK_TO_TYPE_OR_RETURN(args, args[7], Uint32, fs_flags); + CHECK_TO_TYPE_OR_RETURN(args, args[8], Uint32, fd_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_open(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", + dirfd, + dirflags, + path_ptr, + path_len, + o_flags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, + fd_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, fd_ptr, 4); + uvwasi_fd_t fd; + uvwasi_errno_t err = uvwasi_path_open(&wasi->uvw_, + dirfd, + dirflags, + &memory[path_ptr], + path_len, + static_cast(o_flags), + fs_rights_base, + fs_rights_inheriting, + static_cast(fs_flags), + &fd); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, fd, fd_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::PathReadlink(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + uint32_t buf_ptr; + uint32_t buf_len; + uint32_t bufused_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 6); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, buf_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, buf_len); + CHECK_TO_TYPE_OR_RETURN(args, args[5], Uint32, bufused_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_readlink(%d, %d, %d, %d, %d, %d)\n", + fd, + path_ptr, + path_len, + buf_ptr, + buf_len, + bufused_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf_ptr, buf_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, bufused_ptr, 4); + size_t bufused; + uvwasi_errno_t err = uvwasi_path_readlink(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len, + &memory[buf_ptr], + buf_len, + &bufused); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, bufused, bufused_ptr); + + args.GetReturnValue().Set(err); +} + + +void WASI::PathRemoveDirectory(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "path_remove_directory(%d, %d, %d)\n", fd, path_ptr, path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_path_remove_directory(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathRename(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t old_fd; + uint32_t old_path_ptr; + uint32_t old_path_len; + uint32_t new_fd; + uint32_t new_path_ptr; + uint32_t new_path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 6); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, old_fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, old_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, old_path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, new_fd); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, new_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[5], Uint32, new_path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_rename(%d, %d, %d, %d, %d, %d)\n", + old_fd, + old_path_ptr, + old_path_len, + new_fd, + new_path_ptr, + new_path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, old_path_ptr, old_path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, new_path_ptr, new_path_len); + uvwasi_errno_t err = uvwasi_path_rename(&wasi->uvw_, + old_fd, + &memory[old_path_ptr], + old_path_len, + new_fd, + &memory[new_path_ptr], + new_path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathSymlink(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t old_path_ptr; + uint32_t old_path_len; + uint32_t fd; + uint32_t new_path_ptr; + uint32_t new_path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, old_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, old_path_len); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, new_path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, new_path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "path_symlink(%d, %d, %d, %d, %d)\n", + old_path_ptr, + old_path_len, + fd, + new_path_ptr, + new_path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, old_path_ptr, old_path_len); + CHECK_BOUNDS_OR_RETURN(args, mem_size, new_path_ptr, new_path_len); + uvwasi_errno_t err = uvwasi_path_symlink(&wasi->uvw_, + &memory[old_path_ptr], + old_path_len, + fd, + &memory[new_path_ptr], + new_path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PathUnlinkFile(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t fd; + uint32_t path_ptr; + uint32_t path_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 3); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, fd); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, path_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, path_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "path_unlink_file(%d, %d, %d)\n", fd, path_ptr, path_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, path_ptr, path_len); + uvwasi_errno_t err = uvwasi_path_unlink_file(&wasi->uvw_, + fd, + &memory[path_ptr], + path_len); + args.GetReturnValue().Set(err); +} + + +void WASI::PollOneoff(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t in_ptr; + uint32_t out_ptr; + uint32_t nsubscriptions; + uint32_t nevents_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 4); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, in_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, out_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, nsubscriptions); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, nevents_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "poll_oneoff(%d, %d, %d, %d)\n", + in_ptr, + out_ptr, + nsubscriptions, + nevents_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, in_ptr, nsubscriptions * 56); + CHECK_BOUNDS_OR_RETURN(args, mem_size, out_ptr, nsubscriptions * 32); + CHECK_BOUNDS_OR_RETURN(args, mem_size, nevents_ptr, 4); + uvwasi_subscription_t* in = + UncheckedCalloc(nsubscriptions); + + if (in == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + uvwasi_event_t* out = UncheckedCalloc(nsubscriptions); + + if (out == nullptr) { + free(in); + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < nsubscriptions; ++i) { + uvwasi_subscription_t sub = in[i]; + wasi->readUInt64(memory, &sub.userdata, in_ptr); + wasi->readUInt8(memory, &sub.type, in_ptr + 8); + + if (sub.type == UVWASI_EVENTTYPE_CLOCK) { + wasi->readUInt64(memory, &sub.u.clock.identifier, in_ptr + 16); + wasi->readUInt32(memory, &sub.u.clock.clock_id, in_ptr + 24); + wasi->readUInt64(memory, &sub.u.clock.timeout, in_ptr + 32); + wasi->readUInt64(memory, &sub.u.clock.precision, in_ptr + 40); + wasi->readUInt16(memory, &sub.u.clock.flags, in_ptr + 48); + } else if (sub.type == UVWASI_EVENTTYPE_FD_READ || + sub.type == UVWASI_EVENTTYPE_FD_WRITE) { + wasi->readUInt32(memory, &sub.u.fd_readwrite.fd, in_ptr + 16); + } + + in_ptr += 56; + } + + size_t nevents; + uvwasi_errno_t err = uvwasi_poll_oneoff(&wasi->uvw_, + in, + out, + nsubscriptions, + &nevents); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, nevents, nevents_ptr); + + for (uint32_t i = 0; i < nsubscriptions; ++i) { + uvwasi_event_t event = out[i]; + + wasi->writeUInt64(memory, event.userdata, out_ptr); + wasi->writeUInt16(memory, event.error, out_ptr + 8); + wasi->writeUInt8(memory, event.type, out_ptr + 10); + + if (event.type == UVWASI_EVENTTYPE_FD_READ || + event.type == UVWASI_EVENTTYPE_FD_WRITE) { + wasi->writeUInt64(memory, event.u.fd_readwrite.nbytes, out_ptr + 16); + wasi->writeUInt16(memory, event.u.fd_readwrite.flags, out_ptr + 24); + } + + out_ptr += 32; + } + } + + free(in); + free(out); + args.GetReturnValue().Set(err); +} + + +void WASI::ProcExit(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t code; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, code); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "proc_exit(%d)\n", code); + args.GetReturnValue().Set(uvwasi_proc_exit(&wasi->uvw_, code)); +} + + +void WASI::ProcRaise(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t sig; + RETURN_IF_BAD_ARG_COUNT(args, 1); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, sig); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "proc_raise(%d)\n", sig); + uvwasi_errno_t err = uvwasi_proc_raise(&wasi->uvw_, sig); + args.GetReturnValue().Set(err); +} + + +void WASI::RandomGet(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t buf_ptr; + uint32_t buf_len; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, buf_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, buf_len); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "random_get(%d, %d)\n", buf_ptr, buf_len); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, buf_ptr, buf_len); + uvwasi_errno_t err = uvwasi_random_get(&wasi->uvw_, + &memory[buf_ptr], + buf_len); + args.GetReturnValue().Set(err); +} + + +void WASI::SchedYield(const FunctionCallbackInfo& args) { + WASI* wasi; + RETURN_IF_BAD_ARG_COUNT(args, 0); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "sched_yield()\n"); + uvwasi_errno_t err = uvwasi_sched_yield(&wasi->uvw_); + args.GetReturnValue().Set(err); +} + + +void WASI::SockRecv(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t sock; + uint32_t ri_data_ptr; + uint32_t ri_data_len; + uint16_t ri_flags; + uint32_t ro_datalen_ptr; + uint16_t ro_flags_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 6); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, sock); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, ri_data_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, ri_data_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, ri_flags); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, ro_datalen_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[5], Uint32, ro_flags_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "sock_recv(%d, %d, %d, %d, %d, %d)\n", + sock, + ri_data_ptr, + ri_data_len, + ri_flags, + ro_datalen_ptr, + ro_flags_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, ri_data_ptr, ri_data_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, ro_datalen_ptr, 4); + CHECK_BOUNDS_OR_RETURN(args, mem_size, ro_flags_ptr, 4); + uvwasi_iovec_t* ri_data = UncheckedCalloc(ri_data_len); + + if (ri_data == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < ri_data_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, ri_data_ptr); + wasi->readUInt32(memory, &buf_len, ri_data_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(ri_data); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + ri_data_ptr += 8; + ri_data[i].buf = static_cast(&memory[buf_ptr]); + ri_data[i].buf_len = buf_len; + } + + size_t ro_datalen; + uvwasi_roflags_t ro_flags; + uvwasi_errno_t err = uvwasi_sock_recv(&wasi->uvw_, + sock, + ri_data, + ri_data_len, + ri_flags, + &ro_datalen, + &ro_flags); + if (err == UVWASI_ESUCCESS) { + wasi->writeUInt32(memory, ro_datalen, ro_datalen_ptr); + wasi->writeUInt32(memory, ro_flags, ro_flags_ptr); + } + + free(ri_data); + args.GetReturnValue().Set(err); +} + + +void WASI::SockSend(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t sock; + uint32_t si_data_ptr; + uint32_t si_data_len; + uint16_t si_flags; + uint32_t so_datalen_ptr; + char* memory; + size_t mem_size; + RETURN_IF_BAD_ARG_COUNT(args, 5); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, sock); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, si_data_ptr); + CHECK_TO_TYPE_OR_RETURN(args, args[2], Uint32, si_data_len); + CHECK_TO_TYPE_OR_RETURN(args, args[3], Uint32, si_flags); + CHECK_TO_TYPE_OR_RETURN(args, args[4], Uint32, so_datalen_ptr); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, + "sock_send(%d, %d, %d, %d, %d)\n", + sock, + si_data_ptr, + si_data_len, + si_flags, + so_datalen_ptr); + GET_BACKING_STORE_OR_RETURN(wasi, args, &memory, &mem_size); + CHECK_BOUNDS_OR_RETURN(args, mem_size, si_data_ptr, si_data_len * 8); + CHECK_BOUNDS_OR_RETURN(args, mem_size, so_datalen_ptr, 4); + uvwasi_ciovec_t* si_data = UncheckedCalloc(si_data_len); + + if (si_data == nullptr) { + args.GetReturnValue().Set(UVWASI_ENOMEM); + return; + } + + for (uint32_t i = 0; i < si_data_len; ++i) { + uint32_t buf_ptr; + uint32_t buf_len; + + wasi->readUInt32(memory, &buf_ptr, si_data_ptr); + wasi->readUInt32(memory, &buf_len, si_data_ptr + 4); + + if (is_access_oob(mem_size, buf_ptr, buf_len)) { + free(si_data); + args.GetReturnValue().Set(UVWASI_EOVERFLOW); + return; + } + + si_data_ptr += 8; + si_data[i].buf = static_cast(&memory[buf_ptr]); + si_data[i].buf_len = buf_len; + } + + size_t so_datalen; + uvwasi_errno_t err = uvwasi_sock_send(&wasi->uvw_, + sock, + si_data, + si_data_len, + si_flags, + &so_datalen); + if (err == UVWASI_ESUCCESS) + wasi->writeUInt32(memory, so_datalen, so_datalen_ptr); + + free(si_data); + args.GetReturnValue().Set(err); +} + + +void WASI::SockShutdown(const FunctionCallbackInfo& args) { + WASI* wasi; + uint32_t sock; + uint8_t how; + RETURN_IF_BAD_ARG_COUNT(args, 2); + CHECK_TO_TYPE_OR_RETURN(args, args[0], Uint32, sock); + CHECK_TO_TYPE_OR_RETURN(args, args[1], Uint32, how); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + Debug(wasi, "sock_shutdown(%d, %d)\n", sock, how); + uvwasi_errno_t err = uvwasi_sock_shutdown(&wasi->uvw_, sock, how); + args.GetReturnValue().Set(err); +} + + +void WASI::_SetMemory(const FunctionCallbackInfo& args) { + WASI* wasi; + CHECK_EQ(args.Length(), 1); + CHECK(args[0]->IsObject()); + ASSIGN_OR_RETURN_UNWRAP(&wasi, args.This()); + wasi->memory_.Reset(wasi->env()->isolate(), args[0].As()); +} + + +void WASI::readUInt8(char* memory, uint8_t* value, uint32_t offset) { + CHECK_NOT_NULL(memory); + CHECK_NOT_NULL(value); + *value = memory[offset] & 0xFF; +} + + +void WASI::readUInt16(char* memory, uint16_t* value, uint32_t offset) { + CHECK_NOT_NULL(memory); + CHECK_NOT_NULL(value); + *value = (memory[offset] & 0xFF) | + ((memory[offset + 1] & 0xFF) << 8); +} + + +void WASI::readUInt32(char* memory, uint32_t* value, uint32_t offset) { + CHECK_NOT_NULL(memory); + CHECK_NOT_NULL(value); + *value = (memory[offset] & 0xFF) | + ((memory[offset + 1] & 0xFF) << 8) | + ((memory[offset + 2] & 0xFF) << 16) | + ((memory[offset + 3] & 0xFF) << 24); +} + + +void WASI::readUInt64(char* memory, uint64_t* value, uint32_t offset) { + CHECK_NOT_NULL(memory); + CHECK_NOT_NULL(value); + uint64_t low = (memory[offset] & 0xFF) | + ((memory[offset + 1] & 0xFF) << 8) | + ((memory[offset + 2] & 0xFF) << 16) | + ((memory[offset + 3] & 0xFF) << 24); + uint64_t high = (memory[offset + 4] & 0xFF) | + ((memory[offset + 5] & 0xFF) << 8) | + ((memory[offset + 6] & 0xFF) << 16) | + ((memory[offset + 7] & 0xFF) << 24); + *value = (high << 32) + low; +} + + +void WASI::writeUInt8(char* memory, uint8_t value, uint32_t offset) { + CHECK_NOT_NULL(memory); + memory[offset] = value & 0xFF; +} + + +void WASI::writeUInt16(char* memory, uint16_t value, uint32_t offset) { + CHECK_NOT_NULL(memory); + memory[offset++] = value & 0xFF; + memory[offset] = (value >> 8) & 0xFF; +} + + +void WASI::writeUInt32(char* memory, uint32_t value, uint32_t offset) { + CHECK_NOT_NULL(memory); + memory[offset++] = value & 0xFF; + memory[offset++] = (value >> 8) & 0xFF; + memory[offset++] = (value >> 16) & 0xFF; + memory[offset] = (value >> 24) & 0xFF; +} + + +void WASI::writeUInt64(char* memory, uint64_t value, uint32_t offset) { + CHECK_NOT_NULL(memory); + memory[offset++] = value & 0xFF; + memory[offset++] = (value >> 8) & 0xFF; + memory[offset++] = (value >> 16) & 0xFF; + memory[offset++] = (value >> 24) & 0xFF; + memory[offset++] = (value >> 32) & 0xFF; + memory[offset++] = (value >> 40) & 0xFF; + memory[offset++] = (value >> 48) & 0xFF; + memory[offset] = (value >> 56) & 0xFF; +} + + +uvwasi_errno_t WASI::backingStore(char** store, size_t* byte_length) { + Environment* env = this->env(); + Local memory = PersistentToLocal::Strong(this->memory_); + Local prop; + + if (!memory->Get(env->context(), env->buffer_string()).ToLocal(&prop)) + return UVWASI_EINVAL; + + if (!prop->IsArrayBuffer()) + return UVWASI_EINVAL; + + Local ab = prop.As(); + std::shared_ptr backing_store = ab->GetBackingStore(); + *byte_length = backing_store->ByteLength(); + *store = static_cast(backing_store->Data()); + return UVWASI_ESUCCESS; +} + + +static void Initialize(Local target, + Local unused, + Local context, + void* priv) { + Environment* env = Environment::GetCurrent(context); + + Local tmpl = env->NewFunctionTemplate(WASI::New); + auto wasi_wrap_string = FIXED_ONE_BYTE_STRING(env->isolate(), "WASI"); + tmpl->InstanceTemplate()->SetInternalFieldCount(1); + tmpl->SetClassName(wasi_wrap_string); + + env->SetProtoMethod(tmpl, "args_get", WASI::ArgsGet); + env->SetProtoMethod(tmpl, "args_sizes_get", WASI::ArgsSizesGet); + env->SetProtoMethod(tmpl, "clock_res_get", WASI::ClockResGet); + env->SetProtoMethod(tmpl, "clock_time_get", WASI::ClockTimeGet); + env->SetProtoMethod(tmpl, "environ_get", WASI::EnvironGet); + env->SetProtoMethod(tmpl, "environ_sizes_get", WASI::EnvironSizesGet); + env->SetProtoMethod(tmpl, "fd_advise", WASI::FdAdvise); + env->SetProtoMethod(tmpl, "fd_allocate", WASI::FdAllocate); + env->SetProtoMethod(tmpl, "fd_close", WASI::FdClose); + env->SetProtoMethod(tmpl, "fd_datasync", WASI::FdDatasync); + env->SetProtoMethod(tmpl, "fd_fdstat_get", WASI::FdFdstatGet); + env->SetProtoMethod(tmpl, "fd_fdstat_set_flags", WASI::FdFdstatSetFlags); + env->SetProtoMethod(tmpl, "fd_fdstat_set_rights", WASI::FdFdstatSetRights); + env->SetProtoMethod(tmpl, "fd_filestat_get", WASI::FdFilestatGet); + env->SetProtoMethod(tmpl, "fd_filestat_set_size", WASI::FdFilestatSetSize); + env->SetProtoMethod(tmpl, "fd_filestat_set_times", WASI::FdFilestatSetTimes); + env->SetProtoMethod(tmpl, "fd_pread", WASI::FdPread); + env->SetProtoMethod(tmpl, "fd_prestat_get", WASI::FdPrestatGet); + env->SetProtoMethod(tmpl, "fd_prestat_dir_name", WASI::FdPrestatDirName); + env->SetProtoMethod(tmpl, "fd_pwrite", WASI::FdPwrite); + env->SetProtoMethod(tmpl, "fd_read", WASI::FdRead); + env->SetProtoMethod(tmpl, "fd_readdir", WASI::FdReaddir); + env->SetProtoMethod(tmpl, "fd_renumber", WASI::FdRenumber); + env->SetProtoMethod(tmpl, "fd_seek", WASI::FdSeek); + env->SetProtoMethod(tmpl, "fd_sync", WASI::FdSync); + env->SetProtoMethod(tmpl, "fd_tell", WASI::FdTell); + env->SetProtoMethod(tmpl, "fd_write", WASI::FdWrite); + env->SetProtoMethod(tmpl, "path_create_directory", WASI::PathCreateDirectory); + env->SetProtoMethod(tmpl, "path_filestat_get", WASI::PathFilestatGet); + env->SetProtoMethod(tmpl, + "path_filestat_set_times", + WASI::PathFilestatSetTimes); + env->SetProtoMethod(tmpl, "path_link", WASI::PathLink); + env->SetProtoMethod(tmpl, "path_open", WASI::PathOpen); + env->SetProtoMethod(tmpl, "path_readlink", WASI::PathReadlink); + env->SetProtoMethod(tmpl, "path_remove_directory", WASI::PathRemoveDirectory); + env->SetProtoMethod(tmpl, "path_rename", WASI::PathRename); + env->SetProtoMethod(tmpl, "path_symlink", WASI::PathSymlink); + env->SetProtoMethod(tmpl, "path_unlink_file", WASI::PathUnlinkFile); + env->SetProtoMethod(tmpl, "poll_oneoff", WASI::PollOneoff); + env->SetProtoMethod(tmpl, "proc_exit", WASI::ProcExit); + env->SetProtoMethod(tmpl, "proc_raise", WASI::ProcRaise); + env->SetProtoMethod(tmpl, "random_get", WASI::RandomGet); + env->SetProtoMethod(tmpl, "sched_yield", WASI::SchedYield); + env->SetProtoMethod(tmpl, "sock_recv", WASI::SockRecv); + env->SetProtoMethod(tmpl, "sock_send", WASI::SockSend); + env->SetProtoMethod(tmpl, "sock_shutdown", WASI::SockShutdown); + + env->SetInstanceMethod(tmpl, "_setMemory", WASI::_SetMemory); + + target->Set(env->context(), + wasi_wrap_string, + tmpl->GetFunction(context).ToLocalChecked()).ToChecked(); +} + + +} // namespace wasi +} // namespace node + +NODE_MODULE_CONTEXT_AWARE_INTERNAL(wasi, node::wasi::Initialize) diff --git a/src/node_wasi.h b/src/node_wasi.h new file mode 100644 index 0000000000..ca726e48a4 --- /dev/null +++ b/src/node_wasi.h @@ -0,0 +1,103 @@ +#ifndef SRC_NODE_WASI_H_ +#define SRC_NODE_WASI_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#include "base_object.h" +#include "memory_tracker-inl.h" +#include "uvwasi.h" + +namespace node { +namespace wasi { + + +class WASI : public BaseObject { + public: + WASI(Environment* env, + v8::Local object, + uvwasi_options_t* options); + static void New(const v8::FunctionCallbackInfo& args); + void MemoryInfo(MemoryTracker* tracker) const override { + /* TODO(cjihrig): Get memory consumption from uvwasi. */ + tracker->TrackField("memory", memory_); + } + + SET_MEMORY_INFO_NAME(WASI) + SET_SELF_SIZE(WASI) + + static void ArgsGet(const v8::FunctionCallbackInfo& args); + static void ArgsSizesGet(const v8::FunctionCallbackInfo& args); + static void ClockResGet(const v8::FunctionCallbackInfo& args); + static void ClockTimeGet(const v8::FunctionCallbackInfo& args); + static void EnvironGet(const v8::FunctionCallbackInfo& args); + static void EnvironSizesGet(const v8::FunctionCallbackInfo& args); + static void FdAdvise(const v8::FunctionCallbackInfo& args); + static void FdAllocate(const v8::FunctionCallbackInfo& args); + static void FdClose(const v8::FunctionCallbackInfo& args); + static void FdDatasync(const v8::FunctionCallbackInfo& args); + static void FdFdstatGet(const v8::FunctionCallbackInfo& args); + static void FdFdstatSetFlags(const v8::FunctionCallbackInfo& args); + static void FdFdstatSetRights( + const v8::FunctionCallbackInfo& args); + static void FdFilestatGet(const v8::FunctionCallbackInfo& args); + static void FdFilestatSetSize( + const v8::FunctionCallbackInfo& args); + static void FdFilestatSetTimes( + const v8::FunctionCallbackInfo& args); + static void FdPread(const v8::FunctionCallbackInfo& args); + static void FdPrestatGet(const v8::FunctionCallbackInfo& args); + static void FdPrestatDirName(const v8::FunctionCallbackInfo& args); + static void FdPwrite(const v8::FunctionCallbackInfo& args); + static void FdRead(const v8::FunctionCallbackInfo& args); + static void FdReaddir(const v8::FunctionCallbackInfo& args); + static void FdRenumber(const v8::FunctionCallbackInfo& args); + static void FdSeek(const v8::FunctionCallbackInfo& args); + static void FdSync(const v8::FunctionCallbackInfo& args); + static void FdTell(const v8::FunctionCallbackInfo& args); + static void FdWrite(const v8::FunctionCallbackInfo& args); + static void PathCreateDirectory( + const v8::FunctionCallbackInfo& args); + static void PathFilestatGet(const v8::FunctionCallbackInfo& args); + static void PathFilestatSetTimes( + const v8::FunctionCallbackInfo& args); + static void PathLink(const v8::FunctionCallbackInfo& args); + static void PathOpen(const v8::FunctionCallbackInfo& args); + static void PathReadlink(const v8::FunctionCallbackInfo& args); + static void PathRemoveDirectory( + const v8::FunctionCallbackInfo& args); + static void PathRename(const v8::FunctionCallbackInfo& args); + static void PathSymlink(const v8::FunctionCallbackInfo& args); + static void PathUnlinkFile(const v8::FunctionCallbackInfo& args); + static void PollOneoff(const v8::FunctionCallbackInfo& args); + static void ProcExit(const v8::FunctionCallbackInfo& args); + static void ProcRaise(const v8::FunctionCallbackInfo& args); + static void RandomGet(const v8::FunctionCallbackInfo& args); + static void SchedYield(const v8::FunctionCallbackInfo& args); + static void SockRecv(const v8::FunctionCallbackInfo& args); + static void SockSend(const v8::FunctionCallbackInfo& args); + static void SockShutdown(const v8::FunctionCallbackInfo& args); + + static void _SetMemory(const v8::FunctionCallbackInfo& args); + + private: + ~WASI() override; + inline void readUInt8(char* memory, uint8_t* value, uint32_t offset); + inline void readUInt16(char* memory, uint16_t* value, uint32_t offset); + inline void readUInt32(char* memory, uint32_t* value, uint32_t offset); + inline void readUInt64(char* memory, uint64_t* value, uint32_t offset); + inline void writeUInt8(char* memory, uint8_t value, uint32_t offset); + inline void writeUInt16(char* memory, uint16_t value, uint32_t offset); + inline void writeUInt32(char* memory, uint32_t value, uint32_t offset); + inline void writeUInt64(char* memory, uint64_t value, uint32_t offset); + uvwasi_errno_t backingStore(char** store, size_t* byte_length); + uvwasi_t uvw_; + v8::Global memory_; +}; + + +} // namespace wasi +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_NODE_WASI_H_ -- cgit v1.2.3