diff --git a/ecsact/wasm/detail/minst/minst.hh b/ecsact/wasm/detail/minst/minst.hh index 2f6853e..035d6a6 100644 --- a/ecsact/wasm/detail/minst/minst.hh +++ b/ecsact/wasm/detail/minst/minst.hh @@ -86,13 +86,6 @@ public: import_resolver_t import_resolver ) -> std::variant; - /** - * Create a new minst with internal memory copied over. If 'initialize' was - * already called then the memory should be identical, thus 'initialize' - * should not be called again. - */ - static auto copy(minst& other) -> minst; - minst(minst&& other); ~minst(); diff --git a/ecsact/wasm/detail/wasm.cc b/ecsact/wasm/detail/wasm.cc index 4e92342..678b02a 100644 --- a/ecsact/wasm/detail/wasm.cc +++ b/ecsact/wasm/detail/wasm.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include "ecsact/runtime/dynamic.h" #include "ecsact/wasm/detail/minst/minst.hh" #include "ecsact/wasm/detail/logger.hh" @@ -70,21 +71,67 @@ struct minst_ecsact_system_impls { auto trap_handler = ecsactsi_wasm_trap_handler{}; -thread_local auto thread_minst = std::optional{}; +auto all_minsts = std::vector{}; +auto next_available_minst_index = std::atomic_size_t{}; +thread_local auto thread_minst = + std::optional>{}; + +auto ensure_minst() -> minst_ecsact_system_impls& { + if(!thread_minst) { + auto index = ++next_available_minst_index % all_minsts.size(); + thread_minst = all_minsts[index]; + } + + return thread_minst->get(); +} void ecsact_si_wasm_system_impl(ecsact_system_execution_context* ctx) { - auto system_id = ecsact_system_execution_context_id(ctx); - auto itr = thread_minst->sys_impl_exports.find(system_id); - assert(itr != thread_minst->sys_impl_exports.end()); + auto& minst = ensure_minst(); + auto system_id = ecsact_system_execution_context_id(ctx); + auto itr = minst.sys_impl_exports.find(system_id); + assert(itr != minst.sys_impl_exports.end()); auto mem_data = std::array{}; set_call_mem_data(mem_data.data(), mem_data.size()); defer { set_call_mem_data(nullptr, 0); }; - call_mem_alloc(thread_minst->memory.memory); + call_mem_alloc(minst.memory.memory); itr->second.func_call(call_mem_alloc(ctx)); } + +auto get_system_impl_exports( + minst& inst, + int systems_count, + ecsact_system_like_id* system_ids, + const char** wasm_exports, + std::unordered_map& system_impl_exports +) -> ecsactsi_wasm_error { + system_impl_exports.clear(); + system_impl_exports.reserve(systems_count); + + for(auto i = 0; systems_count > i; ++i) { + auto sys_id = system_ids[i]; + auto system_impl_export_name = std::string_view{ + wasm_exports[i], + std::strlen(wasm_exports[i]), + }; + + auto exp = inst.find_export(system_impl_export_name); + + if(!exp) { + return ECSACTSI_WASM_ERR_EXPORT_NOT_FOUND; + } + + if(exp->kind() != WASM_EXTERN_FUNC) { + return ECSACTSI_WASM_ERR_EXPORT_INVALID; + } + + system_impl_exports[sys_id] = *exp; + } + + return ECSACTSI_WASM_OK; +} } // namespace void ecsactsi_wasm_last_error_message( @@ -126,108 +173,106 @@ ecsactsi_wasm_error ecsactsi_wasm_load( return ECSACTSI_WASM_ERR_NO_SET_SYSTEM_EXECUTION; } #endif - - auto result = ecsact::wasm::detail::minst::create( - engine(), - std::span{ - reinterpret_cast(wasm_data), - static_cast(wasm_data_size), - }, - [&](const minst_import imp) -> minst_import_resolve_t { - auto module_name = imp.module(); - auto method_name = imp.name(); - - if(imp.module() == "env") { - auto itr = guest_env_module_imports.find(method_name); - if(itr == guest_env_module_imports.end()) { - return std::nullopt; - } - return itr->second(); + auto import_resolver = [&](const minst_import imp) -> minst_import_resolve_t { + auto module_name = imp.module(); + auto method_name = imp.name(); + + if(imp.module() == "env") { + auto itr = guest_env_module_imports.find(method_name); + if(itr == guest_env_module_imports.end()) { + return std::nullopt; } + return itr->second(); + } - if(imp.module() == "wasi_snapshot_preview1") { - auto itr = guest_wasi_module_imports.find(method_name); - if(itr == guest_wasi_module_imports.end()) { - return std::nullopt; - } - return itr->second(); + if(imp.module() == "wasi_snapshot_preview1") { + auto itr = guest_wasi_module_imports.find(method_name); + if(itr == guest_wasi_module_imports.end()) { + return std::nullopt; } - - return std::nullopt; + return itr->second(); } - ); - if(std::holds_alternative(result)) { - auto err = std::get(result); - switch(err.code) { - case minst_error_code::ok: - assert(err.code != minst_error_code::ok); - case minst_error_code::compile_fail: - return ECSACTSI_WASM_ERR_COMPILE_FAIL; - case minst_error_code::unresolved_guest_import: - return ECSACTSI_WASM_ERR_GUEST_IMPORT_INVALID; - case minst_error_code::instantiate_fail: - return ECSACTSI_WASM_ERR_INSTANTIATE_FAIL; - } - } + return std::nullopt; + }; - auto& inst = std::get(result); - auto system_impl_exports = - std::unordered_map{}; + all_minsts.reserve(100); - system_impl_exports.reserve(systems_count); + for(auto i = 0; 100 > i; ++i) { + auto result = minst::create( + engine(), + std::span{ + reinterpret_cast(wasm_data), + static_cast(wasm_data_size), + }, + import_resolver + ); - for(auto i = 0; systems_count > i; ++i) { - auto sys_id = system_ids[i]; - auto system_impl_export_name = std::string_view{ - wasm_exports[i], - std::strlen(wasm_exports[i]), - }; + if(std::holds_alternative(result)) { + auto err = std::get(result); + switch(err.code) { + case minst_error_code::ok: + assert(err.code != minst_error_code::ok); + case minst_error_code::compile_fail: + return ECSACTSI_WASM_ERR_COMPILE_FAIL; + case minst_error_code::unresolved_guest_import: + return ECSACTSI_WASM_ERR_GUEST_IMPORT_INVALID; + case minst_error_code::instantiate_fail: + return ECSACTSI_WASM_ERR_INSTANTIATE_FAIL; + } + } - auto exp = inst.find_export(system_impl_export_name); + auto& inst = std::get(result); + auto system_impl_exports = + std::unordered_map{}; - if(!exp) { - return ECSACTSI_WASM_ERR_EXPORT_NOT_FOUND; - } + auto err = get_system_impl_exports( + inst, + systems_count, + system_ids, + wasm_exports, + system_impl_exports + ); - if(exp->kind() != WASM_EXTERN_FUNC) { - return ECSACTSI_WASM_ERR_EXPORT_INVALID; + if(err != ECSACTSI_WASM_OK) { + return err; } - system_impl_exports[sys_id] = *exp; - } - - auto wasm_mem = std::optional{}; + auto wasm_mem = std::optional{}; - for(auto exp : inst.exports()) { - if(exp.kind() == WASM_EXTERN_MEMORY) { - wasm_mem = exp; - break; + for(auto exp : inst.exports()) { + if(exp.kind() == WASM_EXTERN_MEMORY) { + wasm_mem = exp; + break; + } } - } - assert(wasm_mem); + assert(wasm_mem); - auto mem_data = std::array{}; - set_call_mem_data(mem_data.data(), mem_data.size()); - call_mem_alloc(wasm_mem->memory); - defer { - set_call_mem_data(nullptr, 0); - }; - auto init_trap = inst.initialize(); - if(init_trap) { - return ECSACTSI_WASM_ERR_INITIALIZE_FAIL; - } + auto mem_data = std::array{}; + set_call_mem_data(mem_data.data(), mem_data.size()); + call_mem_alloc(wasm_mem->memory); + defer { + set_call_mem_data(nullptr, 0); + }; + auto init_trap = inst.initialize(); + if(init_trap) { + return ECSACTSI_WASM_ERR_INITIALIZE_FAIL; + } - for(auto&& [sys_id, exp] : system_impl_exports) { - ecsact_set_system_execution_impl(sys_id, &ecsact_si_wasm_system_impl); + all_minsts.emplace_back( // + std::move(inst), + system_impl_exports, + *wasm_mem + ); } - thread_minst.emplace( // - std::move(inst), - system_impl_exports, - *wasm_mem - ); + for(auto i = 0; systems_count > i; ++i) { + ecsact_set_system_execution_impl( + system_ids[i], + &ecsact_si_wasm_system_impl + ); + } return ECSACTSI_WASM_OK; } diff --git a/test/MODULE.bazel b/test/MODULE.bazel index a78adaa..a4e5766 100644 --- a/test/MODULE.bazel +++ b/test/MODULE.bazel @@ -17,6 +17,7 @@ bazel_dep(name = "ecsact_cli", version = "0.3.4") bazel_dep(name = "rules_ecsact", version = "0.5.1") bazel_dep(name = "xxhash", version = "0.8.2") bazel_dep(name = "ecsact_si_wasm") + local_path_override( module_name = "ecsact_si_wasm", path = "..",