|
19 | 19 | #include <iostream> |
20 | 20 | #include <array> |
21 | 21 | #include <cstddef> |
| 22 | +#include <thread> |
22 | 23 | #include "ecsact/runtime/dynamic.h" |
23 | 24 | #include "ecsact/wasm/detail/minst/minst.hh" |
24 | 25 | #include "ecsact/wasm/detail/logger.hh" |
@@ -70,21 +71,67 @@ struct minst_ecsact_system_impls { |
70 | 71 |
|
71 | 72 | auto trap_handler = ecsactsi_wasm_trap_handler{}; |
72 | 73 |
|
73 | | -thread_local auto thread_minst = std::optional<minst_ecsact_system_impls>{}; |
| 74 | +auto all_minsts = std::vector<minst_ecsact_system_impls>{}; |
| 75 | +auto next_available_minst_index = std::atomic_size_t{}; |
| 76 | +thread_local auto thread_minst = |
| 77 | + std::optional<std::reference_wrapper<minst_ecsact_system_impls>>{}; |
| 78 | + |
| 79 | +auto ensure_minst() -> minst_ecsact_system_impls& { |
| 80 | + if(!thread_minst) { |
| 81 | + auto index = ++next_available_minst_index % all_minsts.size(); |
| 82 | + thread_minst = all_minsts[index]; |
| 83 | + } |
| 84 | + |
| 85 | + return thread_minst->get(); |
| 86 | +} |
74 | 87 |
|
75 | 88 | void ecsact_si_wasm_system_impl(ecsact_system_execution_context* ctx) { |
76 | | - auto system_id = ecsact_system_execution_context_id(ctx); |
77 | | - auto itr = thread_minst->sys_impl_exports.find(system_id); |
78 | | - assert(itr != thread_minst->sys_impl_exports.end()); |
| 89 | + auto& minst = ensure_minst(); |
| 90 | + auto system_id = ecsact_system_execution_context_id(ctx); |
| 91 | + auto itr = minst.sys_impl_exports.find(system_id); |
| 92 | + assert(itr != minst.sys_impl_exports.end()); |
79 | 93 |
|
80 | 94 | auto mem_data = std::array<std::byte, 4096>{}; |
81 | 95 | set_call_mem_data(mem_data.data(), mem_data.size()); |
82 | 96 | defer { |
83 | 97 | set_call_mem_data(nullptr, 0); |
84 | 98 | }; |
85 | | - call_mem_alloc(thread_minst->memory.memory); |
| 99 | + call_mem_alloc(minst.memory.memory); |
86 | 100 | itr->second.func_call(call_mem_alloc(ctx)); |
87 | 101 | } |
| 102 | + |
| 103 | +auto get_system_impl_exports( |
| 104 | + minst& inst, |
| 105 | + int systems_count, |
| 106 | + ecsact_system_like_id* system_ids, |
| 107 | + const char** wasm_exports, |
| 108 | + std::unordered_map<ecsact_system_like_id, minst_export>& system_impl_exports |
| 109 | +) -> ecsactsi_wasm_error { |
| 110 | + system_impl_exports.clear(); |
| 111 | + system_impl_exports.reserve(systems_count); |
| 112 | + |
| 113 | + for(auto i = 0; systems_count > i; ++i) { |
| 114 | + auto sys_id = system_ids[i]; |
| 115 | + auto system_impl_export_name = std::string_view{ |
| 116 | + wasm_exports[i], |
| 117 | + std::strlen(wasm_exports[i]), |
| 118 | + }; |
| 119 | + |
| 120 | + auto exp = inst.find_export(system_impl_export_name); |
| 121 | + |
| 122 | + if(!exp) { |
| 123 | + return ECSACTSI_WASM_ERR_EXPORT_NOT_FOUND; |
| 124 | + } |
| 125 | + |
| 126 | + if(exp->kind() != WASM_EXTERN_FUNC) { |
| 127 | + return ECSACTSI_WASM_ERR_EXPORT_INVALID; |
| 128 | + } |
| 129 | + |
| 130 | + system_impl_exports[sys_id] = *exp; |
| 131 | + } |
| 132 | + |
| 133 | + return ECSACTSI_WASM_OK; |
| 134 | +} |
88 | 135 | } // namespace |
89 | 136 |
|
90 | 137 | void ecsactsi_wasm_last_error_message( |
@@ -126,108 +173,106 @@ ecsactsi_wasm_error ecsactsi_wasm_load( |
126 | 173 | return ECSACTSI_WASM_ERR_NO_SET_SYSTEM_EXECUTION; |
127 | 174 | } |
128 | 175 | #endif |
129 | | - |
130 | | - auto result = ecsact::wasm::detail::minst::create( |
131 | | - engine(), |
132 | | - std::span{ |
133 | | - reinterpret_cast<std::byte*>(wasm_data), |
134 | | - static_cast<size_t>(wasm_data_size), |
135 | | - }, |
136 | | - [&](const minst_import imp) -> minst_import_resolve_t { |
137 | | - auto module_name = imp.module(); |
138 | | - auto method_name = imp.name(); |
139 | | - |
140 | | - if(imp.module() == "env") { |
141 | | - auto itr = guest_env_module_imports.find(method_name); |
142 | | - if(itr == guest_env_module_imports.end()) { |
143 | | - return std::nullopt; |
144 | | - } |
145 | | - return itr->second(); |
| 176 | + auto import_resolver = [&](const minst_import imp) -> minst_import_resolve_t { |
| 177 | + auto module_name = imp.module(); |
| 178 | + auto method_name = imp.name(); |
| 179 | + |
| 180 | + if(imp.module() == "env") { |
| 181 | + auto itr = guest_env_module_imports.find(method_name); |
| 182 | + if(itr == guest_env_module_imports.end()) { |
| 183 | + return std::nullopt; |
146 | 184 | } |
| 185 | + return itr->second(); |
| 186 | + } |
147 | 187 |
|
148 | | - if(imp.module() == "wasi_snapshot_preview1") { |
149 | | - auto itr = guest_wasi_module_imports.find(method_name); |
150 | | - if(itr == guest_wasi_module_imports.end()) { |
151 | | - return std::nullopt; |
152 | | - } |
153 | | - return itr->second(); |
| 188 | + if(imp.module() == "wasi_snapshot_preview1") { |
| 189 | + auto itr = guest_wasi_module_imports.find(method_name); |
| 190 | + if(itr == guest_wasi_module_imports.end()) { |
| 191 | + return std::nullopt; |
154 | 192 | } |
155 | | - |
156 | | - return std::nullopt; |
| 193 | + return itr->second(); |
157 | 194 | } |
158 | | - ); |
159 | 195 |
|
160 | | - if(std::holds_alternative<minst_error>(result)) { |
161 | | - auto err = std::get<minst_error>(result); |
162 | | - switch(err.code) { |
163 | | - case minst_error_code::ok: |
164 | | - assert(err.code != minst_error_code::ok); |
165 | | - case minst_error_code::compile_fail: |
166 | | - return ECSACTSI_WASM_ERR_COMPILE_FAIL; |
167 | | - case minst_error_code::unresolved_guest_import: |
168 | | - return ECSACTSI_WASM_ERR_GUEST_IMPORT_INVALID; |
169 | | - case minst_error_code::instantiate_fail: |
170 | | - return ECSACTSI_WASM_ERR_INSTANTIATE_FAIL; |
171 | | - } |
172 | | - } |
| 196 | + return std::nullopt; |
| 197 | + }; |
173 | 198 |
|
174 | | - auto& inst = std::get<minst>(result); |
175 | | - auto system_impl_exports = |
176 | | - std::unordered_map<ecsact_system_like_id, minst_export>{}; |
| 199 | + all_minsts.reserve(100); |
177 | 200 |
|
178 | | - system_impl_exports.reserve(systems_count); |
| 201 | + for(auto i = 0; 100 > i; ++i) { |
| 202 | + auto result = minst::create( |
| 203 | + engine(), |
| 204 | + std::span{ |
| 205 | + reinterpret_cast<std::byte*>(wasm_data), |
| 206 | + static_cast<size_t>(wasm_data_size), |
| 207 | + }, |
| 208 | + import_resolver |
| 209 | + ); |
179 | 210 |
|
180 | | - for(auto i = 0; systems_count > i; ++i) { |
181 | | - auto sys_id = system_ids[i]; |
182 | | - auto system_impl_export_name = std::string_view{ |
183 | | - wasm_exports[i], |
184 | | - std::strlen(wasm_exports[i]), |
185 | | - }; |
| 211 | + if(std::holds_alternative<minst_error>(result)) { |
| 212 | + auto err = std::get<minst_error>(result); |
| 213 | + switch(err.code) { |
| 214 | + case minst_error_code::ok: |
| 215 | + assert(err.code != minst_error_code::ok); |
| 216 | + case minst_error_code::compile_fail: |
| 217 | + return ECSACTSI_WASM_ERR_COMPILE_FAIL; |
| 218 | + case minst_error_code::unresolved_guest_import: |
| 219 | + return ECSACTSI_WASM_ERR_GUEST_IMPORT_INVALID; |
| 220 | + case minst_error_code::instantiate_fail: |
| 221 | + return ECSACTSI_WASM_ERR_INSTANTIATE_FAIL; |
| 222 | + } |
| 223 | + } |
186 | 224 |
|
187 | | - auto exp = inst.find_export(system_impl_export_name); |
| 225 | + auto& inst = std::get<minst>(result); |
| 226 | + auto system_impl_exports = |
| 227 | + std::unordered_map<ecsact_system_like_id, minst_export>{}; |
188 | 228 |
|
189 | | - if(!exp) { |
190 | | - return ECSACTSI_WASM_ERR_EXPORT_NOT_FOUND; |
191 | | - } |
| 229 | + auto err = get_system_impl_exports( |
| 230 | + inst, |
| 231 | + systems_count, |
| 232 | + system_ids, |
| 233 | + wasm_exports, |
| 234 | + system_impl_exports |
| 235 | + ); |
192 | 236 |
|
193 | | - if(exp->kind() != WASM_EXTERN_FUNC) { |
194 | | - return ECSACTSI_WASM_ERR_EXPORT_INVALID; |
| 237 | + if(err != ECSACTSI_WASM_OK) { |
| 238 | + return err; |
195 | 239 | } |
196 | 240 |
|
197 | | - system_impl_exports[sys_id] = *exp; |
198 | | - } |
199 | | - |
200 | | - auto wasm_mem = std::optional<minst_export>{}; |
| 241 | + auto wasm_mem = std::optional<minst_export>{}; |
201 | 242 |
|
202 | | - for(auto exp : inst.exports()) { |
203 | | - if(exp.kind() == WASM_EXTERN_MEMORY) { |
204 | | - wasm_mem = exp; |
205 | | - break; |
| 243 | + for(auto exp : inst.exports()) { |
| 244 | + if(exp.kind() == WASM_EXTERN_MEMORY) { |
| 245 | + wasm_mem = exp; |
| 246 | + break; |
| 247 | + } |
206 | 248 | } |
207 | | - } |
208 | 249 |
|
209 | | - assert(wasm_mem); |
| 250 | + assert(wasm_mem); |
210 | 251 |
|
211 | | - auto mem_data = std::array<std::byte, 4096>{}; |
212 | | - set_call_mem_data(mem_data.data(), mem_data.size()); |
213 | | - call_mem_alloc<wasm_memory_t*>(wasm_mem->memory); |
214 | | - defer { |
215 | | - set_call_mem_data(nullptr, 0); |
216 | | - }; |
217 | | - auto init_trap = inst.initialize(); |
218 | | - if(init_trap) { |
219 | | - return ECSACTSI_WASM_ERR_INITIALIZE_FAIL; |
220 | | - } |
| 252 | + auto mem_data = std::array<std::byte, 4096>{}; |
| 253 | + set_call_mem_data(mem_data.data(), mem_data.size()); |
| 254 | + call_mem_alloc<wasm_memory_t*>(wasm_mem->memory); |
| 255 | + defer { |
| 256 | + set_call_mem_data(nullptr, 0); |
| 257 | + }; |
| 258 | + auto init_trap = inst.initialize(); |
| 259 | + if(init_trap) { |
| 260 | + return ECSACTSI_WASM_ERR_INITIALIZE_FAIL; |
| 261 | + } |
221 | 262 |
|
222 | | - for(auto&& [sys_id, exp] : system_impl_exports) { |
223 | | - ecsact_set_system_execution_impl(sys_id, &ecsact_si_wasm_system_impl); |
| 263 | + all_minsts.emplace_back( // |
| 264 | + std::move(inst), |
| 265 | + system_impl_exports, |
| 266 | + *wasm_mem |
| 267 | + ); |
224 | 268 | } |
225 | 269 |
|
226 | | - thread_minst.emplace( // |
227 | | - std::move(inst), |
228 | | - system_impl_exports, |
229 | | - *wasm_mem |
230 | | - ); |
| 270 | + for(auto i = 0; systems_count > i; ++i) { |
| 271 | + ecsact_set_system_execution_impl( |
| 272 | + system_ids[i], |
| 273 | + &ecsact_si_wasm_system_impl |
| 274 | + ); |
| 275 | + } |
231 | 276 |
|
232 | 277 | return ECSACTSI_WASM_OK; |
233 | 278 | } |
|
0 commit comments