diff --git a/src/node_wasi.cc b/src/node_wasi.cc index 965a619c8d4acd..228d29cf73332f 100644 --- a/src/node_wasi.cc +++ b/src/node_wasi.cc @@ -72,11 +72,20 @@ inline void Debug(WASI* wasi, Args&&... args) { } \ } while (0) +#define CHECK_BOUNDS_OR_RETURN2(mem_size, offset, buf_size) \ + do { \ + if (!uvwasi_serdes_check_bounds((offset), (mem_size), (buf_size))) { \ + return UVWASI_EOVERFLOW; \ + } \ + } while (0) + using v8::Array; using v8::BackingStore; using v8::BigInt; +using v8::CFunction; using v8::Context; using v8::Exception; +using v8::FastApiCallbackOptions; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Integer; @@ -84,6 +93,7 @@ using v8::Isolate; using v8::Local; using v8::MaybeLocal; using v8::Object; +using v8::Signature; using v8::String; using v8::Uint32; using v8::Value; @@ -248,271 +258,294 @@ void WASI::New(const FunctionCallbackInfo& args) { } } +template +void WASI::WasiFunction::SetFunction( + Environment* env, const char* name, Local tmpl) { + auto c_function = CFunction::Make(FastCallback); + Local t = + v8::FunctionTemplate::New(env->isolate(), + SlowCallback, + Local(), + Local(), + sizeof...(Args), + v8::ConstructorBehavior::kThrow, + v8::SideEffectType::kHasSideEffect, + &c_function); + const v8::NewStringType type = v8::NewStringType::kInternalized; + v8::Local name_string = + v8::String::NewFromUtf8(env->isolate(), name, type).ToLocalChecked(); + tmpl->PrototypeTemplate()->Set(name_string, t); + t->SetClassName(name_string); +} + +template +R WASI::WasiFunction::FastCallback( + Local receiver, Args... args, FastApiCallbackOptions& options) { + WASI* wasi = reinterpret_cast(BaseObject::FromJSObject(receiver)); + if (UNLIKELY(wasi == nullptr)) return UVWASI_EINVAL; + + if (UNLIKELY(options.wasm_memory == nullptr)) return UVWASI_EINVAL; + uint8_t* memory = nullptr; + CHECK(LIKELY(options.wasm_memory->getStorageIfAligned(&memory))); + + return F(*wasi, + {reinterpret_cast(memory), options.wasm_memory->length()}, + args...); +} + +namespace { +template +static bool CheckType(Local v); + +template +static VT ConvertType(Local V); + +template <> +bool CheckType(Local value) { + return value->IsUint32(); +} + +template <> +uint32_t ConvertType(Local value) { + return value.As()->Value(); +} + +template <> +bool CheckType(Local value) { + return value->IsBigInt(); +} -void WASI::ArgsGet(const FunctionCallbackInfo& args) { +template <> +uint64_t ConvertType(Local value) { + Local js_value = value.As(); + bool lossless; + return js_value->Uint64Value(&lossless); +} + +template <> +bool CheckType(Local value) { + return value->IsBigInt(); +} + +template <> +int64_t ConvertType(Local value) { + Local js_value = value.As(); + bool lossless; + return js_value->Int64Value(&lossless); +} + +template +bool CheckTypes(const FunctionCallbackInfo& info, int i, T) { + return CheckType(info[i]); +} + +template +bool CheckTypes(const FunctionCallbackInfo& info, + int i, + T arg, + Ts... args) { + if (!CheckTypes(info, i, arg)) return false; + return CheckTypes(info, i + 1, args...); +} + +template +bool CheckTypes(const FunctionCallbackInfo& info) { + return CheckTypes(info, 0, Args()...); +} + +template <> +bool CheckTypes(const FunctionCallbackInfo& info) { + return true; +} + +} // namespace + +template +template +void WASI::WasiFunction::InnerSlowCallback( + std::index_sequence, 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); + RETURN_IF_BAD_ARG_COUNT(args, sizeof...(Args)); + if (!CheckTypes(args)) { + args.GetReturnValue().Set(UVWASI_EINVAL); + return; + } ASSIGN_INITIALIZED_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 * UVWASI_SERDES_SIZE_uint32_t); - 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); + args.GetReturnValue().Set( + F(*wasi, {memory, mem_size}, ConvertType(args[Indices])...)); +} + +template +void WASI::WasiFunction::SlowCallback( + const FunctionCallbackInfo& args) { + InnerSlowCallback(std::make_index_sequence{}, args); +} + +template +static void SetFunction(R (*f)(WASI&, WasmMemory, Args...), + Environment* env, + const char* name, + Local tmpl) { + CHECK_EQ(F, f); + WASI::WasiFunction::SetFunction(env, name, tmpl); +} + +uint32_t WASI::ArgsGet(WASI& wasi, + WasmMemory memory, + uint32_t argv_offset, + uint32_t argv_buf_offset) { + Debug(&wasi, "args_get(%d, %d)\n", argv_offset, argv_buf_offset); + + CHECK_BOUNDS_OR_RETURN2( + memory.size, argv_buf_offset, wasi.uvw_.argv_buf_size); + CHECK_BOUNDS_OR_RETURN2( + memory.size, argv_offset, wasi.uvw_.argc * UVWASI_SERDES_SIZE_uint32_t); + std::vector argv(wasi.uvw_.argc); + char* argv_buf = &memory.data[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++) { + for (size_t i = 0; i < wasi.uvw_.argc; i++) { uint32_t offset = static_cast(argv_buf_offset + (argv[i] - argv[0])); - uvwasi_serdes_write_uint32_t(memory, - argv_offset + - (i * UVWASI_SERDES_SIZE_uint32_t), - offset); + uvwasi_serdes_write_uint32_t( + memory.data, argv_offset + (i * UVWASI_SERDES_SIZE_uint32_t), offset); } } - args.GetReturnValue().Set(err); + return 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_INITIALIZED_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, - UVWASI_SERDES_SIZE_size_t); - CHECK_BOUNDS_OR_RETURN(args, - mem_size, - argv_buf_offset, - UVWASI_SERDES_SIZE_size_t); +uint32_t WASI::ArgsSizesGet(WASI& wasi, + WasmMemory memory, + uint32_t argc_offset, + uint32_t argv_buf_offset) { + Debug(&wasi, "args_sizes_get(%d, %d)\n", argc_offset, argv_buf_offset); + CHECK_BOUNDS_OR_RETURN2(memory.size, argc_offset, UVWASI_SERDES_SIZE_size_t); + CHECK_BOUNDS_OR_RETURN2( + memory.size, argv_buf_offset, UVWASI_SERDES_SIZE_size_t); uvwasi_size_t argc; uvwasi_size_t argv_buf_size; - uvwasi_errno_t err = uvwasi_args_sizes_get(&wasi->uvw_, - &argc, - &argv_buf_size); + uvwasi_errno_t err = uvwasi_args_sizes_get(&wasi.uvw_, &argc, &argv_buf_size); if (err == UVWASI_ESUCCESS) { - uvwasi_serdes_write_size_t(memory, argc_offset, argc); - uvwasi_serdes_write_size_t(memory, argv_buf_offset, argv_buf_size); + uvwasi_serdes_write_size_t(memory.data, argc_offset, argc); + uvwasi_serdes_write_size_t(memory.data, argv_buf_offset, argv_buf_size); } - args.GetReturnValue().Set(err); + return 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_INITIALIZED_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, - UVWASI_SERDES_SIZE_timestamp_t); +uint32_t WASI::ClockResGet(WASI& wasi, + WasmMemory memory, + uint32_t clock_id, + uint32_t resolution_ptr) { + Debug(&wasi, "clock_res_get(%d, %d)\n", clock_id, resolution_ptr); + CHECK_BOUNDS_OR_RETURN2( + memory.size, resolution_ptr, UVWASI_SERDES_SIZE_timestamp_t); uvwasi_timestamp_t resolution; - uvwasi_errno_t err = uvwasi_clock_res_get(&wasi->uvw_, - clock_id, - &resolution); + uvwasi_errno_t err = uvwasi_clock_res_get(&wasi.uvw_, clock_id, &resolution); if (err == UVWASI_ESUCCESS) - uvwasi_serdes_write_timestamp_t(memory, resolution_ptr, resolution); + uvwasi_serdes_write_timestamp_t(memory.data, resolution_ptr, resolution); - args.GetReturnValue().Set(err); + return 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_INITIALIZED_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, - UVWASI_SERDES_SIZE_timestamp_t); +uint32_t WASI::ClockTimeGet(WASI& wasi, + WasmMemory memory, + uint32_t clock_id, + uint64_t precision, + uint32_t time_ptr) { + Debug(&wasi, "clock_time_get(%d, %d, %d)\n", clock_id, precision, time_ptr); + CHECK_BOUNDS_OR_RETURN2( + memory.size, time_ptr, UVWASI_SERDES_SIZE_timestamp_t); uvwasi_timestamp_t time; - uvwasi_errno_t err = uvwasi_clock_time_get(&wasi->uvw_, - clock_id, - precision, - &time); + uvwasi_errno_t err = + uvwasi_clock_time_get(&wasi.uvw_, clock_id, precision, &time); if (err == UVWASI_ESUCCESS) - uvwasi_serdes_write_timestamp_t(memory, time_ptr, time); + uvwasi_serdes_write_timestamp_t(memory.data, time_ptr, time); - args.GetReturnValue().Set(err); + return 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_INITIALIZED_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 * UVWASI_SERDES_SIZE_uint32_t); - 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); +uint32_t WASI::EnvironGet(WASI& wasi, + WasmMemory memory, + uint32_t environ_offset, + uint32_t environ_buf_offset) { + Debug(&wasi, "environ_get(%d, %d)\n", environ_offset, environ_buf_offset); + CHECK_BOUNDS_OR_RETURN2( + memory.size, environ_buf_offset, wasi.uvw_.env_buf_size); + CHECK_BOUNDS_OR_RETURN2(memory.size, + environ_offset, + wasi.uvw_.envc * UVWASI_SERDES_SIZE_uint32_t); + std::vector environment(wasi.uvw_.envc); + char* environ_buf = &memory.data[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++) { + for (size_t i = 0; i < wasi.uvw_.envc; i++) { uint32_t offset = static_cast( environ_buf_offset + (environment[i] - environment[0])); - uvwasi_serdes_write_uint32_t(memory, - environ_offset + - (i * UVWASI_SERDES_SIZE_uint32_t), - offset); + uvwasi_serdes_write_uint32_t( + memory.data, + environ_offset + (i * UVWASI_SERDES_SIZE_uint32_t), + offset); } } - args.GetReturnValue().Set(err); + return 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_INITIALIZED_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, - UVWASI_SERDES_SIZE_size_t); - CHECK_BOUNDS_OR_RETURN(args, - mem_size, - env_buf_offset, - UVWASI_SERDES_SIZE_size_t); +uint32_t WASI::EnvironSizesGet(WASI& wasi, + WasmMemory memory, + uint32_t envc_offset, + uint32_t env_buf_offset) { + Debug(&wasi, "environ_sizes_get(%d, %d)\n", envc_offset, env_buf_offset); + CHECK_BOUNDS_OR_RETURN2(memory.size, envc_offset, UVWASI_SERDES_SIZE_size_t); + CHECK_BOUNDS_OR_RETURN2( + memory.size, env_buf_offset, UVWASI_SERDES_SIZE_size_t); uvwasi_size_t envc; uvwasi_size_t env_buf_size; - uvwasi_errno_t err = uvwasi_environ_sizes_get(&wasi->uvw_, - &envc, - &env_buf_size); + uvwasi_errno_t err = + uvwasi_environ_sizes_get(&wasi.uvw_, &envc, &env_buf_size); if (err == UVWASI_ESUCCESS) { - uvwasi_serdes_write_size_t(memory, envc_offset, envc); - uvwasi_serdes_write_size_t(memory, env_buf_offset, env_buf_size); + uvwasi_serdes_write_size_t(memory.data, envc_offset, envc); + uvwasi_serdes_write_size_t(memory.data, env_buf_offset, env_buf_size); } - args.GetReturnValue().Set(err); + return 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_INITIALIZED_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); +uint32_t WASI::FdAdvise(WASI& wasi, + WasmMemory, + uint32_t fd, + uint64_t offset, + uint64_t len, + uint32_t advice) { + Debug(&wasi, "fd_advise(%d, %d, %d, %d)\n", fd, offset, len, advice); + return uvwasi_fd_advise(&wasi.uvw_, fd, offset, len, advice); } - -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_INITIALIZED_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); +uint32_t WASI::FdAllocate( + WASI& wasi, WasmMemory, uint32_t fd, uint64_t offset, uint64_t len) { + Debug(&wasi, "fd_allocate(%d, %d, %d)\n", fd, offset, len); + return uvwasi_fd_allocate(&wasi.uvw_, fd, offset, len); } - -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_INITIALIZED_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); +uint32_t WASI::FdClose(WASI& wasi, WasmMemory, uint32_t fd) { + Debug(&wasi, "fd_close(%d)\n", fd); + return uvwasi_fd_close(&wasi.uvw_, fd); } - -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_INITIALIZED_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); +uint32_t WASI::FdDatasync(WASI& wasi, WasmMemory, uint32_t fd) { + Debug(&wasi, "fd_datasync(%d)\n", fd); + return uvwasi_fd_datasync(&wasi.uvw_, fd); } - void WASI::FdFdstatGet(const FunctionCallbackInfo& args) { WASI* wasi; uint32_t fd; @@ -892,40 +925,24 @@ void WASI::FdRenumber(const FunctionCallbackInfo& args) { 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_INITIALIZED_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, - UVWASI_SERDES_SIZE_filesize_t); +uint32_t WASI::FdSeek(WASI& wasi, + WasmMemory memory, + uint32_t fd, + int64_t offset, + uint32_t whence, + uint32_t newoffset_ptr) { + Debug(&wasi, "fd_seek(%d, %d, %d, %d)\n", fd, offset, whence, newoffset_ptr); + CHECK_BOUNDS_OR_RETURN2( + memory.size, newoffset_ptr, UVWASI_SERDES_SIZE_filesize_t); uvwasi_filesize_t newoffset; - uvwasi_errno_t err = uvwasi_fd_seek(&wasi->uvw_, - fd, - offset, - whence, - &newoffset); + uvwasi_errno_t err = + uvwasi_fd_seek(&wasi.uvw_, fd, offset, whence, &newoffset); if (err == UVWASI_ESUCCESS) - uvwasi_serdes_write_filesize_t(memory, newoffset_ptr, newoffset); + uvwasi_serdes_write_filesize_t(memory.data, newoffset_ptr, newoffset); - args.GetReturnValue().Set(err); + return err; } - void WASI::FdSync(const FunctionCallbackInfo& args) { WASI* wasi; uint32_t fd; @@ -1474,37 +1491,20 @@ void WASI::ProcRaise(const FunctionCallbackInfo& args) { 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_INITIALIZED_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); +uint32_t WASI::RandomGet(WASI& wasi, + WasmMemory memory, + uint32_t buf_ptr, + uint32_t buf_len) { + Debug(&wasi, "random_get(%d, %d)\n", buf_ptr, buf_len); + CHECK_BOUNDS_OR_RETURN2(memory.size, buf_ptr, buf_len); + return uvwasi_random_get(&wasi.uvw_, &memory.data[buf_ptr], buf_len); } - -void WASI::SchedYield(const FunctionCallbackInfo& args) { - WASI* wasi; - RETURN_IF_BAD_ARG_COUNT(args, 0); - ASSIGN_INITIALIZED_OR_RETURN_UNWRAP(&wasi, args.This()); - Debug(wasi, "sched_yield()\n"); - uvwasi_errno_t err = uvwasi_sched_yield(&wasi->uvw_); - args.GetReturnValue().Set(err); +uint32_t WASI::SchedYield(WASI& wasi, WasmMemory) { + Debug(&wasi, "sched_yield()\n"); + return uvwasi_sched_yield(&wasi.uvw_); } - void WASI::SockRecv(const FunctionCallbackInfo& args) { WASI* wasi; uint32_t sock; @@ -1673,16 +1673,19 @@ static void Initialize(Local target, tmpl->InstanceTemplate()->SetInternalFieldCount(WASI::kInternalFieldCount); tmpl->Inherit(BaseObject::GetConstructorTemplate(env)); - 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); +#define V(F, name) \ + SetFunction(WASI::F, env, name, tmpl); + + V(ArgsGet, "args_get") + V(ArgsSizesGet, "args_sizes_get") + V(ClockResGet, "clock_res_get") + V(ClockTimeGet, "clock_time_get") + V(EnvironGet, "environ_get") + V(EnvironSizesGet, "environ_sizes_get") + V(FdAdvise, "fd_advise") + V(FdAllocate, "fd_allocate") + V(FdClose, "fd_close") + V(FdDatasync, "fd_datasync") 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); @@ -1696,7 +1699,7 @@ static void Initialize(Local target, 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); + V(FdSeek, "fd_seek") env->SetProtoMethod(tmpl, "fd_sync", WASI::FdSync); env->SetProtoMethod(tmpl, "fd_tell", WASI::FdTell); env->SetProtoMethod(tmpl, "fd_write", WASI::FdWrite); @@ -1715,11 +1718,12 @@ static void Initialize(Local target, 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); + V(RandomGet, "random_get") + V(SchedYield, "sched_yield") env->SetProtoMethod(tmpl, "sock_recv", WASI::SockRecv); env->SetProtoMethod(tmpl, "sock_send", WASI::SockSend); env->SetProtoMethod(tmpl, "sock_shutdown", WASI::SockShutdown); +#undef V env->SetInstanceMethod(tmpl, "_setMemory", WASI::_SetMemory); diff --git a/src/node_wasi.h b/src/node_wasi.h index b3814ddc31033a..1246b305b43697 100644 --- a/src/node_wasi.h +++ b/src/node_wasi.h @@ -10,6 +10,10 @@ namespace node { namespace wasi { +struct WasmMemory { + char* data; + size_t size; +}; class WASI : public BaseObject, public mem::NgLibMemoryManager { @@ -23,16 +27,17 @@ class WASI : public BaseObject, 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 uint32_t ArgsGet(WASI&, WasmMemory, uint32_t, uint32_t); + static uint32_t ArgsSizesGet(WASI&, WasmMemory, uint32_t, uint32_t); + static uint32_t ClockResGet(WASI&, WasmMemory, uint32_t, uint32_t); + static uint32_t ClockTimeGet(WASI&, WasmMemory, uint32_t, uint64_t, uint32_t); + static uint32_t EnvironGet(WASI&, WasmMemory, uint32_t, uint32_t); + static uint32_t EnvironSizesGet(WASI&, WasmMemory, uint32_t, uint32_t); + static uint32_t FdAdvise( + WASI&, WasmMemory, uint32_t, uint64_t, uint64_t, uint32_t); + static uint32_t FdAllocate(WASI&, WasmMemory, uint32_t, uint64_t, uint64_t); + static uint32_t FdClose(WASI&, WasmMemory, uint32_t); + static uint32_t FdDatasync(WASI&, WasmMemory, uint32_t); static void FdFdstatGet(const v8::FunctionCallbackInfo& args); static void FdFdstatSetFlags(const v8::FunctionCallbackInfo& args); static void FdFdstatSetRights( @@ -49,7 +54,8 @@ class WASI : public BaseObject, 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 uint32_t FdSeek( + WASI&, WasmMemory, uint32_t, int64_t, uint32_t, uint32_t); static void FdSync(const v8::FunctionCallbackInfo& args); static void FdTell(const v8::FunctionCallbackInfo& args); static void FdWrite(const v8::FunctionCallbackInfo& args); @@ -69,8 +75,8 @@ class WASI : public BaseObject, 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 uint32_t RandomGet(WASI&, WasmMemory, uint32_t, uint32_t); + static uint32_t SchedYield(WASI&, WasmMemory); static void SockRecv(const v8::FunctionCallbackInfo& args); static void SockSend(const v8::FunctionCallbackInfo& args); static void SockShutdown(const v8::FunctionCallbackInfo& args); @@ -82,6 +88,28 @@ class WASI : public BaseObject, void IncreaseAllocatedSize(size_t size); void DecreaseAllocatedSize(size_t size); + // as a C++14 desugaring of `` + template + class WasiFunction { + public: + static void SetFunction(Environment*, + const char*, + v8::Local); + + private: + static R FastCallback(v8::Local receiver, + Args..., + v8::FastApiCallbackOptions&); + + static void SlowCallback(const v8::FunctionCallbackInfo&); + + // Another hack, SlowCallback is just a dumb wrapper that expands + // `InnerSlowCallback` from `Args...` :( + template + static void InnerSlowCallback(std::index_sequence, + const v8::FunctionCallbackInfo&); + }; + private: ~WASI() override; inline void readUInt8(char* memory, uint8_t* value, uint32_t offset); diff --git a/test/wasi/Makefile b/test/wasi/Makefile index 42d3b4e3fa7a80..14563feda50961 100644 --- a/test/wasi/Makefile +++ b/test/wasi/Makefile @@ -1,12 +1,13 @@ CC = /opt/wasi-sdk/bin/clang -TARGET = wasm32-unknown-wasi +TARGET = wasm32-wasi SYSROOT = +CFLAGS = -D_WASI_EMULATED_PROCESS_CLOCKS -lwasi-emulated-process-clocks OBJ = $(patsubst c/%.c, wasm/%.wasm, $(wildcard c/*.c)) all: $(OBJ) wasm/%.wasm : c/%.c - $(CC) $< --target=$(TARGET) --sysroot=$(SYSROOT) -s -o $@ + $(CC) $< $(CFLAGS) --target=$(TARGET) --sysroot=$(SYSROOT) -s -o $@ .PHONY clean: rm -f $(OBJ) diff --git a/test/wasi/test-wasi.js b/test/wasi/test-wasi.js index 6c00b5a7b72503..d2513a8e87f5c3 100644 --- a/test/wasi/test-wasi.js +++ b/test/wasi/test-wasi.js @@ -50,6 +50,7 @@ if (process.argv[2] === 'wasi-child') { opts.input = options.stdin; const child = cp.spawnSync(process.execPath, [ + ...process.argv.slice(1, -1), '--experimental-wasi-unstable-preview1', __filename, 'wasi-child', diff --git a/test/wasi/wasm/cant_dotdot.wasm b/test/wasi/wasm/cant_dotdot.wasm index 1ffbe23c6afdb2..b078dfca1afbc9 100755 Binary files a/test/wasi/wasm/cant_dotdot.wasm and b/test/wasi/wasm/cant_dotdot.wasm differ diff --git a/test/wasi/wasm/clock_getres.wasm b/test/wasi/wasm/clock_getres.wasm index 510049dca4a009..9d47599c7b9478 100755 Binary files a/test/wasi/wasm/clock_getres.wasm and b/test/wasi/wasm/clock_getres.wasm differ diff --git a/test/wasi/wasm/create_symlink.wasm b/test/wasi/wasm/create_symlink.wasm index 1612e975d87e5d..291f17eedcfa76 100755 Binary files a/test/wasi/wasm/create_symlink.wasm and b/test/wasi/wasm/create_symlink.wasm differ diff --git a/test/wasi/wasm/exitcode.wasm b/test/wasi/wasm/exitcode.wasm index ceb797f8b31ddf..0472e62d851095 100755 Binary files a/test/wasi/wasm/exitcode.wasm and b/test/wasi/wasm/exitcode.wasm differ diff --git a/test/wasi/wasm/fd_prestat_get_refresh.wasm b/test/wasi/wasm/fd_prestat_get_refresh.wasm index 159cfa9e4c8159..d645b42c806791 100755 Binary files a/test/wasi/wasm/fd_prestat_get_refresh.wasm and b/test/wasi/wasm/fd_prestat_get_refresh.wasm differ diff --git a/test/wasi/wasm/follow_symlink.wasm b/test/wasi/wasm/follow_symlink.wasm index f5f236c53f2440..b79242eb13141a 100755 Binary files a/test/wasi/wasm/follow_symlink.wasm and b/test/wasi/wasm/follow_symlink.wasm differ diff --git a/test/wasi/wasm/freopen.wasm b/test/wasi/wasm/freopen.wasm index fb417fbe21fa69..5f774d782332f2 100755 Binary files a/test/wasi/wasm/freopen.wasm and b/test/wasi/wasm/freopen.wasm differ diff --git a/test/wasi/wasm/ftruncate.wasm b/test/wasi/wasm/ftruncate.wasm index a16e90d98ddb28..60542eeb6a0ff6 100755 Binary files a/test/wasi/wasm/ftruncate.wasm and b/test/wasi/wasm/ftruncate.wasm differ diff --git a/test/wasi/wasm/getentropy.wasm b/test/wasi/wasm/getentropy.wasm index 527ac6a17d3008..f9e4cb52869892 100755 Binary files a/test/wasi/wasm/getentropy.wasm and b/test/wasi/wasm/getentropy.wasm differ diff --git a/test/wasi/wasm/getrusage.wasm b/test/wasi/wasm/getrusage.wasm index c9546e232c7956..ff131ee42a09b6 100755 Binary files a/test/wasi/wasm/getrusage.wasm and b/test/wasi/wasm/getrusage.wasm differ diff --git a/test/wasi/wasm/gettimeofday.wasm b/test/wasi/wasm/gettimeofday.wasm index 7629b119d8895d..408a5cfc9ef209 100755 Binary files a/test/wasi/wasm/gettimeofday.wasm and b/test/wasi/wasm/gettimeofday.wasm differ diff --git a/test/wasi/wasm/link.wasm b/test/wasi/wasm/link.wasm index 60f5c07601a2af..4a9719df3035d5 100755 Binary files a/test/wasi/wasm/link.wasm and b/test/wasi/wasm/link.wasm differ diff --git a/test/wasi/wasm/main_args.wasm b/test/wasi/wasm/main_args.wasm index 60cb69defe2d32..1e14b8351b71e6 100755 Binary files a/test/wasi/wasm/main_args.wasm and b/test/wasi/wasm/main_args.wasm differ diff --git a/test/wasi/wasm/notdir.wasm b/test/wasi/wasm/notdir.wasm index 6b592fc17b032f..ae22933603d049 100755 Binary files a/test/wasi/wasm/notdir.wasm and b/test/wasi/wasm/notdir.wasm differ diff --git a/test/wasi/wasm/poll.wasm b/test/wasi/wasm/poll.wasm index 37e17b8d880ad2..22c0fe859d7ad3 100755 Binary files a/test/wasi/wasm/poll.wasm and b/test/wasi/wasm/poll.wasm differ diff --git a/test/wasi/wasm/preopen_populates.wasm b/test/wasi/wasm/preopen_populates.wasm index 618050b3b4c210..1236bbe1cc6e6e 100755 Binary files a/test/wasi/wasm/preopen_populates.wasm and b/test/wasi/wasm/preopen_populates.wasm differ diff --git a/test/wasi/wasm/read_file.wasm b/test/wasi/wasm/read_file.wasm index 1c5e8107e0a9f7..bc1433e09e961e 100755 Binary files a/test/wasi/wasm/read_file.wasm and b/test/wasi/wasm/read_file.wasm differ diff --git a/test/wasi/wasm/read_file_twice.wasm b/test/wasi/wasm/read_file_twice.wasm index 6917a105eb4c08..6b73ae11309fde 100755 Binary files a/test/wasi/wasm/read_file_twice.wasm and b/test/wasi/wasm/read_file_twice.wasm differ diff --git a/test/wasi/wasm/readdir.wasm b/test/wasi/wasm/readdir.wasm index ce6cb4999524db..c315d2d5b8e87e 100755 Binary files a/test/wasi/wasm/readdir.wasm and b/test/wasi/wasm/readdir.wasm differ diff --git a/test/wasi/wasm/stat.wasm b/test/wasi/wasm/stat.wasm index 4a50c0282bb60a..6f924b74d9b22c 100755 Binary files a/test/wasi/wasm/stat.wasm and b/test/wasi/wasm/stat.wasm differ diff --git a/test/wasi/wasm/stdin.wasm b/test/wasi/wasm/stdin.wasm index 3cc548607af2e0..f9ea0fd336d50e 100755 Binary files a/test/wasi/wasm/stdin.wasm and b/test/wasi/wasm/stdin.wasm differ diff --git a/test/wasi/wasm/symlink_escape.wasm b/test/wasi/wasm/symlink_escape.wasm index fcb8cfd5790782..4ff589da7d438c 100755 Binary files a/test/wasi/wasm/symlink_escape.wasm and b/test/wasi/wasm/symlink_escape.wasm differ diff --git a/test/wasi/wasm/symlink_loop.wasm b/test/wasi/wasm/symlink_loop.wasm index 98e5c62f4b8355..409102d7ee21a0 100755 Binary files a/test/wasi/wasm/symlink_loop.wasm and b/test/wasi/wasm/symlink_loop.wasm differ diff --git a/test/wasi/wasm/write_file.wasm b/test/wasi/wasm/write_file.wasm index c21d0c2bfef5c7..005c3da09de043 100755 Binary files a/test/wasi/wasm/write_file.wasm and b/test/wasi/wasm/write_file.wasm differ