summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE25
-rw-r--r--deps/uvwasi/LICENSE21
-rw-r--r--deps/uvwasi/include/clocks.h13
-rw-r--r--deps/uvwasi/include/fd_table.h60
-rw-r--r--deps/uvwasi/include/uv_mapping.h15
-rw-r--r--deps/uvwasi/include/uvwasi.h252
-rw-r--r--deps/uvwasi/include/wasi_types.h323
-rw-r--r--deps/uvwasi/src/clocks.c194
-rw-r--r--deps/uvwasi/src/fd_table.c422
-rw-r--r--deps/uvwasi/src/uv_mapping.c243
-rw-r--r--deps/uvwasi/src/uvwasi.c1918
-rw-r--r--deps/uvwasi/uvwasi.gyp25
-rw-r--r--doc/api/cli.md8
-rw-r--r--doc/api/errors.md5
-rw-r--r--doc/api/index.md1
-rw-r--r--doc/api/wasi.md90
-rw-r--r--doc/node.13
-rw-r--r--lib/internal/bootstrap/loaders.js3
-rw-r--r--lib/internal/errors.js1
-rw-r--r--lib/internal/modules/cjs/helpers.js5
-rw-r--r--lib/wasi.js105
-rw-r--r--node.gyp19
-rw-r--r--src/env-inl.h15
-rw-r--r--src/env.h8
-rw-r--r--src/node_binding.cc1
-rw-r--r--src/node_config.cc3
-rw-r--r--src/node_options.cc4
-rw-r--r--src/node_options.h1
-rw-r--r--src/node_wasi.cc1802
-rw-r--r--src/node_wasi.h103
-rw-r--r--test/fixtures/outside.txt2
-rw-r--r--test/fixtures/wasi/input.txt1
-rw-r--r--test/fixtures/wasi/notadir0
-rwxr-xr-xtest/fixtures/wasi/simple-wasi.wasmbin0 -> 15873 bytes
-rw-r--r--test/fixtures/wasi/simple-wasi.wat6533
l---------test/fixtures/wasi/subdir/input_link.txt1
l---------test/fixtures/wasi/subdir/loop11
l---------test/fixtures/wasi/subdir/loop21
l---------test/fixtures/wasi/subdir/outside.txt1
-rw-r--r--test/wasi/Makefile12
-rw-r--r--test/wasi/README.md8
-rw-r--r--test/wasi/c/cant_dotdot.c11
-rw-r--r--test/wasi/c/clock_getres.c17
-rw-r--r--test/wasi/c/exitcode.c3
-rw-r--r--test/wasi/c/fd_prestat_get_refresh.c8
-rw-r--r--test/wasi/c/follow_symlink.c14
-rw-r--r--test/wasi/c/getentropy.c18
-rw-r--r--test/wasi/c/getrusage.c34
-rw-r--r--test/wasi/c/gettimeofday.c35
-rw-r--r--test/wasi/c/notdir.c11
-rw-r--r--test/wasi/c/poll.c31
-rw-r--r--test/wasi/c/preopen_populates.c3
-rw-r--r--test/wasi/c/read_file.c14
-rw-r--r--test/wasi/c/read_file_twice.c16
-rw-r--r--test/wasi/c/stat.c53
-rw-r--r--test/wasi/c/stdin.c13
-rw-r--r--test/wasi/c/symlink_escape.c9
-rw-r--r--test/wasi/c/symlink_loop.c9
-rw-r--r--test/wasi/c/write_file.c15
-rw-r--r--test/wasi/test-wasi-binding.js19
-rw-r--r--test/wasi/test-wasi-symlinks.js78
-rw-r--r--test/wasi/test-wasi.js81
-rw-r--r--test/wasi/testcfg.py6
-rw-r--r--test/wasi/wasi.status7
-rwxr-xr-xtest/wasi/wasm/cant_dotdot.wasmbin0 -> 33007 bytes
-rwxr-xr-xtest/wasi/wasm/clock_getres.wasmbin0 -> 30146 bytes
-rwxr-xr-xtest/wasi/wasm/exitcode.wasmbin0 -> 12694 bytes
-rwxr-xr-xtest/wasi/wasm/fd_prestat_get_refresh.wasmbin0 -> 12855 bytes
-rwxr-xr-xtest/wasi/wasm/follow_symlink.wasmbin0 -> 34948 bytes
-rwxr-xr-xtest/wasi/wasm/getentropy.wasmbin0 -> 29943 bytes
-rwxr-xr-xtest/wasi/wasm/getrusage.wasmbin0 -> 30602 bytes
-rwxr-xr-xtest/wasi/wasm/gettimeofday.wasmbin0 -> 30428 bytes
-rwxr-xr-xtest/wasi/wasm/notdir.wasmbin0 -> 31267 bytes
-rwxr-xr-xtest/wasi/wasm/poll.wasmbin0 -> 34096 bytes
-rwxr-xr-xtest/wasi/wasm/preopen_populates.wasmbin0 -> 12689 bytes
-rwxr-xr-xtest/wasi/wasm/read_file.wasmbin0 -> 34932 bytes
-rwxr-xr-xtest/wasi/wasm/read_file_twice.wasmbin0 -> 35018 bytes
-rwxr-xr-xtest/wasi/wasm/stat.wasmbin0 -> 34507 bytes
-rwxr-xr-xtest/wasi/wasm/stdin.wasmbin0 -> 18390 bytes
-rwxr-xr-xtest/wasi/wasm/symlink_escape.wasmbin0 -> 33026 bytes
-rwxr-xr-xtest/wasi/wasm/symlink_loop.wasmbin0 -> 33009 bytes
-rwxr-xr-xtest/wasi/wasm/write_file.wasmbin0 -> 33357 bytes
-rw-r--r--tools/doc/type-parser.js2
-rwxr-xr-xtools/license-builder.sh2
84 files changed, 12753 insertions, 4 deletions
diff --git a/LICENSE b/LICENSE
index d09611738b..9d65fc76cb 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1503,3 +1503,28 @@ The externally maintained libraries used by Node.js are:
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
+
+- uvwasi, located at deps/uvwasi, is licensed as follows:
+ """
+ MIT License
+
+ Copyright (c) 2019 Colin Ihrig and Contributors
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ """
diff --git a/deps/uvwasi/LICENSE b/deps/uvwasi/LICENSE
new file mode 100644
index 0000000000..dfb8546af5
--- /dev/null
+++ b/deps/uvwasi/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Colin Ihrig and Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/deps/uvwasi/include/clocks.h b/deps/uvwasi/include/clocks.h
new file mode 100644
index 0000000000..7437d03df6
--- /dev/null
+++ b/deps/uvwasi/include/clocks.h
@@ -0,0 +1,13 @@
+#ifndef __UVWASI_CLOCKS_H__
+#define __UVWASI_CLOCKS_H__
+
+#include "wasi_types.h"
+
+uvwasi_errno_t uvwasi__clock_gettime_realtime(uvwasi_timestamp_t* time);
+uvwasi_errno_t uvwasi__clock_gettime_process_cputime(uvwasi_timestamp_t* time);
+uvwasi_errno_t uvwasi__clock_gettime_thread_cputime(uvwasi_timestamp_t* time);
+
+uvwasi_errno_t uvwasi__clock_getres_process_cputime(uvwasi_timestamp_t* time);
+uvwasi_errno_t uvwasi__clock_getres_thread_cputime(uvwasi_timestamp_t* time);
+
+#endif /* __UVWASI_CLOCKS_H__ */
diff --git a/deps/uvwasi/include/fd_table.h b/deps/uvwasi/include/fd_table.h
new file mode 100644
index 0000000000..ef87a3ff8f
--- /dev/null
+++ b/deps/uvwasi/include/fd_table.h
@@ -0,0 +1,60 @@
+#ifndef __UVWASI_FD_TABLE_H__
+#define __UVWASI_FD_TABLE_H__
+
+#include <stdint.h>
+#include "uv.h"
+#include "wasi_types.h"
+#include "uv_mapping.h"
+
+/* TODO(cjihrig): PATH_MAX_BYTES shouldn't be stack allocated. On Windows, paths
+ can be 32k long, and this PATH_MAX_BYTES is an artificial limitation. */
+#ifdef _WIN32
+/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
+# define PATH_MAX_BYTES (MAX_PATH * 4)
+#else
+# include <limits.h>
+# define PATH_MAX_BYTES (PATH_MAX)
+#endif
+
+
+struct uvwasi_fd_wrap_t {
+ uvwasi_fd_t id;
+ uv_file fd;
+ char path[PATH_MAX_BYTES];
+ char real_path[PATH_MAX_BYTES];
+ uvwasi_filetype_t type;
+ uvwasi_rights_t rights_base;
+ uvwasi_rights_t rights_inheriting;
+ int preopen;
+ int valid;
+};
+
+struct uvwasi_fd_table_t {
+ struct uvwasi_fd_wrap_t* fds;
+ uint32_t size;
+ uint32_t used;
+};
+
+uvwasi_errno_t uvwasi_fd_table_init(struct uvwasi_fd_table_t* table,
+ uint32_t init_size);
+void uvwasi_fd_table_free(struct uvwasi_fd_table_t* table);
+uvwasi_errno_t uvwasi_fd_table_insert_preopen(struct uvwasi_fd_table_t* table,
+ const uv_file fd,
+ const char* path,
+ const char* real_path);
+uvwasi_errno_t uvwasi_fd_table_insert_fd(struct uvwasi_fd_table_t* table,
+ const uv_file fd,
+ const int flags,
+ const char* path,
+ uvwasi_rights_t rights_base,
+ uvwasi_rights_t rights_inheriting,
+ struct uvwasi_fd_wrap_t* wrap);
+uvwasi_errno_t uvwasi_fd_table_get(const struct uvwasi_fd_table_t* table,
+ const uvwasi_fd_t id,
+ struct uvwasi_fd_wrap_t** wrap,
+ uvwasi_rights_t rights_base,
+ uvwasi_rights_t rights_inheriting);
+uvwasi_errno_t uvwasi_fd_table_remove(struct uvwasi_fd_table_t* table,
+ const uvwasi_fd_t id);
+
+#endif /* __UVWASI_FD_TABLE_H__ */
diff --git a/deps/uvwasi/include/uv_mapping.h b/deps/uvwasi/include/uv_mapping.h
new file mode 100644
index 0000000000..d835ca507a
--- /dev/null
+++ b/deps/uvwasi/include/uv_mapping.h
@@ -0,0 +1,15 @@
+#ifndef __UVWASI_UV_MAPPING_H__
+#define __UVWASI_UV_MAPPING_H__
+
+#include "uv.h"
+#include "wasi_types.h"
+
+#define NANOS_PER_SEC 1000000000
+
+uvwasi_errno_t uvwasi__translate_uv_error(int err);
+int uvwasi__translate_to_uv_signal(uvwasi_signal_t sig);
+uvwasi_timestamp_t uvwasi__timespec_to_timestamp(const uv_timespec_t* ts);
+uvwasi_filetype_t uvwasi__stat_to_filetype(const uv_stat_t* stat);
+void uvwasi__stat_to_filestat(const uv_stat_t* stat, uvwasi_filestat_t* fs);
+
+#endif /* __UVWASI_UV_MAPPING_H__ */
diff --git a/deps/uvwasi/include/uvwasi.h b/deps/uvwasi/include/uvwasi.h
new file mode 100644
index 0000000000..a7695734ac
--- /dev/null
+++ b/deps/uvwasi/include/uvwasi.h
@@ -0,0 +1,252 @@
+#ifndef __UVWASI_H__
+#define __UVWASI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "wasi_types.h"
+#include "uv_mapping.h"
+#include "fd_table.h"
+
+#define UVWASI_VERSION_MAJOR 0
+#define UVWASI_VERSION_MINOR 0
+#define UVWASI_VERSION_PATCH 1
+#define UVWASI_VERSION_HEX ((UVWASI_VERSION_MAJOR << 16) | \
+ (UVWASI_VERSION_MINOR << 8) | \
+ (UVWASI_VERSION_PATCH))
+#define UVWASI_STRINGIFY(v) UVWASI_STRINGIFY_HELPER(v)
+#define UVWASI_STRINGIFY_HELPER(v) #v
+#define UVWASI_VERSION_STRING UVWASI_STRINGIFY(UVWASI_VERSION_MAJOR) "." \
+ UVWASI_STRINGIFY(UVWASI_VERSION_MINOR) "." \
+ UVWASI_STRINGIFY(UVWASI_VERSION_PATCH)
+
+
+typedef struct uvwasi_s {
+ struct uvwasi_fd_table_t fds;
+ size_t argc;
+ char** argv;
+ char* argv_buf;
+ size_t argv_buf_size;
+ size_t envc;
+ char** env;
+ char* env_buf;
+ size_t env_buf_size;
+} uvwasi_t;
+
+typedef struct uvwasi_preopen_s {
+ char* mapped_path;
+ char* real_path;
+} uvwasi_preopen_t;
+
+typedef struct uvwasi_options_s {
+ size_t fd_table_size;
+ size_t preopenc;
+ uvwasi_preopen_t* preopens;
+ size_t argc;
+ char** argv;
+ char** envp;
+} uvwasi_options_t;
+
+
+// Embedder API.
+uvwasi_errno_t uvwasi_init(uvwasi_t* uvwasi, uvwasi_options_t* options);
+void uvwasi_destroy(uvwasi_t* uvwasi);
+uvwasi_errno_t uvwasi_embedder_remap_fd(uvwasi_t* uvwasi,
+ const uvwasi_fd_t fd,
+ uv_file new_host_fd);
+
+
+// WASI system call API.
+uvwasi_errno_t uvwasi_args_get(uvwasi_t* uvwasi, char** argv, char* argv_buf);
+uvwasi_errno_t uvwasi_args_sizes_get(uvwasi_t* uvwasi,
+ size_t* argc,
+ size_t* argv_buf_size);
+uvwasi_errno_t uvwasi_clock_res_get(uvwasi_t* uvwasi,
+ uvwasi_clockid_t clock_id,
+ uvwasi_timestamp_t* resolution);
+uvwasi_errno_t uvwasi_clock_time_get(uvwasi_t* uvwasi,
+ uvwasi_clockid_t clock_id,
+ uvwasi_timestamp_t precision,
+ uvwasi_timestamp_t* time);
+uvwasi_errno_t uvwasi_environ_get(uvwasi_t* uvwasi,
+ char** environment,
+ char* environ_buf);
+uvwasi_errno_t uvwasi_environ_sizes_get(uvwasi_t* uvwasi,
+ size_t* environ_count,
+ size_t* environ_buf_size);
+uvwasi_errno_t uvwasi_fd_advise(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t offset,
+ uvwasi_filesize_t len,
+ uvwasi_advice_t advice);
+uvwasi_errno_t uvwasi_fd_allocate(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t offset,
+ uvwasi_filesize_t len);
+uvwasi_errno_t uvwasi_fd_close(uvwasi_t* uvwasi, uvwasi_fd_t fd);
+uvwasi_errno_t uvwasi_fd_datasync(uvwasi_t* uvwasi, uvwasi_fd_t fd);
+uvwasi_errno_t uvwasi_fd_fdstat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_fdstat_t* buf);
+uvwasi_errno_t uvwasi_fd_fdstat_set_flags(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_fdflags_t flags);
+uvwasi_errno_t uvwasi_fd_fdstat_set_rights(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_rights_t fs_rights_base,
+ uvwasi_rights_t fs_rights_inheriting
+ );
+uvwasi_errno_t uvwasi_fd_filestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filestat_t* buf);
+uvwasi_errno_t uvwasi_fd_filestat_set_size(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t st_size);
+uvwasi_errno_t uvwasi_fd_filestat_set_times(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_timestamp_t st_atim,
+ uvwasi_timestamp_t st_mtim,
+ uvwasi_fstflags_t fst_flags);
+uvwasi_errno_t uvwasi_fd_pread(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_iovec_t* iovs,
+ size_t iovs_len,
+ uvwasi_filesize_t offset,
+ size_t* nread);
+uvwasi_errno_t uvwasi_fd_prestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_prestat_t* buf);
+uvwasi_errno_t uvwasi_fd_prestat_dir_name(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ char* path,
+ size_t path_len);
+uvwasi_errno_t uvwasi_fd_pwrite(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_ciovec_t* iovs,
+ size_t iovs_len,
+ uvwasi_filesize_t offset,
+ size_t* nwritten);
+uvwasi_errno_t uvwasi_fd_read(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_iovec_t* iovs,
+ size_t iovs_len,
+ size_t* nread);
+uvwasi_errno_t uvwasi_fd_readdir(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ void* buf,
+ size_t buf_len,
+ uvwasi_dircookie_t cookie,
+ size_t* bufused);
+uvwasi_errno_t uvwasi_fd_renumber(uvwasi_t* uvwasi,
+ uvwasi_fd_t from,
+ uvwasi_fd_t to);
+uvwasi_errno_t uvwasi_fd_seek(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filedelta_t offset,
+ uvwasi_whence_t whence,
+ uvwasi_filesize_t* newoffset);
+uvwasi_errno_t uvwasi_fd_sync(uvwasi_t* uvwasi, uvwasi_fd_t fd);
+uvwasi_errno_t uvwasi_fd_tell(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t* offset);
+uvwasi_errno_t uvwasi_fd_write(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_ciovec_t* iovs,
+ size_t iovs_len,
+ size_t* nwritten);
+uvwasi_errno_t uvwasi_path_create_directory(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len);
+uvwasi_errno_t uvwasi_path_filestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_lookupflags_t flags,
+ const char* path,
+ size_t path_len,
+ uvwasi_filestat_t* buf);
+uvwasi_errno_t uvwasi_path_filestat_set_times(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_lookupflags_t flags,
+ const char* path,
+ size_t path_len,
+ uvwasi_timestamp_t st_atim,
+ uvwasi_timestamp_t st_mtim,
+ uvwasi_fstflags_t fst_flags);
+uvwasi_errno_t uvwasi_path_link(uvwasi_t* uvwasi,
+ uvwasi_fd_t old_fd,
+ uvwasi_lookupflags_t old_flags,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t new_fd,
+ const char* new_path,
+ size_t new_path_len);
+uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi,
+ uvwasi_fd_t dirfd,
+ uvwasi_lookupflags_t dirflags,
+ const char* path,
+ size_t path_len,
+ uvwasi_oflags_t o_flags,
+ uvwasi_rights_t fs_rights_base,
+ uvwasi_rights_t fs_rights_inheriting,
+ uvwasi_fdflags_t fs_flags,
+ uvwasi_fd_t* fd);
+uvwasi_errno_t uvwasi_path_readlink(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len,
+ char* buf,
+ size_t buf_len,
+ size_t* bufused);
+uvwasi_errno_t uvwasi_path_remove_directory(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len);
+uvwasi_errno_t uvwasi_path_rename(uvwasi_t* uvwasi,
+ uvwasi_fd_t old_fd,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t new_fd,
+ const char* new_path,
+ size_t new_path_len);
+uvwasi_errno_t uvwasi_path_symlink(uvwasi_t* uvwasi,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t fd,
+ const char* new_path,
+ size_t new_path_len);
+uvwasi_errno_t uvwasi_path_unlink_file(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len);
+uvwasi_errno_t uvwasi_poll_oneoff(uvwasi_t* uvwasi,
+ const uvwasi_subscription_t* in,
+ uvwasi_event_t* out,
+ size_t nsubscriptions,
+ size_t* nevents);
+uvwasi_errno_t uvwasi_proc_exit(uvwasi_t* uvwasi, uvwasi_exitcode_t rval);
+uvwasi_errno_t uvwasi_proc_raise(uvwasi_t* uvwasi, uvwasi_signal_t sig);
+uvwasi_errno_t uvwasi_random_get(uvwasi_t* uvwasi, void* buf, size_t buf_len);
+uvwasi_errno_t uvwasi_sched_yield(uvwasi_t* uvwasi);
+uvwasi_errno_t uvwasi_sock_recv(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ const uvwasi_iovec_t* ri_data,
+ size_t ri_data_len,
+ uvwasi_riflags_t ri_flags,
+ size_t* ro_datalen,
+ uvwasi_roflags_t* ro_flags);
+uvwasi_errno_t uvwasi_sock_send(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ const uvwasi_ciovec_t* si_data,
+ size_t si_data_len,
+ uvwasi_siflags_t si_flags,
+ size_t* so_datalen);
+uvwasi_errno_t uvwasi_sock_shutdown(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ uvwasi_sdflags_t how);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UVWASI_H__ */
diff --git a/deps/uvwasi/include/wasi_types.h b/deps/uvwasi/include/wasi_types.h
new file mode 100644
index 0000000000..34b5291c57
--- /dev/null
+++ b/deps/uvwasi/include/wasi_types.h
@@ -0,0 +1,323 @@
+#ifndef __UVWASI_WASI_TYPES_H__
+#define __UVWASI_WASI_TYPES_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* API: https://github.com/WebAssembly/WASI/blob/master/phases/unstable/docs/wasi_unstable_preview0.md */
+
+typedef uint8_t uvwasi_advice_t;
+#define UVWASI_ADVICE_NORMAL 0
+#define UVWASI_ADVICE_SEQUENTIAL 1
+#define UVWASI_ADVICE_RANDOM 2
+#define UVWASI_ADVICE_WILLNEED 3
+#define UVWASI_ADVICE_DONTNEED 4
+#define UVWASI_ADVICE_NOREUSE 5
+
+typedef struct uvwasi_ciovec_s {
+ const void* buf;
+ size_t buf_len;
+} uvwasi_ciovec_t;
+
+typedef uint32_t uvwasi_clockid_t;
+#define UVWASI_CLOCK_REALTIME 0
+#define UVWASI_CLOCK_MONOTONIC 1
+#define UVWASI_CLOCK_PROCESS_CPUTIME_ID 2
+#define UVWASI_CLOCK_THREAD_CPUTIME_ID 3
+
+typedef uint64_t uvwasi_device_t;
+
+typedef uint64_t uvwasi_dircookie_t;
+#define UVWASI_DIRCOOKIE_START 0
+
+typedef uint16_t uvwasi_errno_t;
+#define UVWASI_ESUCCESS 0
+#define UVWASI_E2BIG 1
+#define UVWASI_EACCES 2
+#define UVWASI_EADDRINUSE 3
+#define UVWASI_EADDRNOTAVAIL 4
+#define UVWASI_EAFNOSUPPORT 5
+#define UVWASI_EAGAIN 6
+#define UVWASI_EALREADY 7
+#define UVWASI_EBADF 8
+#define UVWASI_EBADMSG 9
+#define UVWASI_EBUSY 10
+#define UVWASI_ECANCELED 11
+#define UVWASI_ECHILD 12
+#define UVWASI_ECONNABORTED 13
+#define UVWASI_ECONNREFUSED 14
+#define UVWASI_ECONNRESET 15
+#define UVWASI_EDEADLK 16
+#define UVWASI_EDESTADDRREQ 17
+#define UVWASI_EDOM 18
+#define UVWASI_EDQUOT 19
+#define UVWASI_EEXIST 20
+#define UVWASI_EFAULT 21
+#define UVWASI_EFBIG 22
+#define UVWASI_EHOSTUNREACH 23
+#define UVWASI_EIDRM 24
+#define UVWASI_EILSEQ 25
+#define UVWASI_EINPROGRESS 26
+#define UVWASI_EINTR 27
+#define UVWASI_EINVAL 28
+#define UVWASI_EIO 29
+#define UVWASI_EISCONN 30
+#define UVWASI_EISDIR 31
+#define UVWASI_ELOOP 32
+#define UVWASI_EMFILE 33
+#define UVWASI_EMLINK 34
+#define UVWASI_EMSGSIZE 35
+#define UVWASI_EMULTIHOP 36
+#define UVWASI_ENAMETOOLONG 37
+#define UVWASI_ENETDOWN 38
+#define UVWASI_ENETRESET 39
+#define UVWASI_ENETUNREACH 40
+#define UVWASI_ENFILE 41
+#define UVWASI_ENOBUFS 42
+#define UVWASI_ENODEV 43
+#define UVWASI_ENOENT 44
+#define UVWASI_ENOEXEC 45
+#define UVWASI_ENOLCK 46
+#define UVWASI_ENOLINK 47
+#define UVWASI_ENOMEM 48
+#define UVWASI_ENOMSG 49
+#define UVWASI_ENOPROTOOPT 50
+#define UVWASI_ENOSPC 51
+#define UVWASI_ENOSYS 52
+#define UVWASI_ENOTCONN 53
+#define UVWASI_ENOTDIR 54
+#define UVWASI_ENOTEMPTY 55
+#define UVWASI_ENOTRECOVERABLE 56
+#define UVWASI_ENOTSOCK 57
+#define UVWASI_ENOTSUP 58
+#define UVWASI_ENOTTY 59
+#define UVWASI_ENXIO 60
+#define UVWASI_EOVERFLOW 61
+#define UVWASI_EOWNERDEAD 62
+#define UVWASI_EPERM 63
+#define UVWASI_EPIPE 64
+#define UVWASI_EPROTO 65
+#define UVWASI_EPROTONOSUPPORT 66
+#define UVWASI_EPROTOTYPE 67
+#define UVWASI_ERANGE 68
+#define UVWASI_EROFS 69
+#define UVWASI_ESPIPE 70
+#define UVWASI_ESRCH 71
+#define UVWASI_ESTALE 72
+#define UVWASI_ETIMEDOUT 73
+#define UVWASI_ETXTBSY 74
+#define UVWASI_EXDEV 75
+#define UVWASI_ENOTCAPABLE 76
+
+typedef uint16_t uvwasi_eventrwflags_t; /* Bitfield */
+#define UVWASI_EVENT_FD_READWRITE_HANGUP (1 << 0)
+
+typedef uint8_t uvwasi_eventtype_t;
+#define UVWASI_EVENTTYPE_CLOCK 0
+#define UVWASI_EVENTTYPE_FD_READ 1
+#define UVWASI_EVENTTYPE_FD_WRITE 2
+
+typedef uint32_t uvwasi_exitcode_t;
+
+typedef uint32_t uvwasi_fd_t;
+
+typedef uint16_t uvwasi_fdflags_t; /* Bitfield */
+#define UVWASI_FDFLAG_APPEND (1 << 0)
+#define UVWASI_FDFLAG_DSYNC (1 << 1)
+#define UVWASI_FDFLAG_NONBLOCK (1 << 2)
+#define UVWASI_FDFLAG_RSYNC (1 << 3)
+#define UVWASI_FDFLAG_SYNC (1 << 4)
+
+typedef int64_t uvwasi_filedelta_t;
+
+typedef uint64_t uvwasi_filesize_t;
+
+typedef uint8_t uvwasi_filetype_t;
+#define UVWASI_FILETYPE_UNKNOWN 0
+#define UVWASI_FILETYPE_BLOCK_DEVICE 1
+#define UVWASI_FILETYPE_CHARACTER_DEVICE 2
+#define UVWASI_FILETYPE_DIRECTORY 3
+#define UVWASI_FILETYPE_REGULAR_FILE 4
+#define UVWASI_FILETYPE_SOCKET_DGRAM 5
+#define UVWASI_FILETYPE_SOCKET_STREAM 6
+#define UVWASI_FILETYPE_SYMBOLIC_LINK 7
+
+typedef uint16_t uvwasi_fstflags_t; /* Bitfield */
+#define UVWASI_FILESTAT_SET_ATIM (1 << 0)
+#define UVWASI_FILESTAT_SET_ATIM_NOW (1 << 1)
+#define UVWASI_FILESTAT_SET_MTIM (1 << 2)
+#define UVWASI_FILESTAT_SET_MTIM_NOW (1 << 3)
+
+typedef uint64_t uvwasi_inode_t;
+
+typedef struct uvwasi_iovec_s {
+ void* buf;
+ size_t buf_len;
+} uvwasi_iovec_t;
+
+typedef uint32_t uvwasi_linkcount_t;
+
+typedef uint32_t uvwasi_lookupflags_t; /* Bitfield */
+#define UVWASI_LOOKUP_SYMLINK_FOLLOW (1 << 0)
+
+typedef uint16_t uvwasi_oflags_t; /* Bitfield */
+#define UVWASI_O_CREAT (1 << 0)
+#define UVWASI_O_DIRECTORY (1 << 1)
+#define UVWASI_O_EXCL (1 << 2)
+#define UVWASI_O_TRUNC (1 << 3)
+
+typedef uint8_t uvwasi_preopentype_t;
+#define UVWASI_PREOPENTYPE_DIR 0
+
+typedef struct uvwasi_prestat_s {
+ uvwasi_preopentype_t pr_type;
+ union uvwasi_prestat_u {
+ struct uvwasi_prestat_dir_t {
+ size_t pr_name_len;
+ } dir;
+ } u;
+} uvwasi_prestat_t;
+
+typedef uint16_t uvwasi_riflags_t; /* Bitfield */
+#define UVWASI_SOCK_RECV_PEEK (1 << 0)
+#define UVWASI_SOCK_RECV_WAITALL (1 << 1)
+
+typedef uint64_t uvwasi_rights_t; /* Bitfield */
+#define UVWASI_RIGHT_FD_DATASYNC (1 << 0)
+#define UVWASI_RIGHT_FD_READ (1 << 1)
+#define UVWASI_RIGHT_FD_SEEK (1 << 2)
+#define UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS (1 << 3)
+#define UVWASI_RIGHT_FD_SYNC (1 << 4)
+#define UVWASI_RIGHT_FD_TELL (1 << 5)
+#define UVWASI_RIGHT_FD_WRITE (1 << 6)
+#define UVWASI_RIGHT_FD_ADVISE (1 << 7)
+#define UVWASI_RIGHT_FD_ALLOCATE (1 << 8)
+#define UVWASI_RIGHT_PATH_CREATE_DIRECTORY (1 << 9)
+#define UVWASI_RIGHT_PATH_CREATE_FILE (1 << 10)
+#define UVWASI_RIGHT_PATH_LINK_SOURCE (1 << 11)
+#define UVWASI_RIGHT_PATH_LINK_TARGET (1 << 12)
+#define UVWASI_RIGHT_PATH_OPEN (1 << 13)
+#define UVWASI_RIGHT_FD_READDIR (1 << 14)
+#define UVWASI_RIGHT_PATH_READLINK (1 << 15)
+#define UVWASI_RIGHT_PATH_RENAME_SOURCE (1 << 16)
+#define UVWASI_RIGHT_PATH_RENAME_TARGET (1 << 17)
+#define UVWASI_RIGHT_PATH_FILESTAT_GET (1 << 18)
+#define UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE (1 << 19)
+#define UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES (1 << 20)
+#define UVWASI_RIGHT_FD_FILESTAT_GET (1 << 21)
+#define UVWASI_RIGHT_FD_FILESTAT_SET_SIZE (1 << 22)
+#define UVWASI_RIGHT_FD_FILESTAT_SET_TIMES (1 << 23)
+#define UVWASI_RIGHT_PATH_SYMLINK (1 << 24)
+#define UVWASI_RIGHT_PATH_REMOVE_DIRECTORY (1 << 25)
+#define UVWASI_RIGHT_PATH_UNLINK_FILE (1 << 26)
+#define UVWASI_RIGHT_POLL_FD_READWRITE (1 << 27)
+#define UVWASI_RIGHT_SOCK_SHUTDOWN (1 << 28)
+
+typedef uint16_t uvwasi_roflags_t; /* Bitfield */
+#define UVWASI_SOCK_RECV_DATA_TRUNCATED (1 << 0)
+
+typedef uint8_t uvwasi_sdflags_t; /* Bitfield */
+#define UVWASI_SHUT_RD (1 << 0)
+#define UVWASI_SHUT_WR (1 << 1)
+
+typedef uint16_t uvwasi_siflags_t; /* Bitfield */
+
+typedef uint8_t uvwasi_signal_t;
+#define UVWASI_SIGHUP 1
+#define UVWASI_SIGINT 2
+#define UVWASI_SIGQUIT 3
+#define UVWASI_SIGILL 4
+#define UVWASI_SIGTRAP 5
+#define UVWASI_SIGABRT 6
+#define UVWASI_SIGBUS 7
+#define UVWASI_SIGFPE 8
+#define UVWASI_SIGKILL 9
+#define UVWASI_SIGUSR1 10
+#define UVWASI_SIGSEGV 11
+#define UVWASI_SIGUSR2 12
+#define UVWASI_SIGPIPE 13
+#define UVWASI_SIGALRM 14
+#define UVWASI_SIGTERM 15
+#define UVWASI_SIGCHLD 16
+#define UVWASI_SIGCONT 17
+#define UVWASI_SIGSTOP 18
+#define UVWASI_SIGTSTP 19
+#define UVWASI_SIGTTIN 20
+#define UVWASI_SIGTTOU 21
+#define UVWASI_SIGURG 22
+#define UVWASI_SIGXCPU 23
+#define UVWASI_SIGXFSZ 24
+#define UVWASI_SIGVTALRM 25
+#define UVWASI_SIGPROF 26
+#define UVWASI_SIGWINCH 27
+#define UVWASI_SIGPOLL 28
+#define UVWASI_SIGPWR 29
+#define UVWASI_SIGSYS 30
+
+typedef uint16_t uvwasi_subclockflags_t; /* Bitfield */
+#define UVWASI_SUBSCRIPTION_CLOCK_ABSTIME (1 << 0)
+
+typedef uint64_t uvwasi_timestamp_t;
+
+typedef uint64_t uvwasi_userdata_t;
+
+typedef struct uvwasi_subscription_s {
+ uvwasi_userdata_t userdata;
+ uvwasi_eventtype_t type;
+ union {
+ struct {
+ uvwasi_userdata_t identifier;
+ uvwasi_clockid_t clock_id;
+ uvwasi_timestamp_t timeout;
+ uvwasi_timestamp_t precision;
+ uvwasi_subclockflags_t flags;
+ } clock;
+ struct {
+ uvwasi_fd_t fd;
+ } fd_readwrite;
+ } u;
+} uvwasi_subscription_t;
+
+typedef struct uvwasi_dirent_s {
+ uvwasi_dircookie_t d_next;
+ uvwasi_inode_t d_ino;
+ uint32_t d_namlen;
+ uvwasi_filetype_t d_type;
+} uvwasi_dirent_t;
+
+typedef struct uvwasi_fdstat_s {
+ uvwasi_filetype_t fs_filetype;
+ uvwasi_fdflags_t fs_flags;
+ uvwasi_rights_t fs_rights_base;
+ uvwasi_rights_t fs_rights_inheriting;
+} uvwasi_fdstat_t;
+
+typedef struct uvwasi_filestat_s {
+ uvwasi_device_t st_dev;
+ uvwasi_inode_t st_ino;
+ uvwasi_filetype_t st_filetype;
+ uvwasi_linkcount_t st_nlink;
+ uvwasi_filesize_t st_size;
+ uvwasi_timestamp_t st_atim;
+ uvwasi_timestamp_t st_mtim;
+ uvwasi_timestamp_t st_ctim;
+} uvwasi_filestat_t;
+
+typedef struct uvwasi_event_s {
+ uvwasi_userdata_t userdata;
+ uvwasi_errno_t error;
+ uvwasi_eventtype_t type;
+ union {
+ struct {
+ uvwasi_filesize_t nbytes;
+ uvwasi_eventrwflags_t flags;
+ } fd_readwrite;
+ } u;
+} uvwasi_event_t;
+
+typedef uint8_t uvwasi_whence_t;
+#define UVWASI_WHENCE_CUR 0
+#define UVWASI_WHENCE_END 1
+#define UVWASI_WHENCE_SET 2
+
+#endif /* __UVWASI_WASI_TYPES_H__ */
diff --git a/deps/uvwasi/src/clocks.c b/deps/uvwasi/src/clocks.c
new file mode 100644
index 0000000000..e1fbc696b6
--- /dev/null
+++ b/deps/uvwasi/src/clocks.c
@@ -0,0 +1,194 @@
+#ifndef _WIN32
+# include <errno.h>
+# include <sys/time.h>
+# include <sys/resource.h>
+# include <time.h>
+#endif /* _WIN32 */
+
+#include "uv.h"
+#include "wasi_types.h"
+#include "uv_mapping.h"
+
+
+#define UVWASI__WIN_TIME_AND_RETURN(handle, time) \
+ do { \
+ FILETIME create; \
+ FILETIME exit; \
+ FILETIME system; \
+ FILETIME user; \
+ SYSTEMTIME sys_system; \
+ SYSTEMTIME sys_user; \
+ if (0 == GetProcessTimes((handle), &create, &exit, &system, &user)) { \
+ return uvwasi__translate_uv_error( \
+ uv_translate_sys_error(GetLastError()) \
+ ); \
+ } \
+ \
+ if (0 == FileTimeToSystemTime(&system, &sys_system)) { \
+ return uvwasi__translate_uv_error( \
+ uv_translate_sys_error(GetLastError()) \
+ ); \
+ } \
+ \
+ if (0 == FileTimeToSystemTime(&user, &sys_user)) { \
+ return uvwasi__translate_uv_error( \
+ uv_translate_sys_error(GetLastError()) \
+ ); \
+ } \
+ \
+ (time) = (((sys_system.wHour * 3600) + (sys_system.wMinute * 60) + \
+ sys_system.wSecond) * NANOS_PER_SEC) + \
+ (sys_system.wMilliseconds * 1000000) + \
+ (((sys_user.wHour * 3600) + (sys_user.wMinute * 60) + \
+ sys_user.wSecond) * NANOS_PER_SEC) + \
+ (sys_user.wMilliseconds * 1000000); \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__CLOCK_GETTIME_AND_RETURN(clk, time) \
+ do { \
+ struct timespec ts; \
+ if (0 != clock_gettime((clk), &ts)) \
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno)); \
+ (time) = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec; \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__GETRUSAGE_AND_RETURN(who, time) \
+ do { \
+ struct rusage ru; \
+ if (0 != getrusage((who), &ru)) \
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno)); \
+ (time) = (ru.ru_utime.tv_sec * NANOS_PER_SEC) + \
+ (ru.ru_utime.tv_usec * 1000) + \
+ (ru.ru_stime.tv_sec * NANOS_PER_SEC) + \
+ (ru.ru_stime.tv_usec * 1000); \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__OSX_THREADTIME_AND_RETURN(time) \
+ do { \
+ mach_port_t thread; \
+ thread_basic_info_data_t info; \
+ mach_msg_type_number_t count; \
+ count = THREAD_BASIC_INFO_COUNT; \
+ thread = pthread_mach_thread_np(pthread_self()); \
+ if (KERN_SUCCESS != thread_info(thread, \
+ THREAD_BASIC_INFO, \
+ (thread_info_t) &info, \
+ &count)) { \
+ return UVWASI_ENOSYS; \
+ } \
+ (time) = (info.user_time.seconds * NANOS_PER_SEC) + \
+ (info.user_time.microseconds * 1000) + \
+ (info.system_time.seconds * NANOS_PER_SEC) + \
+ (info.system_time.microseconds * 1000); \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__WIN_GETRES_AND_RETURN(time) \
+ do { \
+ /* The GetProcessTimes() docs claim a resolution of 100 ns. */ \
+ (time) = 100; \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__CLOCK_GETRES_AND_RETURN(clk, time) \
+ do { \
+ struct timespec ts; \
+ /* Try calling clock_getres(). If it doesn't succeed, then default to \
+ 1000000. We implement all of the clocks, and some platforms (such as \
+ SmartOS) don't support all of the clocks, even though they define \
+ the constants for them. */ \
+ if (0 != clock_getres((clk), &ts)) \
+ (time) = 1000000; \
+ else \
+ (time) = (ts.tv_sec * NANOS_PER_SEC) + ts.tv_nsec; \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+#define UVWASI__SLOW_GETRES_AND_RETURN(time) \
+ do { \
+ /* Assume a "worst case" of 1000000 ns resolution. */ \
+ (time) = 1000000; \
+ return UVWASI_ESUCCESS; \
+ } while (0)
+
+
+uvwasi_errno_t uvwasi__clock_gettime_realtime(uvwasi_timestamp_t* time) {
+ uv_timeval64_t tv;
+ int r;
+
+ r = uv_gettimeofday(&tv);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ *time = (tv.tv_sec * NANOS_PER_SEC) + (tv.tv_usec * 1000);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi__clock_gettime_process_cputime(uvwasi_timestamp_t* time) {
+#if defined(_WIN32)
+ UVWASI__WIN_TIME_AND_RETURN(GetCurrentProcess(), *time);
+#elif defined(CLOCK_PROCESS_CPUTIME_ID) && \
+ !defined(__APPLE__) && \
+ !defined(__sun)
+ UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_PROCESS_CPUTIME_ID, *time);
+#else
+ UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_SELF, *time);
+#endif
+}
+
+
+uvwasi_errno_t uvwasi__clock_gettime_thread_cputime(uvwasi_timestamp_t* time) {
+#if defined(_WIN32)
+ UVWASI__WIN_TIME_AND_RETURN(GetCurrentThread(), *time);
+#elif defined(__APPLE__)
+ UVWASI__OSX_THREADTIME_AND_RETURN(*time);
+#elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__sun)
+ UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_THREAD_CPUTIME_ID, *time);
+#else
+# if defined(RUSAGE_LWP)
+ UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_LWP, *time);
+# elif defined(RUSAGE_THREAD)
+ UVWASI__GETRUSAGE_AND_RETURN(RUSAGE_THREAD, *time);
+# else
+ return UVWASI_ENOSYS;
+# endif /* RUSAGE_LWP */
+#endif
+}
+
+
+uvwasi_errno_t uvwasi__clock_getres_process_cputime(uvwasi_timestamp_t* time) {
+#if defined(_WIN32)
+ UVWASI__WIN_GETRES_AND_RETURN(*time);
+#elif defined(CLOCK_PROCESS_CPUTIME_ID) && \
+ !defined(__APPLE__) && \
+ !defined(__sun)
+ UVWASI__CLOCK_GETRES_AND_RETURN(CLOCK_PROCESS_CPUTIME_ID, *time);
+#else
+ UVWASI__SLOW_GETRES_AND_RETURN(*time);
+#endif
+}
+
+
+uvwasi_errno_t uvwasi__clock_getres_thread_cputime(uvwasi_timestamp_t* time) {
+#if defined(_WIN32)
+ UVWASI__WIN_GETRES_AND_RETURN(*time);
+#elif defined(__APPLE__)
+ UVWASI__SLOW_GETRES_AND_RETURN(*time);
+#elif defined(CLOCK_THREAD_CPUTIME_ID) && !defined(__sun)
+ UVWASI__CLOCK_GETTIME_AND_RETURN(CLOCK_THREAD_CPUTIME_ID, *time);
+#elif defined(RUSAGE_THREAD) || defined(RUSAGE_LWP)
+ UVWASI__SLOW_GETRES_AND_RETURN(*time);
+#else
+ return UVWASI_ENOSYS;
+#endif
+}
diff --git a/deps/uvwasi/src/fd_table.c b/deps/uvwasi/src/fd_table.c
new file mode 100644
index 0000000000..9343868074
--- /dev/null
+++ b/deps/uvwasi/src/fd_table.c
@@ -0,0 +1,422 @@
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#ifndef _WIN32
+# include <sys/types.h>
+#endif /* _WIN32 */
+
+#include "uv.h"
+#include "fd_table.h"
+#include "wasi_types.h"
+#include "uv_mapping.h"
+
+
+#define UVWASI__RIGHTS_ALL (UVWASI_RIGHT_FD_DATASYNC | \
+ UVWASI_RIGHT_FD_READ | \
+ UVWASI_RIGHT_FD_SEEK | \
+ UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
+ UVWASI_RIGHT_FD_SYNC | \
+ UVWASI_RIGHT_FD_TELL | \
+ UVWASI_RIGHT_FD_WRITE | \
+ UVWASI_RIGHT_FD_ADVISE | \
+ UVWASI_RIGHT_FD_ALLOCATE | \
+ UVWASI_RIGHT_PATH_CREATE_DIRECTORY | \
+ UVWASI_RIGHT_PATH_CREATE_FILE | \
+ UVWASI_RIGHT_PATH_LINK_SOURCE | \
+ UVWASI_RIGHT_PATH_LINK_TARGET | \
+ UVWASI_RIGHT_PATH_OPEN | \
+ UVWASI_RIGHT_FD_READDIR | \
+ UVWASI_RIGHT_PATH_READLINK | \
+ UVWASI_RIGHT_PATH_RENAME_SOURCE | \
+ UVWASI_RIGHT_PATH_RENAME_TARGET | \
+ UVWASI_RIGHT_PATH_FILESTAT_GET | \
+ UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE | \
+ UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES | \
+ UVWASI_RIGHT_FD_FILESTAT_GET | \
+ UVWASI_RIGHT_FD_FILESTAT_SET_TIMES | \
+ UVWASI_RIGHT_FD_FILESTAT_SET_SIZE | \
+ UVWASI_RIGHT_PATH_SYMLINK | \
+ UVWASI_RIGHT_PATH_UNLINK_FILE | \
+ UVWASI_RIGHT_PATH_REMOVE_DIRECTORY | \
+ UVWASI_RIGHT_POLL_FD_READWRITE | \
+ UVWASI_RIGHT_SOCK_SHUTDOWN)
+
+#define UVWASI__RIGHTS_BLOCK_DEVICE_BASE UVWASI__RIGHTS_ALL
+#define UVWASI__RIGHTS_BLOCK_DEVICE_INHERITING UVWASI__RIGHTS_ALL
+
+#define UVWASI__RIGHTS_CHARACTER_DEVICE_BASE UVWASI__RIGHTS_ALL
+#define UVWASI__RIGHTS_CHARACTER_DEVICE_INHERITING UVWASI__RIGHTS_ALL
+
+#define UVWASI__RIGHTS_REGULAR_FILE_BASE (UVWASI_RIGHT_FD_DATASYNC | \
+ UVWASI_RIGHT_FD_READ | \
+ UVWASI_RIGHT_FD_SEEK | \
+ UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
+ UVWASI_RIGHT_FD_SYNC | \
+ UVWASI_RIGHT_FD_TELL | \
+ UVWASI_RIGHT_FD_WRITE | \
+ UVWASI_RIGHT_FD_ADVISE | \
+ UVWASI_RIGHT_FD_ALLOCATE | \
+ UVWASI_RIGHT_FD_FILESTAT_GET | \
+ UVWASI_RIGHT_FD_FILESTAT_SET_SIZE | \
+ UVWASI_RIGHT_FD_FILESTAT_SET_TIMES |\
+ UVWASI_RIGHT_POLL_FD_READWRITE)
+#define UVWASI__RIGHTS_REGULAR_FILE_INHERITING 0
+
+#define UVWASI__RIGHTS_DIRECTORY_BASE (UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
+ UVWASI_RIGHT_FD_SYNC | \
+ UVWASI_RIGHT_FD_ADVISE | \
+ UVWASI_RIGHT_PATH_CREATE_DIRECTORY | \
+ UVWASI_RIGHT_PATH_CREATE_FILE | \
+ UVWASI_RIGHT_PATH_LINK_SOURCE | \
+ UVWASI_RIGHT_PATH_LINK_TARGET | \
+ UVWASI_RIGHT_PATH_OPEN | \
+ UVWASI_RIGHT_FD_READDIR | \
+ UVWASI_RIGHT_PATH_READLINK | \
+ UVWASI_RIGHT_PATH_RENAME_SOURCE | \
+ UVWASI_RIGHT_PATH_RENAME_TARGET | \
+ UVWASI_RIGHT_PATH_FILESTAT_GET | \
+ UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE | \
+ UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES | \
+ UVWASI_RIGHT_FD_FILESTAT_GET | \
+ UVWASI_RIGHT_FD_FILESTAT_SET_TIMES | \
+ UVWASI_RIGHT_PATH_SYMLINK | \
+ UVWASI_RIGHT_PATH_UNLINK_FILE | \
+ UVWASI_RIGHT_PATH_REMOVE_DIRECTORY | \
+ UVWASI_RIGHT_POLL_FD_READWRITE)
+#define UVWASI__RIGHTS_DIRECTORY_INHERITING (UVWASI__RIGHTS_DIRECTORY_BASE | \
+ UVWASI__RIGHTS_REGULAR_FILE_BASE)
+
+#define UVWASI__RIGHTS_SOCKET_BASE (UVWASI_RIGHT_FD_READ | \
+ UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
+ UVWASI_RIGHT_FD_WRITE | \
+ UVWASI_RIGHT_FD_FILESTAT_GET | \
+ UVWASI_RIGHT_POLL_FD_READWRITE | \
+ UVWASI_RIGHT_SOCK_SHUTDOWN)
+#define UVWASI__RIGHTS_SOCKET_INHERITING UVWASI__RIGHTS_ALL;
+
+#define UVWASI__RIGHTS_TTY_BASE (UVWASI_RIGHT_FD_READ | \
+ UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS | \
+ UVWASI_RIGHT_FD_WRITE | \
+ UVWASI_RIGHT_FD_FILESTAT_GET | \
+ UVWASI_RIGHT_POLL_FD_READWRITE)
+#define UVWASI__RIGHTS_TTY_INHERITING 0
+
+static uvwasi_errno_t uvwasi__get_type_and_rights(uv_file fd,
+ int flags,
+ uvwasi_filetype_t* type,
+ uvwasi_rights_t* rights_base,
+ uvwasi_rights_t* rights_inheriting) {
+ uv_fs_t req;
+ uvwasi_filetype_t filetype;
+ int read_or_write_only;
+ int r;
+
+ r = uv_fs_fstat(NULL, &req, fd, NULL);
+ filetype = uvwasi__stat_to_filetype(&req.statbuf);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ *type = filetype;
+ switch (filetype) {
+ case UVWASI_FILETYPE_REGULAR_FILE:
+ *rights_base = UVWASI__RIGHTS_REGULAR_FILE_BASE;
+ *rights_inheriting = UVWASI__RIGHTS_REGULAR_FILE_INHERITING;
+ break;
+
+ case UVWASI_FILETYPE_DIRECTORY:
+ *rights_base = UVWASI__RIGHTS_DIRECTORY_BASE;
+ *rights_inheriting = UVWASI__RIGHTS_DIRECTORY_INHERITING;
+ break;
+
+ /* uvwasi__stat_to_filetype() cannot differentiate socket types. It only
+ returns UVWASI_FILETYPE_SOCKET_STREAM. */
+ case UVWASI_FILETYPE_SOCKET_STREAM:
+ if (uv_guess_handle(fd) == UV_UDP)
+ *type = UVWASI_FILETYPE_SOCKET_DGRAM;
+
+ *rights_base = UVWASI__RIGHTS_SOCKET_BASE;
+ *rights_inheriting = UVWASI__RIGHTS_SOCKET_INHERITING;
+ break;
+
+ case UVWASI_FILETYPE_CHARACTER_DEVICE:
+ if (uv_guess_handle(fd) == UV_TTY) {
+ *rights_base = UVWASI__RIGHTS_TTY_BASE;
+ *rights_inheriting = UVWASI__RIGHTS_TTY_INHERITING;
+ } else {
+ *rights_base = UVWASI__RIGHTS_CHARACTER_DEVICE_BASE;
+ *rights_inheriting = UVWASI__RIGHTS_CHARACTER_DEVICE_INHERITING;
+ }
+ break;
+
+ case UVWASI_FILETYPE_BLOCK_DEVICE:
+ *rights_base = UVWASI__RIGHTS_BLOCK_DEVICE_BASE;
+ *rights_inheriting = UVWASI__RIGHTS_BLOCK_DEVICE_INHERITING;
+ break;
+
+ default:
+ *rights_base = 0;
+ *rights_inheriting = 0;
+ }
+
+ if (*type == UVWASI_FILETYPE_UNKNOWN)
+ return UVWASI_EINVAL;
+
+ /* Disable read/write bits depending on access mode. */
+ read_or_write_only = flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
+
+ if (read_or_write_only == UV_FS_O_RDONLY)
+ *rights_base &= ~UVWASI_RIGHT_FD_WRITE;
+ else if (read_or_write_only == UV_FS_O_WRONLY)
+ *rights_base &= ~UVWASI_RIGHT_FD_READ;
+
+ return UVWASI_ESUCCESS;
+}
+
+
+static uvwasi_errno_t uvwasi__fd_table_insert(struct uvwasi_fd_table_t* table,
+ uv_file fd,
+ const char* mapped_path,
+ const char* real_path,
+ uvwasi_filetype_t type,
+ uvwasi_rights_t rights_base,
+ uvwasi_rights_t rights_inheriting,
+ int preopen,
+ struct uvwasi_fd_wrap_t** wrap) {
+ struct uvwasi_fd_wrap_t* entry;
+ struct uvwasi_fd_wrap_t* new_fds;
+ uint32_t new_size;
+ int index;
+ uint32_t i;
+
+ /* Check that there is room for a new item. If there isn't, grow the table. */
+ if (table->used >= table->size) {
+ new_size = table->size * 2;
+ new_fds = realloc(table->fds, new_size * sizeof(*new_fds));
+ if (new_fds == NULL)
+ return UVWASI_ENOMEM;
+
+ for (i = table->size; i < new_size; ++i)
+ new_fds[i].valid = 0;
+
+ index = table->size;
+ table->fds = new_fds;
+ table->size = new_size;
+ } else {
+ /* The table is big enough, so find an empty slot for the new data. */
+ index = -1;
+ for (i = 0; i < table->size; ++i) {
+ if (table->fds[i].valid != 1) {
+ index = i;
+ break;
+ }
+ }
+
+ /* index should never be -1. */
+ if (index == -1)
+ return UVWASI_ENOSPC;
+ }
+
+ entry = &table->fds[index];
+ entry->id = index;
+ entry->fd = fd;
+ strcpy(entry->path, mapped_path);
+ strcpy(entry->real_path, real_path);
+ entry->type = type;
+ entry->rights_base = rights_base;
+ entry->rights_inheriting = rights_inheriting;
+ entry->preopen = preopen;
+ entry->valid = 1;
+ table->used++;
+
+ if (wrap != NULL)
+ *wrap = entry;
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_init(struct uvwasi_fd_table_t* table,
+ uint32_t init_size) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_filetype_t type;
+ uvwasi_rights_t base;
+ uvwasi_rights_t inheriting;
+ uvwasi_errno_t err;
+ uvwasi_fd_t i;
+
+ /* Require an initial size of at least three to store the stdio FDs. */
+ if (table == NULL || init_size < 3)
+ return UVWASI_EINVAL;
+
+ table->used = 0;
+ table->size = init_size;
+ table->fds = calloc(init_size, sizeof(struct uvwasi_fd_wrap_t));
+
+ if (table->fds == NULL)
+ return UVWASI_ENOMEM;
+
+ /* Create the stdio FDs. */
+ for (i = 0; i < 3; ++i) {
+ err = uvwasi__get_type_and_rights(i,
+ UV_FS_O_RDWR,
+ &type,
+ &base,
+ &inheriting);
+ if (err != UVWASI_ESUCCESS)
+ goto error_exit;
+
+ err = uvwasi__fd_table_insert(table,
+ i,
+ "",
+ "",
+ type,
+ base,
+ inheriting,
+ 0,
+ &wrap);
+ if (err != UVWASI_ESUCCESS)
+ goto error_exit;
+
+ if (wrap->id != i || wrap->id != (uvwasi_fd_t) wrap->fd) {
+ err = UVWASI_EBADF;
+ goto error_exit;
+ }
+ }
+
+ return UVWASI_ESUCCESS;
+error_exit:
+ uvwasi_fd_table_free(table);
+ return err;
+}
+
+
+void uvwasi_fd_table_free(struct uvwasi_fd_table_t* table) {
+ if (table == NULL)
+ return;
+
+ free(table->fds);
+ table->fds = NULL;
+ table->size = 0;
+ table->used = 0;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_insert_preopen(struct uvwasi_fd_table_t* table,
+ const uv_file fd,
+ const char* path,
+ const char* real_path) {
+ uvwasi_filetype_t type;
+ uvwasi_rights_t base;
+ uvwasi_rights_t inheriting;
+ uvwasi_errno_t err;
+
+ if (table == NULL || path == NULL || real_path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi__get_type_and_rights(fd, 0, &type, &base, &inheriting);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ if (type != UVWASI_FILETYPE_DIRECTORY)
+ return UVWASI_ENOTDIR;
+
+ err = uvwasi__fd_table_insert(table,
+ fd,
+ path,
+ real_path,
+ UVWASI_FILETYPE_DIRECTORY,
+ UVWASI__RIGHTS_DIRECTORY_BASE,
+ UVWASI__RIGHTS_DIRECTORY_INHERITING,
+ 1,
+ NULL);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_insert_fd(struct uvwasi_fd_table_t* table,
+ const uv_file fd,
+ const int flags,
+ const char* path,
+ uvwasi_rights_t rights_base,
+ uvwasi_rights_t rights_inheriting,
+ struct uvwasi_fd_wrap_t* wrap) {
+ struct uvwasi_fd_wrap_t* fd_wrap;
+ uvwasi_filetype_t type;
+ uvwasi_rights_t max_base;
+ uvwasi_rights_t max_inheriting;
+ uvwasi_errno_t r;
+
+ if (table == NULL || path == NULL || wrap == NULL)
+ return UVWASI_EINVAL;
+
+ r = uvwasi__get_type_and_rights(fd, flags, &type, &max_base, &max_inheriting);
+ if (r != UVWASI_ESUCCESS)
+ return r;
+
+ r = uvwasi__fd_table_insert(table,
+ fd,
+ path,
+ path,
+ type,
+ rights_base & max_base,
+ rights_inheriting & max_inheriting,
+ 0,
+ &fd_wrap);
+ if (r != UVWASI_ESUCCESS)
+ return r;
+
+ *wrap = *fd_wrap;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_get(const struct uvwasi_fd_table_t* table,
+ const uvwasi_fd_t id,
+ struct uvwasi_fd_wrap_t** wrap,
+ uvwasi_rights_t rights_base,
+ uvwasi_rights_t rights_inheriting) {
+ struct uvwasi_fd_wrap_t* entry;
+
+ if (table == NULL || wrap == NULL)
+ return UVWASI_EINVAL;
+ if (id >= table->size)
+ return UVWASI_EBADF;
+
+ entry = &table->fds[id];
+
+ if (entry->valid != 1 || entry->id != id)
+ return UVWASI_EBADF;
+
+ /* Validate that the fd has the necessary rights. */
+ if ((~entry->rights_base & rights_base) != 0 ||
+ (~entry->rights_inheriting & rights_inheriting) != 0)
+ return UVWASI_ENOTCAPABLE;
+
+ *wrap = entry;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_remove(struct uvwasi_fd_table_t* table,
+ const uvwasi_fd_t id) {
+ struct uvwasi_fd_wrap_t* entry;
+
+ if (table == NULL)
+ return UVWASI_EINVAL;
+ if (id >= table->size)
+ return UVWASI_EBADF;
+
+ entry = &table->fds[id];
+
+ if (entry->valid != 1 || entry->id != id)
+ return UVWASI_EBADF;
+
+ entry->valid = 0;
+ table->used--;
+ return UVWASI_ESUCCESS;
+}
diff --git a/deps/uvwasi/src/uv_mapping.c b/deps/uvwasi/src/uv_mapping.c
new file mode 100644
index 0000000000..846dcedbeb
--- /dev/null
+++ b/deps/uvwasi/src/uv_mapping.c
@@ -0,0 +1,243 @@
+#include <sys/stat.h>
+
+#ifndef _WIN32
+# include <sys/types.h>
+#endif /* _WIN32 */
+
+#include "uv.h"
+#include "wasi_types.h"
+#include "uv_mapping.h"
+
+#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
+# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#if !defined(S_ISCHR) && defined(S_IFMT) && defined(S_IFCHR)
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+
+#if !defined(S_ISLNK) && defined(S_IFMT) && defined(S_IFLNK)
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+
+uvwasi_errno_t uvwasi__translate_uv_error(int err) {
+ switch (err) {
+ case UV_E2BIG: return UVWASI_E2BIG;
+ case UV_EACCES: return UVWASI_EACCES;
+ case UV_EADDRINUSE: return UVWASI_EADDRINUSE;
+ case UV_EADDRNOTAVAIL: return UVWASI_EADDRNOTAVAIL;
+ case UV_EAFNOSUPPORT: return UVWASI_EAFNOSUPPORT;
+ case UV_EAGAIN: return UVWASI_EAGAIN;
+ case UV_EALREADY: return UVWASI_EALREADY;
+ case UV_EBADF: return UVWASI_EBADF;
+ case UV_EBUSY: return UVWASI_EBUSY;
+ case UV_ECANCELED: return UVWASI_ECANCELED;
+ case UV_ECONNABORTED: return UVWASI_ECONNABORTED;
+ case UV_ECONNREFUSED: return UVWASI_ECONNREFUSED;
+ case UV_ECONNRESET: return UVWASI_ECONNRESET;
+ case UV_EDESTADDRREQ: return UVWASI_EDESTADDRREQ;
+ case UV_EEXIST: return UVWASI_EEXIST;
+ case UV_EFAULT: return UVWASI_EFAULT;
+ case UV_EFBIG: return UVWASI_EFBIG;
+ case UV_EHOSTUNREACH: return UVWASI_EHOSTUNREACH;
+ case UV_EINTR: return UVWASI_EINTR;
+ case UV_EINVAL: return UVWASI_EINVAL;
+ case UV_EIO: return UVWASI_EIO;
+ case UV_EISCONN: return UVWASI_EISCONN;
+ case UV_EISDIR: return UVWASI_EISDIR;
+ case UV_ELOOP: return UVWASI_ELOOP;
+ case UV_EMFILE: return UVWASI_EMFILE;
+ case UV_EMLINK: return UVWASI_EMLINK;
+ case UV_EMSGSIZE: return UVWASI_EMSGSIZE;
+ case UV_ENAMETOOLONG: return UVWASI_ENAMETOOLONG;
+ case UV_ENETDOWN: return UVWASI_ENETDOWN;
+ case UV_ENETUNREACH: return UVWASI_ENETUNREACH;
+ case UV_ENFILE: return UVWASI_ENFILE;
+ case UV_ENOBUFS: return UVWASI_ENOBUFS;
+ case UV_ENODEV: return UVWASI_ENODEV;
+ case UV_ENOENT: return UVWASI_ENOENT;
+ case UV_ENOMEM: return UVWASI_ENOMEM;
+ case UV_ENOPROTOOPT: return UVWASI_ENOPROTOOPT;
+ case UV_ENOSPC: return UVWASI_ENOSPC;
+ case UV_ENOSYS: return UVWASI_ENOSYS;
+ case UV_ENOTCONN: return UVWASI_ENOTCONN;
+ case UV_ENOTDIR: return UVWASI_ENOTDIR;
+ /* On at least some AIX machines, ENOTEMPTY and EEXIST are equivalent. */
+#if ENOTEMPTY != EEXIST
+ case UV_ENOTEMPTY: return UVWASI_ENOTEMPTY;
+#endif /* ENOTEMPTY != EEXIST */
+ case UV_ENOTSOCK: return UVWASI_ENOTSOCK;
+ case UV_ENOTSUP: return UVWASI_ENOTSUP;
+ case UV_ENXIO: return UVWASI_ENXIO;
+ case UV_EPERM: return UVWASI_EPERM;
+ case UV_EPIPE: return UVWASI_EPIPE;
+ case UV_EPROTO: return UVWASI_EPROTO;
+ case UV_EPROTONOSUPPORT: return UVWASI_EPROTONOSUPPORT;
+ case UV_EPROTOTYPE: return UVWASI_EPROTOTYPE;
+ case UV_ERANGE: return UVWASI_ERANGE;
+ case UV_EROFS: return UVWASI_EROFS;
+ case UV_ESPIPE: return UVWASI_ESPIPE;
+ case UV_ESRCH: return UVWASI_ESRCH;
+ case UV_ETIMEDOUT: return UVWASI_ETIMEDOUT;
+ case UV_ETXTBSY: return UVWASI_ETXTBSY;
+ case UV_EXDEV: return UVWASI_EXDEV;
+ case 0: return UVWASI_ESUCCESS;
+ /* The following libuv error codes have no corresponding WASI error code:
+ UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS, UV_EAI_BADHINTS,
+ UV_EAI_CANCELED, UV_EAI_FAIL, UV_EAI_FAMILY, UV_EAI_MEMORY,
+ UV_EAI_NODATA, UV_EAI_NONAME, UV_EAI_OVERFLOW, UV_EAI_PROTOCOL,
+ UV_EAI_SERVICE, UV_EAI_SOCKTYPE, UV_ECHARSET, UV_ENONET, UV_EOF,
+ UV_ESHUTDOWN, UV_UNKNOWN
+ */
+ default:
+ /* libuv errors are < 0 */
+ if (err > 0)
+ return err;
+
+ return UVWASI_ENOSYS;
+ }
+}
+
+
+int uvwasi__translate_to_uv_signal(uvwasi_signal_t sig) {
+ switch (sig) {
+#ifdef SIGABRT
+ case UVWASI_SIGABRT: return SIGABRT;
+#endif
+#ifdef SIGALRM
+ case UVWASI_SIGALRM: return SIGALRM;
+#endif
+#ifdef SIGBUS
+ case UVWASI_SIGBUS: return SIGBUS;
+#endif
+#ifdef SIGCHLD
+ case UVWASI_SIGCHLD: return SIGCHLD;
+#endif
+#ifdef SIGCONT
+ case UVWASI_SIGCONT: return SIGCONT;
+#endif
+#ifdef SIGFPE
+ case UVWASI_SIGFPE: return SIGFPE;
+#endif
+#ifdef SIGHUP
+ case UVWASI_SIGHUP: return SIGHUP;
+#endif
+#ifdef SIGILL
+ case UVWASI_SIGILL: return SIGILL;
+#endif
+#ifdef SIGINT
+ case UVWASI_SIGINT: return SIGINT;
+#endif
+#ifdef SIGKILL
+ case UVWASI_SIGKILL: return SIGKILL;
+#endif
+#ifdef SIGPIPE
+ case UVWASI_SIGPIPE: return SIGPIPE;
+#endif
+#ifdef SIGQUIT
+ case UVWASI_SIGQUIT: return SIGQUIT;
+#endif
+#ifdef SIGSEGV
+ case UVWASI_SIGSEGV: return SIGSEGV;
+#endif
+#ifdef SIGSTOP
+ case UVWASI_SIGSTOP: return SIGSTOP;
+#endif
+#ifdef SIGSYS
+ case UVWASI_SIGSYS: return SIGSYS;
+#endif
+#ifdef SIGTERM
+ case UVWASI_SIGTERM: return SIGTERM;
+#endif
+#ifdef SIGTRAP
+ case UVWASI_SIGTRAP: return SIGTRAP;
+#endif
+#ifdef SIGTSTP
+ case UVWASI_SIGTSTP: return SIGTSTP;
+#endif
+#ifdef SIGTTIN
+ case UVWASI_SIGTTIN: return SIGTTIN;
+#endif
+#ifdef SIGTTOU
+ case UVWASI_SIGTTOU: return SIGTTOU;
+#endif
+#ifdef SIGURG
+ case UVWASI_SIGURG: return SIGURG;
+#endif
+#ifdef SIGUSR1
+ case UVWASI_SIGUSR1: return SIGUSR1;
+#endif
+#ifdef SIGUSR2
+ case UVWASI_SIGUSR2: return SIGUSR2;
+#endif
+#ifdef SIGVTALRM
+ case UVWASI_SIGVTALRM: return SIGVTALRM;
+#endif
+#ifdef SIGXCPU
+ case UVWASI_SIGXCPU: return SIGXCPU;
+#endif
+#ifdef SIGXFSZ
+ case UVWASI_SIGXFSZ: return SIGXFSZ;
+#endif
+ default: return -1;
+ }
+}
+
+
+uvwasi_timestamp_t uvwasi__timespec_to_timestamp(const uv_timespec_t* ts) {
+ /* TODO(cjihrig): Handle overflow. */
+ return (uvwasi_timestamp_t) ts->tv_sec * NANOS_PER_SEC + ts->tv_nsec;
+}
+
+
+uvwasi_filetype_t uvwasi__stat_to_filetype(const uv_stat_t* stat) {
+ uint64_t mode;
+
+ mode = stat->st_mode;
+
+ if (S_ISREG(mode))
+ return UVWASI_FILETYPE_REGULAR_FILE;
+
+ if (S_ISDIR(mode))
+ return UVWASI_FILETYPE_DIRECTORY;
+
+ if (S_ISCHR(mode))
+ return UVWASI_FILETYPE_CHARACTER_DEVICE;
+
+ if (S_ISLNK(mode))
+ return UVWASI_FILETYPE_SYMBOLIC_LINK;
+
+#ifdef S_ISSOCK
+ if (S_ISSOCK(mode))
+ return UVWASI_FILETYPE_SOCKET_STREAM;
+#endif /* S_ISSOCK */
+
+#ifdef S_ISFIFO
+ if (S_ISFIFO(mode))
+ return UVWASI_FILETYPE_SOCKET_STREAM;
+#endif /* S_ISFIFO */
+
+#ifdef S_ISBLK
+ if (S_ISBLK(mode))
+ return UVWASI_FILETYPE_BLOCK_DEVICE;
+#endif /* S_ISBLK */
+
+ return UVWASI_FILETYPE_UNKNOWN;
+}
+
+
+void uvwasi__stat_to_filestat(const uv_stat_t* stat, uvwasi_filestat_t* fs) {
+ fs->st_dev = stat->st_dev;
+ fs->st_ino = stat->st_ino;
+ fs->st_nlink = stat->st_nlink;
+ fs->st_size = stat->st_size;
+ fs->st_filetype = uvwasi__stat_to_filetype(stat);
+ fs->st_atim = uvwasi__timespec_to_timestamp(&stat->st_atim);
+ fs->st_mtim = uvwasi__timespec_to_timestamp(&stat->st_mtim);
+ fs->st_ctim = uvwasi__timespec_to_timestamp(&stat->st_ctim);
+}
diff --git a/deps/uvwasi/src/uvwasi.c b/deps/uvwasi/src/uvwasi.c
new file mode 100644
index 0000000000..39a94b6d21
--- /dev/null
+++ b/deps/uvwasi/src/uvwasi.c
@@ -0,0 +1,1918 @@
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+# include <sched.h>
+# include <sys/types.h>
+# include <unistd.h>
+# include <dirent.h>
+# include <time.h>
+# define SLASH '/'
+# define SLASH_STR "/"
+# define IS_SLASH(c) ((c) == '/')
+#else
+# define SLASH '\\'
+# define SLASH_STR "\\"
+# define IS_SLASH(c) ((c) == '/' || (c) == '\\')
+#endif /* _WIN32 */
+
+#define UVWASI__READDIR_NUM_ENTRIES 1
+
+#include "uvwasi.h"
+#include "uv.h"
+#include "uv_mapping.h"
+#include "fd_table.h"
+#include "clocks.h"
+
+
+static int uvwasi__is_absolute_path(const char* path, size_t path_len) {
+ /* TODO(cjihrig): Add a Windows implementation. */
+ return path != NULL && path_len > 0 && path[0] == SLASH;
+}
+
+
+static uvwasi_errno_t uvwasi__resolve_path(const struct uvwasi_fd_wrap_t* fd,
+ const char* path,
+ size_t path_len,
+ char* resolved_path,
+ uvwasi_lookupflags_t flags) {
+ /* TODO(cjihrig): path_len is treated as a size. Need to verify if path_len is
+ really a string length or a size. Also need to verify if it is null
+ terminated. */
+ uv_fs_t realpath_req;
+ uvwasi_errno_t err;
+ char* abs_path;
+ char* tok;
+ char* ptr;
+ int realpath_size;
+ int abs_size;
+ int input_is_absolute;
+ int r;
+#ifdef _WIN32
+ int i;
+#endif /* _WIN32 */
+
+ err = UVWASI_ESUCCESS;
+ input_is_absolute = uvwasi__is_absolute_path(path, path_len);
+
+ if (1 == input_is_absolute) {
+ /* TODO(cjihrig): Revisit this. Copying is probably not necessary here. */
+ abs_size = path_len;
+ abs_path = malloc(abs_size);
+ if (abs_path == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ memcpy(abs_path, path, abs_size);
+ } else {
+ /* Resolve the relative path to fd's real path. */
+ abs_size = path_len + strlen(fd->real_path) + 2;
+ abs_path = malloc(abs_size);
+ if (abs_path == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ r = snprintf(abs_path, abs_size, "%s/%s", fd->real_path, path);
+ if (r <= 0) {
+ err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+ goto exit;
+ }
+ }
+
+#ifdef _WIN32
+ /* On Windows, convert slashes to backslashes. */
+ for (i = 0; i < abs_size; ++i) {
+ if (abs_path[i] == '/')
+ abs_path[i] = SLASH;
+ }
+#endif /* _WIN32 */
+
+ ptr = resolved_path;
+ tok = strtok(abs_path, SLASH_STR);
+ for (; tok != NULL; tok = strtok(NULL, SLASH_STR)) {
+ if (0 == strcmp(tok, "."))
+ continue;
+
+ if (0 == strcmp(tok, "..")) {
+ while (*ptr != SLASH && ptr != resolved_path)
+ ptr--;
+ *ptr = '\0';
+ continue;
+ }
+
+#ifdef _WIN32
+ /* On Windows, prevent a leading slash in the path. */
+ if (ptr == resolved_path)
+ r = sprintf(ptr, "%s", tok);
+ else
+#endif /* _WIN32 */
+ r = sprintf(ptr, "%c%s", SLASH, tok);
+
+ if (r < 1) { /* At least one character should have been written. */
+ err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+ goto exit;
+ }
+
+ ptr += r;
+ }
+
+ if ((flags & UVWASI_LOOKUP_SYMLINK_FOLLOW) == UVWASI_LOOKUP_SYMLINK_FOLLOW) {
+ r = uv_fs_realpath(NULL, &realpath_req, resolved_path, NULL);
+ if (r == 0) {
+ realpath_size = strlen(realpath_req.ptr) + 1;
+ if (realpath_size > PATH_MAX_BYTES) {
+ err = UVWASI_ENOBUFS;
+ uv_fs_req_cleanup(&realpath_req);
+ goto exit;
+ }
+
+ memcpy(resolved_path, realpath_req.ptr, realpath_size);
+ } else if (r != UV_ENOENT) {
+ /* Report errors except ENOENT. */
+ err = uvwasi__translate_uv_error(r);
+ uv_fs_req_cleanup(&realpath_req);
+ goto exit;
+ }
+
+ uv_fs_req_cleanup(&realpath_req);
+ }
+
+ /* Verify that the resolved path is still in the sandbox. */
+ if (resolved_path != strstr(resolved_path, fd->real_path)) {
+ err = UVWASI_ENOTCAPABLE;
+ goto exit;
+ }
+
+exit:
+ free(abs_path);
+ return err;
+}
+
+
+static uvwasi_errno_t uvwasi__lseek(uv_file fd,
+ uvwasi_filedelta_t offset,
+ uvwasi_whence_t whence,
+ uvwasi_filesize_t* newoffset) {
+ int real_whence;
+
+ if (whence == UVWASI_WHENCE_CUR)
+ real_whence = SEEK_CUR;
+ else if (whence == UVWASI_WHENCE_END)
+ real_whence = SEEK_END;
+ else if (whence == UVWASI_WHENCE_SET)
+ real_whence = SEEK_SET;
+ else
+ return UVWASI_EINVAL;
+
+#ifdef _WIN32
+ int64_t r;
+
+ r = _lseeki64(fd, offset, real_whence);
+ if (-1L == r)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+#else
+ off_t r;
+
+ r = lseek(fd, offset, real_whence);
+ if ((off_t) -1 == r)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+#endif /* _WIN32 */
+
+ *newoffset = r;
+ return UVWASI_ESUCCESS;
+}
+
+
+static uvwasi_errno_t uvwasi__setup_iovs(uv_buf_t** buffers,
+ const uvwasi_iovec_t* iovs,
+ size_t iovs_len) {
+ uv_buf_t* bufs;
+ size_t i;
+
+ bufs = malloc(iovs_len * sizeof(*bufs));
+ if (bufs == NULL)
+ return UVWASI_ENOMEM;
+
+ for (i = 0; i < iovs_len; ++i)
+ bufs[i] = uv_buf_init(iovs[i].buf, iovs[i].buf_len);
+
+ *buffers = bufs;
+ return UVWASI_ESUCCESS;
+}
+
+
+static uvwasi_errno_t uvwasi__setup_ciovs(uv_buf_t** buffers,
+ const uvwasi_ciovec_t* iovs,
+ size_t iovs_len) {
+ uv_buf_t* bufs;
+ size_t i;
+
+ bufs = malloc(iovs_len * sizeof(*bufs));
+ if (bufs == NULL)
+ return UVWASI_ENOMEM;
+
+ for (i = 0; i < iovs_len; ++i)
+ bufs[i] = uv_buf_init((char*)iovs[i].buf, iovs[i].buf_len);
+
+ *buffers = bufs;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_init(uvwasi_t* uvwasi, uvwasi_options_t* options) {
+ uv_fs_t realpath_req;
+ uv_fs_t open_req;
+ uvwasi_errno_t err;
+ size_t args_size;
+ size_t size;
+ size_t offset;
+ size_t env_count;
+ size_t env_buf_size;
+ size_t i;
+ int r;
+
+ if (uvwasi == NULL || options == NULL || options->fd_table_size == 0)
+ return UVWASI_EINVAL;
+
+ uvwasi->argv_buf = NULL;
+ uvwasi->argv = NULL;
+ uvwasi->env_buf = NULL;
+ uvwasi->env = NULL;
+ uvwasi->fds.fds = NULL;
+
+ args_size = 0;
+ for (i = 0; i < options->argc; ++i)
+ args_size += strlen(options->argv[i]) + 1;
+
+ uvwasi->argc = options->argc;
+ uvwasi->argv_buf_size = args_size;
+
+ if (args_size > 0) {
+ uvwasi->argv_buf = malloc(args_size);
+ if (uvwasi->argv_buf == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ uvwasi->argv = calloc(options->argc, sizeof(char*));
+ if (uvwasi->argv == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ offset = 0;
+ for (i = 0; i < options->argc; ++i) {
+ size = strlen(options->argv[i]) + 1;
+ memcpy(uvwasi->argv_buf + offset, options->argv[i], size);
+ uvwasi->argv[i] = uvwasi->argv_buf + offset;
+ offset += size;
+ }
+ }
+
+ env_count = 0;
+ env_buf_size = 0;
+ if (options->envp != NULL) {
+ while (options->envp[env_count] != NULL) {
+ env_buf_size += strlen(options->envp[env_count]) + 1;
+ env_count++;
+ }
+ }
+
+ uvwasi->envc = env_count;
+ uvwasi->env_buf_size = env_buf_size;
+
+ if (env_buf_size > 0) {
+ uvwasi->env_buf = malloc(env_buf_size);
+ if (uvwasi->env_buf == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ uvwasi->env = calloc(env_count, sizeof(char*));
+ if (uvwasi->env == NULL) {
+ err = UVWASI_ENOMEM;
+ goto exit;
+ }
+
+ offset = 0;
+ for (i = 0; i < env_count; ++i) {
+ size = strlen(options->envp[i]) + 1;
+ memcpy(uvwasi->env_buf + offset, options->envp[i], size);
+ uvwasi->env[i] = uvwasi->env_buf + offset;
+ offset += size;
+ }
+ }
+
+ for (i = 0; i < options->preopenc; ++i) {
+ if (options->preopens[i].real_path == NULL ||
+ options->preopens[i].mapped_path == NULL) {
+ err = UVWASI_EINVAL;
+ goto exit;
+ }
+ }
+
+ err = uvwasi_fd_table_init(&uvwasi->fds, options->fd_table_size);
+ if (err != UVWASI_ESUCCESS)
+ goto exit;
+
+ for (i = 0; i < options->preopenc; ++i) {
+ r = uv_fs_realpath(NULL,
+ &realpath_req,
+ options->preopens[i].real_path,
+ NULL);
+ if (r != 0) {
+ err = uvwasi__translate_uv_error(r);
+ uv_fs_req_cleanup(&realpath_req);
+ goto exit;
+ }
+
+ r = uv_fs_open(NULL, &open_req, realpath_req.ptr, 0, 0666, NULL);
+ if (r < 0) {
+ err = uvwasi__translate_uv_error(r);
+ uv_fs_req_cleanup(&realpath_req);
+ uv_fs_req_cleanup(&open_req);
+ goto exit;
+ }
+
+ err = uvwasi_fd_table_insert_preopen(&uvwasi->fds,
+ open_req.result,
+ options->preopens[i].mapped_path,
+ realpath_req.ptr);
+ uv_fs_req_cleanup(&realpath_req);
+ uv_fs_req_cleanup(&open_req);
+
+ if (err != UVWASI_ESUCCESS)
+ goto exit;
+ }
+
+ return UVWASI_ESUCCESS;
+
+exit:
+ uvwasi_destroy(uvwasi);
+ return err;
+}
+
+
+void uvwasi_destroy(uvwasi_t* uvwasi) {
+ if (uvwasi == NULL)
+ return;
+
+ uvwasi_fd_table_free(&uvwasi->fds);
+ free(uvwasi->argv_buf);
+ free(uvwasi->argv);
+ free(uvwasi->env_buf);
+ free(uvwasi->env);
+ uvwasi->argv_buf = NULL;
+ uvwasi->argv = NULL;
+ uvwasi->env_buf = NULL;
+ uvwasi->env = NULL;
+}
+
+
+uvwasi_errno_t uvwasi_embedder_remap_fd(uvwasi_t* uvwasi,
+ const uvwasi_fd_t fd,
+ uv_file new_host_fd) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ wrap->fd = new_host_fd;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_args_get(uvwasi_t* uvwasi, char** argv, char* argv_buf) {
+ size_t i;
+
+ if (uvwasi == NULL || argv == NULL || argv_buf == NULL)
+ return UVWASI_EINVAL;
+
+ for (i = 0; i < uvwasi->argc; ++i) {
+ argv[i] = argv_buf + (uvwasi->argv[i] - uvwasi->argv_buf);
+ }
+
+ memcpy(argv_buf, uvwasi->argv_buf, uvwasi->argv_buf_size);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_args_sizes_get(uvwasi_t* uvwasi,
+ size_t* argc,
+ size_t* argv_buf_size) {
+ if (uvwasi == NULL || argc == NULL || argv_buf_size == NULL)
+ return UVWASI_EINVAL;
+
+ *argc = uvwasi->argc;
+ *argv_buf_size = uvwasi->argv_buf_size;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_clock_res_get(uvwasi_t* uvwasi,
+ uvwasi_clockid_t clock_id,
+ uvwasi_timestamp_t* resolution) {
+ if (uvwasi == NULL || resolution == NULL)
+ return UVWASI_EINVAL;
+
+ switch (clock_id) {
+ case UVWASI_CLOCK_MONOTONIC:
+ case UVWASI_CLOCK_REALTIME:
+ *resolution = 1; /* Nanosecond precision. */
+ return UVWASI_ESUCCESS;
+ case UVWASI_CLOCK_PROCESS_CPUTIME_ID:
+ return uvwasi__clock_getres_process_cputime(resolution);
+ case UVWASI_CLOCK_THREAD_CPUTIME_ID:
+ return uvwasi__clock_getres_thread_cputime(resolution);
+ default:
+ return UVWASI_EINVAL;
+ }
+}
+
+
+uvwasi_errno_t uvwasi_clock_time_get(uvwasi_t* uvwasi,
+ uvwasi_clockid_t clock_id,
+ uvwasi_timestamp_t precision,
+ uvwasi_timestamp_t* time) {
+ if (uvwasi == NULL || time == NULL)
+ return UVWASI_EINVAL;
+
+ switch (clock_id) {
+ case UVWASI_CLOCK_MONOTONIC:
+ *time = uv_hrtime();
+ return UVWASI_ESUCCESS;
+ case UVWASI_CLOCK_REALTIME:
+ return uvwasi__clock_gettime_realtime(time);
+ case UVWASI_CLOCK_PROCESS_CPUTIME_ID:
+ return uvwasi__clock_gettime_process_cputime(time);
+ case UVWASI_CLOCK_THREAD_CPUTIME_ID:
+ return uvwasi__clock_gettime_thread_cputime(time);
+ default:
+ return UVWASI_EINVAL;
+ }
+}
+
+
+uvwasi_errno_t uvwasi_environ_get(uvwasi_t* uvwasi,
+ char** environment,
+ char* environ_buf) {
+ size_t i;
+
+ if (uvwasi == NULL || environment == NULL || environ_buf == NULL)
+ return UVWASI_EINVAL;
+
+ for (i = 0; i < uvwasi->envc; ++i) {
+ environment[i] = environ_buf + (uvwasi->env[i] - uvwasi->env_buf);
+ }
+
+ memcpy(environ_buf, uvwasi->env_buf, uvwasi->env_buf_size);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_environ_sizes_get(uvwasi_t* uvwasi,
+ size_t* environ_count,
+ size_t* environ_buf_size) {
+ if (uvwasi == NULL || environ_count == NULL || environ_buf_size == NULL)
+ return UVWASI_EINVAL;
+
+ *environ_count = uvwasi->envc;
+ *environ_buf_size = uvwasi->env_buf_size;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_advise(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t offset,
+ uvwasi_filesize_t len,
+ uvwasi_advice_t advice) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+#ifdef POSIX_FADV_NORMAL
+ int mapped_advice;
+ int r;
+#endif /* POSIX_FADV_NORMAL */
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ switch (advice) {
+ case UVWASI_ADVICE_DONTNEED:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_DONTNEED;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_NOREUSE:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_NOREUSE;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_NORMAL:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_NORMAL;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_RANDOM:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_RANDOM;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_SEQUENTIAL:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_SEQUENTIAL;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ case UVWASI_ADVICE_WILLNEED:
+#ifdef POSIX_FADV_NORMAL
+ mapped_advice = POSIX_FADV_WILLNEED;
+#endif /* POSIX_FADV_NORMAL */
+ break;
+ default:
+ return UVWASI_EINVAL;
+ }
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_ADVISE, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+#ifdef POSIX_FADV_NORMAL
+ r = posix_fadvise(wrap->fd, offset, len, mapped_advice);
+ if (r != 0)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(r));
+#endif /* POSIX_FADV_NORMAL */
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_allocate(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t offset,
+ uvwasi_filesize_t len) {
+#if !defined(__POSIX__)
+ uv_fs_t req;
+ uint64_t st_size;
+#endif /* !__POSIX__ */
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_ALLOCATE,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* Try to use posix_fallocate(). If that's not an option, fall back to the
+ race condition prone combination of fstat() + ftruncate(). */
+#if defined(__POSIX__)
+ r = posix_fallocate(wrap->fd, offset, len);
+ if (r != 0)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(r));
+#else
+ r = uv_fs_fstat(NULL, &req, wrap->fd, NULL);
+ st_size = req.statbuf.st_size;
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ if (st_size < offset + len) {
+ r = uv_fs_ftruncate(NULL, &req, wrap->fd, offset + len, NULL);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+ }
+#endif /* __POSIX__ */
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_close(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_close(NULL, &req, wrap->fd, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return uvwasi_fd_table_remove(&uvwasi->fds, fd);
+}
+
+
+uvwasi_errno_t uvwasi_fd_datasync(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_DATASYNC,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_fdatasync(NULL, &req, wrap->fd, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_fdstat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_fdstat_t* buf) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+#ifndef _WIN32
+ int r;
+#endif
+
+ if (uvwasi == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ buf->fs_filetype = wrap->type;
+ buf->fs_rights_base = wrap->rights_base;
+ buf->fs_rights_inheriting = wrap->rights_inheriting;
+#ifdef _WIN32
+ buf->fs_flags = 0; /* TODO(cjihrig): Missing Windows support. */
+#else
+ r = fcntl(wrap->fd, F_GETFL);
+ if (r < 0)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+ buf->fs_flags = r;
+#endif /* _WIN32 */
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_fdstat_set_flags(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_fdflags_t flags) {
+#ifdef _WIN32
+ /* TODO(cjihrig): Missing Windows support. */
+ return UVWASI_ENOSYS;
+#else
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ int mapped_flags;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_FDSTAT_SET_FLAGS,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ mapped_flags = 0;
+
+ if ((flags & UVWASI_FDFLAG_APPEND) == UVWASI_FDFLAG_APPEND)
+ mapped_flags |= O_APPEND;
+
+ if ((flags & UVWASI_FDFLAG_DSYNC) == UVWASI_FDFLAG_DSYNC)
+#ifdef O_DSYNC
+ mapped_flags |= O_DSYNC;
+#else
+ mapped_flags |= O_SYNC;
+#endif /* O_DSYNC */
+
+ if ((flags & UVWASI_FDFLAG_NONBLOCK) == UVWASI_FDFLAG_NONBLOCK)
+ mapped_flags |= O_NONBLOCK;
+
+ if ((flags & UVWASI_FDFLAG_RSYNC) == UVWASI_FDFLAG_RSYNC)
+#ifdef O_RSYNC
+ mapped_flags |= O_RSYNC;
+#else
+ mapped_flags |= O_SYNC;
+#endif /* O_RSYNC */
+
+ if ((flags & UVWASI_FDFLAG_SYNC) == UVWASI_FDFLAG_SYNC)
+ mapped_flags |= O_SYNC;
+
+ r = fcntl(wrap->fd, F_SETFL, mapped_flags);
+ if (r < 0)
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+
+ return UVWASI_ESUCCESS;
+#endif /* _WIN32 */
+}
+
+
+uvwasi_errno_t uvwasi_fd_fdstat_set_rights(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_rights_t fs_rights_base,
+ uvwasi_rights_t fs_rights_inheriting
+ ) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* Check for attempts to add new permissions. */
+ if ((fs_rights_base | wrap->rights_base) > wrap->rights_base)
+ return UVWASI_ENOTCAPABLE;
+ if ((fs_rights_inheriting | wrap->rights_inheriting) >
+ wrap->rights_inheriting) {
+ return UVWASI_ENOTCAPABLE;
+ }
+
+ wrap->rights_base = fs_rights_base;
+ wrap->rights_inheriting = fs_rights_inheriting;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_filestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filestat_t* buf) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_FILESTAT_GET,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_fstat(NULL, &req, wrap->fd, NULL);
+ if (r != 0) {
+ uv_fs_req_cleanup(&req);
+ return uvwasi__translate_uv_error(r);
+ }
+
+ uvwasi__stat_to_filestat(&req.statbuf, buf);
+ uv_fs_req_cleanup(&req);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_filestat_set_size(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t st_size) {
+ /* TODO(cjihrig): uv_fs_ftruncate() takes an int64_t. st_size is uint64_t. */
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_FILESTAT_SET_SIZE,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_ftruncate(NULL, &req, wrap->fd, st_size, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_filestat_set_times(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_timestamp_t st_atim,
+ uvwasi_timestamp_t st_mtim,
+ uvwasi_fstflags_t fst_flags) {
+ /* TODO(cjihrig): libuv does not currently support nanosecond precision. */
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ if (fst_flags & ~(UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW |
+ UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) {
+ return UVWASI_EINVAL;
+ }
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_FILESTAT_SET_TIMES,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* TODO(cjihrig): st_atim and st_mtim should not be unconditionally passed. */
+ r = uv_fs_futime(NULL, &req, wrap->fd, st_atim, st_mtim, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_pread(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_iovec_t* iovs,
+ size_t iovs_len,
+ uvwasi_filesize_t offset,
+ size_t* nread) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_buf_t* bufs;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t uvread;
+ int r;
+
+ if (uvwasi == NULL || iovs == NULL || nread == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_READ | UVWASI_RIGHT_FD_SEEK,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__setup_iovs(&bufs, iovs, iovs_len);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_read(NULL, &req, wrap->fd, bufs, iovs_len, offset, NULL);
+ uvread = req.result;
+ uv_fs_req_cleanup(&req);
+ free(bufs);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ *nread = uvread;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_prestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_prestat_t* buf) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+ if (wrap->preopen != 1)
+ return UVWASI_EINVAL;
+
+ buf->pr_type = UVWASI_PREOPENTYPE_DIR;
+ buf->u.dir.pr_name_len = strlen(wrap->path) + 1;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_prestat_dir_name(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ char* path,
+ size_t path_len) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ size_t size;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+ if (wrap->preopen != 1)
+ return UVWASI_EBADF;
+
+ size = strlen(wrap->path) + 1;
+ if (size > path_len)
+ return UVWASI_ENOBUFS;
+
+ memcpy(path, wrap->path, size);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_pwrite(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_ciovec_t* iovs,
+ size_t iovs_len,
+ uvwasi_filesize_t offset,
+ size_t* nwritten) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_buf_t* bufs;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t uvwritten;
+ int r;
+
+ if (uvwasi == NULL || iovs == NULL || nwritten == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_WRITE | UVWASI_RIGHT_FD_SEEK,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__setup_ciovs(&bufs, iovs, iovs_len);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_write(NULL, &req, wrap->fd, bufs, iovs_len, offset, NULL);
+ uvwritten = req.result;
+ uv_fs_req_cleanup(&req);
+ free(bufs);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ *nwritten = uvwritten;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_read(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_iovec_t* iovs,
+ size_t iovs_len,
+ size_t* nread) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_buf_t* bufs;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t uvread;
+ int r;
+
+ if (uvwasi == NULL || iovs == NULL || nread == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_READ, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__setup_iovs(&bufs, iovs, iovs_len);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_read(NULL, &req, wrap->fd, bufs, iovs_len, -1, NULL);
+ uvread = req.result;
+ uv_fs_req_cleanup(&req);
+ free(bufs);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ *nread = uvread;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_readdir(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ void* buf,
+ size_t buf_len,
+ uvwasi_dircookie_t cookie,
+ size_t* bufused) {
+ /* TODO(cjihrig): Support Windows where seekdir() and telldir() are used. */
+ /* TODO(cjihrig): Avoid opening and closing the directory on each call. */
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_dirent_t dirent;
+ uv_dirent_t dirents[UVWASI__READDIR_NUM_ENTRIES];
+ uv_dir_t* dir;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t name_len;
+ size_t available;
+ size_t size_to_cp;
+ long tell;
+ int i;
+ int r;
+
+ if (uvwasi == NULL || buf == NULL || bufused == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_READDIR,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* Open the directory. */
+ r = uv_fs_opendir(NULL, &req, wrap->real_path, NULL);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ /* Setup for reading the directory. */
+ dir = req.ptr;
+ dir->dirents = dirents;
+ dir->nentries = UVWASI__READDIR_NUM_ENTRIES;
+ uv_fs_req_cleanup(&req);
+
+#ifndef _WIN32
+ /* TODO(cjihrig): Need a Windows equivalent of this logic. */
+ /* Seek to the proper location in the directory. */
+ if (cookie != UVWASI_DIRCOOKIE_START)
+ seekdir(dir->dir, cookie);
+#endif
+
+ /* Read the directory entries into the provided buffer. */
+ err = UVWASI_ESUCCESS;
+ *bufused = 0;
+ while (0 != (r = uv_fs_readdir(NULL, &req, dir, NULL))) {
+ if (r < 0) {
+ err = uvwasi__translate_uv_error(r);
+ uv_fs_req_cleanup(&req);
+ goto exit;
+ }
+
+ for (i = 0; i < r; i++) {
+ /* TODO(cjihrig): This should probably be serialized to the buffer
+ consistently across platforms. In other words, d_next should always
+ be 8 bytes, d_ino should always be 8 bytes, d_namlen should always be
+ 4 bytes, and d_type should always be 1 byte. */
+#ifndef _WIN32
+ tell = telldir(dir->dir);
+ if (tell < 0) {
+ err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+ uv_fs_req_cleanup(&req);
+ goto exit;
+ }
+#else
+ tell = 0; /* TODO(cjihrig): Need to support Windows. */
+#endif /* _WIN32 */
+
+ name_len = strlen(dirents[i].name);
+ dirent.d_next = (uvwasi_dircookie_t) tell;
+ /* TODO(cjihrig): Missing ino libuv (and Windows) support. fstat()? */
+ dirent.d_ino = 0;
+ dirent.d_namlen = name_len;
+
+ switch (dirents[i].type) {
+ case UV_DIRENT_FILE:
+ dirent.d_type = UVWASI_FILETYPE_REGULAR_FILE;
+ break;
+ case UV_DIRENT_DIR:
+ dirent.d_type = UVWASI_FILETYPE_DIRECTORY;
+ break;
+ case UV_DIRENT_SOCKET:
+ dirent.d_type = UVWASI_FILETYPE_SOCKET_STREAM;
+ break;
+ case UV_DIRENT_LINK:
+ dirent.d_type = UVWASI_FILETYPE_SYMBOLIC_LINK;
+ break;
+ case UV_DIRENT_CHAR:
+ dirent.d_type = UVWASI_FILETYPE_CHARACTER_DEVICE;
+ break;
+ case UV_DIRENT_BLOCK:
+ dirent.d_type = UVWASI_FILETYPE_BLOCK_DEVICE;
+ break;
+ case UV_DIRENT_FIFO:
+ case UV_DIRENT_UNKNOWN:
+ default:
+ dirent.d_type = UVWASI_FILETYPE_UNKNOWN;
+ break;
+ }
+
+ /* Write dirent to the buffer. */
+ available = buf_len - *bufused;
+ size_to_cp = sizeof(dirent) > available ? available : sizeof(dirent);
+ memcpy((char*)buf + *bufused, &dirent, size_to_cp);
+ *bufused += size_to_cp;
+ /* Write the entry name to the buffer. */
+ available = buf_len - *bufused;
+ size_to_cp = name_len > available ? available : name_len;
+ memcpy((char*)buf + *bufused, &dirents[i].name, size_to_cp);
+ *bufused += size_to_cp;
+ }
+
+ uv_fs_req_cleanup(&req);
+
+ if (*bufused >= buf_len)
+ break;
+ }
+
+exit:
+ /* Close the directory. */
+ r = uv_fs_closedir(NULL, &req, dir, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return err;
+}
+
+
+uvwasi_errno_t uvwasi_fd_renumber(uvwasi_t* uvwasi,
+ uvwasi_fd_t from,
+ uvwasi_fd_t to) {
+ struct uvwasi_fd_wrap_t* to_wrap;
+ struct uvwasi_fd_wrap_t* from_wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, from, &from_wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, to, &to_wrap, 0, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_close(NULL, &req, to_wrap->fd, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ memcpy(to_wrap, from_wrap, sizeof(*to_wrap));
+ to_wrap->id = to;
+
+ return uvwasi_fd_table_remove(&uvwasi->fds, from);
+}
+
+
+uvwasi_errno_t uvwasi_fd_seek(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filedelta_t offset,
+ uvwasi_whence_t whence,
+ uvwasi_filesize_t* newoffset) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL || newoffset == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_SEEK, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ return uvwasi__lseek(wrap->fd, offset, whence, newoffset);
+}
+
+
+uvwasi_errno_t uvwasi_fd_sync(uvwasi_t* uvwasi, uvwasi_fd_t fd) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_FD_SYNC,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_fsync(NULL, &req, wrap->fd, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_tell(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_filesize_t* offset) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+
+ if (uvwasi == NULL || offset == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_TELL, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ return uvwasi__lseek(wrap->fd, 0, UVWASI_WHENCE_CUR, offset);
+}
+
+
+uvwasi_errno_t uvwasi_fd_write(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const uvwasi_ciovec_t* iovs,
+ size_t iovs_len,
+ size_t* nwritten) {
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_buf_t* bufs;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ size_t uvwritten;
+ int r;
+
+ if (uvwasi == NULL || iovs == NULL || nwritten == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds, fd, &wrap, UVWASI_RIGHT_FD_WRITE, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__setup_ciovs(&bufs, iovs, iovs_len);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_write(NULL, &req, wrap->fd, bufs, iovs_len, -1, NULL);
+ uvwritten = req.result;
+ uv_fs_req_cleanup(&req);
+ free(bufs);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ *nwritten = uvwritten;
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_create_directory(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_CREATE_DIRECTORY,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_mkdir(NULL, &req, resolved_path, 0777, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_filestat_get(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_lookupflags_t flags,
+ const char* path,
+ size_t path_len,
+ uvwasi_filestat_t* buf) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_FILESTAT_GET,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, flags);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_stat(NULL, &req, resolved_path, NULL);
+ if (r != 0) {
+ uv_fs_req_cleanup(&req);
+ return uvwasi__translate_uv_error(r);
+ }
+
+ uvwasi__stat_to_filestat(&req.statbuf, buf);
+ uv_fs_req_cleanup(&req);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_filestat_set_times(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ uvwasi_lookupflags_t flags,
+ const char* path,
+ size_t path_len,
+ uvwasi_timestamp_t st_atim,
+ uvwasi_timestamp_t st_mtim,
+ uvwasi_fstflags_t fst_flags) {
+ /* TODO(cjihrig): libuv does not currently support nanosecond precision. */
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ if (fst_flags & ~(UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW |
+ UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) {
+ return UVWASI_EINVAL;
+ }
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_FILESTAT_SET_TIMES,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, flags);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* TODO(cjihrig): st_atim and st_mtim should not be unconditionally passed. */
+ r = uv_fs_utime(NULL, &req, resolved_path, st_atim, st_mtim, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_link(uvwasi_t* uvwasi,
+ uvwasi_fd_t old_fd,
+ uvwasi_lookupflags_t old_flags,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t new_fd,
+ const char* new_path,
+ size_t new_path_len) {
+ char resolved_old_path[PATH_MAX_BYTES];
+ char resolved_new_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* old_wrap;
+ struct uvwasi_fd_wrap_t* new_wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL || old_path == NULL || new_path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ old_fd,
+ &old_wrap,
+ UVWASI_RIGHT_PATH_LINK_SOURCE,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ new_fd,
+ &new_wrap,
+ UVWASI_RIGHT_PATH_LINK_TARGET,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(old_wrap,
+ old_path,
+ old_path_len,
+ resolved_old_path,
+ old_flags);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(new_wrap,
+ new_path,
+ new_path_len,
+ resolved_new_path,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_link(NULL, &req, resolved_old_path, resolved_new_path, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi,
+ uvwasi_fd_t dirfd,
+ uvwasi_lookupflags_t dirflags,
+ const char* path,
+ size_t path_len,
+ uvwasi_oflags_t o_flags,
+ uvwasi_rights_t fs_rights_base,
+ uvwasi_rights_t fs_rights_inheriting,
+ uvwasi_fdflags_t fs_flags,
+ uvwasi_fd_t* fd) {
+ char resolved_path[PATH_MAX_BYTES];
+ uvwasi_rights_t needed_inheriting;
+ uvwasi_rights_t needed_base;
+ struct uvwasi_fd_wrap_t* dirfd_wrap;
+ struct uvwasi_fd_wrap_t wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int flags;
+ int read;
+ int write;
+ int r;
+
+ if (uvwasi == NULL || path == NULL || fd == NULL)
+ return UVWASI_EINVAL;
+
+ read = 0 != (fs_rights_base & (UVWASI_RIGHT_FD_READ |
+ UVWASI_RIGHT_FD_READDIR));
+ write = 0 != (fs_rights_base & (UVWASI_RIGHT_FD_DATASYNC |
+ UVWASI_RIGHT_FD_WRITE |
+ UVWASI_RIGHT_FD_ALLOCATE |
+ UVWASI_RIGHT_FD_FILESTAT_SET_SIZE));
+ flags = write ? read ? UV_FS_O_RDWR : UV_FS_O_WRONLY : UV_FS_O_RDONLY;
+ needed_base = UVWASI_RIGHT_PATH_OPEN;
+ needed_inheriting = fs_rights_base | fs_rights_inheriting;
+
+ if ((o_flags & UVWASI_O_CREAT) != 0) {
+ flags |= UV_FS_O_CREAT;
+ needed_base |= UVWASI_RIGHT_PATH_CREATE_FILE;
+ }
+ if ((o_flags & UVWASI_O_DIRECTORY) != 0)
+ flags |= UV_FS_O_DIRECTORY;
+ if ((o_flags & UVWASI_O_EXCL) != 0)
+ flags |= UV_FS_O_EXCL;
+ if ((o_flags & UVWASI_O_TRUNC) != 0) {
+ flags |= UV_FS_O_TRUNC;
+ needed_base |= UVWASI_RIGHT_PATH_FILESTAT_SET_SIZE;
+ }
+
+ if ((fs_flags & UVWASI_FDFLAG_APPEND) != 0)
+ flags |= UV_FS_O_APPEND;
+ if ((fs_flags & UVWASI_FDFLAG_DSYNC) != 0) {
+ flags |= UV_FS_O_DSYNC;
+ needed_inheriting |= UVWASI_RIGHT_FD_DATASYNC;
+ }
+ if ((fs_flags & UVWASI_FDFLAG_NONBLOCK) != 0)
+ flags |= UV_FS_O_NONBLOCK;
+ if ((fs_flags & UVWASI_FDFLAG_RSYNC) != 0) {
+#ifdef O_RSYNC
+ flags |= O_RSYNC; /* libuv has no UV_FS_O_RSYNC. */
+#else
+ flags |= UV_FS_O_SYNC;
+#endif
+ needed_inheriting |= UVWASI_RIGHT_FD_SYNC;
+ }
+ if ((fs_flags & UVWASI_FDFLAG_SYNC) != 0) {
+ flags |= UV_FS_O_SYNC;
+ needed_inheriting |= UVWASI_RIGHT_FD_SYNC;
+ }
+ if (write && (flags & (UV_FS_O_APPEND | UV_FS_O_TRUNC)) == 0)
+ needed_inheriting |= UVWASI_RIGHT_FD_SEEK;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ dirfd,
+ &dirfd_wrap,
+ needed_base,
+ needed_inheriting);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(dirfd_wrap,
+ path,
+ path_len,
+ resolved_path,
+ dirflags);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_open(NULL, &req, resolved_path, flags, 0666, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r < 0)
+ return uvwasi__translate_uv_error(r);
+
+ err = uvwasi_fd_table_insert_fd(&uvwasi->fds,
+ r,
+ flags,
+ resolved_path,
+ fs_rights_base,
+ fs_rights_inheriting,
+ &wrap);
+ if (err != UVWASI_ESUCCESS)
+ goto close_file_and_error_exit;
+
+ /* Not all platforms support UV_FS_O_DIRECTORY, so enforce it here as well. */
+ if ((o_flags & UVWASI_O_DIRECTORY) != 0 &&
+ wrap.type != UVWASI_FILETYPE_DIRECTORY) {
+ uvwasi_fd_table_remove(&uvwasi->fds, wrap.id);
+ err = UVWASI_ENOTDIR;
+ goto close_file_and_error_exit;
+ }
+
+ *fd = wrap.id;
+ return UVWASI_ESUCCESS;
+
+close_file_and_error_exit:
+ uv_fs_close(NULL, &req, r, NULL);
+ uv_fs_req_cleanup(&req);
+ return err;
+}
+
+
+uvwasi_errno_t uvwasi_path_readlink(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len,
+ char* buf,
+ size_t buf_len,
+ size_t* bufused) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ size_t len;
+ int r;
+
+ if (uvwasi == NULL || path == NULL || buf == NULL || bufused == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_READLINK,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_readlink(NULL, &req, resolved_path, NULL);
+ if (r != 0) {
+ uv_fs_req_cleanup(&req);
+ return uvwasi__translate_uv_error(r);
+ }
+
+ len = strnlen(req.ptr, buf_len);
+ if (len >= buf_len) {
+ uv_fs_req_cleanup(&req);
+ return UVWASI_ENOBUFS;
+ }
+
+ memcpy(buf, req.ptr, len);
+ buf[len] = '\0';
+ *bufused = len + 1;
+ uv_fs_req_cleanup(&req);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_remove_directory(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_REMOVE_DIRECTORY,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_rmdir(NULL, &req, resolved_path, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_rename(uvwasi_t* uvwasi,
+ uvwasi_fd_t old_fd,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t new_fd,
+ const char* new_path,
+ size_t new_path_len) {
+ char resolved_old_path[PATH_MAX_BYTES];
+ char resolved_new_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* old_wrap;
+ struct uvwasi_fd_wrap_t* new_wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL || old_path == NULL || new_path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ old_fd,
+ &old_wrap,
+ UVWASI_RIGHT_PATH_RENAME_SOURCE,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ new_fd,
+ &new_wrap,
+ UVWASI_RIGHT_PATH_RENAME_TARGET,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(old_wrap,
+ old_path,
+ old_path_len,
+ resolved_old_path,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(new_wrap,
+ new_path,
+ new_path_len,
+ resolved_new_path,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_rename(NULL, &req, resolved_old_path, resolved_new_path, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_symlink(uvwasi_t* uvwasi,
+ const char* old_path,
+ size_t old_path_len,
+ uvwasi_fd_t fd,
+ const char* new_path,
+ size_t new_path_len) {
+ char resolved_new_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uvwasi_errno_t err;
+ uv_fs_t req;
+ int r;
+
+ if (uvwasi == NULL || old_path == NULL || new_path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_SYMLINK,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap,
+ new_path,
+ new_path_len,
+ resolved_new_path,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ /* Windows support may require setting the flags option. */
+ r = uv_fs_symlink(NULL, &req, old_path, resolved_new_path, 0, NULL);
+ uv_fs_req_cleanup(&req);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_path_unlink_file(uvwasi_t* uvwasi,
+ uvwasi_fd_t fd,
+ const char* path,
+ size_t path_len) {
+ char resolved_path[PATH_MAX_BYTES];
+ struct uvwasi_fd_wrap_t* wrap;
+ uv_fs_t req;
+ uvwasi_errno_t err;
+ int r;
+
+ if (uvwasi == NULL || path == NULL)
+ return UVWASI_EINVAL;
+
+ err = uvwasi_fd_table_get(&uvwasi->fds,
+ fd,
+ &wrap,
+ UVWASI_RIGHT_PATH_UNLINK_FILE,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ err = uvwasi__resolve_path(wrap, path, path_len, resolved_path, 0);
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
+ r = uv_fs_unlink(NULL, &req, resolved_path, NULL);
+ uv_fs_req_cleanup(&req);
+
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_poll_oneoff(uvwasi_t* uvwasi,
+ const uvwasi_subscription_t* in,
+ uvwasi_event_t* out,
+ size_t nsubscriptions,
+ size_t* nevents) {
+ /* TODO(cjihrig): Implement this. */
+ return UVWASI_ENOTSUP;
+}
+
+
+uvwasi_errno_t uvwasi_proc_exit(uvwasi_t* uvwasi, uvwasi_exitcode_t rval) {
+ exit(rval);
+ return UVWASI_ESUCCESS; /* This doesn't happen. */
+}
+
+
+uvwasi_errno_t uvwasi_proc_raise(uvwasi_t* uvwasi, uvwasi_signal_t sig) {
+ int r;
+
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+ r = uvwasi__translate_to_uv_signal(sig);
+ if (r == -1)
+ return UVWASI_ENOSYS;
+
+ r = uv_kill(uv_os_getpid(), r);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_random_get(uvwasi_t* uvwasi, void* buf, size_t buf_len) {
+ int r;
+
+ if (uvwasi == NULL || buf == NULL)
+ return UVWASI_EINVAL;
+
+ r = uv_random(NULL, NULL, buf, buf_len, 0, NULL);
+ if (r != 0)
+ return uvwasi__translate_uv_error(r);
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_sched_yield(uvwasi_t* uvwasi) {
+ if (uvwasi == NULL)
+ return UVWASI_EINVAL;
+
+#ifndef _WIN32
+ if (0 != sched_yield())
+ return uvwasi__translate_uv_error(uv_translate_sys_error(errno));
+#else
+ SwitchToThread();
+#endif /* _WIN32 */
+
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_sock_recv(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ const uvwasi_iovec_t* ri_data,
+ size_t ri_data_len,
+ uvwasi_riflags_t ri_flags,
+ size_t* ro_datalen,
+ uvwasi_roflags_t* ro_flags) {
+ /* TODO(cjihrig): Waiting to implement, pending
+ https://github.com/WebAssembly/WASI/issues/4 */
+ return UVWASI_ENOTSUP;
+}
+
+
+uvwasi_errno_t uvwasi_sock_send(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ const uvwasi_ciovec_t* si_data,
+ size_t si_data_len,
+ uvwasi_siflags_t si_flags,
+ size_t* so_datalen) {
+ /* TODO(cjihrig): Waiting to implement, pending
+ https://github.com/WebAssembly/WASI/issues/4 */
+ return UVWASI_ENOTSUP;
+}
+
+
+uvwasi_errno_t uvwasi_sock_shutdown(uvwasi_t* uvwasi,
+ uvwasi_fd_t sock,
+ uvwasi_sdflags_t how) {
+ /* TODO(cjihrig): Waiting to implement, pending
+ https://github.com/WebAssembly/WASI/issues/4 */
+ return UVWASI_ENOTSUP;
+}
diff --git a/deps/uvwasi/uvwasi.gyp b/deps/uvwasi/uvwasi.gyp
new file mode 100644
index 0000000000..c07b07b608
--- /dev/null
+++ b/deps/uvwasi/uvwasi.gyp
@@ -0,0 +1,25 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'uvwasi',
+ 'type': 'static_library',
+ 'cflags': ['-fvisibility=hidden'],
+ 'xcode_settings': {
+ 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
+ },
+ 'include_dirs': ['include'],
+ 'sources': [
+ 'src/clocks.c',
+ 'src/fd_table.c',
+ 'src/uv_mapping.c',
+ 'src/uvwasi.c',
+ ],
+ 'dependencies': [
+ '../uv/uv.gyp:libuv',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': ['include']
+ },
+ }
+ ]
+}
diff --git a/doc/api/cli.md b/doc/api/cli.md
index 333ecd4e09..fa600336b7 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -230,6 +230,13 @@ added: v9.6.0
Enable experimental ES Module support in the `vm` module.
+### `--experimental-wasi-unstable-preview0`
+<!-- YAML
+added: REPLACEME
+-->
+
+Enable experimental WebAssembly System Interface (WASI) support.
+
### `--experimental-wasm-modules`
<!-- YAML
added: v12.3.0
@@ -1048,6 +1055,7 @@ Node.js options that are allowed are:
* `--experimental-report`
* `--experimental-resolve-self`
* `--experimental-vm-modules`
+* `--experimental-wasi-unstable-preview0`
* `--experimental-wasm-modules`
* `--force-context-aware`
* `--force-fips`
diff --git a/doc/api/errors.md b/doc/api/errors.md
index f2aace2c5e..bdfd0df4a7 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1992,6 +1992,11 @@ The fulfilled value of a linking promise is not a `vm.Module` object.
The current module's status does not allow for this operation. The specific
meaning of the error depends on the specific function.
+<a id="ERR_WASI_ALREADY_STARTED"></a>
+### ERR_WASI_ALREADY_STARTED
+
+The WASI instance has already started.
+
<a id="ERR_WORKER_INVALID_EXEC_ARGV"></a>
### ERR_WORKER_INVALID_EXEC_ARGV
diff --git a/doc/api/index.md b/doc/api/index.md
index ceb3ce7f19..6a39e2102c 100644
--- a/doc/api/index.md
+++ b/doc/api/index.md
@@ -57,6 +57,7 @@
* [Utilities](util.html)
* [V8](v8.html)
* [VM](vm.html)
+* [WASI](wasi.html)
* [Worker Threads](worker_threads.html)
* [Zlib](zlib.html)
diff --git a/doc/api/wasi.md b/doc/api/wasi.md
new file mode 100644
index 0000000000..69afa83620
--- /dev/null
+++ b/doc/api/wasi.md
@@ -0,0 +1,90 @@
+# WebAssembly System Interface (WASI)
+
+<!--introduced_in=REPLACEME-->
+
+> Stability: 1 - Experimental
+
+The WASI API provides an implementation of the [WebAssembly System Interface][]
+specification. WASI gives sandboxed WebAssembly applications access to the
+underlying operating system via a collection of POSIX-like functions.
+
+```js
+'use strict';
+const fs = require('fs');
+const { WASI } = require('wasi');
+const wasi = new WASI({
+ args: process.argv,
+ env: process.env,
+ preopens: {
+ '/sandbox': '/some/real/path/that/wasm/can/access'
+ }
+});
+const importObject = { wasi_unstable: wasi.wasiImport };
+
+(async () => {
+ const wasm = await WebAssembly.compile(fs.readFileSync('./binary.wasm'));
+ const instance = await WebAssembly.instantiate(wasm, importObject);
+
+ wasi.start(instance);
+})();
+```
+
+The `--experimental-wasi-unstable-preview0` and `--experimental-wasm-bigint`
+CLI arguments are needed for the previous example to run.
+
+## Class: WASI
+<!-- YAML
+added: REPLACEME
+-->
+
+The `WASI` class provides the WASI system call API and additional convenience
+methods for working with WASI-based applications. Each `WASI` instance
+represents a distinct sandbox environment. For security purposes, each `WASI`
+instance must have its command line arguments, environment variables, and
+sandbox directory structure configured explicitly.
+
+### new WASI(\[options\])
+<!-- YAML
+added: REPLACEME
+-->
+
+* `options` {Object}
+ * `args` {Array} An array of strings that the WebAssembly application will
+ see as command line arguments. The first argument is the virtual path to the
+ WASI command itself. **Default:** `[]`.
+ * `env` {Object} An object similar to `process.env` that the WebAssembly
+ application will see as its environment. **Default:** `{}`.
+ * `preopens` {Object} This object represents the WebAssembly application's
+ sandbox directory structure. The string keys of `preopens` are treated as
+ directories within the sandbox. The corresponding values in `preopens` are
+ the real paths to those directories on the host machine.
+
+### wasi.start(instance)
+<!-- YAML
+added: REPLACEME
+-->
+
+* `instance` {WebAssembly.Instance}
+
+Attempt to begin execution of `instance` by invoking its `_start()` export.
+If `instance` does not contain a `_start()` export, then `start()` attempts to
+invoke the `__wasi_unstable_reactor_start()` export. If neither of those exports
+is present on `instance`, then `start()` does nothing.
+
+`start()` requires that `instance` exports a [`WebAssembly.Memory`][] named
+`memory`. If `instance` does not have a `memory` export an exception is thrown.
+
+### wasi.wasiImport
+<!-- YAML
+added: REPLACEME
+-->
+
+* {Object}
+
+`wasiImport` is an object that implements the WASI system call API. This object
+should be passed as the `wasi_unstable` import during the instantiation of a
+[`WebAssembly.Instance`][].
+
+[`WebAssembly.Instance`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance
+[`WebAssembly.Memory`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory
+[WebAssembly System Interface]: https://wasi.dev/
diff --git a/doc/node.1 b/doc/node.1
index e3628034e8..714772336e 100644
--- a/doc/node.1
+++ b/doc/node.1
@@ -141,6 +141,9 @@ Enable experimental support for a package to load itself.
.It Fl -experimental-vm-modules
Enable experimental ES module support in VM module.
.
+.It Fl -experimental-wasi-unstable-preview0
+Enable experimental WebAssembly System Interface support.
+.
.It Fl -experimental-wasm-modules
Enable experimental WebAssembly module support.
.
diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js
index cfefc56bd8..044bea3114 100644
--- a/lib/internal/bootstrap/loaders.js
+++ b/lib/internal/bootstrap/loaders.js
@@ -157,6 +157,9 @@ function NativeModule(id) {
this.loaded = false;
this.loading = false;
this.canBeRequiredByUsers = !id.startsWith('internal/');
+
+ if (id === 'wasi')
+ this.canBeRequiredByUsers = !!internalBinding('config').experimentalWasi;
}
// To be called during pre-execution when --expose-internals is on.
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index ee467f31f3..88a38f5e1d 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1229,6 +1229,7 @@ E('ERR_VM_MODULE_LINKING_ERRORED',
E('ERR_VM_MODULE_NOT_MODULE',
'Provided module is not an instance of Module', Error);
E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
+E('ERR_WASI_ALREADY_STARTED', 'WASI instance has already started', Error);
E('ERR_WORKER_INVALID_EXEC_ARGV', (errors) =>
`Initiated Worker with invalid execArgv flags: ${errors.join(', ')}`,
Error);
diff --git a/lib/internal/modules/cjs/helpers.js b/lib/internal/modules/cjs/helpers.js
index f7155c4aa1..2d73219a77 100644
--- a/lib/internal/modules/cjs/helpers.js
+++ b/lib/internal/modules/cjs/helpers.js
@@ -117,6 +117,11 @@ const builtinLibs = [
'v8', 'vm', 'worker_threads', 'zlib'
];
+if (internalBinding('config').experimentalWasi) {
+ builtinLibs.push('wasi');
+ builtinLibs.sort();
+}
+
if (typeof internalBinding('inspector').open === 'function') {
builtinLibs.push('inspector');
builtinLibs.sort();
diff --git a/lib/wasi.js b/lib/wasi.js
new file mode 100644
index 0000000000..65b8473624
--- /dev/null
+++ b/lib/wasi.js
@@ -0,0 +1,105 @@
+'use strict';
+/* global WebAssembly */
+const {
+ ArrayIsArray,
+ ArrayPrototypeForEach,
+ ArrayPrototypeMap,
+ FunctionPrototypeBind,
+ ObjectKeys
+} = primordials;
+const {
+ ERR_INVALID_ARG_TYPE,
+ ERR_WASI_ALREADY_STARTED
+} = require('internal/errors').codes;
+const { emitExperimentalWarning } = require('internal/util');
+const { WASI: _WASI } = internalBinding('wasi');
+const kSetMemory = Symbol('setMemory');
+const kStarted = Symbol('started');
+
+emitExperimentalWarning('WASI');
+
+
+class WASI {
+ constructor(options = {}) {
+ if (options === null || typeof options !== 'object')
+ throw new ERR_INVALID_ARG_TYPE('options', 'object', options);
+
+ // eslint-disable-next-line prefer-const
+ let { args, env, preopens } = options;
+
+ if (ArrayIsArray(args))
+ args = ArrayPrototypeMap(args, (arg) => { return String(arg); });
+ else if (args === undefined)
+ args = [];
+ else
+ throw new ERR_INVALID_ARG_TYPE('options.args', 'Array', args);
+
+ const envPairs = [];
+
+ if (env !== null && typeof env === 'object') {
+ for (const key in env) {
+ const value = env[key];
+ if (value !== undefined)
+ envPairs.push(`${key}=${value}`);
+ }
+ } else if (env !== undefined) {
+ throw new ERR_INVALID_ARG_TYPE('options.env', 'Object', env);
+ }
+
+ const preopenArray = [];
+
+ if (typeof preopens === 'object' && preopens !== null) {
+ ArrayPrototypeForEach(ObjectKeys(preopens), (key) => {
+ preopenArray.push(String(key));
+ preopenArray.push(String(preopens[key]));
+ });
+ } else if (preopens !== undefined) {
+ throw new ERR_INVALID_ARG_TYPE('options.preopens', 'Object', preopens);
+ }
+
+ const wrap = new _WASI(args, envPairs, preopenArray);
+
+ for (const prop in wrap) {
+ wrap[prop] = FunctionPrototypeBind(wrap[prop], wrap);
+ }
+
+ this[kSetMemory] = wrap._setMemory;
+ delete wrap._setMemory;
+ this.wasiImport = wrap;
+ this[kStarted] = false;
+ }
+
+ start(instance) {
+ if (!(instance instanceof WebAssembly.Instance)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ 'instance', 'WebAssembly.Instance', instance);
+ }
+
+ const exports = instance.exports;
+
+ if (exports === null || typeof exports !== 'object')
+ throw new ERR_INVALID_ARG_TYPE('instance.exports', 'Object', exports);
+
+ const { memory } = exports;
+
+ if (!(memory instanceof WebAssembly.Memory)) {
+ throw new ERR_INVALID_ARG_TYPE(
+ 'instance.exports.memory', 'WebAssembly.Memory', memory);
+ }
+
+ if (this[kStarted]) {
+ throw new ERR_WASI_ALREADY_STARTED();
+ }
+
+ this[kStarted] = true;
+ this[kSetMemory](memory);
+
+ if (exports._start)
+ exports._start();
+ else if (exports.__wasi_unstable_reactor_start)
+ exports.__wasi_unstable_reactor_start();
+ }
+}
+
+
+module.exports = { WASI };
diff --git a/node.gyp b/node.gyp
index d8b5596083..cffd150845 100644
--- a/node.gyp
+++ b/node.gyp
@@ -82,6 +82,7 @@
'lib/util.js',
'lib/v8.js',
'lib/vm.js',
+ 'lib/wasi.js',
'lib/worker_threads.js',
'lib/zlib.js',
'lib/internal/assert.js',
@@ -321,7 +322,10 @@
'src/node_main.cc'
],
- 'dependencies': [ 'deps/histogram/histogram.gyp:histogram' ],
+ 'dependencies': [
+ 'deps/histogram/histogram.gyp:histogram',
+ 'deps/uvwasi/uvwasi.gyp:uvwasi',
+ ],
'msvs_settings': {
'VCLinkerTool': {
@@ -495,7 +499,10 @@
'src',
'<(SHARED_INTERMEDIATE_DIR)' # for node_natives.h
],
- 'dependencies': [ 'deps/histogram/histogram.gyp:histogram' ],
+ 'dependencies': [
+ 'deps/histogram/histogram.gyp:histogram',
+ 'deps/uvwasi/uvwasi.gyp:uvwasi',
+ ],
'sources': [
'src/api/async_resource.cc',
@@ -560,6 +567,7 @@
'src/node_url.cc',
'src/node_util.cc',
'src/node_v8.cc',
+ 'src/node_wasi.cc',
'src/node_watchdog.cc',
'src/node_worker.cc',
'src/node_zlib.cc',
@@ -638,6 +646,7 @@
'src/node_url.h',
'src/node_version.h',
'src/node_v8_platform-inl.h',
+ 'src/node_wasi.h',
'src/node_watchdog.h',
'src/node_worker.h',
'src/pipe_wrap.h',
@@ -1072,6 +1081,7 @@
'dependencies': [
'<(node_lib_target_name)',
'deps/histogram/histogram.gyp:histogram',
+ 'deps/uvwasi/uvwasi.gyp:uvwasi',
'node_dtrace_header',
'node_dtrace_ustack',
'node_dtrace_provider',
@@ -1087,6 +1097,7 @@
'deps/v8/include',
'deps/cares/include',
'deps/uv/include',
+ 'deps/uvwasi/include',
'test/cctest',
],
@@ -1181,6 +1192,7 @@
'dependencies': [
'<(node_lib_target_name)',
'deps/histogram/histogram.gyp:histogram',
+ 'deps/uvwasi/uvwasi.gyp:uvwasi',
],
'includes': [
@@ -1193,6 +1205,7 @@
'deps/v8/include',
'deps/cares/include',
'deps/uv/include',
+ 'deps/uvwasi/include',
],
'defines': [
@@ -1224,6 +1237,7 @@
'dependencies': [
'<(node_lib_target_name)',
'deps/histogram/histogram.gyp:histogram',
+ 'deps/uvwasi/uvwasi.gyp:uvwasi',
],
'includes': [
@@ -1236,6 +1250,7 @@
'deps/v8/include',
'deps/cares/include',
'deps/uv/include',
+ 'deps/uvwasi/include',
],
'defines': [ 'NODE_WANT_INTERNALS=1' ],
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<v8::FunctionTemplate> that,
+ const char* name,
+ v8::FunctionCallback callback) {
+ v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
+ v8::Local<v8::FunctionTemplate> 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<v8::String> 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<v8::FunctionTemplate> that,
+ const char* name,
+ v8::FunctionCallback callback);
+
+
// Safe variants denote the function has no side effects.
inline void SetMethodNoSideEffect(v8::Local<v8::Object> 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<Object> 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 <typename... Args>
+inline void Debug(WASI* wasi, Args&&... args) {
+ Debug(wasi->env(), DebugCategory::WASI, std::forward<Args>(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<type>()->Value(); \
+ } while (0)
+
+#define UNWRAP_BIGINT_OR_RETURN(args, input, type, result) \
+ do { \
+ if (!(input)->IsBigInt()) { \
+ (args).GetReturnValue().Set(UVWASI_EINVAL); \
+ return; \
+ } \
+ Local<BigInt> js_value = (input).As<BigInt>(); \
+ 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> 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<Value>& 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> context = env->context();
+ Local<Array> argv = args[0].As<Array>();
+ 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<Array> env_pairs = args[1].As<Array>();
+ 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<Array> preopens = args[2].As<Array>();
+ CHECK_EQ(preopens->Length() % 2, 0);
+ options.preopenc = preopens->Length() / 2;
+ options.preopens = UncheckedCalloc<uvwasi_preopen_t>(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<Value>& 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<char*> 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<char*> 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<uvwasi_iovec_t>(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<void*>(&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<Value>& 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<Value>& 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<Value>& 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<uvwasi_ciovec_t>(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<void*>(&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<Value>& 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<uvwasi_iovec_t>(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<void*>(&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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<uvwasi_ciovec_t>(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<void*>(&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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<uvwasi_oflags_t>(o_flags),
+ fs_rights_base,
+ fs_rights_inheriting,
+ static_cast<uvwasi_fdflags_t>(fs_flags),
+ &fd);
+ if (err == UVWASI_ESUCCESS)
+ wasi->writeUInt32(memory, fd, fd_ptr);
+
+ args.GetReturnValue().Set(err);
+}
+
+
+void WASI::PathReadlink(const FunctionCallbackInfo<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<uvwasi_subscription_t>(nsubscriptions);
+
+ if (in == nullptr) {
+ args.GetReturnValue().Set(UVWASI_ENOMEM);
+ return;
+ }
+
+ uvwasi_event_t* out = UncheckedCalloc<uvwasi_event_t>(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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<Value>& 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<uvwasi_iovec_t>(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<void*>(&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<Value>& 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<uvwasi_ciovec_t>(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<void*>(&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<Value>& 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<Value>& 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<Object>());
+}
+
+
+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<Object> memory = PersistentToLocal::Strong(this->memory_);
+ Local<Value> prop;
+
+ if (!memory->Get(env->context(), env->buffer_string()).ToLocal(&prop))
+ return UVWASI_EINVAL;
+
+ if (!prop->IsArrayBuffer())
+ return UVWASI_EINVAL;
+
+ Local<ArrayBuffer> ab = prop.As<ArrayBuffer>();
+ std::shared_ptr<BackingStore> backing_store = ab->GetBackingStore();
+ *byte_length = backing_store->ByteLength();
+ *store = static_cast<char*>(backing_store->Data());
+ return UVWASI_ESUCCESS;
+}
+
+
+static void Initialize(Local<Object> target,
+ Local<Value> unused,
+ Local<Context> context,
+ void* priv) {
+ Environment* env = Environment::GetCurrent(context);
+
+ Local<FunctionTemplate> 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<v8::Object> object,
+ uvwasi_options_t* options);
+ static void New(const v8::FunctionCallbackInfo<v8::Value>& 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<v8::Value>& args);
+ static void ArgsSizesGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void ClockResGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void ClockTimeGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void EnvironGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void EnvironSizesGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdAdvise(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdAllocate(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdClose(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdDatasync(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdFdstatGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdFdstatSetFlags(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdFdstatSetRights(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdFilestatGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdFilestatSetSize(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdFilestatSetTimes(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdPread(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdPrestatGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdPrestatDirName(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdPwrite(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdRead(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdReaddir(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdRenumber(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdSeek(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdSync(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdTell(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void FdWrite(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathCreateDirectory(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathFilestatGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathFilestatSetTimes(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathLink(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathOpen(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathReadlink(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathRemoveDirectory(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathRename(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathSymlink(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PathUnlinkFile(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PollOneoff(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void ProcExit(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void ProcRaise(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void RandomGet(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void SchedYield(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void SockRecv(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void SockSend(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void SockShutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
+
+ static void _SetMemory(const v8::FunctionCallbackInfo<v8::Value>& 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<v8::Object> memory_;
+};
+
+
+} // namespace wasi
+} // namespace node
+
+#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#endif // SRC_NODE_WASI_H_
diff --git a/test/fixtures/outside.txt b/test/fixtures/outside.txt
new file mode 100644
index 0000000000..044c4b9614
--- /dev/null
+++ b/test/fixtures/outside.txt
@@ -0,0 +1,2 @@
+this file is part of the WASI tests. it exists outside of the sandbox, and
+should be inaccessible from the WASI tests.
diff --git a/test/fixtures/wasi/input.txt b/test/fixtures/wasi/input.txt
new file mode 100644
index 0000000000..4c38053764
--- /dev/null
+++ b/test/fixtures/wasi/input.txt
@@ -0,0 +1 @@
+hello from input.txt
diff --git a/test/fixtures/wasi/notadir b/test/fixtures/wasi/notadir
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/fixtures/wasi/notadir
diff --git a/test/fixtures/wasi/simple-wasi.wasm b/test/fixtures/wasi/simple-wasi.wasm
new file mode 100755
index 0000000000..334d3a3dca
--- /dev/null
+++ b/test/fixtures/wasi/simple-wasi.wasm
Binary files differ
diff --git a/test/fixtures/wasi/simple-wasi.wat b/test/fixtures/wasi/simple-wasi.wat
new file mode 100644
index 0000000000..318f390c76
--- /dev/null
+++ b/test/fixtures/wasi/simple-wasi.wat
@@ -0,0 +1,6533 @@
+(module
+ (type (;0;) (func (param i32 i32 i32) (result i32)))
+ (type (;1;) (func (param i32 i64 i32) (result i64)))
+ (type (;2;) (func (param i32 i32) (result i32)))
+ (type (;3;) (func (param i32)))
+ (type (;4;) (func (param i32) (result i32)))
+ (type (;5;) (func (param i32 i32 i32 i32) (result i32)))
+ (type (;6;) (func (param i32 i64 i32 i32) (result i32)))
+ (type (;7;) (func))
+ (type (;8;) (func (result i32)))
+ (import "wasi_unstable" "fd_prestat_get" (func (;0;) (type 2)))
+ (import "wasi_unstable" "fd_prestat_dir_name" (func (;1;) (type 0)))
+ (import "wasi_unstable" "environ_sizes_get" (func (;2;) (type 2)))
+ (import "wasi_unstable" "environ_get" (func (;3;) (type 2)))
+ (import "wasi_unstable" "args_sizes_get" (func (;4;) (type 2)))
+ (import "wasi_unstable" "args_get" (func (;5;) (type 2)))
+ (import "wasi_unstable" "proc_exit" (func (;6;) (type 3)))
+ (import "wasi_unstable" "fd_fdstat_get" (func (;7;) (type 2)))
+ (import "wasi_unstable" "fd_close" (func (;8;) (type 4)))
+ (import "wasi_unstable" "fd_write" (func (;9;) (type 5)))
+ (import "wasi_unstable" "fd_seek" (func (;10;) (type 6)))
+ (func (;11;) (type 7))
+ (func (;12;) (type 7)
+ (local i32 i32 i32 i32)
+ get_global 0
+ i32.const 16
+ i32.sub
+ tee_local 0
+ set_global 0
+ call 23
+ i32.const 3
+ set_local 1
+ block ;; label = @1
+ block ;; label = @2
+ block ;; label = @3
+ block ;; label = @4
+ loop ;; label = @5
+ get_local 1
+ get_local 0
+ call 0
+ tee_local 2
+ i32.const 8
+ i32.eq
+ br_if 1 (;@4;)
+ get_local 2
+ br_if 3 (;@2;)
+ block ;; label = @6
+ get_local 0
+ i32.load8_u
+ br_if 0 (;@6;)
+ get_local 0
+ i32.load offset=4
+ i32.const 1
+ i32.add
+ call 14
+ tee_local 2
+ i32.eqz
+ br_if 4 (;@2;)
+ get_local 1
+ get_local 2
+ get_local 0
+ i32.load offset=4
+ call 1
+ br_if 3 (;@3;)
+ get_local 2
+ get_local 0
+ i32.load offset=4
+ i32.add
+ i32.const 0
+ i32.store8
+ get_local 1
+ get_local 2
+ call 24
+ set_local 3
+ get_local 2
+ call 16
+ get_local 3
+ br_if 4 (;@2;)
+ end
+ get_local 1
+ i32.const 1
+ i32.add
+ tee_local 1
+ br_if 0 (;@5;)
+ end
+ end
+ block ;; label = @4
+ get_local 0
+ get_local 0
+ i32.const 12
+ i32.add
+ call 2
+ br_if 0 (;@4;)
+ i32.const 0
+ get_local 0
+ i32.load
+ i32.const 2
+ i32.shl
+ i32.const 4
+ i32.add
+ call 14
+ i32.store offset=1544
+ get_local 0
+ i32.load offset=12
+ call 14
+ tee_local 1
+ i32.eqz
+ br_if 0 (;@4;)
+ i32.const 0
+ i32.load offset=1544
+ tee_local 2
+ i32.eqz
+ br_if 0 (;@4;)
+ get_local 2
+ get_local 0
+ i32.load
+ i32.const 2
+ i32.shl
+ i32.add
+ i32.const 0
+ i32.store
+ i32.const 0
+ i32.load offset=1544
+ get_local 1
+ call 3
+ br_if 0 (;@4;)
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ get_local 0
+ i32.const 12
+ i32.add
+ get_local 0
+ call 4
+ br_if 0 (;@7;)
+ get_local 0
+ i32.load offset=12
+ tee_local 1
+ i32.eqz
+ br_if 1 (;@6;)
+ get_local 1
+ i32.const 2
+ i32.shl
+ i32.const 4
+ i32.add
+ call 14
+ set_local 1
+ get_local 0
+ i32.load
+ call 14
+ set_local 2
+ get_local 1
+ i32.eqz
+ br_if 0 (;@7;)
+ get_local 2
+ i32.eqz
+ br_if 0 (;@7;)
+ get_local 1
+ i32.const 0
+ i32.store
+ get_local 1
+ get_local 2
+ call 5
+ i32.eqz
+ br_if 2 (;@5;)
+ end
+ i32.const 71
+ call 19
+ unreachable
+ end
+ end
+ call 11
+ get_local 0
+ i32.load offset=12
+ get_local 1
+ call 13
+ set_local 1
+ call 27
+ get_local 1
+ br_if 3 (;@1;)
+ get_local 0
+ i32.const 16
+ i32.add
+ set_global 0
+ return
+ end
+ i32.const 71
+ call 19
+ unreachable
+ end
+ get_local 2
+ call 16
+ end
+ i32.const 71
+ call 19
+ unreachable
+ end
+ get_local 1
+ call 19
+ unreachable)
+ (func (;13;) (type 2) (param i32 i32) (result i32)
+ i32.const 1024
+ call 35
+ drop
+ i32.const 0)
+ (func (;14;) (type 4) (param i32) (result i32)
+ get_local 0
+ call 15)
+ (func (;15;) (type 4) (param i32) (result i32)
+ (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
+ get_global 0
+ i32.const 16
+ i32.sub
+ tee_local 1
+ set_global 0
+ block ;; label = @1
+ block ;; label = @2
+ block ;; label = @3
+ block ;; label = @4
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ block ;; label = @8
+ block ;; label = @9
+ block ;; label = @10
+ block ;; label = @11
+ block ;; label = @12
+ block ;; label = @13
+ block ;; label = @14
+ block ;; label = @15
+ block ;; label = @16
+ block ;; label = @17
+ block ;; label = @18
+ block ;; label = @19
+ block ;; label = @20
+ block ;; label = @21
+ block ;; label = @22
+ block ;; label = @23
+ block ;; label = @24
+ block ;; label = @25
+ block ;; label = @26
+ block ;; label = @27
+ block ;; label = @28
+ block ;; label = @29
+ block ;; label = @30
+ block ;; label = @31
+ block ;; label = @32
+ block ;; label = @33
+ block ;; label = @34
+ block ;; label = @35
+ block ;; label = @36
+ block ;; label = @37
+ block ;; label = @38
+ get_local 0
+ i32.const 244
+ i32.gt_u
+ br_if 0 (;@38;)
+ i32.const 0
+ i32.load offset=1040
+ tee_local 2
+ i32.const 16
+ get_local 0
+ i32.const 11
+ i32.add
+ i32.const -8
+ i32.and
+ get_local 0
+ i32.const 11
+ i32.lt_u
+ select
+ tee_local 3
+ i32.const 3
+ i32.shr_u
+ tee_local 4
+ i32.shr_u
+ tee_local 0
+ i32.const 3
+ i32.and
+ i32.eqz
+ br_if 1 (;@37;)
+ get_local 0
+ i32.const -1
+ i32.xor
+ i32.const 1
+ i32.and
+ get_local 4
+ i32.add
+ tee_local 5
+ i32.const 3
+ i32.shl
+ tee_local 6
+ i32.const 1088
+ i32.add
+ i32.load
+ tee_local 4
+ i32.const 8
+ i32.add
+ set_local 0
+ get_local 4
+ i32.load offset=8
+ tee_local 3
+ get_local 6
+ i32.const 1080
+ i32.add
+ tee_local 6
+ i32.eq
+ br_if 2 (;@36;)
+ get_local 3
+ get_local 6
+ i32.store offset=12
+ get_local 6
+ i32.const 8
+ i32.add
+ get_local 3
+ i32.store
+ br 3 (;@35;)
+ end
+ i32.const -1
+ set_local 3
+ get_local 0
+ i32.const -65
+ i32.gt_u
+ br_if 14 (;@23;)
+ get_local 0
+ i32.const 11
+ i32.add
+ tee_local 0
+ i32.const -8
+ i32.and
+ set_local 3
+ i32.const 0
+ i32.load offset=1044
+ tee_local 7
+ i32.eqz
+ br_if 14 (;@23;)
+ i32.const 0
+ set_local 8
+ block ;; label = @38
+ get_local 0
+ i32.const 8
+ i32.shr_u
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@38;)
+ i32.const 31
+ set_local 8
+ get_local 3
+ i32.const 16777215
+ i32.gt_u
+ br_if 0 (;@38;)
+ get_local 3
+ i32.const 14
+ get_local 0
+ get_local 0
+ i32.const 1048320
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 8
+ i32.and
+ tee_local 4
+ i32.shl
+ tee_local 0
+ i32.const 520192
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 4
+ i32.and
+ tee_local 5
+ get_local 4
+ i32.or
+ get_local 0
+ get_local 5
+ i32.shl
+ tee_local 0
+ i32.const 245760
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 2
+ i32.and
+ tee_local 4
+ i32.or
+ i32.sub
+ get_local 0
+ get_local 4
+ i32.shl
+ i32.const 15
+ i32.shr_u
+ i32.add
+ tee_local 0
+ i32.const 7
+ i32.add
+ i32.shr_u
+ i32.const 1
+ i32.and
+ get_local 0
+ i32.const 1
+ i32.shl
+ i32.or
+ set_local 8
+ end
+ i32.const 0
+ get_local 3
+ i32.sub
+ set_local 5
+ get_local 8
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ i32.load
+ tee_local 4
+ i32.eqz
+ br_if 3 (;@34;)
+ get_local 3
+ i32.const 0
+ i32.const 25
+ get_local 8
+ i32.const 1
+ i32.shr_u
+ i32.sub
+ get_local 8
+ i32.const 31
+ i32.eq
+ select
+ i32.shl
+ set_local 6
+ i32.const 0
+ set_local 0
+ i32.const 0
+ set_local 9
+ loop ;; label = @38
+ block ;; label = @39
+ get_local 4
+ i32.load offset=4
+ i32.const -8
+ i32.and
+ get_local 3
+ i32.sub
+ tee_local 2
+ get_local 5
+ i32.ge_u
+ br_if 0 (;@39;)
+ get_local 2
+ set_local 5
+ get_local 4
+ set_local 9
+ get_local 2
+ i32.eqz
+ br_if 8 (;@31;)
+ end
+ get_local 0
+ get_local 4
+ i32.const 20
+ i32.add
+ i32.load
+ tee_local 2
+ get_local 2
+ get_local 4
+ get_local 6
+ i32.const 29
+ i32.shr_u
+ i32.const 4
+ i32.and
+ i32.add
+ i32.const 16
+ i32.add
+ i32.load
+ tee_local 4
+ i32.eq
+ select
+ get_local 0
+ get_local 2
+ select
+ set_local 0
+ get_local 6
+ get_local 4
+ i32.const 0
+ i32.ne
+ i32.shl
+ set_local 6
+ get_local 4
+ br_if 0 (;@38;)
+ end
+ get_local 0
+ get_local 9
+ i32.or
+ i32.eqz
+ br_if 4 (;@33;)
+ br 11 (;@26;)
+ end
+ get_local 3
+ i32.const 0
+ i32.load offset=1048
+ tee_local 7
+ i32.le_u
+ br_if 13 (;@23;)
+ get_local 0
+ i32.eqz
+ br_if 4 (;@32;)
+ get_local 0
+ get_local 4
+ i32.shl
+ i32.const 2
+ get_local 4
+ i32.shl
+ tee_local 0
+ i32.const 0
+ get_local 0
+ i32.sub
+ i32.or
+ i32.and
+ tee_local 0
+ i32.const 0
+ get_local 0
+ i32.sub
+ i32.and
+ i32.const -1
+ i32.add
+ tee_local 0
+ get_local 0
+ i32.const 12
+ i32.shr_u
+ i32.const 16
+ i32.and
+ tee_local 0
+ i32.shr_u
+ tee_local 4
+ i32.const 5
+ i32.shr_u
+ i32.const 8
+ i32.and
+ tee_local 5
+ get_local 0
+ i32.or
+ get_local 4
+ get_local 5
+ i32.shr_u
+ tee_local 0
+ i32.const 2
+ i32.shr_u
+ i32.const 4
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ tee_local 0
+ i32.const 1
+ i32.shr_u
+ i32.const 2
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ tee_local 0
+ i32.const 1
+ i32.shr_u
+ i32.const 1
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ i32.add
+ tee_local 5
+ i32.const 3
+ i32.shl
+ tee_local 6
+ i32.const 1088
+ i32.add
+ i32.load
+ tee_local 4
+ i32.load offset=8
+ tee_local 0
+ get_local 6
+ i32.const 1080
+ i32.add
+ tee_local 6
+ i32.eq
+ br_if 6 (;@30;)
+ get_local 0
+ get_local 6
+ i32.store offset=12
+ get_local 6
+ i32.const 8
+ i32.add
+ get_local 0
+ i32.store
+ br 7 (;@29;)
+ end
+ i32.const 0
+ get_local 2
+ i32.const -2
+ get_local 5
+ i32.rotl
+ i32.and
+ i32.store offset=1040
+ end
+ get_local 4
+ get_local 5
+ i32.const 3
+ i32.shl
+ tee_local 5
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 4
+ get_local 5
+ i32.add
+ tee_local 4
+ get_local 4
+ i32.load offset=4
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ br 33 (;@1;)
+ end
+ i32.const 0
+ set_local 0
+ i32.const 0
+ set_local 9
+ i32.const 0
+ i32.const 0
+ i32.or
+ br_if 7 (;@26;)
+ end
+ i32.const 2
+ get_local 8
+ i32.shl
+ tee_local 0
+ i32.const 0
+ get_local 0
+ i32.sub
+ i32.or
+ get_local 7
+ i32.and
+ tee_local 0
+ i32.eqz
+ br_if 9 (;@23;)
+ get_local 0
+ i32.const 0
+ get_local 0
+ i32.sub
+ i32.and
+ i32.const -1
+ i32.add
+ tee_local 0
+ get_local 0
+ i32.const 12
+ i32.shr_u
+ i32.const 16
+ i32.and
+ tee_local 0
+ i32.shr_u
+ tee_local 4
+ i32.const 5
+ i32.shr_u
+ i32.const 8
+ i32.and
+ tee_local 6
+ get_local 0
+ i32.or
+ get_local 4
+ get_local 6
+ i32.shr_u
+ tee_local 0
+ i32.const 2
+ i32.shr_u
+ i32.const 4
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ tee_local 0
+ i32.const 1
+ i32.shr_u
+ i32.const 2
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ tee_local 0
+ i32.const 1
+ i32.shr_u
+ i32.const 1
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ i32.add
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ i32.load
+ tee_local 0
+ br_if 7 (;@25;)
+ br 8 (;@24;)
+ end
+ i32.const 0
+ i32.load offset=1044
+ tee_local 10
+ i32.eqz
+ br_if 8 (;@23;)
+ get_local 10
+ i32.const 0
+ get_local 10
+ i32.sub
+ i32.and
+ i32.const -1
+ i32.add
+ tee_local 0
+ get_local 0
+ i32.const 12
+ i32.shr_u
+ i32.const 16
+ i32.and
+ tee_local 0
+ i32.shr_u
+ tee_local 4
+ i32.const 5
+ i32.shr_u
+ i32.const 8
+ i32.and
+ tee_local 5
+ get_local 0
+ i32.or
+ get_local 4
+ get_local 5
+ i32.shr_u
+ tee_local 0
+ i32.const 2
+ i32.shr_u
+ i32.const 4
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ tee_local 0
+ i32.const 1
+ i32.shr_u
+ i32.const 2
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ tee_local 0
+ i32.const 1
+ i32.shr_u
+ i32.const 1
+ i32.and
+ tee_local 4
+ i32.or
+ get_local 0
+ get_local 4
+ i32.shr_u
+ i32.add
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ i32.load
+ tee_local 6
+ i32.load offset=4
+ i32.const -8
+ i32.and
+ get_local 3
+ i32.sub
+ set_local 5
+ get_local 6
+ tee_local 9
+ i32.load offset=16
+ tee_local 0
+ i32.eqz
+ br_if 3 (;@28;)
+ i32.const 1
+ set_local 4
+ br 4 (;@27;)
+ end
+ i32.const 0
+ set_local 5
+ get_local 4
+ set_local 9
+ get_local 4
+ set_local 0
+ br 5 (;@25;)
+ end
+ i32.const 0
+ get_local 2
+ i32.const -2
+ get_local 5
+ i32.rotl
+ i32.and
+ tee_local 2
+ i32.store offset=1040
+ end
+ get_local 4
+ i32.const 8
+ i32.add
+ set_local 0
+ get_local 4
+ get_local 3
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 4
+ get_local 5
+ i32.const 3
+ i32.shl
+ tee_local 5
+ i32.add
+ get_local 5
+ get_local 3
+ i32.sub
+ tee_local 5
+ i32.store
+ get_local 4
+ get_local 3
+ i32.add
+ tee_local 6
+ get_local 5
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ block ;; label = @29
+ get_local 7
+ i32.eqz
+ br_if 0 (;@29;)
+ get_local 7
+ i32.const 3
+ i32.shr_u
+ tee_local 9
+ i32.const 3
+ i32.shl
+ i32.const 1080
+ i32.add
+ set_local 3
+ i32.const 0
+ i32.load offset=1060
+ set_local 4
+ block ;; label = @30
+ block ;; label = @31
+ get_local 2
+ i32.const 1
+ get_local 9
+ i32.shl
+ tee_local 9
+ i32.and
+ i32.eqz
+ br_if 0 (;@31;)
+ get_local 3
+ i32.load offset=8
+ set_local 9
+ br 1 (;@30;)
+ end
+ i32.const 0
+ get_local 2
+ get_local 9
+ i32.or
+ i32.store offset=1040
+ get_local 3
+ set_local 9
+ end
+ get_local 9
+ get_local 4
+ i32.store offset=12
+ get_local 3
+ get_local 4
+ i32.store offset=8
+ get_local 4
+ get_local 3
+ i32.store offset=12
+ get_local 4
+ get_local 9
+ i32.store offset=8
+ end
+ i32.const 0
+ get_local 6
+ i32.store offset=1060
+ i32.const 0
+ get_local 5
+ i32.store offset=1048
+ br 27 (;@1;)
+ end
+ i32.const 0
+ set_local 4
+ end
+ block ;; label = @27
+ block ;; label = @28
+ loop ;; label = @29
+ block ;; label = @30
+ block ;; label = @31
+ block ;; label = @32
+ block ;; label = @33
+ get_local 4
+ br_table 1 (;@32;) 0 (;@33;) 0 (;@33;)
+ end
+ get_local 0
+ i32.load offset=4
+ i32.const -8
+ i32.and
+ get_local 3
+ i32.sub
+ tee_local 4
+ get_local 5
+ get_local 4
+ get_local 5
+ i32.lt_u
+ tee_local 4
+ select
+ set_local 5
+ get_local 0
+ get_local 6
+ get_local 4
+ select
+ set_local 6
+ get_local 0
+ tee_local 9
+ i32.load offset=16
+ tee_local 0
+ br_if 1 (;@31;)
+ i32.const 0
+ set_local 4
+ br 3 (;@29;)
+ end
+ get_local 9
+ i32.const 20
+ i32.add
+ i32.load
+ tee_local 0
+ br_if 1 (;@30;)
+ get_local 6
+ get_local 3
+ i32.add
+ tee_local 11
+ get_local 6
+ i32.le_u
+ br_if 8 (;@23;)
+ get_local 6
+ i32.load offset=24
+ set_local 12
+ block ;; label = @32
+ get_local 6
+ i32.load offset=12
+ tee_local 9
+ get_local 6
+ i32.eq
+ br_if 0 (;@32;)
+ get_local 6
+ i32.load offset=8
+ tee_local 0
+ get_local 9
+ i32.store offset=12
+ get_local 9
+ get_local 0
+ i32.store offset=8
+ get_local 12
+ br_if 4 (;@28;)
+ br 5 (;@27;)
+ end
+ block ;; label = @32
+ block ;; label = @33
+ get_local 6
+ i32.const 20
+ i32.add
+ tee_local 4
+ i32.load
+ tee_local 0
+ br_if 0 (;@33;)
+ get_local 6
+ i32.load offset=16
+ tee_local 0
+ i32.eqz
+ br_if 1 (;@32;)
+ get_local 6
+ i32.const 16
+ i32.add
+ set_local 4
+ end
+ loop ;; label = @33
+ get_local 4
+ set_local 8
+ get_local 0
+ tee_local 9
+ i32.const 20
+ i32.add
+ tee_local 4
+ i32.load
+ tee_local 0
+ br_if 0 (;@33;)
+ get_local 9
+ i32.const 16
+ i32.add
+ set_local 4
+ get_local 9
+ i32.load offset=16
+ tee_local 0
+ br_if 0 (;@33;)
+ end
+ get_local 8
+ i32.const 0
+ i32.store
+ get_local 12
+ i32.eqz
+ br_if 5 (;@27;)
+ br 4 (;@28;)
+ end
+ i32.const 0
+ set_local 9
+ get_local 12
+ br_if 3 (;@28;)
+ br 4 (;@27;)
+ end
+ i32.const 1
+ set_local 4
+ br 1 (;@29;)
+ end
+ i32.const 1
+ set_local 4
+ br 0 (;@29;)
+ end
+ end
+ block ;; label = @28
+ block ;; label = @29
+ block ;; label = @30
+ get_local 6
+ get_local 6
+ i32.load offset=28
+ tee_local 4
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ tee_local 0
+ i32.load
+ i32.eq
+ br_if 0 (;@30;)
+ get_local 12
+ i32.const 16
+ i32.const 20
+ get_local 12
+ i32.load offset=16
+ get_local 6
+ i32.eq
+ select
+ i32.add
+ get_local 9
+ i32.store
+ get_local 9
+ br_if 1 (;@29;)
+ br 3 (;@27;)
+ end
+ get_local 0
+ get_local 9
+ i32.store
+ get_local 9
+ i32.eqz
+ br_if 1 (;@28;)
+ end
+ get_local 9
+ get_local 12
+ i32.store offset=24
+ block ;; label = @29
+ get_local 6
+ i32.load offset=16
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@29;)
+ get_local 9
+ get_local 0
+ i32.store offset=16
+ get_local 0
+ get_local 9
+ i32.store offset=24
+ end
+ get_local 6
+ i32.const 20
+ i32.add
+ i32.load
+ tee_local 0
+ i32.eqz
+ br_if 1 (;@27;)
+ get_local 9
+ i32.const 20
+ i32.add
+ get_local 0
+ i32.store
+ get_local 0
+ get_local 9
+ i32.store offset=24
+ br 1 (;@27;)
+ end
+ i32.const 0
+ get_local 10
+ i32.const -2
+ get_local 4
+ i32.rotl
+ i32.and
+ i32.store offset=1044
+ end
+ block ;; label = @27
+ block ;; label = @28
+ get_local 5
+ i32.const 15
+ i32.gt_u
+ br_if 0 (;@28;)
+ get_local 6
+ get_local 5
+ get_local 3
+ i32.add
+ tee_local 0
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 6
+ get_local 0
+ i32.add
+ tee_local 0
+ get_local 0
+ i32.load offset=4
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ br 1 (;@27;)
+ end
+ get_local 11
+ get_local 5
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ get_local 6
+ get_local 3
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 11
+ get_local 5
+ i32.add
+ get_local 5
+ i32.store
+ block ;; label = @28
+ get_local 7
+ i32.eqz
+ br_if 0 (;@28;)
+ get_local 7
+ i32.const 3
+ i32.shr_u
+ tee_local 3
+ i32.const 3
+ i32.shl
+ i32.const 1080
+ i32.add
+ set_local 4
+ i32.const 0
+ i32.load offset=1060
+ set_local 0
+ block ;; label = @29
+ block ;; label = @30
+ i32.const 1
+ get_local 3
+ i32.shl
+ tee_local 3
+ get_local 2
+ i32.and
+ i32.eqz
+ br_if 0 (;@30;)
+ get_local 4
+ i32.load offset=8
+ set_local 3
+ br 1 (;@29;)
+ end
+ i32.const 0
+ get_local 3
+ get_local 2
+ i32.or
+ i32.store offset=1040
+ get_local 4
+ set_local 3
+ end
+ get_local 3
+ get_local 0
+ i32.store offset=12
+ get_local 4
+ get_local 0
+ i32.store offset=8
+ get_local 0
+ get_local 4
+ i32.store offset=12
+ get_local 0
+ get_local 3
+ i32.store offset=8
+ end
+ i32.const 0
+ get_local 11
+ i32.store offset=1060
+ i32.const 0
+ get_local 5
+ i32.store offset=1048
+ end
+ get_local 6
+ i32.const 8
+ i32.add
+ set_local 0
+ br 25 (;@1;)
+ end
+ get_local 0
+ i32.eqz
+ br_if 1 (;@24;)
+ end
+ loop ;; label = @25
+ get_local 0
+ i32.load offset=4
+ i32.const -8
+ i32.and
+ get_local 3
+ i32.sub
+ tee_local 2
+ get_local 5
+ i32.lt_u
+ set_local 6
+ block ;; label = @26
+ get_local 0
+ i32.load offset=16
+ tee_local 4
+ br_if 0 (;@26;)
+ get_local 0
+ i32.const 20
+ i32.add
+ i32.load
+ set_local 4
+ end
+ get_local 2
+ get_local 5
+ get_local 6
+ select
+ set_local 5
+ get_local 0
+ get_local 9
+ get_local 6
+ select
+ set_local 9
+ get_local 4
+ set_local 0
+ get_local 4
+ br_if 0 (;@25;)
+ end
+ end
+ get_local 9
+ i32.eqz
+ br_if 0 (;@23;)
+ get_local 5
+ i32.const 0
+ i32.load offset=1048
+ get_local 3
+ i32.sub
+ i32.ge_u
+ br_if 0 (;@23;)
+ get_local 9
+ get_local 3
+ i32.add
+ tee_local 8
+ get_local 9
+ i32.le_u
+ br_if 0 (;@23;)
+ get_local 9
+ i32.load offset=24
+ set_local 10
+ get_local 9
+ i32.load offset=12
+ tee_local 6
+ get_local 9
+ i32.eq
+ br_if 1 (;@22;)
+ get_local 9
+ i32.load offset=8
+ tee_local 0
+ get_local 6
+ i32.store offset=12
+ get_local 6
+ get_local 0
+ i32.store offset=8
+ get_local 10
+ br_if 20 (;@3;)
+ br 21 (;@2;)
+ end
+ block ;; label = @23
+ block ;; label = @24
+ block ;; label = @25
+ block ;; label = @26
+ block ;; label = @27
+ block ;; label = @28
+ i32.const 0
+ i32.load offset=1048
+ tee_local 0
+ get_local 3
+ i32.ge_u
+ br_if 0 (;@28;)
+ i32.const 0
+ i32.load offset=1052
+ tee_local 6
+ get_local 3
+ i32.le_u
+ br_if 1 (;@27;)
+ i32.const 0
+ i32.load offset=1064
+ tee_local 0
+ get_local 3
+ i32.add
+ tee_local 4
+ get_local 6
+ get_local 3
+ i32.sub
+ tee_local 5
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ i32.const 0
+ get_local 5
+ i32.store offset=1052
+ i32.const 0
+ get_local 4
+ i32.store offset=1064
+ get_local 0
+ get_local 3
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 0
+ i32.const 8
+ i32.add
+ set_local 0
+ br 27 (;@1;)
+ end
+ i32.const 0
+ i32.load offset=1060
+ set_local 4
+ get_local 0
+ get_local 3
+ i32.sub
+ tee_local 5
+ i32.const 16
+ i32.lt_u
+ br_if 1 (;@26;)
+ get_local 4
+ get_local 3
+ i32.add
+ tee_local 6
+ get_local 5
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ i32.const 0
+ get_local 5
+ i32.store offset=1048
+ i32.const 0
+ get_local 6
+ i32.store offset=1060
+ get_local 4
+ get_local 0
+ i32.add
+ get_local 5
+ i32.store
+ get_local 4
+ get_local 3
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ br 2 (;@25;)
+ end
+ i32.const 0
+ i32.load offset=1512
+ i32.eqz
+ br_if 2 (;@24;)
+ i32.const 0
+ i32.load offset=1520
+ set_local 4
+ br 3 (;@23;)
+ end
+ get_local 4
+ get_local 0
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 4
+ get_local 0
+ i32.add
+ tee_local 0
+ get_local 0
+ i32.load offset=4
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ i32.const 0
+ i32.const 0
+ i32.store offset=1060
+ i32.const 0
+ i32.const 0
+ i32.store offset=1048
+ end
+ get_local 4
+ i32.const 8
+ i32.add
+ set_local 0
+ br 23 (;@1;)
+ end
+ i32.const 0
+ i64.const -1
+ i64.store offset=1524 align=4
+ i32.const 0
+ i64.const 281474976776192
+ i64.store offset=1516 align=4
+ i32.const 0
+ get_local 1
+ i32.const 12
+ i32.add
+ i32.const -16
+ i32.and
+ i32.const 1431655768
+ i32.xor
+ i32.store offset=1512
+ i32.const 0
+ i32.const 0
+ i32.store offset=1532
+ i32.const 0
+ i32.const 0
+ i32.store offset=1484
+ i32.const 65536
+ set_local 4
+ end
+ i32.const 0
+ set_local 0
+ block ;; label = @23
+ block ;; label = @24
+ get_local 4
+ get_local 3
+ i32.const 47
+ i32.add
+ tee_local 7
+ i32.add
+ tee_local 2
+ i32.const 0
+ get_local 4
+ i32.sub
+ tee_local 8
+ i32.and
+ tee_local 9
+ get_local 3
+ i32.le_u
+ br_if 0 (;@24;)
+ block ;; label = @25
+ i32.const 0
+ i32.load offset=1480
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@25;)
+ i32.const 0
+ i32.load offset=1472
+ tee_local 4
+ get_local 9
+ i32.add
+ tee_local 5
+ get_local 4
+ i32.le_u
+ br_if 2 (;@23;)
+ get_local 5
+ get_local 0
+ i32.gt_u
+ br_if 2 (;@23;)
+ end
+ i32.const 0
+ i32.load8_u offset=1484
+ i32.const 4
+ i32.and
+ br_if 10 (;@14;)
+ block ;; label = @25
+ i32.const 0
+ i32.load offset=1064
+ tee_local 4
+ i32.eqz
+ br_if 0 (;@25;)
+ i32.const 1488
+ set_local 0
+ loop ;; label = @26
+ block ;; label = @27
+ get_local 0
+ i32.load
+ tee_local 5
+ get_local 4
+ i32.gt_u
+ br_if 0 (;@27;)
+ get_local 5
+ get_local 0
+ i32.load offset=4
+ i32.add
+ get_local 4
+ i32.gt_u
+ br_if 6 (;@21;)
+ end
+ get_local 0
+ i32.load offset=8
+ tee_local 0
+ br_if 0 (;@26;)
+ end
+ end
+ i32.const 0
+ call 25
+ tee_local 6
+ i32.const -1
+ i32.eq
+ br_if 9 (;@15;)
+ get_local 9
+ set_local 2
+ block ;; label = @25
+ i32.const 0
+ i32.load offset=1516
+ tee_local 0
+ i32.const -1
+ i32.add
+ tee_local 4
+ get_local 6
+ i32.and
+ i32.eqz
+ br_if 0 (;@25;)
+ get_local 9
+ get_local 6
+ i32.sub
+ get_local 4
+ get_local 6
+ i32.add
+ i32.const 0
+ get_local 0
+ i32.sub
+ i32.and
+ i32.add
+ set_local 2
+ end
+ get_local 2
+ get_local 3
+ i32.le_u
+ br_if 9 (;@15;)
+ get_local 2
+ i32.const 2147483646
+ i32.gt_u
+ br_if 9 (;@15;)
+ block ;; label = @25
+ i32.const 0
+ i32.load offset=1480
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@25;)
+ i32.const 0
+ i32.load offset=1472
+ tee_local 4
+ get_local 2
+ i32.add
+ tee_local 5
+ get_local 4
+ i32.le_u
+ br_if 10 (;@15;)
+ get_local 5
+ get_local 0
+ i32.gt_u
+ br_if 10 (;@15;)
+ end
+ get_local 2
+ call 25
+ tee_local 0
+ get_local 6
+ i32.ne
+ br_if 4 (;@20;)
+ br 11 (;@13;)
+ end
+ i32.const 0
+ i32.const 48
+ i32.store offset=1536
+ br 22 (;@1;)
+ end
+ i32.const 0
+ set_local 0
+ i32.const 0
+ i32.const 48
+ i32.store offset=1536
+ br 21 (;@1;)
+ end
+ block ;; label = @22
+ get_local 9
+ i32.const 20
+ i32.add
+ tee_local 4
+ i32.load
+ tee_local 0
+ br_if 0 (;@22;)
+ get_local 9
+ i32.load offset=16
+ tee_local 0
+ i32.eqz
+ br_if 3 (;@19;)
+ get_local 9
+ i32.const 16
+ i32.add
+ set_local 4
+ end
+ loop ;; label = @22
+ get_local 4
+ set_local 2
+ get_local 0
+ tee_local 6
+ i32.const 20
+ i32.add
+ tee_local 4
+ i32.load
+ tee_local 0
+ br_if 0 (;@22;)
+ get_local 6
+ i32.const 16
+ i32.add
+ set_local 4
+ get_local 6
+ i32.load offset=16
+ tee_local 0
+ br_if 0 (;@22;)
+ end
+ get_local 2
+ i32.const 0
+ i32.store
+ get_local 10
+ i32.eqz
+ br_if 19 (;@2;)
+ br 18 (;@3;)
+ end
+ get_local 2
+ get_local 6
+ i32.sub
+ get_local 8
+ i32.and
+ tee_local 2
+ i32.const 2147483646
+ i32.gt_u
+ br_if 5 (;@15;)
+ get_local 2
+ call 25
+ tee_local 6
+ get_local 0
+ i32.load
+ get_local 0
+ i32.load offset=4
+ i32.add
+ i32.eq
+ br_if 3 (;@17;)
+ get_local 6
+ set_local 0
+ end
+ get_local 0
+ set_local 6
+ get_local 3
+ i32.const 48
+ i32.add
+ get_local 2
+ i32.le_u
+ br_if 1 (;@18;)
+ get_local 2
+ i32.const 2147483646
+ i32.gt_u
+ br_if 1 (;@18;)
+ get_local 6
+ i32.const -1
+ i32.eq
+ br_if 1 (;@18;)
+ get_local 7
+ get_local 2
+ i32.sub
+ i32.const 0
+ i32.load offset=1520
+ tee_local 0
+ i32.add
+ i32.const 0
+ get_local 0
+ i32.sub
+ i32.and
+ tee_local 0
+ i32.const 2147483646
+ i32.gt_u
+ br_if 6 (;@13;)
+ get_local 0
+ call 25
+ i32.const -1
+ i32.eq
+ br_if 3 (;@16;)
+ get_local 0
+ get_local 2
+ i32.add
+ set_local 2
+ br 6 (;@13;)
+ end
+ i32.const 0
+ set_local 6
+ get_local 10
+ br_if 15 (;@3;)
+ br 16 (;@2;)
+ end
+ get_local 6
+ i32.const -1
+ i32.ne
+ br_if 4 (;@13;)
+ br 2 (;@15;)
+ end
+ get_local 6
+ i32.const -1
+ i32.ne
+ br_if 3 (;@13;)
+ br 1 (;@15;)
+ end
+ i32.const 0
+ get_local 2
+ i32.sub
+ call 25
+ drop
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1484
+ i32.const 4
+ i32.or
+ i32.store offset=1484
+ end
+ get_local 9
+ i32.const 2147483646
+ i32.gt_u
+ br_if 1 (;@12;)
+ get_local 9
+ call 25
+ tee_local 6
+ i32.const 0
+ call 25
+ tee_local 0
+ i32.ge_u
+ br_if 1 (;@12;)
+ get_local 6
+ i32.const -1
+ i32.eq
+ br_if 1 (;@12;)
+ get_local 0
+ i32.const -1
+ i32.eq
+ br_if 1 (;@12;)
+ get_local 0
+ get_local 6
+ i32.sub
+ tee_local 2
+ get_local 3
+ i32.const 40
+ i32.add
+ i32.le_u
+ br_if 1 (;@12;)
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1472
+ get_local 2
+ i32.add
+ tee_local 0
+ i32.store offset=1472
+ block ;; label = @13
+ get_local 0
+ i32.const 0
+ i32.load offset=1476
+ i32.le_u
+ br_if 0 (;@13;)
+ i32.const 0
+ get_local 0
+ i32.store offset=1476
+ end
+ block ;; label = @13
+ block ;; label = @14
+ block ;; label = @15
+ block ;; label = @16
+ i32.const 0
+ i32.load offset=1064
+ tee_local 4
+ i32.eqz
+ br_if 0 (;@16;)
+ i32.const 1488
+ set_local 0
+ loop ;; label = @17
+ get_local 6
+ get_local 0
+ i32.load
+ tee_local 5
+ get_local 0
+ i32.load offset=4
+ tee_local 9
+ i32.add
+ i32.eq
+ br_if 2 (;@15;)
+ get_local 0
+ i32.load offset=8
+ tee_local 0
+ br_if 0 (;@17;)
+ br 3 (;@14;)
+ end
+ end
+ block ;; label = @16
+ block ;; label = @17
+ i32.const 0
+ i32.load offset=1056
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@17;)
+ get_local 6
+ get_local 0
+ i32.ge_u
+ br_if 1 (;@16;)
+ end
+ i32.const 0
+ get_local 6
+ i32.store offset=1056
+ end
+ i32.const 0
+ set_local 0
+ i32.const 0
+ get_local 2
+ i32.store offset=1492
+ i32.const 0
+ get_local 6
+ i32.store offset=1488
+ i32.const 0
+ i32.const -1
+ i32.store offset=1072
+ i32.const 0
+ i32.const 0
+ i32.load offset=1512
+ i32.store offset=1076
+ i32.const 0
+ i32.const 0
+ i32.store offset=1500
+ loop ;; label = @16
+ get_local 0
+ i32.const 1088
+ i32.add
+ get_local 0
+ i32.const 1080
+ i32.add
+ tee_local 4
+ i32.store
+ get_local 0
+ i32.const 1092
+ i32.add
+ get_local 4
+ i32.store
+ get_local 0
+ i32.const 8
+ i32.add
+ tee_local 0
+ i32.const 256
+ i32.ne
+ br_if 0 (;@16;)
+ end
+ get_local 6
+ i32.const -8
+ get_local 6
+ i32.sub
+ i32.const 7
+ i32.and
+ i32.const 0
+ get_local 6
+ i32.const 8
+ i32.add
+ i32.const 7
+ i32.and
+ select
+ tee_local 0
+ i32.add
+ tee_local 4
+ get_local 2
+ i32.const -40
+ i32.add
+ tee_local 5
+ get_local 0
+ i32.sub
+ tee_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ i32.const 0
+ i32.const 0
+ i32.load offset=1528
+ i32.store offset=1068
+ i32.const 0
+ get_local 0
+ i32.store offset=1052
+ i32.const 0
+ get_local 4
+ i32.store offset=1064
+ get_local 6
+ get_local 5
+ i32.add
+ i32.const 40
+ i32.store offset=4
+ br 2 (;@13;)
+ end
+ get_local 0
+ i32.load8_u offset=12
+ i32.const 8
+ i32.and
+ br_if 0 (;@14;)
+ get_local 6
+ get_local 4
+ i32.le_u
+ br_if 0 (;@14;)
+ get_local 5
+ get_local 4
+ i32.gt_u
+ br_if 0 (;@14;)
+ get_local 4
+ i32.const -8
+ get_local 4
+ i32.sub
+ i32.const 7
+ i32.and
+ i32.const 0
+ get_local 4
+ i32.const 8
+ i32.add
+ i32.const 7
+ i32.and
+ select
+ tee_local 5
+ i32.add
+ tee_local 6
+ i32.const 0
+ i32.load offset=1052
+ get_local 2
+ i32.add
+ tee_local 8
+ get_local 5
+ i32.sub
+ tee_local 5
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ get_local 0
+ i32.const 4
+ i32.add
+ get_local 9
+ get_local 2
+ i32.add
+ i32.store
+ i32.const 0
+ i32.const 0
+ i32.load offset=1528
+ i32.store offset=1068
+ i32.const 0
+ get_local 5
+ i32.store offset=1052
+ i32.const 0
+ get_local 6
+ i32.store offset=1064
+ get_local 4
+ get_local 8
+ i32.add
+ i32.const 40
+ i32.store offset=4
+ br 1 (;@13;)
+ end
+ block ;; label = @14
+ get_local 6
+ i32.const 0
+ i32.load offset=1056
+ i32.ge_u
+ br_if 0 (;@14;)
+ i32.const 0
+ get_local 6
+ i32.store offset=1056
+ end
+ get_local 6
+ get_local 2
+ i32.add
+ set_local 5
+ i32.const 1488
+ set_local 0
+ block ;; label = @14
+ block ;; label = @15
+ block ;; label = @16
+ block ;; label = @17
+ block ;; label = @18
+ block ;; label = @19
+ block ;; label = @20
+ block ;; label = @21
+ loop ;; label = @22
+ get_local 0
+ i32.load
+ get_local 5
+ i32.eq
+ br_if 1 (;@21;)
+ get_local 0
+ i32.load offset=8
+ tee_local 0
+ br_if 0 (;@22;)
+ br 2 (;@20;)
+ end
+ end
+ get_local 0
+ i32.load8_u offset=12
+ i32.const 8
+ i32.and
+ br_if 0 (;@20;)
+ get_local 0
+ get_local 6
+ i32.store
+ get_local 0
+ get_local 0
+ i32.load offset=4
+ get_local 2
+ i32.add
+ i32.store offset=4
+ get_local 6
+ i32.const -8
+ get_local 6
+ i32.sub
+ i32.const 7
+ i32.and
+ i32.const 0
+ get_local 6
+ i32.const 8
+ i32.add
+ i32.const 7
+ i32.and
+ select
+ i32.add
+ tee_local 2
+ get_local 3
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 5
+ i32.const -8
+ get_local 5
+ i32.sub
+ i32.const 7
+ i32.and
+ i32.const 0
+ get_local 5
+ i32.const 8
+ i32.add
+ i32.const 7
+ i32.and
+ select
+ i32.add
+ tee_local 6
+ get_local 2
+ i32.sub
+ get_local 3
+ i32.sub
+ set_local 0
+ get_local 2
+ get_local 3
+ i32.add
+ set_local 5
+ get_local 4
+ get_local 6
+ i32.eq
+ br_if 1 (;@19;)
+ i32.const 0
+ i32.load offset=1060
+ get_local 6
+ i32.eq
+ br_if 9 (;@11;)
+ get_local 6
+ i32.load offset=4
+ tee_local 4
+ i32.const 3
+ i32.and
+ i32.const 1
+ i32.ne
+ br_if 15 (;@5;)
+ get_local 4
+ i32.const -8
+ i32.and
+ set_local 7
+ get_local 4
+ i32.const 255
+ i32.gt_u
+ br_if 10 (;@10;)
+ get_local 6
+ i32.load offset=12
+ tee_local 3
+ get_local 6
+ i32.load offset=8
+ tee_local 9
+ i32.eq
+ br_if 11 (;@9;)
+ get_local 3
+ get_local 9
+ i32.store offset=8
+ get_local 9
+ get_local 3
+ i32.store offset=12
+ br 14 (;@6;)
+ end
+ i32.const 1488
+ set_local 0
+ block ;; label = @20
+ loop ;; label = @21
+ block ;; label = @22
+ get_local 0
+ i32.load
+ tee_local 5
+ get_local 4
+ i32.gt_u
+ br_if 0 (;@22;)
+ get_local 5
+ get_local 0
+ i32.load offset=4
+ i32.add
+ tee_local 5
+ get_local 4
+ i32.gt_u
+ br_if 2 (;@20;)
+ end
+ get_local 0
+ i32.load offset=8
+ set_local 0
+ br 0 (;@21;)
+ end
+ end
+ get_local 6
+ i32.const -8
+ get_local 6
+ i32.sub
+ i32.const 7
+ i32.and
+ i32.const 0
+ get_local 6
+ i32.const 8
+ i32.add
+ i32.const 7
+ i32.and
+ select
+ tee_local 0
+ i32.add
+ tee_local 8
+ get_local 2
+ i32.const -40
+ i32.add
+ tee_local 9
+ get_local 0
+ i32.sub
+ tee_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ get_local 6
+ get_local 9
+ i32.add
+ i32.const 40
+ i32.store offset=4
+ get_local 4
+ get_local 5
+ i32.const 39
+ get_local 5
+ i32.sub
+ i32.const 7
+ i32.and
+ i32.const 0
+ get_local 5
+ i32.const -39
+ i32.add
+ i32.const 7
+ i32.and
+ select
+ i32.add
+ i32.const -47
+ i32.add
+ tee_local 9
+ get_local 9
+ get_local 4
+ i32.const 16
+ i32.add
+ i32.lt_u
+ select
+ tee_local 9
+ i32.const 27
+ i32.store offset=4
+ i32.const 0
+ i32.const 0
+ i32.load offset=1528
+ i32.store offset=1068
+ i32.const 0
+ get_local 0
+ i32.store offset=1052
+ i32.const 0
+ get_local 8
+ i32.store offset=1064
+ get_local 9
+ i32.const 16
+ i32.add
+ i32.const 0
+ i64.load offset=1496 align=4
+ i64.store align=4
+ get_local 9
+ i32.const 0
+ i64.load offset=1488 align=4
+ i64.store offset=8 align=4
+ i32.const 0
+ get_local 2
+ i32.store offset=1492
+ i32.const 0
+ get_local 6
+ i32.store offset=1488
+ i32.const 0
+ get_local 9
+ i32.const 8
+ i32.add
+ i32.store offset=1496
+ i32.const 0
+ i32.const 0
+ i32.store offset=1500
+ get_local 9
+ i32.const 28
+ i32.add
+ set_local 0
+ loop ;; label = @20
+ get_local 0
+ i32.const 7
+ i32.store
+ get_local 0
+ i32.const 4
+ i32.add
+ tee_local 0
+ get_local 5
+ i32.lt_u
+ br_if 0 (;@20;)
+ end
+ get_local 9
+ get_local 4
+ i32.eq
+ br_if 6 (;@13;)
+ get_local 9
+ i32.const 4
+ i32.add
+ tee_local 0
+ get_local 0
+ i32.load
+ i32.const -2
+ i32.and
+ i32.store
+ get_local 9
+ get_local 9
+ get_local 4
+ i32.sub
+ tee_local 2
+ i32.store
+ get_local 4
+ get_local 2
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ block ;; label = @20
+ get_local 2
+ i32.const 255
+ i32.gt_u
+ br_if 0 (;@20;)
+ get_local 2
+ i32.const 3
+ i32.shr_u
+ tee_local 5
+ i32.const 3
+ i32.shl
+ i32.const 1080
+ i32.add
+ set_local 0
+ i32.const 0
+ i32.load offset=1040
+ tee_local 6
+ i32.const 1
+ get_local 5
+ i32.shl
+ tee_local 5
+ i32.and
+ i32.eqz
+ br_if 2 (;@18;)
+ get_local 0
+ i32.load offset=8
+ set_local 5
+ br 3 (;@17;)
+ end
+ i32.const 0
+ set_local 0
+ block ;; label = @20
+ get_local 2
+ i32.const 8
+ i32.shr_u
+ tee_local 5
+ i32.eqz
+ br_if 0 (;@20;)
+ i32.const 31
+ set_local 0
+ get_local 2
+ i32.const 16777215
+ i32.gt_u
+ br_if 0 (;@20;)
+ get_local 2
+ i32.const 14
+ get_local 5
+ get_local 5
+ i32.const 1048320
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 8
+ i32.and
+ tee_local 0
+ i32.shl
+ tee_local 5
+ i32.const 520192
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 4
+ i32.and
+ tee_local 6
+ get_local 0
+ i32.or
+ get_local 5
+ get_local 6
+ i32.shl
+ tee_local 0
+ i32.const 245760
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 2
+ i32.and
+ tee_local 5
+ i32.or
+ i32.sub
+ get_local 0
+ get_local 5
+ i32.shl
+ i32.const 15
+ i32.shr_u
+ i32.add
+ tee_local 0
+ i32.const 7
+ i32.add
+ i32.shr_u
+ i32.const 1
+ i32.and
+ get_local 0
+ i32.const 1
+ i32.shl
+ i32.or
+ set_local 0
+ end
+ get_local 4
+ i64.const 0
+ i64.store offset=16 align=4
+ get_local 4
+ i32.const 28
+ i32.add
+ get_local 0
+ i32.store
+ get_local 0
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ set_local 5
+ i32.const 0
+ i32.load offset=1044
+ tee_local 6
+ i32.const 1
+ get_local 0
+ i32.shl
+ tee_local 9
+ i32.and
+ i32.eqz
+ br_if 3 (;@16;)
+ get_local 2
+ i32.const 0
+ i32.const 25
+ get_local 0
+ i32.const 1
+ i32.shr_u
+ i32.sub
+ get_local 0
+ i32.const 31
+ i32.eq
+ select
+ i32.shl
+ set_local 0
+ get_local 5
+ i32.load
+ set_local 6
+ loop ;; label = @20
+ get_local 6
+ tee_local 5
+ i32.load offset=4
+ i32.const -8
+ i32.and
+ get_local 2
+ i32.eq
+ br_if 6 (;@14;)
+ get_local 0
+ i32.const 29
+ i32.shr_u
+ set_local 6
+ get_local 0
+ i32.const 1
+ i32.shl
+ set_local 0
+ get_local 5
+ get_local 6
+ i32.const 4
+ i32.and
+ i32.add
+ i32.const 16
+ i32.add
+ tee_local 9
+ i32.load
+ tee_local 6
+ br_if 0 (;@20;)
+ end
+ get_local 9
+ get_local 4
+ i32.store
+ get_local 4
+ i32.const 24
+ i32.add
+ get_local 5
+ i32.store
+ br 4 (;@15;)
+ end
+ i32.const 0
+ get_local 5
+ i32.store offset=1064
+ i32.const 0
+ i32.const 0
+ i32.load offset=1052
+ get_local 0
+ i32.add
+ tee_local 0
+ i32.store offset=1052
+ get_local 5
+ get_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ br 14 (;@4;)
+ end
+ i32.const 0
+ get_local 6
+ get_local 5
+ i32.or
+ i32.store offset=1040
+ get_local 0
+ set_local 5
+ end
+ get_local 5
+ get_local 4
+ i32.store offset=12
+ get_local 0
+ get_local 4
+ i32.store offset=8
+ get_local 4
+ get_local 0
+ i32.store offset=12
+ get_local 4
+ get_local 5
+ i32.store offset=8
+ br 3 (;@13;)
+ end
+ get_local 5
+ get_local 4
+ i32.store
+ i32.const 0
+ get_local 6
+ get_local 9
+ i32.or
+ i32.store offset=1044
+ get_local 4
+ i32.const 24
+ i32.add
+ get_local 5
+ i32.store
+ end
+ get_local 4
+ get_local 4
+ i32.store offset=12
+ get_local 4
+ get_local 4
+ i32.store offset=8
+ br 1 (;@13;)
+ end
+ get_local 5
+ i32.load offset=8
+ tee_local 0
+ get_local 4
+ i32.store offset=12
+ get_local 5
+ get_local 4
+ i32.store offset=8
+ get_local 4
+ i32.const 24
+ i32.add
+ i32.const 0
+ i32.store
+ get_local 4
+ get_local 5
+ i32.store offset=12
+ get_local 4
+ get_local 0
+ i32.store offset=8
+ end
+ i32.const 0
+ i32.load offset=1052
+ tee_local 0
+ get_local 3
+ i32.le_u
+ br_if 0 (;@12;)
+ i32.const 0
+ i32.load offset=1064
+ tee_local 4
+ get_local 3
+ i32.add
+ tee_local 5
+ get_local 0
+ get_local 3
+ i32.sub
+ tee_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ i32.const 0
+ get_local 0
+ i32.store offset=1052
+ i32.const 0
+ get_local 5
+ i32.store offset=1064
+ get_local 4
+ get_local 3
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 4
+ i32.const 8
+ i32.add
+ set_local 0
+ br 11 (;@1;)
+ end
+ i32.const 0
+ set_local 0
+ i32.const 0
+ i32.const 48
+ i32.store offset=1536
+ br 10 (;@1;)
+ end
+ i32.const 0
+ get_local 5
+ i32.store offset=1060
+ i32.const 0
+ i32.const 0
+ i32.load offset=1048
+ get_local 0
+ i32.add
+ tee_local 0
+ i32.store offset=1048
+ get_local 5
+ get_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ get_local 5
+ get_local 0
+ i32.add
+ get_local 0
+ i32.store
+ br 6 (;@4;)
+ end
+ get_local 6
+ i32.load offset=24
+ set_local 10
+ get_local 6
+ i32.load offset=12
+ tee_local 9
+ get_local 6
+ i32.eq
+ br_if 1 (;@8;)
+ get_local 6
+ i32.load offset=8
+ tee_local 4
+ get_local 9
+ i32.store offset=12
+ get_local 9
+ get_local 4
+ i32.store offset=8
+ get_local 10
+ br_if 2 (;@7;)
+ br 3 (;@6;)
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1040
+ i32.const -2
+ get_local 4
+ i32.const 3
+ i32.shr_u
+ i32.rotl
+ i32.and
+ i32.store offset=1040
+ br 2 (;@6;)
+ end
+ block ;; label = @8
+ block ;; label = @9
+ get_local 6
+ i32.const 20
+ i32.add
+ tee_local 4
+ i32.load
+ tee_local 3
+ br_if 0 (;@9;)
+ get_local 6
+ i32.const 16
+ i32.add
+ tee_local 4
+ i32.load
+ tee_local 3
+ i32.eqz
+ br_if 1 (;@8;)
+ end
+ loop ;; label = @9
+ get_local 4
+ set_local 8
+ get_local 3
+ tee_local 9
+ i32.const 20
+ i32.add
+ tee_local 4
+ i32.load
+ tee_local 3
+ br_if 0 (;@9;)
+ get_local 9
+ i32.const 16
+ i32.add
+ set_local 4
+ get_local 9
+ i32.load offset=16
+ tee_local 3
+ br_if 0 (;@9;)
+ end
+ get_local 8
+ i32.const 0
+ i32.store
+ get_local 10
+ i32.eqz
+ br_if 2 (;@6;)
+ br 1 (;@7;)
+ end
+ i32.const 0
+ set_local 9
+ get_local 10
+ i32.eqz
+ br_if 1 (;@6;)
+ end
+ block ;; label = @7
+ block ;; label = @8
+ block ;; label = @9
+ get_local 6
+ i32.load offset=28
+ tee_local 3
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ tee_local 4
+ i32.load
+ get_local 6
+ i32.eq
+ br_if 0 (;@9;)
+ get_local 10
+ i32.const 16
+ i32.const 20
+ get_local 10
+ i32.load offset=16
+ get_local 6
+ i32.eq
+ select
+ i32.add
+ get_local 9
+ i32.store
+ get_local 9
+ br_if 1 (;@8;)
+ br 3 (;@6;)
+ end
+ get_local 4
+ get_local 9
+ i32.store
+ get_local 9
+ i32.eqz
+ br_if 1 (;@7;)
+ end
+ get_local 9
+ get_local 10
+ i32.store offset=24
+ block ;; label = @8
+ get_local 6
+ i32.load offset=16
+ tee_local 4
+ i32.eqz
+ br_if 0 (;@8;)
+ get_local 9
+ get_local 4
+ i32.store offset=16
+ get_local 4
+ get_local 9
+ i32.store offset=24
+ end
+ get_local 6
+ i32.const 20
+ i32.add
+ i32.load
+ tee_local 4
+ i32.eqz
+ br_if 1 (;@6;)
+ get_local 9
+ i32.const 20
+ i32.add
+ get_local 4
+ i32.store
+ get_local 4
+ get_local 9
+ i32.store offset=24
+ br 1 (;@6;)
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1044
+ i32.const -2
+ get_local 3
+ i32.rotl
+ i32.and
+ i32.store offset=1044
+ end
+ get_local 7
+ get_local 0
+ i32.add
+ set_local 0
+ get_local 6
+ get_local 7
+ i32.add
+ set_local 6
+ end
+ get_local 6
+ get_local 6
+ i32.load offset=4
+ i32.const -2
+ i32.and
+ i32.store offset=4
+ get_local 5
+ get_local 0
+ i32.add
+ get_local 0
+ i32.store
+ get_local 5
+ get_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ block ;; label = @8
+ block ;; label = @9
+ block ;; label = @10
+ get_local 0
+ i32.const 255
+ i32.gt_u
+ br_if 0 (;@10;)
+ get_local 0
+ i32.const 3
+ i32.shr_u
+ tee_local 4
+ i32.const 3
+ i32.shl
+ i32.const 1080
+ i32.add
+ set_local 0
+ i32.const 0
+ i32.load offset=1040
+ tee_local 3
+ i32.const 1
+ get_local 4
+ i32.shl
+ tee_local 4
+ i32.and
+ i32.eqz
+ br_if 1 (;@9;)
+ get_local 0
+ i32.load offset=8
+ set_local 4
+ br 2 (;@8;)
+ end
+ i32.const 0
+ set_local 4
+ block ;; label = @10
+ get_local 0
+ i32.const 8
+ i32.shr_u
+ tee_local 3
+ i32.eqz
+ br_if 0 (;@10;)
+ i32.const 31
+ set_local 4
+ get_local 0
+ i32.const 16777215
+ i32.gt_u
+ br_if 0 (;@10;)
+ get_local 0
+ i32.const 14
+ get_local 3
+ get_local 3
+ i32.const 1048320
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 8
+ i32.and
+ tee_local 4
+ i32.shl
+ tee_local 3
+ i32.const 520192
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 4
+ i32.and
+ tee_local 6
+ get_local 4
+ i32.or
+ get_local 3
+ get_local 6
+ i32.shl
+ tee_local 4
+ i32.const 245760
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 2
+ i32.and
+ tee_local 3
+ i32.or
+ i32.sub
+ get_local 4
+ get_local 3
+ i32.shl
+ i32.const 15
+ i32.shr_u
+ i32.add
+ tee_local 4
+ i32.const 7
+ i32.add
+ i32.shr_u
+ i32.const 1
+ i32.and
+ get_local 4
+ i32.const 1
+ i32.shl
+ i32.or
+ set_local 4
+ end
+ get_local 5
+ get_local 4
+ i32.store offset=28
+ get_local 5
+ i64.const 0
+ i64.store offset=16 align=4
+ get_local 4
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ set_local 3
+ i32.const 0
+ i32.load offset=1044
+ tee_local 6
+ i32.const 1
+ get_local 4
+ i32.shl
+ tee_local 9
+ i32.and
+ i32.eqz
+ br_if 2 (;@7;)
+ get_local 0
+ i32.const 0
+ i32.const 25
+ get_local 4
+ i32.const 1
+ i32.shr_u
+ i32.sub
+ get_local 4
+ i32.const 31
+ i32.eq
+ select
+ i32.shl
+ set_local 4
+ get_local 3
+ i32.load
+ set_local 6
+ loop ;; label = @10
+ get_local 6
+ tee_local 3
+ i32.load offset=4
+ i32.const -8
+ i32.and
+ get_local 0
+ i32.eq
+ br_if 5 (;@5;)
+ get_local 4
+ i32.const 29
+ i32.shr_u
+ set_local 6
+ get_local 4
+ i32.const 1
+ i32.shl
+ set_local 4
+ get_local 3
+ get_local 6
+ i32.const 4
+ i32.and
+ i32.add
+ i32.const 16
+ i32.add
+ tee_local 9
+ i32.load
+ tee_local 6
+ br_if 0 (;@10;)
+ end
+ get_local 9
+ get_local 5
+ i32.store
+ get_local 5
+ get_local 3
+ i32.store offset=24
+ br 3 (;@6;)
+ end
+ i32.const 0
+ get_local 3
+ get_local 4
+ i32.or
+ i32.store offset=1040
+ get_local 0
+ set_local 4
+ end
+ get_local 4
+ get_local 5
+ i32.store offset=12
+ get_local 0
+ get_local 5
+ i32.store offset=8
+ get_local 5
+ get_local 0
+ i32.store offset=12
+ get_local 5
+ get_local 4
+ i32.store offset=8
+ br 3 (;@4;)
+ end
+ get_local 3
+ get_local 5
+ i32.store
+ i32.const 0
+ get_local 6
+ get_local 9
+ i32.or
+ i32.store offset=1044
+ get_local 5
+ get_local 3
+ i32.store offset=24
+ end
+ get_local 5
+ get_local 5
+ i32.store offset=12
+ get_local 5
+ get_local 5
+ i32.store offset=8
+ br 1 (;@4;)
+ end
+ get_local 3
+ i32.load offset=8
+ tee_local 0
+ get_local 5
+ i32.store offset=12
+ get_local 3
+ get_local 5
+ i32.store offset=8
+ get_local 5
+ i32.const 0
+ i32.store offset=24
+ get_local 5
+ get_local 3
+ i32.store offset=12
+ get_local 5
+ get_local 0
+ i32.store offset=8
+ end
+ get_local 2
+ i32.const 8
+ i32.add
+ set_local 0
+ br 2 (;@1;)
+ end
+ block ;; label = @3
+ block ;; label = @4
+ block ;; label = @5
+ get_local 9
+ get_local 9
+ i32.load offset=28
+ tee_local 4
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ tee_local 0
+ i32.load
+ i32.eq
+ br_if 0 (;@5;)
+ get_local 10
+ i32.const 16
+ i32.const 20
+ get_local 10
+ i32.load offset=16
+ get_local 9
+ i32.eq
+ select
+ i32.add
+ get_local 6
+ i32.store
+ get_local 6
+ br_if 1 (;@4;)
+ br 3 (;@2;)
+ end
+ get_local 0
+ get_local 6
+ i32.store
+ get_local 6
+ i32.eqz
+ br_if 1 (;@3;)
+ end
+ get_local 6
+ get_local 10
+ i32.store offset=24
+ block ;; label = @4
+ get_local 9
+ i32.load offset=16
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@4;)
+ get_local 6
+ get_local 0
+ i32.store offset=16
+ get_local 0
+ get_local 6
+ i32.store offset=24
+ end
+ get_local 9
+ i32.const 20
+ i32.add
+ i32.load
+ tee_local 0
+ i32.eqz
+ br_if 1 (;@2;)
+ get_local 6
+ i32.const 20
+ i32.add
+ get_local 0
+ i32.store
+ get_local 0
+ get_local 6
+ i32.store offset=24
+ br 1 (;@2;)
+ end
+ i32.const 0
+ get_local 7
+ i32.const -2
+ get_local 4
+ i32.rotl
+ i32.and
+ tee_local 7
+ i32.store offset=1044
+ end
+ block ;; label = @2
+ block ;; label = @3
+ get_local 5
+ i32.const 15
+ i32.gt_u
+ br_if 0 (;@3;)
+ get_local 9
+ get_local 5
+ get_local 3
+ i32.add
+ tee_local 0
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 9
+ get_local 0
+ i32.add
+ tee_local 0
+ get_local 0
+ i32.load offset=4
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ br 1 (;@2;)
+ end
+ get_local 8
+ get_local 5
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ get_local 9
+ get_local 3
+ i32.const 3
+ i32.or
+ i32.store offset=4
+ get_local 8
+ get_local 5
+ i32.add
+ get_local 5
+ i32.store
+ block ;; label = @3
+ block ;; label = @4
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ get_local 5
+ i32.const 255
+ i32.gt_u
+ br_if 0 (;@7;)
+ get_local 5
+ i32.const 3
+ i32.shr_u
+ tee_local 4
+ i32.const 3
+ i32.shl
+ i32.const 1080
+ i32.add
+ set_local 0
+ i32.const 0
+ i32.load offset=1040
+ tee_local 5
+ i32.const 1
+ get_local 4
+ i32.shl
+ tee_local 4
+ i32.and
+ i32.eqz
+ br_if 1 (;@6;)
+ get_local 0
+ i32.load offset=8
+ set_local 4
+ br 2 (;@5;)
+ end
+ get_local 5
+ i32.const 8
+ i32.shr_u
+ tee_local 4
+ i32.eqz
+ br_if 2 (;@4;)
+ i32.const 31
+ set_local 0
+ get_local 5
+ i32.const 16777215
+ i32.gt_u
+ br_if 3 (;@3;)
+ get_local 5
+ i32.const 14
+ get_local 4
+ get_local 4
+ i32.const 1048320
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 8
+ i32.and
+ tee_local 0
+ i32.shl
+ tee_local 4
+ i32.const 520192
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 4
+ i32.and
+ tee_local 3
+ get_local 0
+ i32.or
+ get_local 4
+ get_local 3
+ i32.shl
+ tee_local 0
+ i32.const 245760
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 2
+ i32.and
+ tee_local 4
+ i32.or
+ i32.sub
+ get_local 0
+ get_local 4
+ i32.shl
+ i32.const 15
+ i32.shr_u
+ i32.add
+ tee_local 0
+ i32.const 7
+ i32.add
+ i32.shr_u
+ i32.const 1
+ i32.and
+ get_local 0
+ i32.const 1
+ i32.shl
+ i32.or
+ set_local 0
+ br 3 (;@3;)
+ end
+ i32.const 0
+ get_local 5
+ get_local 4
+ i32.or
+ i32.store offset=1040
+ get_local 0
+ set_local 4
+ end
+ get_local 4
+ get_local 8
+ i32.store offset=12
+ get_local 0
+ get_local 8
+ i32.store offset=8
+ get_local 8
+ get_local 0
+ i32.store offset=12
+ get_local 8
+ get_local 4
+ i32.store offset=8
+ br 2 (;@2;)
+ end
+ i32.const 0
+ set_local 0
+ end
+ get_local 8
+ get_local 0
+ i32.store offset=28
+ get_local 8
+ i64.const 0
+ i64.store offset=16 align=4
+ get_local 0
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ set_local 4
+ block ;; label = @3
+ block ;; label = @4
+ block ;; label = @5
+ get_local 7
+ i32.const 1
+ get_local 0
+ i32.shl
+ tee_local 3
+ i32.and
+ i32.eqz
+ br_if 0 (;@5;)
+ get_local 5
+ i32.const 0
+ i32.const 25
+ get_local 0
+ i32.const 1
+ i32.shr_u
+ i32.sub
+ get_local 0
+ i32.const 31
+ i32.eq
+ select
+ i32.shl
+ set_local 0
+ get_local 4
+ i32.load
+ set_local 3
+ loop ;; label = @6
+ get_local 3
+ tee_local 4
+ i32.load offset=4
+ i32.const -8
+ i32.and
+ get_local 5
+ i32.eq
+ br_if 3 (;@3;)
+ get_local 0
+ i32.const 29
+ i32.shr_u
+ set_local 3
+ get_local 0
+ i32.const 1
+ i32.shl
+ set_local 0
+ get_local 4
+ get_local 3
+ i32.const 4
+ i32.and
+ i32.add
+ i32.const 16
+ i32.add
+ tee_local 6
+ i32.load
+ tee_local 3
+ br_if 0 (;@6;)
+ end
+ get_local 6
+ get_local 8
+ i32.store
+ get_local 8
+ get_local 4
+ i32.store offset=24
+ br 1 (;@4;)
+ end
+ get_local 4
+ get_local 8
+ i32.store
+ i32.const 0
+ get_local 7
+ get_local 3
+ i32.or
+ i32.store offset=1044
+ get_local 8
+ get_local 4
+ i32.store offset=24
+ end
+ get_local 8
+ get_local 8
+ i32.store offset=12
+ get_local 8
+ get_local 8
+ i32.store offset=8
+ br 1 (;@2;)
+ end
+ get_local 4
+ i32.load offset=8
+ tee_local 0
+ get_local 8
+ i32.store offset=12
+ get_local 4
+ get_local 8
+ i32.store offset=8
+ get_local 8
+ i32.const 0
+ i32.store offset=24
+ get_local 8
+ get_local 4
+ i32.store offset=12
+ get_local 8
+ get_local 0
+ i32.store offset=8
+ end
+ get_local 9
+ i32.const 8
+ i32.add
+ set_local 0
+ end
+ get_local 1
+ i32.const 16
+ i32.add
+ set_global 0
+ get_local 0)
+ (func (;16;) (type 3) (param i32)
+ get_local 0
+ call 17)
+ (func (;17;) (type 3) (param i32)
+ (local i32 i32 i32 i32 i32 i32 i32)
+ block ;; label = @1
+ block ;; label = @2
+ get_local 0
+ i32.eqz
+ br_if 0 (;@2;)
+ get_local 0
+ i32.const -8
+ i32.add
+ tee_local 1
+ get_local 0
+ i32.const -4
+ i32.add
+ i32.load
+ tee_local 2
+ i32.const -8
+ i32.and
+ tee_local 0
+ i32.add
+ set_local 3
+ block ;; label = @3
+ block ;; label = @4
+ get_local 2
+ i32.const 1
+ i32.and
+ br_if 0 (;@4;)
+ get_local 2
+ i32.const 3
+ i32.and
+ i32.eqz
+ br_if 2 (;@2;)
+ get_local 1
+ get_local 1
+ i32.load
+ tee_local 2
+ i32.sub
+ tee_local 1
+ i32.const 0
+ i32.load offset=1056
+ i32.lt_u
+ br_if 2 (;@2;)
+ get_local 2
+ get_local 0
+ i32.add
+ set_local 0
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ block ;; label = @8
+ block ;; label = @9
+ i32.const 0
+ i32.load offset=1060
+ get_local 1
+ i32.eq
+ br_if 0 (;@9;)
+ get_local 2
+ i32.const 255
+ i32.gt_u
+ br_if 1 (;@8;)
+ get_local 1
+ i32.load offset=12
+ tee_local 4
+ get_local 1
+ i32.load offset=8
+ tee_local 5
+ i32.eq
+ br_if 2 (;@7;)
+ get_local 4
+ get_local 5
+ i32.store offset=8
+ get_local 5
+ get_local 4
+ i32.store offset=12
+ get_local 1
+ get_local 3
+ i32.lt_u
+ br_if 6 (;@3;)
+ br 7 (;@2;)
+ end
+ get_local 3
+ i32.load offset=4
+ tee_local 2
+ i32.const 3
+ i32.and
+ i32.const 3
+ i32.ne
+ br_if 4 (;@4;)
+ get_local 3
+ i32.const 4
+ i32.add
+ get_local 2
+ i32.const -2
+ i32.and
+ i32.store
+ i32.const 0
+ get_local 0
+ i32.store offset=1048
+ get_local 1
+ get_local 0
+ i32.add
+ get_local 0
+ i32.store
+ get_local 1
+ get_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ return
+ end
+ get_local 1
+ i32.load offset=24
+ set_local 6
+ get_local 1
+ i32.load offset=12
+ tee_local 5
+ get_local 1
+ i32.eq
+ br_if 1 (;@6;)
+ get_local 1
+ i32.load offset=8
+ tee_local 2
+ get_local 5
+ i32.store offset=12
+ get_local 5
+ get_local 2
+ i32.store offset=8
+ get_local 6
+ br_if 2 (;@5;)
+ br 3 (;@4;)
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1040
+ i32.const -2
+ get_local 2
+ i32.const 3
+ i32.shr_u
+ i32.rotl
+ i32.and
+ i32.store offset=1040
+ get_local 1
+ get_local 3
+ i32.lt_u
+ br_if 3 (;@3;)
+ br 4 (;@2;)
+ end
+ block ;; label = @6
+ block ;; label = @7
+ get_local 1
+ i32.const 20
+ i32.add
+ tee_local 2
+ i32.load
+ tee_local 4
+ br_if 0 (;@7;)
+ get_local 1
+ i32.const 16
+ i32.add
+ tee_local 2
+ i32.load
+ tee_local 4
+ i32.eqz
+ br_if 1 (;@6;)
+ end
+ loop ;; label = @7
+ get_local 2
+ set_local 7
+ get_local 4
+ tee_local 5
+ i32.const 20
+ i32.add
+ tee_local 2
+ i32.load
+ tee_local 4
+ br_if 0 (;@7;)
+ get_local 5
+ i32.const 16
+ i32.add
+ set_local 2
+ get_local 5
+ i32.load offset=16
+ tee_local 4
+ br_if 0 (;@7;)
+ end
+ get_local 7
+ i32.const 0
+ i32.store
+ get_local 6
+ i32.eqz
+ br_if 2 (;@4;)
+ br 1 (;@5;)
+ end
+ i32.const 0
+ set_local 5
+ get_local 6
+ i32.eqz
+ br_if 1 (;@4;)
+ end
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ get_local 1
+ i32.load offset=28
+ tee_local 4
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ tee_local 2
+ i32.load
+ get_local 1
+ i32.eq
+ br_if 0 (;@7;)
+ get_local 6
+ i32.const 16
+ i32.const 20
+ get_local 6
+ i32.load offset=16
+ get_local 1
+ i32.eq
+ select
+ i32.add
+ get_local 5
+ i32.store
+ get_local 5
+ br_if 1 (;@6;)
+ br 3 (;@4;)
+ end
+ get_local 2
+ get_local 5
+ i32.store
+ get_local 5
+ i32.eqz
+ br_if 1 (;@5;)
+ end
+ get_local 5
+ get_local 6
+ i32.store offset=24
+ block ;; label = @6
+ get_local 1
+ i32.load offset=16
+ tee_local 2
+ i32.eqz
+ br_if 0 (;@6;)
+ get_local 5
+ get_local 2
+ i32.store offset=16
+ get_local 2
+ get_local 5
+ i32.store offset=24
+ end
+ get_local 1
+ i32.const 20
+ i32.add
+ i32.load
+ tee_local 2
+ i32.eqz
+ br_if 1 (;@4;)
+ get_local 5
+ i32.const 20
+ i32.add
+ get_local 2
+ i32.store
+ get_local 2
+ get_local 5
+ i32.store offset=24
+ get_local 1
+ get_local 3
+ i32.lt_u
+ br_if 2 (;@3;)
+ br 3 (;@2;)
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1044
+ i32.const -2
+ get_local 4
+ i32.rotl
+ i32.and
+ i32.store offset=1044
+ end
+ get_local 1
+ get_local 3
+ i32.ge_u
+ br_if 1 (;@2;)
+ end
+ get_local 3
+ i32.load offset=4
+ tee_local 2
+ i32.const 1
+ i32.and
+ i32.eqz
+ br_if 0 (;@2;)
+ block ;; label = @3
+ block ;; label = @4
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ block ;; label = @8
+ block ;; label = @9
+ block ;; label = @10
+ block ;; label = @11
+ get_local 2
+ i32.const 2
+ i32.and
+ br_if 0 (;@11;)
+ i32.const 0
+ i32.load offset=1064
+ get_local 3
+ i32.eq
+ br_if 1 (;@10;)
+ i32.const 0
+ i32.load offset=1060
+ get_local 3
+ i32.eq
+ br_if 2 (;@9;)
+ get_local 2
+ i32.const -8
+ i32.and
+ get_local 0
+ i32.add
+ set_local 0
+ get_local 2
+ i32.const 255
+ i32.gt_u
+ br_if 3 (;@8;)
+ get_local 3
+ i32.load offset=12
+ tee_local 4
+ get_local 3
+ i32.load offset=8
+ tee_local 5
+ i32.eq
+ br_if 4 (;@7;)
+ get_local 4
+ get_local 5
+ i32.store offset=8
+ get_local 5
+ get_local 4
+ i32.store offset=12
+ br 7 (;@4;)
+ end
+ get_local 3
+ i32.const 4
+ i32.add
+ get_local 2
+ i32.const -2
+ i32.and
+ i32.store
+ get_local 1
+ get_local 0
+ i32.add
+ get_local 0
+ i32.store
+ get_local 1
+ get_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ br 7 (;@3;)
+ end
+ i32.const 0
+ get_local 1
+ i32.store offset=1064
+ i32.const 0
+ i32.const 0
+ i32.load offset=1052
+ get_local 0
+ i32.add
+ tee_local 0
+ i32.store offset=1052
+ get_local 1
+ get_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ get_local 1
+ i32.const 0
+ i32.load offset=1060
+ i32.ne
+ br_if 7 (;@2;)
+ i32.const 0
+ i32.const 0
+ i32.store offset=1048
+ i32.const 0
+ i32.const 0
+ i32.store offset=1060
+ return
+ end
+ i32.const 0
+ get_local 1
+ i32.store offset=1060
+ i32.const 0
+ i32.const 0
+ i32.load offset=1048
+ get_local 0
+ i32.add
+ tee_local 0
+ i32.store offset=1048
+ get_local 1
+ get_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ get_local 1
+ get_local 0
+ i32.add
+ get_local 0
+ i32.store
+ return
+ end
+ get_local 3
+ i32.load offset=24
+ set_local 6
+ get_local 3
+ i32.load offset=12
+ tee_local 5
+ get_local 3
+ i32.eq
+ br_if 1 (;@6;)
+ get_local 3
+ i32.load offset=8
+ tee_local 2
+ get_local 5
+ i32.store offset=12
+ get_local 5
+ get_local 2
+ i32.store offset=8
+ get_local 6
+ br_if 2 (;@5;)
+ br 3 (;@4;)
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1040
+ i32.const -2
+ get_local 2
+ i32.const 3
+ i32.shr_u
+ i32.rotl
+ i32.and
+ i32.store offset=1040
+ br 2 (;@4;)
+ end
+ block ;; label = @6
+ block ;; label = @7
+ get_local 3
+ i32.const 20
+ i32.add
+ tee_local 2
+ i32.load
+ tee_local 4
+ br_if 0 (;@7;)
+ get_local 3
+ i32.const 16
+ i32.add
+ tee_local 2
+ i32.load
+ tee_local 4
+ i32.eqz
+ br_if 1 (;@6;)
+ end
+ loop ;; label = @7
+ get_local 2
+ set_local 7
+ get_local 4
+ tee_local 5
+ i32.const 20
+ i32.add
+ tee_local 2
+ i32.load
+ tee_local 4
+ br_if 0 (;@7;)
+ get_local 5
+ i32.const 16
+ i32.add
+ set_local 2
+ get_local 5
+ i32.load offset=16
+ tee_local 4
+ br_if 0 (;@7;)
+ end
+ get_local 7
+ i32.const 0
+ i32.store
+ get_local 6
+ i32.eqz
+ br_if 2 (;@4;)
+ br 1 (;@5;)
+ end
+ i32.const 0
+ set_local 5
+ get_local 6
+ i32.eqz
+ br_if 1 (;@4;)
+ end
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ get_local 3
+ i32.load offset=28
+ tee_local 4
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ tee_local 2
+ i32.load
+ get_local 3
+ i32.eq
+ br_if 0 (;@7;)
+ get_local 6
+ i32.const 16
+ i32.const 20
+ get_local 6
+ i32.load offset=16
+ get_local 3
+ i32.eq
+ select
+ i32.add
+ get_local 5
+ i32.store
+ get_local 5
+ br_if 1 (;@6;)
+ br 3 (;@4;)
+ end
+ get_local 2
+ get_local 5
+ i32.store
+ get_local 5
+ i32.eqz
+ br_if 1 (;@5;)
+ end
+ get_local 5
+ get_local 6
+ i32.store offset=24
+ block ;; label = @6
+ get_local 3
+ i32.load offset=16
+ tee_local 2
+ i32.eqz
+ br_if 0 (;@6;)
+ get_local 5
+ get_local 2
+ i32.store offset=16
+ get_local 2
+ get_local 5
+ i32.store offset=24
+ end
+ get_local 3
+ i32.const 20
+ i32.add
+ i32.load
+ tee_local 2
+ i32.eqz
+ br_if 1 (;@4;)
+ get_local 5
+ i32.const 20
+ i32.add
+ get_local 2
+ i32.store
+ get_local 2
+ get_local 5
+ i32.store offset=24
+ br 1 (;@4;)
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1044
+ i32.const -2
+ get_local 4
+ i32.rotl
+ i32.and
+ i32.store offset=1044
+ end
+ get_local 1
+ get_local 0
+ i32.add
+ get_local 0
+ i32.store
+ get_local 1
+ get_local 0
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ get_local 1
+ i32.const 0
+ i32.load offset=1060
+ i32.ne
+ br_if 0 (;@3;)
+ i32.const 0
+ get_local 0
+ i32.store offset=1048
+ return
+ end
+ block ;; label = @3
+ block ;; label = @4
+ block ;; label = @5
+ block ;; label = @6
+ block ;; label = @7
+ block ;; label = @8
+ block ;; label = @9
+ get_local 0
+ i32.const 255
+ i32.gt_u
+ br_if 0 (;@9;)
+ get_local 0
+ i32.const 3
+ i32.shr_u
+ tee_local 2
+ i32.const 3
+ i32.shl
+ i32.const 1080
+ i32.add
+ set_local 0
+ i32.const 0
+ i32.load offset=1040
+ tee_local 4
+ i32.const 1
+ get_local 2
+ i32.shl
+ tee_local 2
+ i32.and
+ i32.eqz
+ br_if 1 (;@8;)
+ get_local 0
+ i32.load offset=8
+ set_local 2
+ br 2 (;@7;)
+ end
+ i32.const 0
+ set_local 2
+ block ;; label = @9
+ get_local 0
+ i32.const 8
+ i32.shr_u
+ tee_local 4
+ i32.eqz
+ br_if 0 (;@9;)
+ i32.const 31
+ set_local 2
+ get_local 0
+ i32.const 16777215
+ i32.gt_u
+ br_if 0 (;@9;)
+ get_local 0
+ i32.const 14
+ get_local 4
+ get_local 4
+ i32.const 1048320
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 8
+ i32.and
+ tee_local 2
+ i32.shl
+ tee_local 4
+ i32.const 520192
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 4
+ i32.and
+ tee_local 5
+ get_local 2
+ i32.or
+ get_local 4
+ get_local 5
+ i32.shl
+ tee_local 2
+ i32.const 245760
+ i32.add
+ i32.const 16
+ i32.shr_u
+ i32.const 2
+ i32.and
+ tee_local 4
+ i32.or
+ i32.sub
+ get_local 2
+ get_local 4
+ i32.shl
+ i32.const 15
+ i32.shr_u
+ i32.add
+ tee_local 2
+ i32.const 7
+ i32.add
+ i32.shr_u
+ i32.const 1
+ i32.and
+ get_local 2
+ i32.const 1
+ i32.shl
+ i32.or
+ set_local 2
+ end
+ get_local 1
+ i64.const 0
+ i64.store offset=16 align=4
+ get_local 1
+ i32.const 28
+ i32.add
+ get_local 2
+ i32.store
+ get_local 2
+ i32.const 2
+ i32.shl
+ i32.const 1344
+ i32.add
+ set_local 4
+ i32.const 0
+ i32.load offset=1044
+ tee_local 5
+ i32.const 1
+ get_local 2
+ i32.shl
+ tee_local 3
+ i32.and
+ i32.eqz
+ br_if 2 (;@6;)
+ get_local 0
+ i32.const 0
+ i32.const 25
+ get_local 2
+ i32.const 1
+ i32.shr_u
+ i32.sub
+ get_local 2
+ i32.const 31
+ i32.eq
+ select
+ i32.shl
+ set_local 2
+ get_local 4
+ i32.load
+ set_local 5
+ loop ;; label = @9
+ get_local 5
+ tee_local 4
+ i32.load offset=4
+ i32.const -8
+ i32.and
+ get_local 0
+ i32.eq
+ br_if 5 (;@4;)
+ get_local 2
+ i32.const 29
+ i32.shr_u
+ set_local 5
+ get_local 2
+ i32.const 1
+ i32.shl
+ set_local 2
+ get_local 4
+ get_local 5
+ i32.const 4
+ i32.and
+ i32.add
+ i32.const 16
+ i32.add
+ tee_local 3
+ i32.load
+ tee_local 5
+ br_if 0 (;@9;)
+ end
+ get_local 3
+ get_local 1
+ i32.store
+ get_local 1
+ i32.const 24
+ i32.add
+ get_local 4
+ i32.store
+ br 3 (;@5;)
+ end
+ i32.const 0
+ get_local 4
+ get_local 2
+ i32.or
+ i32.store offset=1040
+ get_local 0
+ set_local 2
+ end
+ get_local 2
+ get_local 1
+ i32.store offset=12
+ get_local 0
+ get_local 1
+ i32.store offset=8
+ get_local 1
+ get_local 0
+ i32.store offset=12
+ get_local 1
+ get_local 2
+ i32.store offset=8
+ return
+ end
+ get_local 4
+ get_local 1
+ i32.store
+ i32.const 0
+ get_local 5
+ get_local 3
+ i32.or
+ i32.store offset=1044
+ get_local 1
+ i32.const 24
+ i32.add
+ get_local 4
+ i32.store
+ end
+ get_local 1
+ get_local 1
+ i32.store offset=12
+ get_local 1
+ get_local 1
+ i32.store offset=8
+ br 1 (;@3;)
+ end
+ get_local 4
+ i32.load offset=8
+ tee_local 0
+ get_local 1
+ i32.store offset=12
+ get_local 4
+ get_local 1
+ i32.store offset=8
+ get_local 1
+ i32.const 24
+ i32.add
+ i32.const 0
+ i32.store
+ get_local 1
+ get_local 4
+ i32.store offset=12
+ get_local 1
+ get_local 0
+ i32.store offset=8
+ end
+ i32.const 0
+ i32.const 0
+ i32.load offset=1072
+ i32.const -1
+ i32.add
+ tee_local 1
+ i32.store offset=1072
+ get_local 1
+ i32.eqz
+ br_if 1 (;@1;)
+ end
+ return
+ end
+ i32.const 1496
+ set_local 1
+ loop ;; label = @1
+ get_local 1
+ i32.load
+ tee_local 0
+ i32.const 8
+ i32.add
+ set_local 1
+ get_local 0
+ br_if 0 (;@1;)
+ end
+ i32.const 0
+ i32.const -1
+ i32.store offset=1072)
+ (func (;18;) (type 2) (param i32 i32) (result i32)
+ (local i32)
+ block ;; label = @1
+ block ;; label = @2
+ block ;; label = @3
+ get_local 0
+ i32.eqz
+ br_if 0 (;@3;)
+ get_local 1
+ get_local 0
+ i32.mul
+ set_local 2
+ block ;; label = @4
+ get_local 1
+ get_local 0
+ i32.or
+ i32.const 65536
+ i32.lt_u
+ br_if 0 (;@4;)
+ get_local 2
+ i32.const -1
+ get_local 2
+ get_local 0
+ i32.div_u
+ get_local 1
+ i32.eq
+ select
+ set_local 2
+ end
+ get_local 2
+ call 15
+ tee_local 0
+ br_if 1 (;@2;)
+ br 2 (;@1;)
+ end
+ i32.const 0
+ set_local 2
+ i32.const 0
+ call 15
+ tee_local 0
+ i32.eqz
+ br_if 1 (;@1;)
+ end
+ get_local 0
+ i32.const -4
+ i32.add
+ i32.load8_u
+ i32.const 3
+ i32.and
+ i32.eqz
+ br_if 0 (;@1;)
+ get_local 0
+ i32.const 0
+ get_local 2
+ call 44
+ drop
+ end
+ get_local 0)
+ (func (;19;) (type 3) (param i32)
+ get_local 0
+ call 6
+ unreachable)
+ (func (;20;) (type 7)
+ unreachable
+ unreachable)
+ (func (;21;) (type 4) (param i32) (result i32)
+ block ;; label = @1
+ get_local 0
+ call 8
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@1;)
+ i32.const 0
+ get_local 0
+ i32.store offset=1536
+ i32.const -1
+ return
+ end
+ i32.const 0)
+ (func (;22;) (type 3) (param i32)
+ (local i32 i32)
+ block ;; label = @1
+ get_local 0
+ i32.load
+ i32.const 0
+ i32.le_s
+ br_if 0 (;@1;)
+ get_local 0
+ i32.load offset=12
+ tee_local 1
+ get_local 0
+ i32.load offset=8
+ tee_local 2
+ i32.gt_u
+ br_if 0 (;@1;)
+ get_local 0
+ i32.load offset=4
+ set_local 0
+ block ;; label = @2
+ get_local 2
+ i32.eqz
+ br_if 0 (;@2;)
+ get_local 0
+ i32.eqz
+ br_if 1 (;@1;)
+ end
+ block ;; label = @2
+ get_local 1
+ i32.eqz
+ br_if 0 (;@2;)
+ i32.const 0
+ set_local 2
+ loop ;; label = @3
+ get_local 0
+ i32.load
+ i32.eqz
+ br_if 2 (;@1;)
+ get_local 0
+ i32.const 4
+ i32.add
+ i32.load
+ i32.const -1
+ i32.le_s
+ br_if 2 (;@1;)
+ get_local 0
+ i32.const 24
+ i32.add
+ set_local 0
+ get_local 2
+ i32.const 1
+ i32.add
+ tee_local 2
+ get_local 1
+ i32.lt_u
+ br_if 0 (;@3;)
+ end
+ end
+ return
+ end
+ call 20
+ unreachable)
+ (func (;23;) (type 7)
+ (local i32 i32)
+ block ;; label = @1
+ i32.const 16
+ call 14
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@1;)
+ get_local 0
+ i32.const 24
+ i32.const 4
+ call 18
+ tee_local 1
+ i32.store offset=4
+ block ;; label = @2
+ get_local 1
+ i32.eqz
+ br_if 0 (;@2;)
+ get_local 0
+ i64.const 4
+ i64.store offset=8 align=4
+ get_local 0
+ i32.const 1
+ i32.store
+ get_local 0
+ call 22
+ i32.const 0
+ get_local 0
+ i32.store offset=1540
+ get_local 0
+ call 22
+ return
+ end
+ get_local 0
+ call 16
+ end
+ i32.const 0
+ i32.const 0
+ i32.store offset=1540
+ unreachable
+ unreachable)
+ (func (;24;) (type 2) (param i32 i32) (result i32)
+ (local i32 i32 i32 i32 i32 i32)
+ get_global 0
+ i32.const 32
+ i32.sub
+ tee_local 2
+ set_global 0
+ i32.const 0
+ i32.load offset=1540
+ call 22
+ i32.const -1
+ set_local 3
+ block ;; label = @1
+ get_local 1
+ i32.eqz
+ br_if 0 (;@1;)
+ i32.const 0
+ i32.load offset=1540
+ tee_local 4
+ call 22
+ get_local 0
+ i32.const 0
+ i32.lt_s
+ br_if 0 (;@1;)
+ block ;; label = @2
+ block ;; label = @3
+ get_local 4
+ i32.load offset=12
+ tee_local 5
+ get_local 4
+ i32.load offset=8
+ i32.ne
+ br_if 0 (;@3;)
+ i32.const 24
+ get_local 5
+ i32.const 1
+ i32.shl
+ call 18
+ tee_local 6
+ i32.eqz
+ br_if 2 (;@1;)
+ get_local 6
+ get_local 4
+ i32.load offset=4
+ get_local 4
+ i32.const 12
+ i32.add
+ tee_local 5
+ i32.load
+ i32.const 24
+ i32.mul
+ call 43
+ drop
+ get_local 4
+ i32.load offset=4
+ call 16
+ get_local 4
+ get_local 6
+ i32.store offset=4
+ get_local 4
+ i32.const 8
+ i32.add
+ tee_local 7
+ get_local 7
+ i32.load
+ i32.const 1
+ i32.shl
+ i32.store
+ get_local 5
+ i32.load
+ set_local 5
+ br 1 (;@2;)
+ end
+ get_local 4
+ i32.load offset=4
+ set_local 6
+ end
+ get_local 4
+ i32.const 12
+ i32.add
+ get_local 5
+ i32.const 1
+ i32.add
+ i32.store
+ get_local 1
+ call 45
+ set_local 7
+ get_local 6
+ get_local 5
+ i32.const 24
+ i32.mul
+ i32.add
+ tee_local 1
+ get_local 0
+ i32.store offset=4
+ get_local 1
+ get_local 7
+ i32.store
+ block ;; label = @2
+ get_local 0
+ get_local 2
+ i32.const 8
+ i32.add
+ call 7
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@2;)
+ i32.const 0
+ get_local 0
+ i32.store offset=1536
+ br 1 (;@1;)
+ end
+ get_local 1
+ get_local 2
+ i64.load offset=16
+ i64.store offset=8
+ get_local 1
+ get_local 2
+ i64.load offset=24
+ i64.store offset=16
+ get_local 4
+ call 22
+ get_local 4
+ call 22
+ i32.const 0
+ set_local 3
+ i32.const 0
+ get_local 4
+ i32.store offset=1540
+ end
+ get_local 2
+ i32.const 32
+ i32.add
+ set_global 0
+ get_local 3)
+ (func (;25;) (type 4) (param i32) (result i32)
+ block ;; label = @1
+ get_local 0
+ i32.const 65535
+ i32.and
+ br_if 0 (;@1;)
+ get_local 0
+ i32.const -1
+ i32.le_s
+ br_if 0 (;@1;)
+ block ;; label = @2
+ get_local 0
+ i32.const 16
+ i32.shr_u
+ grow_memory
+ tee_local 0
+ i32.const -1
+ i32.eq
+ br_if 0 (;@2;)
+ get_local 0
+ i32.const 16
+ i32.shl
+ return
+ end
+ i32.const 0
+ i32.const 48
+ i32.store offset=1536
+ i32.const -1
+ return
+ end
+ call 20
+ unreachable)
+ (func (;26;) (type 7))
+ (func (;27;) (type 7)
+ call 26
+ call 29)
+ (func (;28;) (type 8) (result i32)
+ i32.const 1548)
+ (func (;29;) (type 7)
+ (local i32 i32 i32)
+ block ;; label = @1
+ call 28
+ i32.load
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@1;)
+ loop ;; label = @2
+ block ;; label = @3
+ get_local 0
+ i32.load offset=20
+ get_local 0
+ i32.load offset=24
+ i32.eq
+ br_if 0 (;@3;)
+ get_local 0
+ i32.const 0
+ i32.const 0
+ get_local 0
+ i32.load offset=32
+ call_indirect (type 0)
+ drop
+ end
+ block ;; label = @3
+ get_local 0
+ i32.load offset=4
+ tee_local 1
+ get_local 0
+ i32.load offset=8
+ tee_local 2
+ i32.eq
+ br_if 0 (;@3;)
+ get_local 0
+ get_local 1
+ get_local 2
+ i32.sub
+ i64.extend_s/i32
+ i32.const 0
+ get_local 0
+ i32.load offset=36
+ call_indirect (type 1)
+ drop
+ end
+ get_local 0
+ i32.load offset=52
+ tee_local 0
+ br_if 0 (;@2;)
+ end
+ end
+ block ;; label = @1
+ i32.const 0
+ i32.load offset=1552
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@1;)
+ block ;; label = @2
+ get_local 0
+ i32.load offset=20
+ get_local 0
+ i32.load offset=24
+ i32.eq
+ br_if 0 (;@2;)
+ get_local 0
+ i32.const 0
+ i32.const 0
+ get_local 0
+ i32.load offset=32
+ call_indirect (type 0)
+ drop
+ end
+ get_local 0
+ i32.load offset=4
+ tee_local 1
+ get_local 0
+ i32.load offset=8
+ tee_local 2
+ i32.eq
+ br_if 0 (;@1;)
+ get_local 0
+ get_local 1
+ get_local 2
+ i32.sub
+ i64.extend_s/i32
+ i32.const 0
+ get_local 0
+ i32.load offset=36
+ call_indirect (type 1)
+ drop
+ end
+ block ;; label = @1
+ i32.const 0
+ i32.load offset=2712
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@1;)
+ block ;; label = @2
+ get_local 0
+ i32.load offset=20
+ get_local 0
+ i32.load offset=24
+ i32.eq
+ br_if 0 (;@2;)
+ get_local 0
+ i32.const 0
+ i32.const 0
+ get_local 0
+ i32.load offset=32
+ call_indirect (type 0)
+ drop
+ end
+ get_local 0
+ i32.load offset=4
+ tee_local 1
+ get_local 0
+ i32.load offset=8
+ tee_local 2
+ i32.eq
+ br_if 0 (;@1;)
+ get_local 0
+ get_local 1
+ get_local 2
+ i32.sub
+ i64.extend_s/i32
+ i32.const 0
+ get_local 0
+ i32.load offset=36
+ call_indirect (type 1)
+ drop
+ end
+ block ;; label = @1
+ i32.const 0
+ i32.load offset=1552
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@1;)
+ block ;; label = @2
+ get_local 0
+ i32.load offset=20
+ get_local 0
+ i32.load offset=24
+ i32.eq
+ br_if 0 (;@2;)
+ get_local 0
+ i32.const 0
+ i32.const 0
+ get_local 0
+ i32.load offset=32
+ call_indirect (type 0)
+ drop
+ end
+ get_local 0
+ i32.load offset=4
+ tee_local 1
+ get_local 0
+ i32.load offset=8
+ tee_local 2
+ i32.eq
+ br_if 0 (;@1;)
+ get_local 0
+ get_local 1
+ get_local 2
+ i32.sub
+ i64.extend_s/i32
+ i32.const 0
+ get_local 0
+ i32.load offset=36
+ call_indirect (type 1)
+ drop
+ end)
+ (func (;30;) (type 4) (param i32) (result i32)
+ (local i32)
+ get_local 0
+ get_local 0
+ i32.load offset=60
+ tee_local 1
+ i32.const -1
+ i32.add
+ get_local 1
+ i32.or
+ i32.store offset=60
+ block ;; label = @1
+ get_local 0
+ i32.load
+ tee_local 1
+ i32.const 8
+ i32.and
+ br_if 0 (;@1;)
+ get_local 0
+ i64.const 0
+ i64.store offset=4 align=4
+ get_local 0
+ get_local 0
+ i32.load offset=40
+ tee_local 1
+ i32.store offset=24
+ get_local 0
+ get_local 1
+ i32.store offset=20
+ get_local 0
+ get_local 1
+ get_local 0
+ i32.load offset=44
+ i32.add
+ i32.store offset=16
+ i32.const 0
+ return
+ end
+ get_local 0
+ get_local 1
+ i32.const 32
+ i32.or
+ i32.store
+ i32.const -1)
+ (func (;31;) (type 0) (param i32 i32 i32) (result i32)
+ (local i32 i32 i32 i32 i32 i32)
+ block ;; label = @1
+ block ;; label = @2
+ get_local 2
+ i32.load offset=16
+ tee_local 3
+ br_if 0 (;@2;)
+ i32.const 0
+ set_local 6
+ get_local 2
+ call 30
+ br_if 1 (;@1;)
+ get_local 2
+ i32.const 16
+ i32.add
+ i32.load
+ set_local 3
+ end
+ block ;; label = @2
+ get_local 3
+ get_local 2
+ i32.load offset=20
+ tee_local 4
+ i32.sub
+ get_local 1
+ i32.ge_u
+ br_if 0 (;@2;)
+ get_local 2
+ get_local 0
+ get_local 1
+ get_local 2
+ i32.load offset=32
+ call_indirect (type 0)
+ return
+ end
+ i32.const 0
+ set_local 5
+ block ;; label = @2
+ get_local 2
+ i32.load offset=64
+ i32.const 0
+ i32.lt_s
+ br_if 0 (;@2;)
+ i32.const 0
+ set_local 5
+ get_local 0
+ set_local 6
+ i32.const 0
+ set_local 3
+ loop ;; label = @3
+ get_local 1
+ get_local 3
+ i32.eq
+ br_if 1 (;@2;)
+ get_local 3
+ i32.const 1
+ i32.add
+ set_local 3
+ get_local 6
+ get_local 1
+ i32.add
+ set_local 7
+ get_local 6
+ i32.const -1
+ i32.add
+ tee_local 8
+ set_local 6
+ get_local 7
+ i32.const -1
+ i32.add
+ i32.load8_u
+ i32.const 10
+ i32.ne
+ br_if 0 (;@3;)
+ end
+ get_local 2
+ get_local 0
+ get_local 1
+ get_local 3
+ i32.sub
+ i32.const 1
+ i32.add
+ tee_local 5
+ get_local 2
+ i32.load offset=32
+ call_indirect (type 0)
+ tee_local 6
+ get_local 5
+ i32.lt_u
+ br_if 1 (;@1;)
+ get_local 8
+ get_local 1
+ i32.add
+ i32.const 1
+ i32.add
+ set_local 0
+ get_local 2
+ i32.const 20
+ i32.add
+ i32.load
+ set_local 4
+ get_local 3
+ i32.const -1
+ i32.add
+ set_local 1
+ end
+ get_local 4
+ get_local 0
+ get_local 1
+ call 43
+ drop
+ get_local 2
+ i32.const 20
+ i32.add
+ tee_local 3
+ get_local 3
+ i32.load
+ get_local 1
+ i32.add
+ i32.store
+ get_local 5
+ get_local 1
+ i32.add
+ return
+ end
+ get_local 6)
+ (func (;32;) (type 5) (param i32 i32 i32 i32) (result i32)
+ (local i32)
+ block ;; label = @1
+ get_local 0
+ get_local 2
+ get_local 1
+ i32.mul
+ tee_local 4
+ get_local 3
+ call 31
+ tee_local 0
+ get_local 4
+ i32.ne
+ br_if 0 (;@1;)
+ get_local 2
+ i32.const 0
+ get_local 1
+ select
+ return
+ end
+ get_local 0
+ get_local 1
+ i32.div_u)
+ (func (;33;) (type 2) (param i32 i32) (result i32)
+ (local i32)
+ i32.const -1
+ i32.const 0
+ get_local 0
+ call 46
+ tee_local 2
+ get_local 0
+ i32.const 1
+ get_local 2
+ get_local 1
+ call 32
+ i32.ne
+ select)
+ (func (;34;) (type 2) (param i32 i32) (result i32)
+ (local i32 i32 i32)
+ get_global 0
+ i32.const 16
+ i32.sub
+ tee_local 2
+ set_global 0
+ get_local 2
+ get_local 1
+ i32.store8 offset=15
+ block ;; label = @1
+ block ;; label = @2
+ get_local 0
+ i32.load offset=16
+ tee_local 3
+ br_if 0 (;@2;)
+ i32.const -1
+ set_local 3
+ get_local 0
+ call 30
+ br_if 1 (;@1;)
+ get_local 0
+ i32.const 16
+ i32.add
+ i32.load
+ set_local 3
+ end
+ block ;; label = @2
+ block ;; label = @3
+ get_local 0
+ i32.load offset=20
+ tee_local 4
+ get_local 3
+ i32.eq
+ br_if 0 (;@3;)
+ get_local 0
+ i32.load offset=64
+ get_local 1
+ i32.const 255
+ i32.and
+ tee_local 3
+ i32.ne
+ br_if 1 (;@2;)
+ end
+ i32.const -1
+ set_local 3
+ get_local 0
+ get_local 2
+ i32.const 15
+ i32.add
+ i32.const 1
+ get_local 0
+ i32.load offset=32
+ call_indirect (type 0)
+ i32.const 1
+ i32.ne
+ br_if 1 (;@1;)
+ get_local 2
+ i32.load8_u offset=15
+ set_local 3
+ br 1 (;@1;)
+ end
+ get_local 0
+ i32.const 20
+ i32.add
+ get_local 4
+ i32.const 1
+ i32.add
+ i32.store
+ get_local 4
+ get_local 1
+ i32.store8
+ end
+ get_local 2
+ i32.const 16
+ i32.add
+ set_global 0
+ get_local 3)
+ (func (;35;) (type 4) (param i32) (result i32)
+ block ;; label = @1
+ get_local 0
+ i32.const 2600
+ call 33
+ i32.const 0
+ i32.lt_s
+ br_if 0 (;@1;)
+ block ;; label = @2
+ i32.const 0
+ i32.load offset=2664
+ i32.const 10
+ i32.eq
+ br_if 0 (;@2;)
+ i32.const 0
+ i32.load offset=2620
+ tee_local 0
+ i32.const 0
+ i32.load offset=2616
+ i32.eq
+ br_if 0 (;@2;)
+ i32.const 0
+ get_local 0
+ i32.const 1
+ i32.add
+ i32.store offset=2620
+ get_local 0
+ i32.const 10
+ i32.store8
+ i32.const 0
+ return
+ end
+ i32.const 2600
+ i32.const 10
+ call 34
+ i32.const 31
+ i32.shr_s
+ return
+ end
+ i32.const -1)
+ (func (;36;) (type 4) (param i32) (result i32)
+ get_local 0
+ i32.load offset=56
+ call 21)
+ (func (;37;) (type 0) (param i32 i32 i32) (result i32)
+ (local i32 i32)
+ get_global 0
+ i32.const 16
+ i32.sub
+ tee_local 3
+ set_global 0
+ i32.const -1
+ set_local 4
+ block ;; label = @1
+ block ;; label = @2
+ block ;; label = @3
+ get_local 2
+ i32.const -1
+ i32.le_s
+ br_if 0 (;@3;)
+ get_local 0
+ get_local 1
+ get_local 2
+ get_local 3
+ i32.const 12
+ i32.add
+ call 9
+ tee_local 2
+ i32.eqz
+ br_if 1 (;@2;)
+ i32.const 0
+ get_local 2
+ i32.store offset=1536
+ i32.const -1
+ set_local 4
+ br 2 (;@1;)
+ end
+ i32.const 0
+ i32.const 28
+ i32.store offset=1536
+ br 1 (;@1;)
+ end
+ get_local 3
+ i32.load offset=12
+ set_local 4
+ end
+ get_local 3
+ i32.const 16
+ i32.add
+ set_global 0
+ get_local 4)
+ (func (;38;) (type 0) (param i32 i32 i32) (result i32)
+ (local i32 i32 i32 i32 i32 i32 i32)
+ get_global 0
+ i32.const 16
+ i32.sub
+ tee_local 3
+ set_global 0
+ get_local 3
+ get_local 2
+ i32.store offset=12
+ get_local 3
+ get_local 1
+ i32.store offset=8
+ get_local 3
+ get_local 0
+ i32.load offset=24
+ tee_local 1
+ i32.store
+ get_local 3
+ get_local 0
+ i32.load offset=20
+ get_local 1
+ i32.sub
+ tee_local 1
+ i32.store offset=4
+ i32.const 2
+ set_local 4
+ block ;; label = @1
+ block ;; label = @2
+ block ;; label = @3
+ get_local 1
+ get_local 2
+ i32.add
+ tee_local 5
+ get_local 0
+ i32.load offset=56
+ get_local 3
+ i32.const 2
+ call 37
+ tee_local 6
+ i32.eq
+ br_if 0 (;@3;)
+ get_local 3
+ set_local 1
+ get_local 0
+ i32.const 56
+ i32.add
+ set_local 7
+ loop ;; label = @4
+ get_local 6
+ i32.const -1
+ i32.le_s
+ br_if 2 (;@2;)
+ get_local 1
+ i32.const 8
+ i32.add
+ get_local 1
+ get_local 6
+ get_local 1
+ i32.load offset=4
+ tee_local 8
+ i32.gt_u
+ tee_local 9
+ select
+ tee_local 1
+ get_local 1
+ i32.load
+ get_local 6
+ get_local 8
+ i32.const 0
+ get_local 9
+ select
+ i32.sub
+ tee_local 8
+ i32.add
+ i32.store
+ get_local 1
+ get_local 1
+ i32.load offset=4
+ get_local 8
+ i32.sub
+ i32.store offset=4
+ get_local 5
+ get_local 6
+ i32.sub
+ set_local 5
+ get_local 7
+ i32.load
+ get_local 1
+ get_local 4
+ get_local 9
+ i32.sub
+ tee_local 4
+ call 37
+ tee_local 9
+ set_local 6
+ get_local 5
+ get_local 9
+ i32.ne
+ br_if 0 (;@4;)
+ end
+ end
+ get_local 0
+ i32.const 24
+ i32.add
+ get_local 0
+ i32.load offset=40
+ tee_local 1
+ i32.store
+ get_local 0
+ i32.const 20
+ i32.add
+ get_local 1
+ i32.store
+ get_local 0
+ get_local 1
+ get_local 0
+ i32.load offset=44
+ i32.add
+ i32.store offset=16
+ get_local 2
+ set_local 6
+ br 1 (;@1;)
+ end
+ get_local 0
+ i64.const 0
+ i64.store offset=16
+ i32.const 0
+ set_local 6
+ get_local 0
+ i32.const 24
+ i32.add
+ i32.const 0
+ i32.store
+ get_local 0
+ get_local 0
+ i32.load
+ i32.const 32
+ i32.or
+ i32.store
+ get_local 4
+ i32.const 2
+ i32.eq
+ br_if 0 (;@1;)
+ get_local 2
+ get_local 1
+ i32.load offset=4
+ i32.sub
+ set_local 6
+ end
+ get_local 3
+ i32.const 16
+ i32.add
+ set_global 0
+ get_local 6)
+ (func (;39;) (type 4) (param i32) (result i32)
+ (local i32 i32)
+ get_global 0
+ i32.const 32
+ i32.sub
+ tee_local 1
+ set_global 0
+ block ;; label = @1
+ block ;; label = @2
+ block ;; label = @3
+ get_local 0
+ get_local 1
+ i32.const 8
+ i32.add
+ call 7
+ tee_local 0
+ br_if 0 (;@3;)
+ i32.const 59
+ set_local 0
+ get_local 1
+ i32.load8_u offset=8
+ i32.const 2
+ i32.ne
+ br_if 0 (;@3;)
+ get_local 1
+ i32.load8_u offset=16
+ i32.const 36
+ i32.and
+ i32.eqz
+ br_if 1 (;@2;)
+ end
+ i32.const 0
+ set_local 2
+ i32.const 0
+ get_local 0
+ i32.store offset=1536
+ br 1 (;@1;)
+ end
+ i32.const 1
+ set_local 2
+ end
+ get_local 1
+ i32.const 32
+ i32.add
+ set_global 0
+ get_local 2)
+ (func (;40;) (type 0) (param i32 i32 i32) (result i32)
+ get_local 0
+ i32.const 1
+ i32.store offset=32
+ block ;; label = @1
+ block ;; label = @2
+ get_local 0
+ i32.load8_u
+ i32.const 64
+ i32.and
+ br_if 0 (;@2;)
+ get_local 0
+ i32.load offset=56
+ call 39
+ i32.eqz
+ br_if 1 (;@1;)
+ end
+ get_local 0
+ get_local 1
+ get_local 2
+ call 38
+ return
+ end
+ get_local 0
+ i32.const -1
+ i32.store offset=64
+ get_local 0
+ get_local 1
+ get_local 2
+ call 38)
+ (func (;41;) (type 1) (param i32 i64 i32) (result i64)
+ (local i32)
+ get_global 0
+ i32.const 16
+ i32.sub
+ tee_local 3
+ set_global 0
+ block ;; label = @1
+ block ;; label = @2
+ get_local 0
+ get_local 1
+ get_local 2
+ i32.const 255
+ i32.and
+ get_local 3
+ i32.const 8
+ i32.add
+ call 10
+ tee_local 0
+ i32.eqz
+ br_if 0 (;@2;)
+ i32.const 0
+ i32.const 70
+ get_local 0
+ get_local 0
+ i32.const 76
+ i32.eq
+ select
+ i32.store offset=1536
+ i64.const -1
+ set_local 1
+ br 1 (;@1;)
+ end
+ get_local 3
+ i64.load offset=8
+ set_local 1
+ end
+ get_local 3
+ i32.const 16
+ i32.add
+ set_global 0
+ get_local 1)
+ (func (;42;) (type 1) (param i32 i64 i32) (result i64)
+ get_local 0
+ i32.load offset=56
+ get_local 1
+ get_local 2
+ call 41)
+ (func (;43;) (type 0) (param i32 i32 i32) (result i32)
+ (local i32 i32 i32 i32 i32 i32 i32 i32)
+ block ;; label = @1
+ block ;; label = @2
+ block ;; label = @3
+ block ;; label = @4
+ get_local 2
+ i32.eqz
+ br_if 0 (;@4;)
+ get_local 1
+ i32.const 3
+ i32.and
+ i32.eqz
+ br_if 0 (;@4;)
+ get_local 0
+ set_local 3
+ block ;; label = @5
+ loop ;; label = @6
+ get_local 3
+ get_local 1
+ i32.load8_u
+ i32.store8
+ get_local 2
+ i32.const -1
+ i32.add
+ set_local 4
+ get_local 3
+ i32.const 1
+ i32.add
+ set_local 3
+ get_local 1
+ i32.const 1
+ i32.add
+ set_local 1
+ get_local 2
+ i32.const 1
+ i32.eq
+ br_if 1 (;@5;)
+ get_local 4
+ set_local 2
+ get_local 1
+ i32.const 3
+ i32.and
+ br_if 0 (;@6;)
+ end
+ end
+ get_local 3
+ i32.const 3
+ i32.and
+ tee_local 2
+ i32.eqz
+ br_if 1 (;@3;)
+ br 2 (;@2;)
+ end
+ get_local 2
+ set_local 4
+ get_local 0
+ tee_local 3
+ i32.const 3
+ i32.and
+ tee_local 2
+ br_if 1 (;@2;)
+ end
+ block ;; label = @3
+ block ;; label = @4
+ get_local 4
+ i32.const 16
+ i32.lt_u
+ br_if 0 (;@4;)
+ get_local 4
+ i32.const -16
+ i32.add
+ set_local 2
+ loop ;; label = @5
+ get_local 3
+ get_local 1
+ i32.load
+ i32.store
+ get_local 3
+ i32.const 4
+ i32.add
+ get_local 1
+ i32.const 4
+ i32.add
+ i32.load
+ i32.store
+ get_local 3
+ i32.const 8
+ i32.add
+ get_local 1
+ i32.const 8
+ i32.add
+ i32.load
+ i32.store
+ get_local 3
+ i32.const 12
+ i32.add
+ get_local 1
+ i32.const 12
+ i32.add
+ i32.load
+ i32.store
+ get_local 3
+ i32.const 16
+ i32.add
+ set_local 3
+ get_local 1
+ i32.const 16
+ i32.add
+ set_local 1
+ get_local 4
+ i32.const -16
+ i32.add
+ tee_local 4
+ i32.const 15
+ i32.gt_u
+ br_if 0 (;@5;)
+ br 2 (;@3;)
+ end
+ end
+ get_local 4
+ set_local 2
+ end
+ block ;; label = @3
+ get_local 2
+ i32.const 8
+ i32.and
+ i32.eqz
+ br_if 0 (;@3;)
+ get_local 3
+ get_local 1
+ i64.load align=4
+ i64.store align=4
+ get_local 1
+ i32.const 8
+ i32.add
+ set_local 1
+ get_local 3
+ i32.const 8
+ i32.add
+ set_local 3
+ end
+ block ;; label = @3
+ get_local 2
+ i32.const 4
+ i32.and
+ i32.eqz
+ br_if 0 (;@3;)
+ get_local 3
+ get_local 1
+ i32.load
+ i32.store
+ get_local 1
+ i32.const 4
+ i32.add
+ set_local 1
+ get_local 3
+ i32.const 4
+ i32.add
+ set_local 3
+ end
+ block ;; label = @3
+ get_local 2
+ i32.const 2
+ i32.and
+ i32.eqz
+ br_if 0 (;@3;)
+ get_local 3
+ get_local 1
+ i32.load8_u
+ i32.store8
+ get_local 3
+ get_local 1
+ i32.load8_u offset=1
+ i32.store8 offset=1
+ get_local 3
+ i32.const 2
+ i32.add
+ set_local 3
+ get_local 1
+ i32.const 2
+ i32.add
+ set_local 1
+ end
+ get_local 2
+ i32.const 1
+ i32.and
+ i32.eqz
+ br_if 1 (;@1;)
+ get_local 3
+ get_local 1
+ i32.load8_u
+ i32.store8
+ get_local 0
+ return
+ end
+ block ;; label = @2
+ get_local 4
+ i32.const 32
+ i32.lt_u
+ br_if 0 (;@2;)
+ block ;; label = @3
+ block ;; label = @4
+ get_local 2
+ i32.const 3
+ i32.eq
+ br_if 0 (;@4;)
+ get_local 2
+ i32.const 2
+ i32.eq
+ br_if 1 (;@3;)
+ get_local 2
+ i32.const 1
+ i32.ne
+ br_if 2 (;@2;)
+ get_local 3
+ get_local 1
+ i32.load8_u offset=1
+ i32.store8 offset=1
+ get_local 3
+ get_local 1
+ i32.load
+ tee_local 5
+ i32.store8
+ get_local 3
+ get_local 1
+ i32.load8_u offset=2
+ i32.store8 offset=2
+ get_local 4
+ i32.const -3
+ i32.add
+ set_local 6
+ get_local 3
+ i32.const 3
+ i32.add
+ set_local 7
+ get_local 4
+ i32.const -20
+ i32.add
+ i32.const -16
+ i32.and
+ set_local 8
+ i32.const 0
+ set_local 2
+ loop ;; label = @5
+ get_local 7
+ get_local 2
+ i32.add
+ tee_local 3
+ get_local 1
+ get_local 2
+ i32.add
+ tee_local 9
+ i32.const 4
+ i32.add
+ i32.load
+ tee_local 10
+ i32.const 8
+ i32.shl
+ get_local 5
+ i32.const 24
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 4
+ i32.add
+ get_local 9
+ i32.const 8
+ i32.add
+ i32.load
+ tee_local 5
+ i32.const 8
+ i32.shl
+ get_local 10
+ i32.const 24
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 8
+ i32.add
+ get_local 9
+ i32.const 12
+ i32.add
+ i32.load
+ tee_local 10
+ i32.const 8
+ i32.shl
+ get_local 5
+ i32.const 24
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 12
+ i32.add
+ get_local 9
+ i32.const 16
+ i32.add
+ i32.load
+ tee_local 5
+ i32.const 8
+ i32.shl
+ get_local 10
+ i32.const 24
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 2
+ i32.const 16
+ i32.add
+ set_local 2
+ get_local 6
+ i32.const -16
+ i32.add
+ tee_local 6
+ i32.const 16
+ i32.gt_u
+ br_if 0 (;@5;)
+ end
+ get_local 7
+ get_local 2
+ i32.add
+ set_local 3
+ get_local 1
+ get_local 2
+ i32.add
+ i32.const 3
+ i32.add
+ set_local 1
+ get_local 4
+ i32.const -19
+ i32.add
+ get_local 8
+ i32.sub
+ set_local 4
+ br 2 (;@2;)
+ end
+ get_local 3
+ get_local 1
+ i32.load
+ tee_local 5
+ i32.store8
+ get_local 4
+ i32.const -1
+ i32.add
+ set_local 6
+ get_local 3
+ i32.const 1
+ i32.add
+ set_local 7
+ get_local 4
+ i32.const -20
+ i32.add
+ i32.const -16
+ i32.and
+ set_local 8
+ i32.const 0
+ set_local 2
+ loop ;; label = @4
+ get_local 7
+ get_local 2
+ i32.add
+ tee_local 3
+ get_local 1
+ get_local 2
+ i32.add
+ tee_local 9
+ i32.const 4
+ i32.add
+ i32.load
+ tee_local 10
+ i32.const 24
+ i32.shl
+ get_local 5
+ i32.const 8
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 4
+ i32.add
+ get_local 9
+ i32.const 8
+ i32.add
+ i32.load
+ tee_local 5
+ i32.const 24
+ i32.shl
+ get_local 10
+ i32.const 8
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 8
+ i32.add
+ get_local 9
+ i32.const 12
+ i32.add
+ i32.load
+ tee_local 10
+ i32.const 24
+ i32.shl
+ get_local 5
+ i32.const 8
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 12
+ i32.add
+ get_local 9
+ i32.const 16
+ i32.add
+ i32.load
+ tee_local 5
+ i32.const 24
+ i32.shl
+ get_local 10
+ i32.const 8
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 2
+ i32.const 16
+ i32.add
+ set_local 2
+ get_local 6
+ i32.const -16
+ i32.add
+ tee_local 6
+ i32.const 18
+ i32.gt_u
+ br_if 0 (;@4;)
+ end
+ get_local 7
+ get_local 2
+ i32.add
+ set_local 3
+ get_local 1
+ get_local 2
+ i32.add
+ i32.const 1
+ i32.add
+ set_local 1
+ get_local 4
+ i32.const -17
+ i32.add
+ get_local 8
+ i32.sub
+ set_local 4
+ br 1 (;@2;)
+ end
+ get_local 3
+ get_local 1
+ i32.load
+ tee_local 5
+ i32.store8
+ get_local 3
+ get_local 1
+ i32.load8_u offset=1
+ i32.store8 offset=1
+ get_local 4
+ i32.const -2
+ i32.add
+ set_local 6
+ get_local 3
+ i32.const 2
+ i32.add
+ set_local 7
+ get_local 4
+ i32.const -20
+ i32.add
+ i32.const -16
+ i32.and
+ set_local 8
+ i32.const 0
+ set_local 2
+ loop ;; label = @3
+ get_local 7
+ get_local 2
+ i32.add
+ tee_local 3
+ get_local 1
+ get_local 2
+ i32.add
+ tee_local 9
+ i32.const 4
+ i32.add
+ i32.load
+ tee_local 10
+ i32.const 16
+ i32.shl
+ get_local 5
+ i32.const 16
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 4
+ i32.add
+ get_local 9
+ i32.const 8
+ i32.add
+ i32.load
+ tee_local 5
+ i32.const 16
+ i32.shl
+ get_local 10
+ i32.const 16
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 8
+ i32.add
+ get_local 9
+ i32.const 12
+ i32.add
+ i32.load
+ tee_local 10
+ i32.const 16
+ i32.shl
+ get_local 5
+ i32.const 16
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 3
+ i32.const 12
+ i32.add
+ get_local 9
+ i32.const 16
+ i32.add
+ i32.load
+ tee_local 5
+ i32.const 16
+ i32.shl
+ get_local 10
+ i32.const 16
+ i32.shr_u
+ i32.or
+ i32.store
+ get_local 2
+ i32.const 16
+ i32.add
+ set_local 2
+ get_local 6
+ i32.const -16
+ i32.add
+ tee_local 6
+ i32.const 17
+ i32.gt_u
+ br_if 0 (;@3;)
+ end
+ get_local 7
+ get_local 2
+ i32.add
+ set_local 3
+ get_local 1
+ get_local 2
+ i32.add
+ i32.const 2
+ i32.add
+ set_local 1
+ get_local 4
+ i32.const -18
+ i32.add
+ get_local 8
+ i32.sub
+ set_local 4
+ end
+ block ;; label = @2
+ get_local 4
+ i32.const 16
+ i32.and
+ i32.eqz
+ br_if 0 (;@2;)
+ get_local 3
+ get_local 1
+ i32.load16_u align=1
+ i32.store16 align=1
+ get_local 3
+ get_local 1
+ i32.load8_u offset=2
+ i32.store8 offset=2
+ get_local 3
+ get_local 1
+ i32.load8_u offset=3
+ i32.store8 offset=3
+ get_local 3
+ get_local 1
+ i32.load8_u offset=4
+ i32.store8 offset=4
+ get_local 3
+ get_local 1
+ i32.load8_u offset=5
+ i32.store8 offset=5
+ get_local 3
+ get_local 1
+ i32.load8_u offset=6
+ i32.store8 offset=6
+ get_local 3
+ get_local 1
+ i32.load8_u offset=7
+ i32.store8 offset=7
+ get_local 3
+ get_local 1
+ i32.load8_u offset=8
+ i32.store8 offset=8
+ get_local 3
+ get_local 1
+ i32.load8_u offset=9
+ i32.store8 offset=9
+ get_local 3
+ get_local 1
+ i32.load8_u offset=10
+ i32.store8 offset=10
+ get_local 3
+ get_local 1
+ i32.load8_u offset=11
+ i32.store8 offset=11
+ get_local 3
+ get_local 1
+ i32.load8_u offset=12
+ i32.store8 offset=12
+ get_local 3
+ get_local 1
+ i32.load8_u offset=13
+ i32.store8 offset=13
+ get_local 3
+ get_local 1
+ i32.load8_u offset=14
+ i32.store8 offset=14
+ get_local 3
+ get_local 1
+ i32.load8_u offset=15
+ i32.store8 offset=15
+ get_local 3
+ i32.const 16
+ i32.add
+ set_local 3
+ get_local 1
+ i32.const 16
+ i32.add
+ set_local 1
+ end
+ block ;; label = @2
+ get_local 4
+ i32.const 8
+ i32.and
+ i32.eqz
+ br_if 0 (;@2;)
+ get_local 3
+ get_local 1
+ i32.load8_u
+ i32.store8
+ get_local 3
+ get_local 1
+ i32.load8_u offset=1
+ i32.store8 offset=1
+ get_local 3
+ get_local 1
+ i32.load8_u offset=2
+ i32.store8 offset=2
+ get_local 3
+ get_local 1
+ i32.load8_u offset=3
+ i32.store8 offset=3
+ get_local 3
+ get_local 1
+ i32.load8_u offset=4
+ i32.store8 offset=4
+ get_local 3
+ get_local 1
+ i32.load8_u offset=5
+ i32.store8 offset=5
+ get_local 3
+ get_local 1
+ i32.load8_u offset=6
+ i32.store8 offset=6
+ get_local 3
+ get_local 1
+ i32.load8_u offset=7
+ i32.store8 offset=7
+ get_local 3
+ i32.const 8
+ i32.add
+ set_local 3
+ get_local 1
+ i32.const 8
+ i32.add
+ set_local 1
+ end
+ block ;; label = @2
+ get_local 4
+ i32.const 4
+ i32.and
+ i32.eqz
+ br_if 0 (;@2;)
+ get_local 3
+ get_local 1
+ i32.load8_u
+ i32.store8
+ get_local 3
+ get_local 1
+ i32.load8_u offset=1
+ i32.store8 offset=1
+ get_local 3
+ get_local 1
+ i32.load8_u offset=2
+ i32.store8 offset=2
+ get_local 3
+ get_local 1
+ i32.load8_u offset=3
+ i32.store8 offset=3
+ get_local 3
+ i32.const 4
+ i32.add
+ set_local 3
+ get_local 1
+ i32.const 4
+ i32.add
+ set_local 1
+ end
+ block ;; label = @2
+ get_local 4
+ i32.const 2
+ i32.and
+ i32.eqz
+ br_if 0 (;@2;)
+ get_local 3
+ get_local 1
+ i32.load8_u
+ i32.store8
+ get_local 3
+ get_local 1
+ i32.load8_u offset=1
+ i32.store8 offset=1
+ get_local 3
+ i32.const 2
+ i32.add
+ set_local 3
+ get_local 1
+ i32.const 2
+ i32.add
+ set_local 1
+ end
+ get_local 4
+ i32.const 1
+ i32.and
+ i32.eqz
+ br_if 0 (;@1;)
+ get_local 3
+ get_local 1
+ i32.load8_u
+ i32.store8
+ end
+ get_local 0)
+ (func (;44;) (type 0) (param i32 i32 i32) (result i32)
+ (local i32 i32 i32 i64)
+ block ;; label = @1
+ get_local 2
+ i32.eqz
+ br_if 0 (;@1;)
+ get_local 0
+ get_local 1
+ i32.store8
+ get_local 0
+ get_local 2
+ i32.add
+ tee_local 3
+ i32.const -1
+ i32.add
+ get_local 1
+ i32.store8
+ get_local 2
+ i32.const 3
+ i32.lt_u
+ br_if 0 (;@1;)
+ get_local 0
+ get_local 1
+ i32.store8 offset=2
+ get_local 0
+ get_local 1
+ i32.store8 offset=1
+ get_local 3
+ i32.const -3
+ i32.add
+ get_local 1
+ i32.store8
+ get_local 3
+ i32.const -2
+ i32.add
+ get_local 1
+ i32.store8
+ get_local 2
+ i32.const 7
+ i32.lt_u
+ br_if 0 (;@1;)
+ get_local 0
+ get_local 1
+ i32.store8 offset=3
+ get_local 3
+ i32.const -4
+ i32.add
+ get_local 1
+ i32.store8
+ get_local 2
+ i32.const 9
+ i32.lt_u
+ br_if 0 (;@1;)
+ get_local 0
+ i32.const 0
+ get_local 0
+ i32.sub
+ i32.const 3
+ i32.and
+ tee_local 4
+ i32.add
+ tee_local 3
+ get_local 1
+ i32.const 255
+ i32.and
+ i32.const 16843009
+ i32.mul
+ tee_local 1
+ i32.store
+ get_local 3
+ get_local 2
+ get_local 4
+ i32.sub
+ i32.const -4
+ i32.and
+ tee_local 4
+ i32.add
+ tee_local 2
+ i32.const -4
+ i32.add
+ get_local 1
+ i32.store
+ get_local 4
+ i32.const 9
+ i32.lt_u
+ br_if 0 (;@1;)
+ get_local 3
+ get_local 1
+ i32.store offset=8
+ get_local 3
+ get_local 1
+ i32.store offset=4
+ get_local 2
+ i32.const -8
+ i32.add
+ get_local 1
+ i32.store
+ get_local 2
+ i32.const -12
+ i32.add
+ get_local 1
+ i32.store
+ get_local 4
+ i32.const 25
+ i32.lt_u
+ br_if 0 (;@1;)
+ get_local 3
+ get_local 1
+ i32.store offset=24
+ get_local 3
+ get_local 1
+ i32.store offset=20
+ get_local 3
+ get_local 1
+ i32.store offset=16
+ get_local 3
+ get_local 1
+ i32.store offset=12
+ get_local 2
+ i32.const -16
+ i32.add
+ get_local 1
+ i32.store
+ get_local 2
+ i32.const -20
+ i32.add
+ get_local 1
+ i32.store
+ get_local 2
+ i32.const -24
+ i32.add
+ get_local 1
+ i32.store
+ get_local 2
+ i32.const -28
+ i32.add
+ get_local 1
+ i32.store
+ get_local 4
+ get_local 3
+ i32.const 4
+ i32.and
+ i32.const 24
+ i32.or
+ tee_local 5
+ i32.sub
+ tee_local 2
+ i32.const 32
+ i32.lt_u
+ br_if 0 (;@1;)
+ get_local 1
+ i64.extend_u/i32
+ tee_local 6
+ i64.const 32
+ i64.shl
+ get_local 6
+ i64.or
+ set_local 6
+ get_local 3
+ get_local 5
+ i32.add
+ set_local 1
+ loop ;; label = @2
+ get_local 1
+ get_local 6
+ i64.store
+ get_local 1
+ i32.const 24
+ i32.add
+ get_local 6
+ i64.store
+ get_local 1
+ i32.const 16
+ i32.add
+ get_local 6
+ i64.store
+ get_local 1
+ i32.const 8
+ i32.add
+ get_local 6
+ i64.store
+ get_local 1
+ i32.const 32
+ i32.add
+ set_local 1
+ get_local 2
+ i32.const -32
+ i32.add
+ tee_local 2
+ i32.const 31
+ i32.gt_u
+ br_if 0 (;@2;)
+ end
+ end
+ get_local 0)
+ (func (;45;) (type 4) (param i32) (result i32)
+ (local i32 i32)
+ block ;; label = @1
+ get_local 0
+ call 46
+ i32.const 1
+ i32.add
+ tee_local 1
+ call 14
+ tee_local 2
+ i32.eqz
+ br_if 0 (;@1;)
+ get_local 2
+ get_local 0
+ get_local 1
+ call 43
+ return
+ end
+ i32.const 0)
+ (func (;46;) (type 4) (param i32) (result i32)
+ (local i32 i32 i32)
+ get_local 0
+ set_local 1
+ block ;; label = @1
+ block ;; label = @2
+ block ;; label = @3
+ get_local 0
+ i32.const 3
+ i32.and
+ i32.eqz
+ br_if 0 (;@3;)
+ get_local 0
+ i32.load8_u
+ i32.eqz
+ br_if 1 (;@2;)
+ get_local 0
+ i32.const 1
+ i32.add
+ set_local 1
+ loop ;; label = @4
+ get_local 1
+ i32.const 3
+ i32.and
+ i32.eqz
+ br_if 1 (;@3;)
+ get_local 1
+ i32.load8_u
+ set_local 2
+ get_local 1
+ i32.const 1
+ i32.add
+ tee_local 3
+ set_local 1
+ get_local 2
+ br_if 0 (;@4;)
+ end
+ get_local 3
+ i32.const -1
+ i32.add
+ get_local 0
+ i32.sub
+ return
+ end
+ get_local 1
+ i32.const -4
+ i32.add
+ set_local 1
+ loop ;; label = @3
+ get_local 1
+ i32.const 4
+ i32.add
+ tee_local 1
+ i32.load
+ tee_local 2
+ i32.const -1
+ i32.xor
+ get_local 2
+ i32.const -16843009
+ i32.add
+ i32.and
+ i32.const -2139062144
+ i32.and
+ i32.eqz
+ br_if 0 (;@3;)
+ end
+ get_local 2
+ i32.const 255
+ i32.and
+ i32.eqz
+ br_if 1 (;@1;)
+ loop ;; label = @3
+ get_local 1
+ i32.load8_u offset=1
+ set_local 2
+ get_local 1
+ i32.const 1
+ i32.add
+ tee_local 3
+ set_local 1
+ get_local 2
+ br_if 0 (;@3;)
+ end
+ get_local 3
+ get_local 0
+ i32.sub
+ return
+ end
+ get_local 0
+ get_local 0
+ i32.sub
+ return
+ end
+ get_local 1
+ get_local 0
+ i32.sub)
+ (table (;0;) 5 5 anyfunc)
+ (memory (;0;) 2)
+ (global (;0;) (mut i32) (i32.const 68256))
+ (global (;1;) i32 (i32.const 68256))
+ (global (;2;) i32 (i32.const 2716))
+ (export "memory" (memory 0))
+ (export "__heap_base" (global 1))
+ (export "__data_end" (global 2))
+ (export "_start" (func 12))
+ (elem (i32.const 1) 38 36 40 42)
+ (data (i32.const 1024) "simple-wasi...\00")
+ (data (i32.const 1040) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+ (data (i32.const 2600) "\05\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\03\00\00\00\04\00\00\00(\06\00\00\00\04\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00\00\00\00\0a\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00(\0a\00\00"))
diff --git a/test/fixtures/wasi/subdir/input_link.txt b/test/fixtures/wasi/subdir/input_link.txt
new file mode 120000
index 0000000000..4a6d09bf82
--- /dev/null
+++ b/test/fixtures/wasi/subdir/input_link.txt
@@ -0,0 +1 @@
+../input.txt \ No newline at end of file
diff --git a/test/fixtures/wasi/subdir/loop1 b/test/fixtures/wasi/subdir/loop1
new file mode 120000
index 0000000000..433d7fdbce
--- /dev/null
+++ b/test/fixtures/wasi/subdir/loop1
@@ -0,0 +1 @@
+./loop2 \ No newline at end of file
diff --git a/test/fixtures/wasi/subdir/loop2 b/test/fixtures/wasi/subdir/loop2
new file mode 120000
index 0000000000..2907735afc
--- /dev/null
+++ b/test/fixtures/wasi/subdir/loop2
@@ -0,0 +1 @@
+./loop1 \ No newline at end of file
diff --git a/test/fixtures/wasi/subdir/outside.txt b/test/fixtures/wasi/subdir/outside.txt
new file mode 120000
index 0000000000..2e06947067
--- /dev/null
+++ b/test/fixtures/wasi/subdir/outside.txt
@@ -0,0 +1 @@
+../../outside.txt \ No newline at end of file
diff --git a/test/wasi/Makefile b/test/wasi/Makefile
new file mode 100644
index 0000000000..42d3b4e3fa
--- /dev/null
+++ b/test/wasi/Makefile
@@ -0,0 +1,12 @@
+CC = /opt/wasi-sdk/bin/clang
+TARGET = wasm32-unknown-wasi
+SYSROOT =
+
+OBJ = $(patsubst c/%.c, wasm/%.wasm, $(wildcard c/*.c))
+all: $(OBJ)
+
+wasm/%.wasm : c/%.c
+ $(CC) $< --target=$(TARGET) --sysroot=$(SYSROOT) -s -o $@
+
+.PHONY clean:
+ rm -f $(OBJ)
diff --git a/test/wasi/README.md b/test/wasi/README.md
new file mode 100644
index 0000000000..ccb02d095e
--- /dev/null
+++ b/test/wasi/README.md
@@ -0,0 +1,8 @@
+# WASI Tests
+
+Compile with clang and `wasm32-wasi` target. The clang version used must be
+built with wasi-libc. You can specify the location for clang and the sysroot
+if needed when running make:
+```console
+$ make CC=/usr/local/opt/llvm/bin/clang SYSROOT=/path/to/wasi-libc/sysroot
+```
diff --git a/test/wasi/c/cant_dotdot.c b/test/wasi/c/cant_dotdot.c
new file mode 100644
index 0000000000..e2722062cd
--- /dev/null
+++ b/test/wasi/c/cant_dotdot.c
@@ -0,0 +1,11 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main() {
+ FILE* file = fopen("/sandbox/../outside.txt", "r");
+ assert(file == NULL);
+ assert(errno == ENOTCAPABLE);
+
+ return 0;
+}
diff --git a/test/wasi/c/clock_getres.c b/test/wasi/c/clock_getres.c
new file mode 100644
index 0000000000..eaac02c665
--- /dev/null
+++ b/test/wasi/c/clock_getres.c
@@ -0,0 +1,17 @@
+#include <assert.h>
+#include <time.h>
+
+int main() {
+ struct timespec ts;
+ int r;
+
+ // supported clocks
+ r = clock_getres(CLOCK_REALTIME, &ts);
+ assert(r == 0);
+ r = clock_getres(CLOCK_MONOTONIC, &ts);
+ assert(r == 0);
+ r = clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts);
+ assert(r == 0);
+ r = clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts);
+ assert(r == 0);
+}
diff --git a/test/wasi/c/exitcode.c b/test/wasi/c/exitcode.c
new file mode 100644
index 0000000000..9c44b0de74
--- /dev/null
+++ b/test/wasi/c/exitcode.c
@@ -0,0 +1,3 @@
+int main() {
+ return 120;
+}
diff --git a/test/wasi/c/fd_prestat_get_refresh.c b/test/wasi/c/fd_prestat_get_refresh.c
new file mode 100644
index 0000000000..fb644ab49b
--- /dev/null
+++ b/test/wasi/c/fd_prestat_get_refresh.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+
+int main(void) {
+ isatty(1);
+ __builtin_wasm_memory_grow(0, 1);
+ isatty(1);
+ return 0;
+}
diff --git a/test/wasi/c/follow_symlink.c b/test/wasi/c/follow_symlink.c
new file mode 100644
index 0000000000..badb0ee267
--- /dev/null
+++ b/test/wasi/c/follow_symlink.c
@@ -0,0 +1,14 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main() {
+ FILE* file = fopen("/sandbox/subdir/input_link.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ int wrote = fputc(c, stdout);
+ assert(wrote != EOF);
+ c = fgetc(file);
+ }
+}
diff --git a/test/wasi/c/getentropy.c b/test/wasi/c/getentropy.c
new file mode 100644
index 0000000000..75547e1c47
--- /dev/null
+++ b/test/wasi/c/getentropy.c
@@ -0,0 +1,18 @@
+#include <assert.h>
+#include <unistd.h>
+
+int main() {
+ char buf[256] = {0};
+ int r = getentropy(buf, 256);
+ assert(r == 0);
+
+ for (int i = 0; i < 256; i++) {
+ if (buf[i] != 0) {
+ return 0;
+ }
+ }
+
+ // if this ever is reached, we either have a bug or should buy a lottery
+ // ticket
+ return 1;
+}
diff --git a/test/wasi/c/getrusage.c b/test/wasi/c/getrusage.c
new file mode 100644
index 0000000000..ad1e430b85
--- /dev/null
+++ b/test/wasi/c/getrusage.c
@@ -0,0 +1,34 @@
+#include <assert.h>
+#include <sys/resource.h>
+
+int main() {
+ struct rusage ru1;
+ struct rusage ru2;
+ long long s1;
+ long long us1;
+ long long s2;
+ long long us2;
+ int r;
+ int success = 0;
+
+ r = getrusage(RUSAGE_SELF, &ru1);
+ assert(r == 0);
+ s1 = ru1.ru_utime.tv_sec;
+ us1 = ru1.ru_utime.tv_usec;
+
+ for (int i = 0; i < 10000; i++) {
+ r = getrusage(RUSAGE_SELF, &ru2);
+ assert(r == 0);
+ s2 = ru2.ru_utime.tv_sec;
+ us2 = ru2.ru_utime.tv_usec;
+ assert(s1 <= s2);
+
+ // Verify that some time has passed.
+ if (s2 > s1 || (s2 == s1 && us2 > us1)) {
+ success = 1;
+ break;
+ }
+ }
+
+ assert(success == 1);
+}
diff --git a/test/wasi/c/gettimeofday.c b/test/wasi/c/gettimeofday.c
new file mode 100644
index 0000000000..209a54e498
--- /dev/null
+++ b/test/wasi/c/gettimeofday.c
@@ -0,0 +1,35 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+int main() {
+ struct timeval tv1;
+ struct timeval tv2;
+ long long s1;
+ long long us1;
+ long long s2;
+ long long us2;
+ int r;
+ int success = 0;
+
+ r = gettimeofday(&tv1, NULL);
+ assert(r == 0);
+ s1 = tv1.tv_sec;
+ us1 = tv1.tv_usec;
+
+ for (int i = 0; i < 10000; i++) {
+ r = gettimeofday(&tv2, NULL);
+ assert(r == 0);
+ s2 = tv2.tv_sec;
+ us2 = tv2.tv_usec;
+ assert(s1 <= s2);
+
+ // Verify that some time has passed.
+ if (s2 > s1 || (s2 == s1 && us2 > us1)) {
+ success = 1;
+ break;
+ }
+ }
+
+ assert(success == 1);
+}
diff --git a/test/wasi/c/notdir.c b/test/wasi/c/notdir.c
new file mode 100644
index 0000000000..03f369ffd3
--- /dev/null
+++ b/test/wasi/c/notdir.c
@@ -0,0 +1,11 @@
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+
+int main() {
+ DIR* dir = opendir("/sandbox/notadir");
+ assert(dir == NULL);
+ assert(errno == ENOTDIR);
+
+ return 0;
+}
diff --git a/test/wasi/c/poll.c b/test/wasi/c/poll.c
new file mode 100644
index 0000000000..6b6ef71fd6
--- /dev/null
+++ b/test/wasi/c/poll.c
@@ -0,0 +1,31 @@
+#include <assert.h>
+#include <poll.h>
+#include <time.h>
+#include <unistd.h>
+
+int main(void) {
+ struct pollfd fds[2];
+ time_t before, now;
+ int ret;
+
+ fds[0] = (struct pollfd){.fd = 1, .events = POLLOUT, .revents = 0};
+ fds[1] = (struct pollfd){.fd = 2, .events = POLLOUT, .revents = 0};
+
+ ret = poll(fds, 2, -1);
+ assert(ret == 2);
+ assert(fds[0].revents == POLLOUT);
+ assert(fds[1].revents == POLLOUT);
+
+ fds[0] = (struct pollfd){.fd = 0, .events = POLLIN, .revents = 0};
+ time(&before);
+ ret = poll(fds, 1, 2000);
+ time(&now);
+ assert(ret == 0);
+ assert(now - before >= 2);
+
+ sleep(1);
+ time(&now);
+ assert(now - before >= 3);
+
+ return 0;
+}
diff --git a/test/wasi/c/preopen_populates.c b/test/wasi/c/preopen_populates.c
new file mode 100644
index 0000000000..03b2213bb9
--- /dev/null
+++ b/test/wasi/c/preopen_populates.c
@@ -0,0 +1,3 @@
+int main(void) {
+ return 0;
+}
diff --git a/test/wasi/c/read_file.c b/test/wasi/c/read_file.c
new file mode 100644
index 0000000000..40023e29e2
--- /dev/null
+++ b/test/wasi/c/read_file.c
@@ -0,0 +1,14 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main() {
+ FILE* file = fopen("/sandbox/input.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ int wrote = fputc(c, stdout);
+ assert(wrote != EOF);
+ c = fgetc(file);
+ }
+}
diff --git a/test/wasi/c/read_file_twice.c b/test/wasi/c/read_file_twice.c
new file mode 100644
index 0000000000..e295e38a3b
--- /dev/null
+++ b/test/wasi/c/read_file_twice.c
@@ -0,0 +1,16 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main() {
+ for (int i = 0; i < 2; i++) {
+ FILE* file = fopen("/sandbox/input.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ int wrote = fputc(c, stdout);
+ assert(wrote != EOF);
+ c = fgetc(file);
+ }
+ }
+}
diff --git a/test/wasi/c/stat.c b/test/wasi/c/stat.c
new file mode 100644
index 0000000000..fd3854937b
--- /dev/null
+++ b/test/wasi/c/stat.c
@@ -0,0 +1,53 @@
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#define BASE_DIR "/tmp"
+#define OUTPUT_DIR BASE_DIR "/testdir"
+#define PATH OUTPUT_DIR "/output.txt"
+#define SIZE 500
+
+int main(void) {
+ struct stat st;
+ int fd;
+ int ret;
+ off_t pos;
+
+ (void)st;
+ ret = mkdir(OUTPUT_DIR, 0755);
+ assert(ret == 0);
+
+ fd = open(PATH, O_CREAT | O_WRONLY, 0666);
+ assert(fd != -1);
+
+ pos = lseek(fd, SIZE - 1, SEEK_SET);
+ assert(pos == SIZE - 1);
+
+ ret = (int)write(fd, "", 1);
+ assert(ret == 1);
+
+ ret = fstat(fd, &st);
+ assert(ret == 0);
+ assert(st.st_size == SIZE);
+
+ ret = close(fd);
+ assert(ret == 0);
+
+ ret = access(PATH, R_OK);
+ assert(ret == 0);
+
+ ret = stat(PATH, &st);
+ assert(ret == 0);
+ assert(st.st_size == SIZE);
+
+ ret = unlink(PATH);
+ assert(ret == 0);
+
+ ret = stat(PATH, &st);
+ assert(ret == -1);
+
+ return 0;
+}
diff --git a/test/wasi/c/stdin.c b/test/wasi/c/stdin.c
new file mode 100644
index 0000000000..5a81ea1265
--- /dev/null
+++ b/test/wasi/c/stdin.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+int main(void) {
+ char x[32];
+
+ if (fgets(x, sizeof x, stdin) == NULL) {
+ return ferror(stdin);
+ }
+ if (fputs(x, stdout) == EOF) {
+ return ferror(stdout);
+ }
+ return 0;
+}
diff --git a/test/wasi/c/symlink_escape.c b/test/wasi/c/symlink_escape.c
new file mode 100644
index 0000000000..32dcc64eeb
--- /dev/null
+++ b/test/wasi/c/symlink_escape.c
@@ -0,0 +1,9 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main() {
+ FILE* file = fopen("/sandbox/subdir/outside.txt", "r");
+ assert(file == NULL);
+ assert(errno == ENOTCAPABLE);
+}
diff --git a/test/wasi/c/symlink_loop.c b/test/wasi/c/symlink_loop.c
new file mode 100644
index 0000000000..23bd70ba60
--- /dev/null
+++ b/test/wasi/c/symlink_loop.c
@@ -0,0 +1,9 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main() {
+ FILE* file = fopen("/sandbox/subdir/loop1", "r");
+ assert(file == NULL);
+ assert(errno == ELOOP);
+}
diff --git a/test/wasi/c/write_file.c b/test/wasi/c/write_file.c
new file mode 100644
index 0000000000..c4cf30cf29
--- /dev/null
+++ b/test/wasi/c/write_file.c
@@ -0,0 +1,15 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+static char* message = "hello, file!";
+
+int main() {
+ FILE* file = fopen("/tmp/output.txt", "w");
+ assert(file != NULL);
+
+ int nwritten = fprintf(file, "%s", message);
+ assert(nwritten == strlen(message));
+ int r = fclose(file);
+ assert(r == 0);
+}
diff --git a/test/wasi/test-wasi-binding.js b/test/wasi/test-wasi-binding.js
new file mode 100644
index 0000000000..876c8a15a7
--- /dev/null
+++ b/test/wasi/test-wasi-binding.js
@@ -0,0 +1,19 @@
+// Flags: --experimental-wasi-unstable-preview0
+'use strict';
+
+const common = require('../common');
+
+const assert = require('assert');
+const fixtures = require('../common/fixtures');
+const buffer = fixtures.readSync(['wasi', 'simple-wasi.wasm']);
+const { WASI } = require('wasi');
+const wasi = new WASI({ args: [], env: process.env });
+const importObject = {
+ wasi_unstable: wasi.wasiImport
+};
+
+WebAssembly.instantiate(buffer, importObject)
+.then(common.mustCall((results) => {
+ assert(results.instance.exports._start);
+ wasi.start(results.instance);
+}));
diff --git a/test/wasi/test-wasi-symlinks.js b/test/wasi/test-wasi-symlinks.js
new file mode 100644
index 0000000000..3829464198
--- /dev/null
+++ b/test/wasi/test-wasi-symlinks.js
@@ -0,0 +1,78 @@
+'use strict';
+const common = require('../common');
+const fs = require('fs');
+const path = require('path');
+
+if (process.argv[2] === 'wasi-child') {
+ common.expectWarning('ExperimentalWarning',
+ 'WASI is an experimental feature. This feature could ' +
+ 'change at any time');
+
+ const { WASI } = require('wasi');
+ const wasmDir = path.join(__dirname, 'wasm');
+ const wasi = new WASI({
+ args: [],
+ env: process.env,
+ preopens: {
+ '/sandbox': process.argv[4]
+ }
+ });
+ const importObject = { wasi_unstable: wasi.wasiImport };
+ const modulePath = path.join(wasmDir, `${process.argv[3]}.wasm`);
+ const buffer = fs.readFileSync(modulePath);
+
+ (async () => {
+ const { instance } = await WebAssembly.instantiate(buffer, importObject);
+
+ wasi.start(instance);
+ })();
+} else {
+ if (!common.canCreateSymLink()) {
+ common.skip('insufficient privileges');
+ }
+
+ const assert = require('assert');
+ const cp = require('child_process');
+ const tmpdir = require('../../test/common/tmpdir');
+
+ // Setup the sandbox environment.
+ tmpdir.refresh();
+ const sandbox = path.join(tmpdir.path, 'sandbox');
+ const sandboxedFile = path.join(sandbox, 'input.txt');
+ const externalFile = path.join(tmpdir.path, 'outside.txt');
+ const sandboxedDir = path.join(sandbox, 'subdir');
+ const sandboxedSymlink = path.join(sandboxedDir, 'input_link.txt');
+ const escapingSymlink = path.join(sandboxedDir, 'outside.txt');
+ const loopSymlink1 = path.join(sandboxedDir, 'loop1');
+ const loopSymlink2 = path.join(sandboxedDir, 'loop2');
+
+ fs.mkdirSync(sandbox);
+ fs.mkdirSync(sandboxedDir);
+ fs.writeFileSync(sandboxedFile, 'hello from input.txt', 'utf8');
+ fs.writeFileSync(externalFile, 'this should be inaccessible', 'utf8');
+ fs.symlinkSync(sandboxedFile, sandboxedSymlink, 'file');
+ fs.symlinkSync(externalFile, escapingSymlink, 'file');
+ fs.symlinkSync(loopSymlink2, loopSymlink1, 'file');
+ fs.symlinkSync(loopSymlink1, loopSymlink2, 'file');
+
+ function runWASI(options) {
+ console.log('executing', options.test);
+ const opts = { env: { ...process.env, NODE_DEBUG_NATIVE: 'wasi' } };
+ const child = cp.spawnSync(process.execPath, [
+ '--experimental-wasi-unstable-preview0',
+ '--experimental-wasm-bigint',
+ __filename,
+ 'wasi-child',
+ options.test,
+ sandbox
+ ], opts);
+ console.log(child.stderr.toString());
+ assert.strictEqual(child.status, 0);
+ assert.strictEqual(child.signal, null);
+ assert.strictEqual(child.stdout.toString(), options.stdout || '');
+ }
+
+ runWASI({ test: 'follow_symlink', stdout: 'hello from input.txt' });
+ runWASI({ test: 'symlink_escape' });
+ runWASI({ test: 'symlink_loop' });
+}
diff --git a/test/wasi/test-wasi.js b/test/wasi/test-wasi.js
new file mode 100644
index 0000000000..fa2e0894c9
--- /dev/null
+++ b/test/wasi/test-wasi.js
@@ -0,0 +1,81 @@
+'use strict';
+const common = require('../common');
+
+if (process.argv[2] === 'wasi-child') {
+ const fixtures = require('../common/fixtures');
+ const tmpdir = require('../../test/common/tmpdir');
+ const fs = require('fs');
+ const path = require('path');
+
+ common.expectWarning('ExperimentalWarning',
+ 'WASI is an experimental feature. This feature could ' +
+ 'change at any time');
+
+ const { WASI } = require('wasi');
+ tmpdir.refresh();
+ const wasmDir = path.join(__dirname, 'wasm');
+ const wasi = new WASI({
+ args: [],
+ env: process.env,
+ preopens: {
+ '/sandbox': fixtures.path('wasi'),
+ '/tmp': tmpdir.path
+ }
+ });
+ const importObject = { wasi_unstable: wasi.wasiImport };
+ const modulePath = path.join(wasmDir, `${process.argv[3]}.wasm`);
+ const buffer = fs.readFileSync(modulePath);
+
+ (async () => {
+ const { instance } = await WebAssembly.instantiate(buffer, importObject);
+
+ wasi.start(instance);
+ })();
+} else {
+ const assert = require('assert');
+ const cp = require('child_process');
+ const { EOL } = require('os');
+
+ function runWASI(options) {
+ console.log('executing', options.test);
+ const opts = { env: { ...process.env, NODE_DEBUG_NATIVE: 'wasi' } };
+
+ if (options.stdin !== undefined)
+ opts.input = options.stdin;
+
+ const child = cp.spawnSync(process.execPath, [
+ '--experimental-wasi-unstable-preview0',
+ '--experimental-wasm-bigint',
+ __filename,
+ 'wasi-child',
+ options.test
+ ], opts);
+ console.log(child.stderr.toString());
+ assert.strictEqual(child.status, options.exitCode || 0);
+ assert.strictEqual(child.signal, null);
+ assert.strictEqual(child.stdout.toString(), options.stdout || '');
+ }
+
+ runWASI({ test: 'cant_dotdot' });
+ runWASI({ test: 'clock_getres' });
+ runWASI({ test: 'exitcode', exitCode: 120 });
+ runWASI({ test: 'fd_prestat_get_refresh' });
+ runWASI({ test: 'getentropy' });
+ runWASI({ test: 'getrusage' });
+ runWASI({ test: 'gettimeofday' });
+ runWASI({ test: 'notdir' });
+ // runWASI({ test: 'poll' });
+ runWASI({ test: 'preopen_populates' });
+ runWASI({ test: 'read_file', stdout: `hello from input.txt${EOL}` });
+ runWASI({
+ test: 'read_file_twice',
+ stdout: `hello from input.txt${EOL}hello from input.txt${EOL}`
+ });
+ runWASI({ test: 'stat' });
+ runWASI({ test: 'write_file' });
+
+ // Tests that are currently unsupported on Windows.
+ if (!common.isWindows) {
+ runWASI({ test: 'stdin', stdin: 'hello world', stdout: 'hello world' });
+ }
+}
diff --git a/test/wasi/testcfg.py b/test/wasi/testcfg.py
new file mode 100644
index 0000000000..ec6cbc5fe3
--- /dev/null
+++ b/test/wasi/testcfg.py
@@ -0,0 +1,6 @@
+import sys, os
+sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+import testpy
+
+def GetConfiguration(context, root):
+ return testpy.ParallelTestConfiguration(context, root, 'wasi')
diff --git a/test/wasi/wasi.status b/test/wasi/wasi.status
new file mode 100644
index 0000000000..12212e8f72
--- /dev/null
+++ b/test/wasi/wasi.status
@@ -0,0 +1,7 @@
+prefix wasi
+
+# To mark a test as flaky, list the test name in the appropriate section
+# below, without ".js", followed by ": PASS,FLAKY". Example:
+# sample-test : PASS,FLAKY
+
+[true] # This section applies to all platforms
diff --git a/test/wasi/wasm/cant_dotdot.wasm b/test/wasi/wasm/cant_dotdot.wasm
new file mode 100755
index 0000000000..61e202d691
--- /dev/null
+++ b/test/wasi/wasm/cant_dotdot.wasm
Binary files differ
diff --git a/test/wasi/wasm/clock_getres.wasm b/test/wasi/wasm/clock_getres.wasm
new file mode 100755
index 0000000000..fac14edb04
--- /dev/null
+++ b/test/wasi/wasm/clock_getres.wasm
Binary files differ
diff --git a/test/wasi/wasm/exitcode.wasm b/test/wasi/wasm/exitcode.wasm
new file mode 100755
index 0000000000..b2d9ef5e11
--- /dev/null
+++ b/test/wasi/wasm/exitcode.wasm
Binary files differ
diff --git a/test/wasi/wasm/fd_prestat_get_refresh.wasm b/test/wasi/wasm/fd_prestat_get_refresh.wasm
new file mode 100755
index 0000000000..cf4bb97c3b
--- /dev/null
+++ b/test/wasi/wasm/fd_prestat_get_refresh.wasm
Binary files differ
diff --git a/test/wasi/wasm/follow_symlink.wasm b/test/wasi/wasm/follow_symlink.wasm
new file mode 100755
index 0000000000..48cf8da1eb
--- /dev/null
+++ b/test/wasi/wasm/follow_symlink.wasm
Binary files differ
diff --git a/test/wasi/wasm/getentropy.wasm b/test/wasi/wasm/getentropy.wasm
new file mode 100755
index 0000000000..6e3e8c8a8e
--- /dev/null
+++ b/test/wasi/wasm/getentropy.wasm
Binary files differ
diff --git a/test/wasi/wasm/getrusage.wasm b/test/wasi/wasm/getrusage.wasm
new file mode 100755
index 0000000000..524e809175
--- /dev/null
+++ b/test/wasi/wasm/getrusage.wasm
Binary files differ
diff --git a/test/wasi/wasm/gettimeofday.wasm b/test/wasi/wasm/gettimeofday.wasm
new file mode 100755
index 0000000000..94627f0086
--- /dev/null
+++ b/test/wasi/wasm/gettimeofday.wasm
Binary files differ
diff --git a/test/wasi/wasm/notdir.wasm b/test/wasi/wasm/notdir.wasm
new file mode 100755
index 0000000000..f83a790ddc
--- /dev/null
+++ b/test/wasi/wasm/notdir.wasm
Binary files differ
diff --git a/test/wasi/wasm/poll.wasm b/test/wasi/wasm/poll.wasm
new file mode 100755
index 0000000000..98d0736762
--- /dev/null
+++ b/test/wasi/wasm/poll.wasm
Binary files differ
diff --git a/test/wasi/wasm/preopen_populates.wasm b/test/wasi/wasm/preopen_populates.wasm
new file mode 100755
index 0000000000..e7c34bc964
--- /dev/null
+++ b/test/wasi/wasm/preopen_populates.wasm
Binary files differ
diff --git a/test/wasi/wasm/read_file.wasm b/test/wasi/wasm/read_file.wasm
new file mode 100755
index 0000000000..2b9db77d27
--- /dev/null
+++ b/test/wasi/wasm/read_file.wasm
Binary files differ
diff --git a/test/wasi/wasm/read_file_twice.wasm b/test/wasi/wasm/read_file_twice.wasm
new file mode 100755
index 0000000000..cd075a4de7
--- /dev/null
+++ b/test/wasi/wasm/read_file_twice.wasm
Binary files differ
diff --git a/test/wasi/wasm/stat.wasm b/test/wasi/wasm/stat.wasm
new file mode 100755
index 0000000000..9007334d37
--- /dev/null
+++ b/test/wasi/wasm/stat.wasm
Binary files differ
diff --git a/test/wasi/wasm/stdin.wasm b/test/wasi/wasm/stdin.wasm
new file mode 100755
index 0000000000..7264608753
--- /dev/null
+++ b/test/wasi/wasm/stdin.wasm
Binary files differ
diff --git a/test/wasi/wasm/symlink_escape.wasm b/test/wasi/wasm/symlink_escape.wasm
new file mode 100755
index 0000000000..0cdb8327a1
--- /dev/null
+++ b/test/wasi/wasm/symlink_escape.wasm
Binary files differ
diff --git a/test/wasi/wasm/symlink_loop.wasm b/test/wasi/wasm/symlink_loop.wasm
new file mode 100755
index 0000000000..3883d5278c
--- /dev/null
+++ b/test/wasi/wasm/symlink_loop.wasm
Binary files differ
diff --git a/test/wasi/wasm/write_file.wasm b/test/wasi/wasm/write_file.wasm
new file mode 100755
index 0000000000..500405e0fb
--- /dev/null
+++ b/test/wasi/wasm/write_file.wasm
Binary files differ
diff --git a/tools/doc/type-parser.js b/tools/doc/type-parser.js
index 0b9458351e..ef4499e50f 100644
--- a/tools/doc/type-parser.js
+++ b/tools/doc/type-parser.js
@@ -18,7 +18,7 @@ const jsGlobalTypes = [
'Array', 'ArrayBuffer', 'ArrayBufferView', 'DataView', 'Date', 'Error',
'EvalError', 'Function', 'Map', 'Object', 'Promise', 'RangeError',
'ReferenceError', 'RegExp', 'Set', 'SharedArrayBuffer', 'SyntaxError',
- 'TypeError', 'TypedArray', 'URIError', 'Uint8Array',
+ 'TypeError', 'TypedArray', 'URIError', 'Uint8Array', 'WebAssembly.Instance',
];
const customTypesMap = {
diff --git a/tools/license-builder.sh b/tools/license-builder.sh
index 60f38e5ceb..51c5b4d0c6 100755
--- a/tools/license-builder.sh
+++ b/tools/license-builder.sh
@@ -108,4 +108,6 @@ addlicense "node-heapdump" "src/heap_utils.cc" \
addlicense "rimraf" "lib/internal/fs/rimraf.js" \
"$(curl -sL https://raw.githubusercontent.com/isaacs/rimraf/0e365ac4e4d64a25aa2a3cc026348f13410210e1/LICENSE)"
+addlicense "uvwasi" "deps/uvwasi" "$(cat ${rootdir}/deps/uvwasi/LICENSE)"
+
mv $tmplicense $licensefile