From 83a905dd733c899d2b6b26a3118642a94c984d4e Mon Sep 17 00:00:00 2001 From: seaubot <81010316+seaubot@users.noreply.github.com> Date: Thu, 30 May 2024 14:57:09 -0700 Subject: [PATCH] chore: sync with ecsact_common (#56) Co-authored-by: seaubot Co-authored-by: Ezekiel Warren --- .bazelignore | 2 +- .editorconfig | 6 + .github/workflows/main.yml | 3 + .gitignore | 14 +- CHANGELOG.md | 2 +- cog.toml | 15 +- ecsact/wasm.h | 430 +++++----- ecsact/wasm/detail/guest_imports/README.md | 2 +- ecsact/wasm/detail/guest_imports/env.hh | 302 +++---- .../guest_imports/wasi_snapshot_preview1.hh | 236 +++--- ecsact/wasm/detail/util.hh | 86 +- ecsact/wasm/detail/wasi.cc | 490 +++++------ ecsact/wasm/detail/wasi.hh | 762 +++++++++--------- renovate.json | 2 +- 14 files changed, 1179 insertions(+), 1173 deletions(-) create mode 100644 .editorconfig diff --git a/.bazelignore b/.bazelignore index a41f26e..ed53218 100644 --- a/.bazelignore +++ b/.bazelignore @@ -1,2 +1,2 @@ test -example \ No newline at end of file +example diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9b1aeae --- /dev/null +++ b/.editorconfig @@ -0,0 +1,6 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 99d5c7d..307688b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,10 +20,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: greut/eclint-action@v0 - uses: jidicula/clang-format-action@v4.11.0 with: { clang-format-version: "18" } test-windows: + if: github.event_name == 'merge_group' runs-on: windows-latest steps: - name: Setup Wasmer @@ -41,6 +43,7 @@ jobs: working-directory: test test-linux: + if: github.event_name == 'merge_group' runs-on: ubuntu-latest steps: - name: Setup Wasmer diff --git a/.gitignore b/.gitignore index 1c28d98..9488de0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -bazel-* -user.bazelrc -.doxygen -external -compile_commands.json -.cache -*.bazel.lock +bazel-* +user.bazelrc +.doxygen +external +compile_commands.json +.cache +*.bazel.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index f48ee0f..0941bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,4 +26,4 @@ All notable changes to this project will be documented in this file. See [conven - - - -Changelog generated by [cocogitto](https://github.com/cocogitto/cocogitto). \ No newline at end of file +Changelog generated by [cocogitto](https://github.com/cocogitto/cocogitto). diff --git a/cog.toml b/cog.toml index 5158c53..c7d273c 100644 --- a/cog.toml +++ b/cog.toml @@ -1,14 +1,11 @@ pre_bump_hooks = [ - # Ecsact pre 1.0.0 the 0.X.0 is our 'major' version - "buildozer 'set version {{version}}' 'set compatibility_level {{version.minor}}' //MODULE.bazel:%module", - "bazel mod tidy", + # Ecsact pre 1.0.0 the 0.X.0 is our 'major' version + "buildozer 'set version {{version}}' 'set compatibility_level {{version.minor}}' //MODULE.bazel:%module", + "bazel mod tidy", ] post_bump_hooks = [ - "git push", - "git push origin {{version}}", - "gh release create {{version}} --generate-notes --latest -t {{version}} --verify-tag", + "git push", + "git push origin {{version}}", + "gh release create {{version}} --generate-notes --latest -t {{version}} --verify-tag", ] - -[packages] -test = { path = "test", pre_bump_hooks = ["bazel mod tidy"] } diff --git a/ecsact/wasm.h b/ecsact/wasm.h index 0783502..0aa2d34 100644 --- a/ecsact/wasm.h +++ b/ecsact/wasm.h @@ -1,215 +1,215 @@ -/** - * @file - * @brief Ecsact System Implementation with WebAssembly header - */ - -#ifndef ECSACTSI_WASM_H -#define ECSACTSI_WASM_H - -#include "ecsact/runtime/common.h" - -#ifndef ECSACTSI_WASM_API_VISIBILITY -# ifdef ECSACTSI_WASM_API_LOAD_AT_RUNTIME -# define ECSACTSI_WASM_API_VISIBILITY -# else -# ifdef ECSACTSI_WASM_API_EXPORT -# ifdef _WIN32 -# define ECSACTSI_WASM_API_VISIBILITY __declspec(dllexport) -# else -# define ECSACTSI_WASM_API_VISIBILITY \ - __attribute__((visibility("default"))) -# endif -# else -# ifdef _WIN32 -# define ECSACTSI_WASM_API_VISIBILITY __declspec(dllimport) -# else -# define ECSACTSI_WASM_API_VISIBILITY -# endif -# endif -# endif -#endif // ECSACTSI_WASM_API_VISIBILITY - -#ifndef ECSACTSI_WASM_API -# ifdef __cplusplus -# define ECSACTSI_WASM_API extern "C" ECSACTSI_WASM_API_VISIBILITY -# else -# define ECSACTSI_WASM_API extern ECSACTSI_WASM_API_VISIBILITY -# endif -#endif // ECSACTSI_WASM_API - -#ifndef ECSACTSI_WASM_API_FN -# ifdef ECSACTSI_WASM_API_LOAD_AT_RUNTIME -# define ECSACTSI_WASM_API_FN(ret, name) ECSACTSI_WASM_API ret(*name) -# else -# define ECSACTSI_WASM_API_FN(ret, name) ECSACTSI_WASM_API ret name -# endif -#endif // ECSACTSI_WASM_API_FN - -typedef enum ecsactsi_wasm_error { - /** - * No error. - */ - ECSACTSI_WASM_OK, - - /** - * Unable to open WASM file. - */ - ECSACTSI_WASM_ERR_FILE_OPEN_FAIL, - - /** - * Unable to read WASM file. - */ - ECSACTSI_WASM_ERR_FILE_READ_FAIL, - - /** - * Unable to compile WASM file module. - */ - ECSACTSI_WASM_ERR_COMPILE_FAIL, - - /** - * Unable to instantiate WASM file module. - */ - ECSACTSI_WASM_ERR_INSTANTIATE_FAIL, - - /** - * Export name was not found in WASM file. - */ - ECSACTSI_WASM_ERR_EXPORT_NOT_FOUND, - - /** - * Export name was found, but was not a function. - */ - ECSACTSI_WASM_ERR_EXPORT_INVALID, - - /** - * WASM file contains an unknown guest import. - */ - ECSACTSI_WASM_ERR_GUEST_IMPORT_UNKNOWN, - - /** - * WASM file contains correctly named guest import, but was not a function - */ - ECSACTSI_WASM_ERR_GUEST_IMPORT_INVALID, - - /** - * Invoking `_initialize()` resulted in a wasm trap - */ - ECSACTSI_WASM_ERR_INITIALIZE_FAIL, -} ecsactsi_wasm_error; - -ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_last_error_message) -( // - char* out_message, - int32_t out_message_max_length -); - -ECSACTSI_WASM_API_FN(int32_t, ecsactsi_wasm_last_error_message_length)(); - -/** - * Load WASM file at path `wasm_file_path` and call - * `ecsact_set_system_execution_impl` for the specified `system_ids` matching - * the `wasm_exports` names. - * @param wasm_file_path path to WASM file - * @param systems_count Length of `system_ids` and `wasm_exports` - * @param system_ids Sequential array of system ids that will have their system - * implementations set to by the wasm exports dicated by `wasm_exports` - * in the same order. Length is determined by `systems_count`. - * @param wasm_exports Sequential array of wasm export names used as system - * implementations in the same order as `system_ids`. Length is - * determined by `systems_count`. - * @return `ECSACTSI_WASM_OK` if no error. If there is an error for _any_ of the - * systems then **none of the systems are loaded**. - */ -ECSACTSI_WASM_API_FN(ecsactsi_wasm_error, ecsactsi_wasm_load_file) -( // - const char* wasm_file_path, - int systems_count, - ecsact_system_like_id* system_ids, - const char** wasm_exports -); - -ECSACTSI_WASM_API_FN(ecsactsi_wasm_error, ecsactsi_wasm_load) -( // - char* wasm_data, - int wasm_data_size, - int systems_count, - ecsact_system_like_id* system_ids, - const char** wasm_exports -); - -/** - * Unload 1 or more systems. If a system is not already loaded this is a noop. - * @param systems_count number of systems impls to unload - * @param system_ids array of system IDs to unload. Sequential list length of - * @p systems_count. - */ -ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_unload) -( // - int systems_count, - ecsact_system_like_id* system_ids -); - -/** - * Reset state. Effectively called `ecsactsi_wasm_unload` for each system - * implementation and clears the trap handler. - */ -ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_reset)(); - -/** - * @param system_id System ID associated with the impl that triggered the trap - * @param trap_message The trap message contents. Null-terminated string. - */ -typedef void (*ecsactsi_wasm_trap_handler)( // - ecsact_system_like_id system_id, - const char* trap_message -); - -/** - * Register a function to be called when a system implementation trap occurs. It - * is recommended that a trap handler is set otherwise the trap message will be - * quietly discarded. - * @param handler The handler function that will be called when a system impl - * function trap occurs. Calling this overwrites the last handler. May be - * `NULL` to remove the current handler. - */ -ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_set_trap_handler) -( // - ecsactsi_wasm_trap_handler handler -); - -typedef enum ecsactsi_wasm_log_level { - ECSACTSI_WASM_LOG_LEVEL_INFO = 0, - ECSACTSI_WASM_LOG_LEVEL_WARNING = 1, - ECSACTSI_WASM_LOG_LEVEL_ERROR = 2, -} ecsactsi_wasm_log_level; - -typedef void (*ecsactsi_wasm_log_consumer)( // - ecsactsi_wasm_log_level log_level, - const char* message, - int32_t message_length, - void* user_data -); - -/** - * Invokes @p consumer for 1 or more lines that have been printed to stdout or - * stderr between the last `ecsactsi_wasm_consume_logs` call until there are no - * more lines left to consume. - */ -ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_consume_logs) -( // - ecsactsi_wasm_log_consumer consumer, - void* consumer_user_data -); - -/** - * Expose a file on the host for read access during initialization. - */ -ECSACTSI_WASM_API_FN(int32_t, ecsactsi_wasm_allow_file_read_access) -( // - const char* real_file_path, - int32_t real_file_path_length, - const char* virtual_file_path, - int32_t virtual_file_path_length -); - -#endif // ECSACTSI_WASM_H +/** + * @file + * @brief Ecsact System Implementation with WebAssembly header + */ + +#ifndef ECSACTSI_WASM_H +#define ECSACTSI_WASM_H + +#include "ecsact/runtime/common.h" + +#ifndef ECSACTSI_WASM_API_VISIBILITY +# ifdef ECSACTSI_WASM_API_LOAD_AT_RUNTIME +# define ECSACTSI_WASM_API_VISIBILITY +# else +# ifdef ECSACTSI_WASM_API_EXPORT +# ifdef _WIN32 +# define ECSACTSI_WASM_API_VISIBILITY __declspec(dllexport) +# else +# define ECSACTSI_WASM_API_VISIBILITY \ + __attribute__((visibility("default"))) +# endif +# else +# ifdef _WIN32 +# define ECSACTSI_WASM_API_VISIBILITY __declspec(dllimport) +# else +# define ECSACTSI_WASM_API_VISIBILITY +# endif +# endif +# endif +#endif // ECSACTSI_WASM_API_VISIBILITY + +#ifndef ECSACTSI_WASM_API +# ifdef __cplusplus +# define ECSACTSI_WASM_API extern "C" ECSACTSI_WASM_API_VISIBILITY +# else +# define ECSACTSI_WASM_API extern ECSACTSI_WASM_API_VISIBILITY +# endif +#endif // ECSACTSI_WASM_API + +#ifndef ECSACTSI_WASM_API_FN +# ifdef ECSACTSI_WASM_API_LOAD_AT_RUNTIME +# define ECSACTSI_WASM_API_FN(ret, name) ECSACTSI_WASM_API ret(*name) +# else +# define ECSACTSI_WASM_API_FN(ret, name) ECSACTSI_WASM_API ret name +# endif +#endif // ECSACTSI_WASM_API_FN + +typedef enum ecsactsi_wasm_error { + /** + * No error. + */ + ECSACTSI_WASM_OK, + + /** + * Unable to open WASM file. + */ + ECSACTSI_WASM_ERR_FILE_OPEN_FAIL, + + /** + * Unable to read WASM file. + */ + ECSACTSI_WASM_ERR_FILE_READ_FAIL, + + /** + * Unable to compile WASM file module. + */ + ECSACTSI_WASM_ERR_COMPILE_FAIL, + + /** + * Unable to instantiate WASM file module. + */ + ECSACTSI_WASM_ERR_INSTANTIATE_FAIL, + + /** + * Export name was not found in WASM file. + */ + ECSACTSI_WASM_ERR_EXPORT_NOT_FOUND, + + /** + * Export name was found, but was not a function. + */ + ECSACTSI_WASM_ERR_EXPORT_INVALID, + + /** + * WASM file contains an unknown guest import. + */ + ECSACTSI_WASM_ERR_GUEST_IMPORT_UNKNOWN, + + /** + * WASM file contains correctly named guest import, but was not a function + */ + ECSACTSI_WASM_ERR_GUEST_IMPORT_INVALID, + + /** + * Invoking `_initialize()` resulted in a wasm trap + */ + ECSACTSI_WASM_ERR_INITIALIZE_FAIL, +} ecsactsi_wasm_error; + +ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_last_error_message) +( // + char* out_message, + int32_t out_message_max_length +); + +ECSACTSI_WASM_API_FN(int32_t, ecsactsi_wasm_last_error_message_length)(); + +/** + * Load WASM file at path `wasm_file_path` and call + * `ecsact_set_system_execution_impl` for the specified `system_ids` matching + * the `wasm_exports` names. + * @param wasm_file_path path to WASM file + * @param systems_count Length of `system_ids` and `wasm_exports` + * @param system_ids Sequential array of system ids that will have their system + * implementations set to by the wasm exports dicated by `wasm_exports` + * in the same order. Length is determined by `systems_count`. + * @param wasm_exports Sequential array of wasm export names used as system + * implementations in the same order as `system_ids`. Length is + * determined by `systems_count`. + * @return `ECSACTSI_WASM_OK` if no error. If there is an error for _any_ of the + * systems then **none of the systems are loaded**. + */ +ECSACTSI_WASM_API_FN(ecsactsi_wasm_error, ecsactsi_wasm_load_file) +( // + const char* wasm_file_path, + int systems_count, + ecsact_system_like_id* system_ids, + const char** wasm_exports +); + +ECSACTSI_WASM_API_FN(ecsactsi_wasm_error, ecsactsi_wasm_load) +( // + char* wasm_data, + int wasm_data_size, + int systems_count, + ecsact_system_like_id* system_ids, + const char** wasm_exports +); + +/** + * Unload 1 or more systems. If a system is not already loaded this is a noop. + * @param systems_count number of systems impls to unload + * @param system_ids array of system IDs to unload. Sequential list length of + * @p systems_count. + */ +ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_unload) +( // + int systems_count, + ecsact_system_like_id* system_ids +); + +/** + * Reset state. Effectively called `ecsactsi_wasm_unload` for each system + * implementation and clears the trap handler. + */ +ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_reset)(); + +/** + * @param system_id System ID associated with the impl that triggered the trap + * @param trap_message The trap message contents. Null-terminated string. + */ +typedef void (*ecsactsi_wasm_trap_handler)( // + ecsact_system_like_id system_id, + const char* trap_message +); + +/** + * Register a function to be called when a system implementation trap occurs. It + * is recommended that a trap handler is set otherwise the trap message will be + * quietly discarded. + * @param handler The handler function that will be called when a system impl + * function trap occurs. Calling this overwrites the last handler. May be + * `NULL` to remove the current handler. + */ +ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_set_trap_handler) +( // + ecsactsi_wasm_trap_handler handler +); + +typedef enum ecsactsi_wasm_log_level { + ECSACTSI_WASM_LOG_LEVEL_INFO = 0, + ECSACTSI_WASM_LOG_LEVEL_WARNING = 1, + ECSACTSI_WASM_LOG_LEVEL_ERROR = 2, +} ecsactsi_wasm_log_level; + +typedef void (*ecsactsi_wasm_log_consumer)( // + ecsactsi_wasm_log_level log_level, + const char* message, + int32_t message_length, + void* user_data +); + +/** + * Invokes @p consumer for 1 or more lines that have been printed to stdout or + * stderr between the last `ecsactsi_wasm_consume_logs` call until there are no + * more lines left to consume. + */ +ECSACTSI_WASM_API_FN(void, ecsactsi_wasm_consume_logs) +( // + ecsactsi_wasm_log_consumer consumer, + void* consumer_user_data +); + +/** + * Expose a file on the host for read access during initialization. + */ +ECSACTSI_WASM_API_FN(int32_t, ecsactsi_wasm_allow_file_read_access) +( // + const char* real_file_path, + int32_t real_file_path_length, + const char* virtual_file_path, + int32_t virtual_file_path_length +); + +#endif // ECSACTSI_WASM_H diff --git a/ecsact/wasm/detail/guest_imports/README.md b/ecsact/wasm/detail/guest_imports/README.md index 3636197..e0f89fb 100644 --- a/ecsact/wasm/detail/guest_imports/README.md +++ b/ecsact/wasm/detail/guest_imports/README.md @@ -1 +1 @@ -Each header in this folder represents a WASM guest import module. +Each header in this folder represents a WASM guest import module. diff --git a/ecsact/wasm/detail/guest_imports/env.hh b/ecsact/wasm/detail/guest_imports/env.hh index bfb1558..deff809 100644 --- a/ecsact/wasm/detail/guest_imports/env.hh +++ b/ecsact/wasm/detail/guest_imports/env.hh @@ -1,151 +1,151 @@ -#pragma once - -#include "ecsact/wasm/detail/guest_imports.hh" -#include "ecsact/wasm/detail/util.hh" -#include "ecsact/wasm/detail/wasm_ecsact_system_execution.h" - -namespace ecsact::wasm::detail { - -const auto guest_env_module_imports = allowed_guest_imports_t{ - { - "ecsact_system_execution_context_action", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_2_0( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32) // out_action_data - ), - &wasm_ecsact_system_execution_context_action, - }; - }, - }, - { - "ecsact_system_execution_context_parent", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_1_1( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32) // parent context (return) - ), - &wasm_ecsact_system_execution_context_parent, - }; - }, - }, - { - "ecsact_system_execution_context_same", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_2_1( - wasm_valtype_new(WASM_I32), // context a - wasm_valtype_new(WASM_I32), // context b - wasm_valtype_new(WASM_I32) // same bool (return) - ), - &wasm_ecsact_system_execution_context_same, - }; - }, - }, - { - "ecsact_system_execution_context_get", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_3_0( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32), // component_id - wasm_valtype_new(WASM_I32) // out_component_data - ), - &wasm_ecsact_system_execution_context_get, - }; - }, - }, - { - "ecsact_system_execution_context_update", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_3_0( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32), // component_id - wasm_valtype_new(WASM_I32) // component_data - ), - &wasm_ecsact_system_execution_context_update, - }; - }, - }, - { - "ecsact_system_execution_context_has", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_2_0( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32) // component_id - ), - &wasm_ecsact_system_execution_context_has, - }; - }, - }, - { - "ecsact_system_execution_context_generate", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_4_0( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32), // component_count - wasm_valtype_new(WASM_I32), // component_ids - wasm_valtype_new(WASM_I32) // components_data - ), - &wasm_ecsact_system_execution_context_generate, - }; - }, - }, - { - "ecsact_system_execution_context_add", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_3_0( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32), // component_id - wasm_valtype_new(WASM_I32) // component_data - ), - &wasm_ecsact_system_execution_context_add, - }; - }, - }, - { - "ecsact_system_execution_context_remove", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_2_0( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32) // component_id - ), - &wasm_ecsact_system_execution_context_remove, - }; - }, - }, - { - "ecsact_system_execution_context_other", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_2_1( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32), // entity_id - wasm_valtype_new(WASM_I32) // other context (return) - ), - &wasm_ecsact_system_execution_context_other, - }; - }, - }, - { - "ecsact_system_execution_context_entity", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_1_1( - wasm_valtype_new(WASM_I32), // context - wasm_valtype_new(WASM_I32) // entity 9return) - ), - &wasm_ecsact_system_execution_context_entity, - }; - }, - }, -}; - -} // namespace ecsact::wasm::detail +#pragma once + +#include "ecsact/wasm/detail/guest_imports.hh" +#include "ecsact/wasm/detail/util.hh" +#include "ecsact/wasm/detail/wasm_ecsact_system_execution.h" + +namespace ecsact::wasm::detail { + +const auto guest_env_module_imports = allowed_guest_imports_t{ + { + "ecsact_system_execution_context_action", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_2_0( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32) // out_action_data + ), + &wasm_ecsact_system_execution_context_action, + }; + }, + }, + { + "ecsact_system_execution_context_parent", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_1_1( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32) // parent context (return) + ), + &wasm_ecsact_system_execution_context_parent, + }; + }, + }, + { + "ecsact_system_execution_context_same", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_2_1( + wasm_valtype_new(WASM_I32), // context a + wasm_valtype_new(WASM_I32), // context b + wasm_valtype_new(WASM_I32) // same bool (return) + ), + &wasm_ecsact_system_execution_context_same, + }; + }, + }, + { + "ecsact_system_execution_context_get", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_3_0( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32), // component_id + wasm_valtype_new(WASM_I32) // out_component_data + ), + &wasm_ecsact_system_execution_context_get, + }; + }, + }, + { + "ecsact_system_execution_context_update", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_3_0( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32), // component_id + wasm_valtype_new(WASM_I32) // component_data + ), + &wasm_ecsact_system_execution_context_update, + }; + }, + }, + { + "ecsact_system_execution_context_has", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_2_0( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32) // component_id + ), + &wasm_ecsact_system_execution_context_has, + }; + }, + }, + { + "ecsact_system_execution_context_generate", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_4_0( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32), // component_count + wasm_valtype_new(WASM_I32), // component_ids + wasm_valtype_new(WASM_I32) // components_data + ), + &wasm_ecsact_system_execution_context_generate, + }; + }, + }, + { + "ecsact_system_execution_context_add", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_3_0( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32), // component_id + wasm_valtype_new(WASM_I32) // component_data + ), + &wasm_ecsact_system_execution_context_add, + }; + }, + }, + { + "ecsact_system_execution_context_remove", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_2_0( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32) // component_id + ), + &wasm_ecsact_system_execution_context_remove, + }; + }, + }, + { + "ecsact_system_execution_context_other", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_2_1( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32), // entity_id + wasm_valtype_new(WASM_I32) // other context (return) + ), + &wasm_ecsact_system_execution_context_other, + }; + }, + }, + { + "ecsact_system_execution_context_entity", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_1_1( + wasm_valtype_new(WASM_I32), // context + wasm_valtype_new(WASM_I32) // entity 9return) + ), + &wasm_ecsact_system_execution_context_entity, + }; + }, + }, +}; + +} // namespace ecsact::wasm::detail diff --git a/ecsact/wasm/detail/guest_imports/wasi_snapshot_preview1.hh b/ecsact/wasm/detail/guest_imports/wasi_snapshot_preview1.hh index f77ca06..0548f95 100644 --- a/ecsact/wasm/detail/guest_imports/wasi_snapshot_preview1.hh +++ b/ecsact/wasm/detail/guest_imports/wasi_snapshot_preview1.hh @@ -1,118 +1,118 @@ -#pragma once - -#include "ecsact/wasm/detail/guest_imports.hh" -#include "ecsact/wasm/detail/util.hh" -#include "ecsact/wasm/detail/wasi.hh" - -namespace ecsact::wasm::detail { -const auto guest_wasi_module_imports = allowed_guest_imports_t{ - { - "proc_exit", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_1_0( // - wasm_valtype_new(WASM_I32) // exit_code - ), - &ecsactsi_wasi_proc_exit, - }; - }, - }, - { - "fd_seek", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_4_1( - wasm_valtype_new_i32(), // fd - wasm_valtype_new_i64(), // offset - wasm_valtype_new_i32(), // whence - wasm_valtype_new_i32(), // retptr0 - wasm_valtype_new_i32() // error code (return) - ), - &ecsactsi_wasi_fd_seek, - }; - }, - }, - { - "fd_write", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_4_1( - wasm_valtype_new_i32(), // fd - wasm_valtype_new_i32(), // iovs - wasm_valtype_new_i32(), // iovs_len - wasm_valtype_new_i32(), // retptr0 - wasm_valtype_new_i32() // error code (return) - ), - &ecsactsi_wasi_fd_write, - }; - }, - }, - { - "fd_read", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_4_1( - wasm_valtype_new_i32(), // fd - wasm_valtype_new_i32(), // iovs - wasm_valtype_new_i32(), // iovs_len - wasm_valtype_new_i32(), // retptr0 - wasm_valtype_new_i32() // error code (return) - ), - &ecsactsi_wasi_fd_read, - }; - }, - }, - { - "fd_close", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_1_1( - wasm_valtype_new_i32(), // fd - wasm_valtype_new_i32() // error code (return) - ), - &ecsactsi_wasi_fd_close, - }; - }, - }, - { - "environ_sizes_get", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_2_1( - wasm_valtype_new_i32(), // retptr0 - wasm_valtype_new_i32(), // retptr1 - wasm_valtype_new_i32() // error code (return) - ), - &ecsactsi_wasi_environ_sizes_get, - }; - }, - }, - { - "environ_get", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_2_1( - wasm_valtype_new_i32(), // environ - wasm_valtype_new_i32(), // environ_buf - wasm_valtype_new_i32() // error code (return) - ), - &ecsactsi_wasi_environ_get, - }; - }, - }, - { - "fd_fdstat_get", - []() -> minst_import_resolve_func { - return { - wasm_functype_new_2_1( - wasm_valtype_new_i32(), // fd - wasm_valtype_new_i32(), // retptr0 - wasm_valtype_new_i32() // error code (return) - ), - &ecsactsi_wasi_fd_fdstat_get, - }; - }, - }, -}; - -} // namespace ecsact::wasm::detail +#pragma once + +#include "ecsact/wasm/detail/guest_imports.hh" +#include "ecsact/wasm/detail/util.hh" +#include "ecsact/wasm/detail/wasi.hh" + +namespace ecsact::wasm::detail { +const auto guest_wasi_module_imports = allowed_guest_imports_t{ + { + "proc_exit", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_1_0( // + wasm_valtype_new(WASM_I32) // exit_code + ), + &ecsactsi_wasi_proc_exit, + }; + }, + }, + { + "fd_seek", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_4_1( + wasm_valtype_new_i32(), // fd + wasm_valtype_new_i64(), // offset + wasm_valtype_new_i32(), // whence + wasm_valtype_new_i32(), // retptr0 + wasm_valtype_new_i32() // error code (return) + ), + &ecsactsi_wasi_fd_seek, + }; + }, + }, + { + "fd_write", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_4_1( + wasm_valtype_new_i32(), // fd + wasm_valtype_new_i32(), // iovs + wasm_valtype_new_i32(), // iovs_len + wasm_valtype_new_i32(), // retptr0 + wasm_valtype_new_i32() // error code (return) + ), + &ecsactsi_wasi_fd_write, + }; + }, + }, + { + "fd_read", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_4_1( + wasm_valtype_new_i32(), // fd + wasm_valtype_new_i32(), // iovs + wasm_valtype_new_i32(), // iovs_len + wasm_valtype_new_i32(), // retptr0 + wasm_valtype_new_i32() // error code (return) + ), + &ecsactsi_wasi_fd_read, + }; + }, + }, + { + "fd_close", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_1_1( + wasm_valtype_new_i32(), // fd + wasm_valtype_new_i32() // error code (return) + ), + &ecsactsi_wasi_fd_close, + }; + }, + }, + { + "environ_sizes_get", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_2_1( + wasm_valtype_new_i32(), // retptr0 + wasm_valtype_new_i32(), // retptr1 + wasm_valtype_new_i32() // error code (return) + ), + &ecsactsi_wasi_environ_sizes_get, + }; + }, + }, + { + "environ_get", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_2_1( + wasm_valtype_new_i32(), // environ + wasm_valtype_new_i32(), // environ_buf + wasm_valtype_new_i32() // error code (return) + ), + &ecsactsi_wasi_environ_get, + }; + }, + }, + { + "fd_fdstat_get", + []() -> minst_import_resolve_func { + return { + wasm_functype_new_2_1( + wasm_valtype_new_i32(), // fd + wasm_valtype_new_i32(), // retptr0 + wasm_valtype_new_i32() // error code (return) + ), + &ecsactsi_wasi_fd_fdstat_get, + }; + }, + }, +}; + +} // namespace ecsact::wasm::detail diff --git a/ecsact/wasm/detail/util.hh b/ecsact/wasm/detail/util.hh index 42d1ec3..51facfb 100644 --- a/ecsact/wasm/detail/util.hh +++ b/ecsact/wasm/detail/util.hh @@ -1,43 +1,43 @@ -#pragma once - -#include - -namespace ecsact::wasm::detail { - -inline wasm_functype_t* wasm_functype_new_4_0( - wasm_valtype_t* p1, - wasm_valtype_t* p2, - wasm_valtype_t* p3, - wasm_valtype_t* p4 -) { - wasm_valtype_t* ps[4] = {p1, p2, p3, p4}; - wasm_valtype_vec_t params, results; - wasm_valtype_vec_new(¶ms, 4, ps); - wasm_valtype_vec_new_empty(&results); - return wasm_functype_new(¶ms, &results); -} - -inline wasm_functype_t* wasm_functype_new_4_1( - wasm_valtype_t* p1, - wasm_valtype_t* p2, - wasm_valtype_t* p3, - wasm_valtype_t* p4, - wasm_valtype_t* r -) { - wasm_valtype_t* rs[1] = {r}; - wasm_valtype_t* ps[4] = {p1, p2, p3, p4}; - wasm_valtype_vec_t params, results; - wasm_valtype_vec_new(¶ms, 4, ps); - wasm_valtype_vec_new(&results, 1, rs); - return wasm_functype_new(¶ms, &results); -} - -template -auto wasm_memory_cast( // - wasm_memory_t* wasm_mem, - int32_t wasm_guest_ptr -) -> T* { - auto mem_bytes = wasm_memory_data(wasm_mem); - return reinterpret_cast(mem_bytes + wasm_guest_ptr); -} -} // namespace ecsact::wasm::detail +#pragma once + +#include + +namespace ecsact::wasm::detail { + +inline wasm_functype_t* wasm_functype_new_4_0( + wasm_valtype_t* p1, + wasm_valtype_t* p2, + wasm_valtype_t* p3, + wasm_valtype_t* p4 +) { + wasm_valtype_t* ps[4] = {p1, p2, p3, p4}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 4, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +inline wasm_functype_t* wasm_functype_new_4_1( + wasm_valtype_t* p1, + wasm_valtype_t* p2, + wasm_valtype_t* p3, + wasm_valtype_t* p4, + wasm_valtype_t* r +) { + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_t* ps[4] = {p1, p2, p3, p4}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 4, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +template +auto wasm_memory_cast( // + wasm_memory_t* wasm_mem, + int32_t wasm_guest_ptr +) -> T* { + auto mem_bytes = wasm_memory_data(wasm_mem); + return reinterpret_cast(mem_bytes + wasm_guest_ptr); +} +} // namespace ecsact::wasm::detail diff --git a/ecsact/wasm/detail/wasi.cc b/ecsact/wasm/detail/wasi.cc index 614341a..380977f 100644 --- a/ecsact/wasm/detail/wasi.cc +++ b/ecsact/wasm/detail/wasi.cc @@ -1,245 +1,245 @@ -#include "ecsact/wasm/detail/wasi.hh" - -#include -#include -#include -#include "ecsact/wasm/detail/wasi_fs.hh" -#include "ecsact/wasm/detail/logger.hh" -#include "ecsact/wasm/detail/mem_stack.hh" -#include "ecsact/wasm/detail/util.hh" - -using ecsact::wasm::detail::call_mem_read; -using ecsact::wasm::detail::debug_trace_method; -using ecsact::wasm::detail::wasm_memory_cast; - -constexpr int32_t WASI_STDIN_FD = 0; -constexpr int32_t WASI_STDOUT_FD = 1; -constexpr int32_t WASI_STDERR_FD = 2; - -wasm_trap_t* ecsactsi_wasi_proc_exit( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -) { - debug_trace_method("proc_exit"); - return nullptr; -} - -wasm_trap_t* ecsactsi_wasi_fd_seek( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -) { - debug_trace_method("fd_seek"); - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 0; - - return nullptr; -} - -wasm_trap_t* ecsactsi_wasi_fd_write( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -) { - debug_trace_method("fd_write"); - auto mem = call_mem_read(0); - assert(args->data[0].kind == WASM_I32); - auto fd = args->data[0].of.i32; - - assert(args->data[1].kind == WASM_I32); - auto iovec = - wasm_memory_cast(mem, args->data[1].of.i32); - - assert(args->data[2].kind == WASM_I32); - auto iovec_len = args->data[2].of.i32; - - assert(args->data[3].kind == WASM_I32); - auto out_write_amount = wasm_memory_cast(mem, args->data[3].of.i32); - - if(fd == WASI_STDERR_FD || fd == WASI_STDOUT_FD) { - auto write_amount = size_t{}; - auto log_level = fd == WASI_STDOUT_FD // - ? ECSACTSI_WASM_LOG_LEVEL_INFO - : ECSACTSI_WASM_LOG_LEVEL_ERROR; - - for(int i = 0; iovec_len > i; ++i) { - auto io = iovec[i]; - - if(io.buf_len > 0) { - auto buf = wasm_memory_cast(mem, io.buf); - auto str = std::string_view(buf, io.buf_len); - write_amount += io.buf_len; - ecsact::wasm::detail::push_stdio_str(log_level, str); - } - } - - *out_write_amount = write_amount; - - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 0; - } else { - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 1; - } - - return nullptr; -} - -wasm_trap_t* ecsactsi_wasi_fd_read( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -) { - debug_trace_method("fd_read"); - auto mem = call_mem_read(0); - assert(args->data[0].kind == WASM_I32); - auto fd = args->data[0].of.i32; - - assert(args->data[1].kind == WASM_I32); - auto iovec = - wasm_memory_cast(mem, args->data[1].of.i32); - - assert(args->data[2].kind == WASM_I32); - auto iovec_len = args->data[2].of.i32; - - assert(args->data[3].kind == WASM_I32); - auto out_read_amount = wasm_memory_cast(mem, args->data[3].of.i32); - - auto f = ecsact::wasm::detail::wasi::fs::ensure_open(fd); - auto read_amount = size_t{}; - - for(int i = 0; iovec_len > i; ++i) { - auto io = iovec[i]; - - if(io.buf_len > 0) { - auto buf = wasm_memory_cast(mem, io.buf); - read_amount += std::fread(buf, 1, io.buf_len, f); - } - } - - *out_read_amount = read_amount; - - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 0; - - return nullptr; -} - -wasm_trap_t* ecsactsi_wasi_fd_close( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -) { - debug_trace_method("fd_close"); - assert(args->data[0].kind == WASM_I32); - auto fd = args->data[0].of.i32; - - if(fd != WASI_STDOUT_FD && fd != WASI_STDERR_FD && fd != WASI_STDIN_FD) { - ecsact::wasm::detail::wasi::fs::close(fd); - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 0; - } else { - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 1; - } - - return nullptr; -} - -wasm_trap_t* ecsactsi_wasi_environ_sizes_get( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -) { - debug_trace_method("environ_sizes_get"); - auto mem = call_mem_read(0); - auto retptr0 = wasm_memory_cast(mem, args->data[0].of.i32); - auto retptr1 = wasm_memory_cast(mem, args->data[1].of.i32); - - *retptr0 = 0; - *retptr1 = 0; - - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 0; - - return nullptr; -} - -wasm_trap_t* ecsactsi_wasi_environ_get( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -) { - debug_trace_method("environ_get"); - auto mem = call_mem_read(0); - auto environ_arg = wasm_memory_cast(mem, args->data[0].of.i32); - auto environ_buf_arg = wasm_memory_cast(mem, args->data[1].of.i32); - - // Even though our environment variable size is `0` the API expects the key - // values pairs to be null terminated. - environ_arg[0] = '\0'; - environ_buf_arg[0] = '\0'; - - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 0; - - return nullptr; -} - -wasm_trap_t* ecsactsi_wasi_fd_fdstat_get( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -) { - debug_trace_method("fd_fdstat_get"); - const auto default_fdstats = std::map{ - { - WASI_STDIN_FD, - ecsactsi_wasi_fdstat_t{}, - }, - { - WASI_STDOUT_FD, - ecsactsi_wasi_fdstat_t{ - .fs_filetype = ecsactsi_wasi_filetype::character_device, - .fs_flags = {}, - .fs_rights_base = ecsactsi_wasi_rights::fd_datasync | - ecsactsi_wasi_rights::fd_sync | ecsactsi_wasi_rights::fd_write | - ecsactsi_wasi_rights::fd_advise | - ecsactsi_wasi_rights::fd_filestat_get | - ecsactsi_wasi_rights::poll_fd_readwrite, - .fs_rights_inheriting = {}, - }, - }, - { - WASI_STDERR_FD, - ecsactsi_wasi_fdstat_t{ - .fs_filetype = ecsactsi_wasi_filetype::character_device, - .fs_flags = {}, - .fs_rights_base = ecsactsi_wasi_rights::fd_datasync | - ecsactsi_wasi_rights::fd_sync | ecsactsi_wasi_rights::fd_write | - ecsactsi_wasi_rights::fd_advise | - ecsactsi_wasi_rights::fd_filestat_get | - ecsactsi_wasi_rights::poll_fd_readwrite, - .fs_rights_inheriting = {}, - }, - }, - }; - - auto mem = call_mem_read(0); - - assert(args->data[0].kind == WASM_I32); - auto fd = args->data[0].of.i32; - - assert(args->data[1].kind == WASM_I32); - auto ret = - wasm_memory_cast(mem, args->data[1].of.i32); - - if(default_fdstats.contains(fd)) { - *ret = default_fdstats.at(fd); - } else { - *ret = ecsact::wasm::detail::wasi::fs::fdstat(fd); - } - - if(ret->fs_filetype != ecsactsi_wasi_filetype::unknown) { - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 0; - } else { - results->data[0].kind = WASM_I32; - results->data[0].of.i32 = 1; - } - - return nullptr; -} +#include "ecsact/wasm/detail/wasi.hh" + +#include +#include +#include +#include "ecsact/wasm/detail/wasi_fs.hh" +#include "ecsact/wasm/detail/logger.hh" +#include "ecsact/wasm/detail/mem_stack.hh" +#include "ecsact/wasm/detail/util.hh" + +using ecsact::wasm::detail::call_mem_read; +using ecsact::wasm::detail::debug_trace_method; +using ecsact::wasm::detail::wasm_memory_cast; + +constexpr int32_t WASI_STDIN_FD = 0; +constexpr int32_t WASI_STDOUT_FD = 1; +constexpr int32_t WASI_STDERR_FD = 2; + +wasm_trap_t* ecsactsi_wasi_proc_exit( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +) { + debug_trace_method("proc_exit"); + return nullptr; +} + +wasm_trap_t* ecsactsi_wasi_fd_seek( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +) { + debug_trace_method("fd_seek"); + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 0; + + return nullptr; +} + +wasm_trap_t* ecsactsi_wasi_fd_write( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +) { + debug_trace_method("fd_write"); + auto mem = call_mem_read(0); + assert(args->data[0].kind == WASM_I32); + auto fd = args->data[0].of.i32; + + assert(args->data[1].kind == WASM_I32); + auto iovec = + wasm_memory_cast(mem, args->data[1].of.i32); + + assert(args->data[2].kind == WASM_I32); + auto iovec_len = args->data[2].of.i32; + + assert(args->data[3].kind == WASM_I32); + auto out_write_amount = wasm_memory_cast(mem, args->data[3].of.i32); + + if(fd == WASI_STDERR_FD || fd == WASI_STDOUT_FD) { + auto write_amount = size_t{}; + auto log_level = fd == WASI_STDOUT_FD // + ? ECSACTSI_WASM_LOG_LEVEL_INFO + : ECSACTSI_WASM_LOG_LEVEL_ERROR; + + for(int i = 0; iovec_len > i; ++i) { + auto io = iovec[i]; + + if(io.buf_len > 0) { + auto buf = wasm_memory_cast(mem, io.buf); + auto str = std::string_view(buf, io.buf_len); + write_amount += io.buf_len; + ecsact::wasm::detail::push_stdio_str(log_level, str); + } + } + + *out_write_amount = write_amount; + + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 0; + } else { + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 1; + } + + return nullptr; +} + +wasm_trap_t* ecsactsi_wasi_fd_read( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +) { + debug_trace_method("fd_read"); + auto mem = call_mem_read(0); + assert(args->data[0].kind == WASM_I32); + auto fd = args->data[0].of.i32; + + assert(args->data[1].kind == WASM_I32); + auto iovec = + wasm_memory_cast(mem, args->data[1].of.i32); + + assert(args->data[2].kind == WASM_I32); + auto iovec_len = args->data[2].of.i32; + + assert(args->data[3].kind == WASM_I32); + auto out_read_amount = wasm_memory_cast(mem, args->data[3].of.i32); + + auto f = ecsact::wasm::detail::wasi::fs::ensure_open(fd); + auto read_amount = size_t{}; + + for(int i = 0; iovec_len > i; ++i) { + auto io = iovec[i]; + + if(io.buf_len > 0) { + auto buf = wasm_memory_cast(mem, io.buf); + read_amount += std::fread(buf, 1, io.buf_len, f); + } + } + + *out_read_amount = read_amount; + + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 0; + + return nullptr; +} + +wasm_trap_t* ecsactsi_wasi_fd_close( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +) { + debug_trace_method("fd_close"); + assert(args->data[0].kind == WASM_I32); + auto fd = args->data[0].of.i32; + + if(fd != WASI_STDOUT_FD && fd != WASI_STDERR_FD && fd != WASI_STDIN_FD) { + ecsact::wasm::detail::wasi::fs::close(fd); + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 0; + } else { + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 1; + } + + return nullptr; +} + +wasm_trap_t* ecsactsi_wasi_environ_sizes_get( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +) { + debug_trace_method("environ_sizes_get"); + auto mem = call_mem_read(0); + auto retptr0 = wasm_memory_cast(mem, args->data[0].of.i32); + auto retptr1 = wasm_memory_cast(mem, args->data[1].of.i32); + + *retptr0 = 0; + *retptr1 = 0; + + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 0; + + return nullptr; +} + +wasm_trap_t* ecsactsi_wasi_environ_get( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +) { + debug_trace_method("environ_get"); + auto mem = call_mem_read(0); + auto environ_arg = wasm_memory_cast(mem, args->data[0].of.i32); + auto environ_buf_arg = wasm_memory_cast(mem, args->data[1].of.i32); + + // Even though our environment variable size is `0` the API expects the key + // values pairs to be null terminated. + environ_arg[0] = '\0'; + environ_buf_arg[0] = '\0'; + + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 0; + + return nullptr; +} + +wasm_trap_t* ecsactsi_wasi_fd_fdstat_get( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +) { + debug_trace_method("fd_fdstat_get"); + const auto default_fdstats = std::map{ + { + WASI_STDIN_FD, + ecsactsi_wasi_fdstat_t{}, + }, + { + WASI_STDOUT_FD, + ecsactsi_wasi_fdstat_t{ + .fs_filetype = ecsactsi_wasi_filetype::character_device, + .fs_flags = {}, + .fs_rights_base = ecsactsi_wasi_rights::fd_datasync | + ecsactsi_wasi_rights::fd_sync | ecsactsi_wasi_rights::fd_write | + ecsactsi_wasi_rights::fd_advise | + ecsactsi_wasi_rights::fd_filestat_get | + ecsactsi_wasi_rights::poll_fd_readwrite, + .fs_rights_inheriting = {}, + }, + }, + { + WASI_STDERR_FD, + ecsactsi_wasi_fdstat_t{ + .fs_filetype = ecsactsi_wasi_filetype::character_device, + .fs_flags = {}, + .fs_rights_base = ecsactsi_wasi_rights::fd_datasync | + ecsactsi_wasi_rights::fd_sync | ecsactsi_wasi_rights::fd_write | + ecsactsi_wasi_rights::fd_advise | + ecsactsi_wasi_rights::fd_filestat_get | + ecsactsi_wasi_rights::poll_fd_readwrite, + .fs_rights_inheriting = {}, + }, + }, + }; + + auto mem = call_mem_read(0); + + assert(args->data[0].kind == WASM_I32); + auto fd = args->data[0].of.i32; + + assert(args->data[1].kind == WASM_I32); + auto ret = + wasm_memory_cast(mem, args->data[1].of.i32); + + if(default_fdstats.contains(fd)) { + *ret = default_fdstats.at(fd); + } else { + *ret = ecsact::wasm::detail::wasi::fs::fdstat(fd); + } + + if(ret->fs_filetype != ecsactsi_wasi_filetype::unknown) { + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 0; + } else { + results->data[0].kind = WASM_I32; + results->data[0].of.i32 = 1; + } + + return nullptr; +} diff --git a/ecsact/wasm/detail/wasi.hh b/ecsact/wasm/detail/wasi.hh index 7850bdd..b053ee6 100644 --- a/ecsact/wasm/detail/wasi.hh +++ b/ecsact/wasm/detail/wasi.hh @@ -1,381 +1,381 @@ -#ifndef ECSACTSI_WASI_H -#define ECSACTSI_WASI_H - -#include -#include - -/** - * A region of memory for scatter/gather writes. - */ -typedef struct ecsactsi_wasi_ciovec_t { - /** - * The guest pointer of the buffer to be written. - */ - int32_t buf; - - /** - * The length of the buffer to be written. - */ - int32_t buf_len; -} ecsactsi_wasi_ciovec_t; - -static_assert(sizeof(ecsactsi_wasi_ciovec_t) == 8); -static_assert(alignof(ecsactsi_wasi_ciovec_t) == 4); -// static_assert(offsetof(ecsactsi_wasi_ciovec_t, buf) == 0); -// static_assert(offsetof(ecsactsi_wasi_ciovec_t, buf_len) == 4); - -enum class ecsactsi_wasi_filetype : uint8_t { - /** - * The type of the file descriptor or file is unknown or is different from any - * of the other types specified. - */ - unknown = 0, - - /** - * The file descriptor or file refers to a block device inode. - */ - block_device = 1, - - /** - * The file descriptor or file refers to a character device inode. - */ - character_device = 2, - - /** - * The file descriptor or file refers to a directory inode. - */ - directory = 3, - - /** - * The file descriptor or file refers to a regular file inode. - */ - regular_file = 4, - - /** - * The file descriptor or file refers to a datagram socket. - */ - socket_dgram = 5, - - /** - * The file descriptor or file refers to a byte-stream socket. - */ - socket_stream = 6, - - /** - * The file refers to a symbolic link inode. - */ - symbolic_link = 7, -}; - -enum class ecsactsi_wasi_fdflags : uint16_t { - /** - * Append mode: Data written to the file is always appended to the file's end. - */ - append = 1 << 0, - - /** - * Write according to synchronized I/O data integrity completion. Only the - * data stored in the file is synchronized. - */ - dsync = 1 << 1, - - /** - * Non-blocking mode. - */ - nonblock = 1 << 2, - - /** - * Synchronized read I/O operations. - */ - rsync = 1 << 3, - - /** - * Write according to synchronized I/O file integrity completion. In - * addition to synchronizing the data stored in the file, the implementation - * may also synchronously update the file's metadata. - */ - sync = 1 << 4, -}; - -inline ecsactsi_wasi_fdflags operator|( - ecsactsi_wasi_fdflags a, - ecsactsi_wasi_fdflags b -) { - return static_cast( - static_cast(a) | static_cast(b) - ); -} - -inline ecsactsi_wasi_fdflags operator&( - ecsactsi_wasi_fdflags a, - ecsactsi_wasi_fdflags b -) { - return static_cast( - static_cast(a) & static_cast(b) - ); -} - -/** - * File descriptor rights, determining which actions may be performed. - */ -enum class ecsactsi_wasi_rights : uint64_t { - /** - * The right to invoke `fd_datasync`. - * If `path_open` is set, includes the right to invoke - * `path_open` with `fdflags::dsync`. - */ - fd_datasync = 1 << 0, - - /** - * The right to invoke `fd_read` and `sock_recv`. - * If `rights::fd_seek` is set, includes the right to invoke `fd_pread`. - */ - fd_read = 1 << 1, - - /** - * The right to invoke `fd_seek`. This flag implies `rights::fd_tell`. - */ - fd_seek = 1 << 2, - - /** - * The right to invoke `fd_fdstat_set_flags`. - */ - fd_fdstat_set_flags = 1 << 3, - - /** - * The right to invoke `fd_sync`. - * If `path_open` is set, includes the right to invoke - * `path_open` with `fdflags::rsync` and `fdflags::dsync`. - */ - fd_sync = 1 << 4, - - /** - * The right to invoke `fd_seek` in such a way that the file offset - * remains unaltered (i.e., `whence::cur` with offset zero), or to - * invoke `fd_tell`. - */ - fd_tell = 1 << 5, - - /** - * The right to invoke `fd_write` and `sock_send`. - * If `rights::fd_seek` is set, includes the right to invoke `fd_pwrite`. - */ - fd_write = 1 << 6, - - /** - * The right to invoke `fd_advise`. - */ - fd_advise = 1 << 7, - - /** - * The right to invoke `fd_allocate`. - */ - fd_allocate = 1 << 8, - - /** - * The right to invoke `path_create_directory`. - */ - path_create_directory = 1 << 9, - - /** - * If `path_open` is set, the right to invoke `path_open` with - * `oflags::creat`. - */ - path_create_file = 1 << 10, - - /** - * The right to invoke `path_link` with the file descriptor as the - * source directory. - */ - path_link_source = 1 << 11, - - /** - * The right to invoke `path_link` with the file descriptor as the - * target directory. - */ - path_link_target = 1 << 12, - - /** - * The right to invoke `path_open`. - */ - path_open = 1 << 13, - - /** - * The right to invoke `fd_readdir`. - */ - fd_readdir = 1 << 14, - - /** - * The right to invoke `path_readlink`. - */ - path_readlink = 1 << 15, - - /** - * The right to invoke `path_rename` with the file descriptor as the source - * directory. - */ - path_rename_source = 1 << 16, - - /** - * The right to invoke `path_rename` with the file descriptor as the target - * directory. - */ - path_rename_target = 1 << 17, - - /** - * The right to invoke `path_filestat_get`. - */ - path_filestat_get = 1 << 18, - - /** - * The right to change a file's size (there is no `path_filestat_set_size`). - * If `path_open` is set, includes the right to invoke `path_open` with - * `oflags::trunc`. - */ - path_filestat_set_size = 1 << 19, - - /** - * The right to invoke `path_filestat_set_times`. - */ - path_filestat_set_times = 1 << 20, - - /** - * The right to invoke `fd_filestat_get`. - */ - fd_filestat_get = 1 << 21, - - /** - * The right to invoke `fd_filestat_set_size`. - */ - fd_filestat_set_size = 1 << 22, - - /** - * The right to invoke `fd_filestat_set_times`. - */ - fd_filestat_set_times = 1 << 23, - - /** - * The right to invoke `path_symlink`. - */ - path_symlink = 1 << 24, - - /** - * The right to invoke `path_remove_directory`. - */ - path_remove_directory = 1 << 25, - - /** - * The right to invoke `path_unlink_file`. - */ - path_unlink_file = 1 << 26, - - /** - * If `rights::fd_read` is set, includes the right to invoke `poll_oneoff` to - * subscribe to `eventtype::fd_read`. If `rights::fd_write` is set, includes - * the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_write`. - */ - poll_fd_readwrite = 1 << 27, - - /** - * The right to invoke `sock_shutdown`. - */ - sock_shutdown = 1 << 28, - - /** - * The right to invoke `sock_accept`. - */ - sock_accept = 1 << 29, -}; - -inline ecsactsi_wasi_rights operator|( - ecsactsi_wasi_rights a, - ecsactsi_wasi_rights b -) { - return static_cast( - static_cast(a) | static_cast(b) - ); -} - -inline ecsactsi_wasi_rights operator&( - ecsactsi_wasi_rights a, - ecsactsi_wasi_rights b -) { - return static_cast( - static_cast(a) & static_cast(b) - ); -} - -typedef struct ecsactsi_wasi_fdstat_t { - /** - * File type. - */ - ecsactsi_wasi_filetype fs_filetype; - - /** - * File descriptor flags. - */ - ecsactsi_wasi_fdflags fs_flags; - - /** - * Rights that apply to this file descriptor. - */ - ecsactsi_wasi_rights fs_rights_base; - - /** - * Maximum set of rights that may be installed on new file descriptors that - * are created through this file descriptor, e.g., through `path_open`. - */ - ecsactsi_wasi_rights fs_rights_inheriting; - -} ecsactsi_wasi_fdstat_t; - -static_assert(sizeof(ecsactsi_wasi_fdstat_t) == 24); - -/** - * Ecsact system implementation exited prematurely. Unlike normal usage of this - * function @p exit_code being `0` does NOT mean success. - * @param exit_code may be logged to the host, but otherwise is meaningless to - * the ecsact wasm host. - */ -// void ecsactsi_wasi_proc_exit(int32_t exit_code); -wasm_trap_t* ecsactsi_wasi_proc_exit( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -); - -wasm_trap_t* ecsactsi_wasi_fd_seek( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -); - -wasm_trap_t* ecsactsi_wasi_fd_write( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -); - -wasm_trap_t* ecsactsi_wasi_fd_read( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -); - -wasm_trap_t* ecsactsi_wasi_fd_close( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -); - -wasm_trap_t* ecsactsi_wasi_environ_sizes_get( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -); - -wasm_trap_t* ecsactsi_wasi_environ_get( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -); - -wasm_trap_t* ecsactsi_wasi_fd_fdstat_get( - const wasm_val_vec_t* args, - wasm_val_vec_t* results -); - -#endif // ECSACTSI_WASI_H +#ifndef ECSACTSI_WASI_H +#define ECSACTSI_WASI_H + +#include +#include + +/** + * A region of memory for scatter/gather writes. + */ +typedef struct ecsactsi_wasi_ciovec_t { + /** + * The guest pointer of the buffer to be written. + */ + int32_t buf; + + /** + * The length of the buffer to be written. + */ + int32_t buf_len; +} ecsactsi_wasi_ciovec_t; + +static_assert(sizeof(ecsactsi_wasi_ciovec_t) == 8); +static_assert(alignof(ecsactsi_wasi_ciovec_t) == 4); +// static_assert(offsetof(ecsactsi_wasi_ciovec_t, buf) == 0); +// static_assert(offsetof(ecsactsi_wasi_ciovec_t, buf_len) == 4); + +enum class ecsactsi_wasi_filetype : uint8_t { + /** + * The type of the file descriptor or file is unknown or is different from any + * of the other types specified. + */ + unknown = 0, + + /** + * The file descriptor or file refers to a block device inode. + */ + block_device = 1, + + /** + * The file descriptor or file refers to a character device inode. + */ + character_device = 2, + + /** + * The file descriptor or file refers to a directory inode. + */ + directory = 3, + + /** + * The file descriptor or file refers to a regular file inode. + */ + regular_file = 4, + + /** + * The file descriptor or file refers to a datagram socket. + */ + socket_dgram = 5, + + /** + * The file descriptor or file refers to a byte-stream socket. + */ + socket_stream = 6, + + /** + * The file refers to a symbolic link inode. + */ + symbolic_link = 7, +}; + +enum class ecsactsi_wasi_fdflags : uint16_t { + /** + * Append mode: Data written to the file is always appended to the file's end. + */ + append = 1 << 0, + + /** + * Write according to synchronized I/O data integrity completion. Only the + * data stored in the file is synchronized. + */ + dsync = 1 << 1, + + /** + * Non-blocking mode. + */ + nonblock = 1 << 2, + + /** + * Synchronized read I/O operations. + */ + rsync = 1 << 3, + + /** + * Write according to synchronized I/O file integrity completion. In + * addition to synchronizing the data stored in the file, the implementation + * may also synchronously update the file's metadata. + */ + sync = 1 << 4, +}; + +inline ecsactsi_wasi_fdflags operator|( + ecsactsi_wasi_fdflags a, + ecsactsi_wasi_fdflags b +) { + return static_cast( + static_cast(a) | static_cast(b) + ); +} + +inline ecsactsi_wasi_fdflags operator&( + ecsactsi_wasi_fdflags a, + ecsactsi_wasi_fdflags b +) { + return static_cast( + static_cast(a) & static_cast(b) + ); +} + +/** + * File descriptor rights, determining which actions may be performed. + */ +enum class ecsactsi_wasi_rights : uint64_t { + /** + * The right to invoke `fd_datasync`. + * If `path_open` is set, includes the right to invoke + * `path_open` with `fdflags::dsync`. + */ + fd_datasync = 1 << 0, + + /** + * The right to invoke `fd_read` and `sock_recv`. + * If `rights::fd_seek` is set, includes the right to invoke `fd_pread`. + */ + fd_read = 1 << 1, + + /** + * The right to invoke `fd_seek`. This flag implies `rights::fd_tell`. + */ + fd_seek = 1 << 2, + + /** + * The right to invoke `fd_fdstat_set_flags`. + */ + fd_fdstat_set_flags = 1 << 3, + + /** + * The right to invoke `fd_sync`. + * If `path_open` is set, includes the right to invoke + * `path_open` with `fdflags::rsync` and `fdflags::dsync`. + */ + fd_sync = 1 << 4, + + /** + * The right to invoke `fd_seek` in such a way that the file offset + * remains unaltered (i.e., `whence::cur` with offset zero), or to + * invoke `fd_tell`. + */ + fd_tell = 1 << 5, + + /** + * The right to invoke `fd_write` and `sock_send`. + * If `rights::fd_seek` is set, includes the right to invoke `fd_pwrite`. + */ + fd_write = 1 << 6, + + /** + * The right to invoke `fd_advise`. + */ + fd_advise = 1 << 7, + + /** + * The right to invoke `fd_allocate`. + */ + fd_allocate = 1 << 8, + + /** + * The right to invoke `path_create_directory`. + */ + path_create_directory = 1 << 9, + + /** + * If `path_open` is set, the right to invoke `path_open` with + * `oflags::creat`. + */ + path_create_file = 1 << 10, + + /** + * The right to invoke `path_link` with the file descriptor as the + * source directory. + */ + path_link_source = 1 << 11, + + /** + * The right to invoke `path_link` with the file descriptor as the + * target directory. + */ + path_link_target = 1 << 12, + + /** + * The right to invoke `path_open`. + */ + path_open = 1 << 13, + + /** + * The right to invoke `fd_readdir`. + */ + fd_readdir = 1 << 14, + + /** + * The right to invoke `path_readlink`. + */ + path_readlink = 1 << 15, + + /** + * The right to invoke `path_rename` with the file descriptor as the source + * directory. + */ + path_rename_source = 1 << 16, + + /** + * The right to invoke `path_rename` with the file descriptor as the target + * directory. + */ + path_rename_target = 1 << 17, + + /** + * The right to invoke `path_filestat_get`. + */ + path_filestat_get = 1 << 18, + + /** + * The right to change a file's size (there is no `path_filestat_set_size`). + * If `path_open` is set, includes the right to invoke `path_open` with + * `oflags::trunc`. + */ + path_filestat_set_size = 1 << 19, + + /** + * The right to invoke `path_filestat_set_times`. + */ + path_filestat_set_times = 1 << 20, + + /** + * The right to invoke `fd_filestat_get`. + */ + fd_filestat_get = 1 << 21, + + /** + * The right to invoke `fd_filestat_set_size`. + */ + fd_filestat_set_size = 1 << 22, + + /** + * The right to invoke `fd_filestat_set_times`. + */ + fd_filestat_set_times = 1 << 23, + + /** + * The right to invoke `path_symlink`. + */ + path_symlink = 1 << 24, + + /** + * The right to invoke `path_remove_directory`. + */ + path_remove_directory = 1 << 25, + + /** + * The right to invoke `path_unlink_file`. + */ + path_unlink_file = 1 << 26, + + /** + * If `rights::fd_read` is set, includes the right to invoke `poll_oneoff` to + * subscribe to `eventtype::fd_read`. If `rights::fd_write` is set, includes + * the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_write`. + */ + poll_fd_readwrite = 1 << 27, + + /** + * The right to invoke `sock_shutdown`. + */ + sock_shutdown = 1 << 28, + + /** + * The right to invoke `sock_accept`. + */ + sock_accept = 1 << 29, +}; + +inline ecsactsi_wasi_rights operator|( + ecsactsi_wasi_rights a, + ecsactsi_wasi_rights b +) { + return static_cast( + static_cast(a) | static_cast(b) + ); +} + +inline ecsactsi_wasi_rights operator&( + ecsactsi_wasi_rights a, + ecsactsi_wasi_rights b +) { + return static_cast( + static_cast(a) & static_cast(b) + ); +} + +typedef struct ecsactsi_wasi_fdstat_t { + /** + * File type. + */ + ecsactsi_wasi_filetype fs_filetype; + + /** + * File descriptor flags. + */ + ecsactsi_wasi_fdflags fs_flags; + + /** + * Rights that apply to this file descriptor. + */ + ecsactsi_wasi_rights fs_rights_base; + + /** + * Maximum set of rights that may be installed on new file descriptors that + * are created through this file descriptor, e.g., through `path_open`. + */ + ecsactsi_wasi_rights fs_rights_inheriting; + +} ecsactsi_wasi_fdstat_t; + +static_assert(sizeof(ecsactsi_wasi_fdstat_t) == 24); + +/** + * Ecsact system implementation exited prematurely. Unlike normal usage of this + * function @p exit_code being `0` does NOT mean success. + * @param exit_code may be logged to the host, but otherwise is meaningless to + * the ecsact wasm host. + */ +// void ecsactsi_wasi_proc_exit(int32_t exit_code); +wasm_trap_t* ecsactsi_wasi_proc_exit( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +); + +wasm_trap_t* ecsactsi_wasi_fd_seek( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +); + +wasm_trap_t* ecsactsi_wasi_fd_write( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +); + +wasm_trap_t* ecsactsi_wasi_fd_read( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +); + +wasm_trap_t* ecsactsi_wasi_fd_close( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +); + +wasm_trap_t* ecsactsi_wasi_environ_sizes_get( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +); + +wasm_trap_t* ecsactsi_wasi_environ_get( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +); + +wasm_trap_t* ecsactsi_wasi_fd_fdstat_get( + const wasm_val_vec_t* args, + wasm_val_vec_t* results +); + +#endif // ECSACTSI_WASI_H diff --git a/renovate.json b/renovate.json index fa1abeb..25b1be3 100644 --- a/renovate.json +++ b/renovate.json @@ -3,4 +3,4 @@ "extends": [ "github>ecsact-dev/renovate-config" ] -} \ No newline at end of file +}