/src/WasmEdge/lib/vm/vm.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "vm/vm.h" |
5 | | |
6 | | #include "plugin_modules.h" |
7 | | |
8 | | #include "ast/module.h" |
9 | | #include "common/errcode.h" |
10 | | #include "common/types.h" |
11 | | #include "host/wasi/wasimodule.h" |
12 | | #include "plugin/plugin.h" |
13 | | #include "llvm/compiler.h" |
14 | | #include "llvm/jit.h" |
15 | | |
16 | | #include "validator/validator.h" |
17 | | #include <memory> |
18 | | #include <variant> |
19 | | |
20 | | namespace WasmEdge { |
21 | | namespace VM { |
22 | | |
23 | | VM::VM(const Configure &Conf) |
24 | 0 | : Conf(Conf), Stage(VMStage::Inited), |
25 | 0 | LoaderEngine(Conf, &Executor::Executor::Intrinsics), |
26 | 0 | ValidatorEngine(Conf), ExecutorEngine(Conf, &Stat), |
27 | 0 | Store(std::make_unique<Runtime::StoreManager>()), StoreRef(*Store.get()) { |
28 | 0 | unsafeInitVM(); |
29 | 0 | } |
30 | | |
31 | | VM::VM(const Configure &Conf, Runtime::StoreManager &S) |
32 | 0 | : Conf(Conf), Stage(VMStage::Inited), |
33 | 0 | LoaderEngine(Conf, &Executor::Executor::Intrinsics), |
34 | 0 | ValidatorEngine(Conf), ExecutorEngine(Conf, &Stat), StoreRef(S) { |
35 | 0 | unsafeInitVM(); |
36 | 0 | } |
37 | | |
38 | 0 | void VM::unsafeInitVM() { |
39 | | // Load the built-in modules and the plug-ins. |
40 | 0 | unsafeLoadBuiltInHosts(); |
41 | 0 | unsafeLoadPlugInHosts(); |
42 | | |
43 | | // Set up the lazy JIT engine if lazy JIT mode is enabled. |
44 | 0 | #ifdef WASMEDGE_USE_LLVM |
45 | 0 | if (Conf.getRuntimeConfigure().getRunMode() == RunMode::LazyJIT) { |
46 | 0 | spdlog::warn( |
47 | 0 | "Lazy JIT is an alpha and experimental feature, which is not ready for production use."sv); |
48 | 0 | LazyEngine = std::make_unique<LLVM::LazyJITEngine>(Conf); |
49 | 0 | ExecutorEngine.registerLazyCompilationCallback( |
50 | 0 | [this](const Runtime::Instance::FunctionInstance *FuncInst) |
51 | 0 | -> Expect<void> { return LazyEngine->compileOnDemand(FuncInst); }); |
52 | 0 | } |
53 | 0 | #endif |
54 | | |
55 | | // Register all module instances. |
56 | 0 | unsafeRegisterBuiltInHosts(); |
57 | 0 | unsafeRegisterPlugInHosts(); |
58 | 0 | } |
59 | | |
60 | 0 | void VM::unsafeLoadBuiltInHosts() { |
61 | | // Load the built-in host modules from configuration. |
62 | | // TODO: This will be extended for versioned WASI in the future. |
63 | 0 | cleanupModInstContainer(BuiltInModInsts); |
64 | 0 | if (Conf.hasHostRegistration(HostRegistration::Wasi)) { |
65 | 0 | std::unique_ptr<Runtime::Instance::ModuleInstance> WasiMod = |
66 | 0 | std::make_unique<Host::WasiModule>(); |
67 | 0 | BuiltInModInsts.insert({HostRegistration::Wasi, std::move(WasiMod)}); |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | 0 | void VM::unsafeLoadPlugInHosts() { |
72 | | // Load the official plugin modules and mock them if not found. |
73 | 0 | cleanupModInstContainer(PlugInModInsts); |
74 | 0 | PlugInModInsts = loadOfficialPluginModules(); |
75 | | |
76 | | // Load the other non-official plugins. |
77 | 0 | for (const auto &Plugin : Plugin::Plugin::plugins()) { |
78 | 0 | if (Conf.isForbiddenPlugins(Plugin.name())) { |
79 | 0 | continue; |
80 | 0 | } |
81 | 0 | if (isOfficialPlugin(Plugin.name())) { |
82 | 0 | continue; |
83 | 0 | } |
84 | 0 | for (const auto &Module : Plugin.modules()) { |
85 | 0 | PlugInModInsts.push_back(Module.create()); |
86 | 0 | } |
87 | 0 | for (const auto &Component : Plugin.components()) { |
88 | 0 | PlugInCompInsts.push_back(Component.create()); |
89 | 0 | } |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | 0 | void VM::unsafeRegisterBuiltInHosts() { |
94 | | // Register all created WASI host modules. |
95 | 0 | for (auto &It : BuiltInModInsts) { |
96 | 0 | ExecutorEngine.registerModule(StoreRef, *(It.second.get())); |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | 0 | void VM::unsafeRegisterPlugInHosts() { |
101 | | // Register all created module instances from plugins. |
102 | 0 | for (auto &It : PlugInModInsts) { |
103 | 0 | ExecutorEngine.registerModule(StoreRef, *(It.get())); |
104 | 0 | } |
105 | 0 | for (auto &It : PlugInCompInsts) { |
106 | 0 | ExecutorEngine.registerComponent(StoreRef, *(It.get())); |
107 | 0 | } |
108 | 0 | } |
109 | | |
110 | | Expect<void> VM::unsafeRegisterModule(std::string_view Name, |
111 | 0 | const std::filesystem::path &Path) { |
112 | | // Load module. |
113 | 0 | EXPECTED_TRY(std::shared_ptr<AST::Module> Module, |
114 | 0 | LoaderEngine.parseModule(Path)); |
115 | 0 | return unsafeRegisterModule(Name, std::move(Module)); |
116 | 0 | } |
117 | | |
118 | | Expect<void> VM::unsafeRegisterModule(std::string_view Name, |
119 | 0 | Span<const Byte> Code) { |
120 | | // Load module. |
121 | 0 | EXPECTED_TRY(std::shared_ptr<AST::Module> Module, |
122 | 0 | LoaderEngine.parseModule(Code)); |
123 | 0 | return unsafeRegisterModule(Name, std::move(Module)); |
124 | 0 | } |
125 | | |
126 | | Expect<void> VM::unsafeRegisterModule(std::string_view Name, |
127 | 0 | const AST::Module &Module) { |
128 | 0 | #ifdef WASMEDGE_USE_LLVM |
129 | 0 | if (LazyEngine) { |
130 | | // The lazy JIT engine needs to own the AST module and hook the compiled |
131 | | // executable into it, so register an owned copy instead of mutating the |
132 | | // caller's module. |
133 | 0 | return unsafeRegisterModule(Name, std::make_shared<AST::Module>(Module)); |
134 | 0 | } |
135 | 0 | #endif |
136 | 0 | unsafeRevertStageToValidated(); |
137 | | // Validate module. |
138 | 0 | EXPECTED_TRY(ValidatorEngine.validate(Module)); |
139 | | // Instantiate and register module. |
140 | 0 | EXPECTED_TRY(auto ModInst, |
141 | 0 | ExecutorEngine.registerModule(StoreRef, Module, Name)); |
142 | 0 | RegModInsts.push_back(std::move(ModInst)); |
143 | 0 | return {}; |
144 | 0 | } |
145 | | |
146 | | Expect<void> VM::unsafeRegisterModule(std::string_view Name, |
147 | 0 | std::shared_ptr<AST::Module> Module) { |
148 | 0 | unsafeRevertStageToValidated(); |
149 | | // Validate module. |
150 | 0 | EXPECTED_TRY(ValidatorEngine.validate(*Module)); |
151 | | |
152 | 0 | #ifdef WASMEDGE_USE_LLVM |
153 | 0 | if (LazyEngine && !Module->getSymbol()) { |
154 | 0 | EXPECTED_TRY(auto Exec, LazyEngine->prepare(Module)); |
155 | 0 | EXPECTED_TRY(LoaderEngine.loadExecutable(*Module, std::move(Exec))); |
156 | 0 | } |
157 | 0 | #endif |
158 | | |
159 | | // Instantiate and register module. |
160 | 0 | EXPECTED_TRY(auto ModInst, |
161 | 0 | ExecutorEngine.registerModule(StoreRef, *Module, Name)); |
162 | |
|
163 | 0 | #ifdef WASMEDGE_USE_LLVM |
164 | 0 | if (LazyEngine) { |
165 | 0 | LazyEngine->registerInstance(*ModInst, std::move(Module)); |
166 | 0 | } |
167 | 0 | #endif |
168 | |
|
169 | 0 | RegModInsts.push_back(std::move(ModInst)); |
170 | 0 | return {}; |
171 | 0 | } |
172 | | |
173 | | Expect<void> |
174 | | VM::unsafeRegisterModule(std::string_view Name, |
175 | 0 | const Runtime::Instance::ModuleInstance &ModInst) { |
176 | 0 | unsafeRevertStageToValidated(); |
177 | 0 | return ExecutorEngine.registerModule(StoreRef, ModInst, Name); |
178 | 0 | } |
179 | | |
180 | 0 | Expect<void> VM::unsafeUnregisterModule(std::string_view Name) { |
181 | 0 | auto InstIt = std::find_if( |
182 | 0 | RegModInsts.begin(), RegModInsts.end(), |
183 | 0 | [&Name](const std::unique_ptr<Runtime::Instance::ModuleInstance> &Inst) { |
184 | 0 | return Inst && Inst->getModuleName() == Name; |
185 | 0 | }); |
186 | 0 | if (InstIt != RegModInsts.end()) { |
187 | 0 | auto *ModInst = (*InstIt).release(); |
188 | |
|
189 | 0 | if (ModInst) { |
190 | 0 | #ifdef WASMEDGE_USE_LLVM |
191 | 0 | if (LazyEngine) { |
192 | 0 | LazyEngine->unregisterInstance(*ModInst); |
193 | 0 | } |
194 | 0 | #endif |
195 | 0 | ModInst->terminate(); |
196 | 0 | } |
197 | 0 | return {}; |
198 | 0 | } |
199 | 0 | for (auto It = BuiltInModInsts.begin(); It != BuiltInModInsts.end(); ++It) { |
200 | 0 | if (It->second && It->second->getModuleName() == Name) { |
201 | 0 | auto *ModInst = It->second.release(); |
202 | 0 | BuiltInModInsts.erase(It); |
203 | |
|
204 | 0 | if (ModInst) { |
205 | 0 | ModInst->terminate(); |
206 | 0 | } |
207 | 0 | return {}; |
208 | 0 | } |
209 | 0 | } |
210 | 0 | for (auto It = PlugInModInsts.begin(); It != PlugInModInsts.end(); ++It) { |
211 | 0 | if (*It && (*It)->getModuleName() == Name) { |
212 | 0 | auto *ModInst = It->release(); |
213 | 0 | PlugInModInsts.erase(It); |
214 | |
|
215 | 0 | if (ModInst) { |
216 | 0 | ModInst->terminate(); |
217 | 0 | } |
218 | 0 | return {}; |
219 | 0 | } |
220 | 0 | } |
221 | | |
222 | 0 | return {}; |
223 | 0 | } |
224 | | |
225 | | VM::WasmUnitKind |
226 | | VM::unsafeStoreWasmUnit(std::variant<std::unique_ptr<AST::Component::Component>, |
227 | 0 | std::unique_ptr<AST::Module>> &&Unit) { |
228 | 0 | if (auto *M = std::get_if<std::unique_ptr<AST::Module>>(&Unit)) { |
229 | 0 | Mod = std::move(*M); |
230 | 0 | return WasmUnitKind::Module; |
231 | 0 | } |
232 | 0 | Comp = std::move(std::get<std::unique_ptr<AST::Component::Component>>(Unit)); |
233 | 0 | return WasmUnitKind::Component; |
234 | 0 | } |
235 | | |
236 | | Expect<std::vector<std::pair<ValVariant, ValType>>> |
237 | | VM::unsafeRunWasmFile(const std::filesystem::path &Path, std::string_view Func, |
238 | | Span<const ValVariant> Params, |
239 | 0 | Span<const ValType> ParamTypes) { |
240 | 0 | unsafeRevertStageToValidated(); |
241 | | // Load wasm unit. |
242 | 0 | EXPECTED_TRY(auto ComponentOrModule, LoaderEngine.parseWasmUnit(Path)); |
243 | 0 | if (unsafeStoreWasmUnit(std::move(ComponentOrModule)) == |
244 | 0 | WasmUnitKind::Component) { |
245 | 0 | return unsafeRunWasmFile(*Comp, Func, Params, ParamTypes); |
246 | 0 | } |
247 | 0 | return unsafeRunWasmFile(*Mod, Func, Params, ParamTypes); |
248 | 0 | } |
249 | | |
250 | | Expect<std::vector<std::pair<ValVariant, ValType>>> |
251 | | VM::unsafeRunWasmFile(Span<const Byte> Code, std::string_view Func, |
252 | | Span<const ValVariant> Params, |
253 | 0 | Span<const ValType> ParamTypes) { |
254 | 0 | unsafeRevertStageToValidated(); |
255 | | // Load wasm unit. |
256 | 0 | EXPECTED_TRY(auto ComponentOrModule, LoaderEngine.parseWasmUnit(Code)); |
257 | 0 | if (unsafeStoreWasmUnit(std::move(ComponentOrModule)) == |
258 | 0 | WasmUnitKind::Component) { |
259 | 0 | return unsafeRunWasmFile(*Comp, Func, Params, ParamTypes); |
260 | 0 | } |
261 | 0 | return unsafeRunWasmFile(*Mod, Func, Params, ParamTypes); |
262 | 0 | } |
263 | | |
264 | | Expect<std::vector<std::pair<ValVariant, ValType>>> |
265 | | VM::unsafeRunWasmFile(const AST::Component::Component &Component, |
266 | | std::string_view, Span<const ValVariant>, |
267 | 0 | Span<const ValType>) { |
268 | 0 | unsafeRevertStageToValidated(); |
269 | 0 | EXPECTED_TRY(ValidatorEngine.validate(Component)); |
270 | 0 | spdlog::error("component execution is not done yet."sv); |
271 | 0 | return Unexpect(ErrCode::Value::RuntimeError); |
272 | 0 | } |
273 | | |
274 | | Expect<std::vector<std::pair<ValVariant, ValType>>> |
275 | | VM::unsafeRunWasmFile(const AST::Module &Module, std::string_view Func, |
276 | | Span<const ValVariant> Params, |
277 | 0 | Span<const ValType> ParamTypes) { |
278 | 0 | unsafeRevertStageToValidated(); |
279 | 0 | EXPECTED_TRY(ValidatorEngine.validate(Module)); |
280 | 0 | #ifdef WASMEDGE_USE_LLVM |
281 | 0 | if (LazyEngine) { |
282 | | // This one-shot path takes no shared ownership of the module, so it is |
283 | | // not bound to the lazy JIT engine and executes in the interpreter. |
284 | 0 | spdlog::debug("[lazy-jit]: runWasmFile executes in interpreter mode"sv); |
285 | 0 | } |
286 | 0 | #endif |
287 | 0 | EXPECTED_TRY(auto NewModInst, |
288 | 0 | ExecutorEngine.instantiateModule(StoreRef, Module)); |
289 | 0 | #ifdef WASMEDGE_USE_LLVM |
290 | | // Drop the lazy binding of the replaced instance only after the new |
291 | | // instantiation succeeds, so a failed run keeps the current instance bound. |
292 | 0 | if (LazyEngine && ActiveModInst) { |
293 | 0 | LazyEngine->unregisterInstance(*ActiveModInst); |
294 | 0 | } |
295 | 0 | #endif |
296 | 0 | ActiveModInst = std::move(NewModInst); |
297 | | |
298 | | // Get module instance. |
299 | 0 | if (ActiveModInst) { |
300 | | // Execute function and return values using the module instance. |
301 | 0 | return unsafeExecute(ActiveModInst.get(), Func, Params, ParamTypes); |
302 | 0 | } |
303 | 0 | spdlog::error(ErrCode::Value::WrongInstanceAddress); |
304 | 0 | spdlog::error(ErrInfo::InfoExecuting(""sv, Func)); |
305 | 0 | return Unexpect(ErrCode::Value::WrongInstanceAddress); |
306 | 0 | } |
307 | | |
308 | | Async<Expect<std::vector<std::pair<ValVariant, ValType>>>> |
309 | | VM::asyncRunWasmFile(const std::filesystem::path &Path, std::string_view Func, |
310 | | Span<const ValVariant> Params, |
311 | 0 | Span<const ValType> ParamTypes) { |
312 | 0 | Expect<std::vector<std::pair<ValVariant, ValType>>> (VM::*FPtr)( |
313 | 0 | const std::filesystem::path &, std::string_view, Span<const ValVariant>, |
314 | 0 | Span<const ValType>) = &VM::runWasmFile; |
315 | 0 | return {FPtr, |
316 | 0 | *this, |
317 | 0 | std::filesystem::path(Path), |
318 | 0 | std::string(Func), |
319 | 0 | std::vector(Params.begin(), Params.end()), |
320 | 0 | std::vector(ParamTypes.begin(), ParamTypes.end())}; |
321 | 0 | } |
322 | | |
323 | | Async<Expect<std::vector<std::pair<ValVariant, ValType>>>> |
324 | | VM::asyncRunWasmFile(Span<const Byte> Code, std::string_view Func, |
325 | | Span<const ValVariant> Params, |
326 | 0 | Span<const ValType> ParamTypes) { |
327 | 0 | Expect<std::vector<std::pair<ValVariant, ValType>>> (VM::*FPtr)( |
328 | 0 | Span<const Byte>, std::string_view, Span<const ValVariant>, |
329 | 0 | Span<const ValType>) = &VM::runWasmFile; |
330 | 0 | return {FPtr, |
331 | 0 | *this, |
332 | 0 | Code, |
333 | 0 | std::string(Func), |
334 | 0 | std::vector(Params.begin(), Params.end()), |
335 | 0 | std::vector(ParamTypes.begin(), ParamTypes.end())}; |
336 | 0 | } |
337 | | |
338 | | Async<Expect<std::vector<std::pair<ValVariant, ValType>>>> |
339 | | VM::asyncRunWasmFile(const AST::Module &Module, std::string_view Func, |
340 | | Span<const ValVariant> Params, |
341 | 0 | Span<const ValType> ParamTypes) { |
342 | 0 | Expect<std::vector<std::pair<ValVariant, ValType>>> (VM::*FPtr)( |
343 | 0 | const AST::Module &, std::string_view, Span<const ValVariant>, |
344 | 0 | Span<const ValType>) = &VM::runWasmFile; |
345 | 0 | return {FPtr, |
346 | 0 | *this, |
347 | 0 | Module, |
348 | 0 | std::string(Func), |
349 | 0 | std::vector(Params.begin(), Params.end()), |
350 | 0 | std::vector(ParamTypes.begin(), ParamTypes.end())}; |
351 | 0 | } |
352 | | |
353 | 0 | Expect<void> VM::unsafeLoadWasm(const std::filesystem::path &Path) { |
354 | | // If loading does not succeed, the previous status will be preserved. |
355 | 0 | EXPECTED_TRY(auto ComponentOrModule, LoaderEngine.parseWasmUnit(Path)); |
356 | 0 | unsafeStoreWasmUnit(std::move(ComponentOrModule)); |
357 | 0 | Stage = VMStage::Loaded; |
358 | 0 | return {}; |
359 | 0 | } |
360 | | |
361 | 0 | Expect<void> VM::unsafeLoadWasm(Span<const Byte> Code) { |
362 | | // If loading does not succeed, the previous status will be preserved. |
363 | 0 | EXPECTED_TRY(auto ComponentOrModule, LoaderEngine.parseWasmUnit(Code)); |
364 | 0 | unsafeStoreWasmUnit(std::move(ComponentOrModule)); |
365 | 0 | Stage = VMStage::Loaded; |
366 | 0 | return {}; |
367 | 0 | } |
368 | | |
369 | 0 | Expect<void> VM::unsafeLoadWasm(const AST::Module &Module) { |
370 | 0 | Mod = std::make_shared<AST::Module>(Module); |
371 | 0 | Stage = VMStage::Loaded; |
372 | 0 | return {}; |
373 | 0 | } |
374 | | |
375 | 0 | Expect<void> VM::unsafeValidate() { |
376 | 0 | if (Stage < VMStage::Loaded) { |
377 | | // Do not validate when the module is not loaded. |
378 | 0 | spdlog::error(ErrCode::Value::WrongVMWorkflow); |
379 | 0 | return Unexpect(ErrCode::Value::WrongVMWorkflow); |
380 | 0 | } |
381 | | |
382 | 0 | if (Mod) { |
383 | 0 | EXPECTED_TRY(ValidatorEngine.validate(*Mod.get())); |
384 | 0 | } else if (Comp) { |
385 | 0 | EXPECTED_TRY(ValidatorEngine.validate(*Comp.get())); |
386 | 0 | } else { |
387 | 0 | spdlog::error(ErrCode::Value::WrongVMWorkflow); |
388 | 0 | return Unexpect(ErrCode::Value::WrongVMWorkflow); |
389 | 0 | } |
390 | 0 | Stage = VMStage::Validated; |
391 | 0 | return {}; |
392 | 0 | } |
393 | | |
394 | 0 | Expect<void> VM::unsafeLoadJITExecutable() { |
395 | 0 | if ((Conf.getRuntimeConfigure().getRunMode() != RunMode::JIT && |
396 | 0 | Conf.getRuntimeConfigure().getRunMode() != RunMode::LazyJIT) || |
397 | 0 | Mod->getSymbol()) { |
398 | 0 | return {}; |
399 | 0 | } |
400 | 0 | #ifdef WASMEDGE_USE_LLVM |
401 | 0 | if (LazyEngine) { |
402 | 0 | EXPECTED_TRY(auto Exec, LazyEngine->prepare(Mod)); |
403 | 0 | EXPECTED_TRY(LoaderEngine.loadExecutable(*Mod, std::move(Exec))); |
404 | 0 | return {}; |
405 | 0 | } |
406 | 0 | LLVM::Compiler Compiler(Conf); |
407 | 0 | Compiler.checkConfigure() |
408 | 0 | .map_error([](uint32_t Err) { |
409 | 0 | if (Err != ErrCode::Value::Success) { |
410 | 0 | spdlog::error("Compiler Configure failed. Error code: {}, use " |
411 | 0 | "interpreter mode instead."sv, |
412 | 0 | Err); |
413 | 0 | } |
414 | 0 | return ErrCode::Value::Success; |
415 | 0 | }) |
416 | 0 | .and_then([&]() { return Compiler.compile(*Mod); }) |
417 | 0 | .map_error([](uint32_t Err) { |
418 | 0 | if (Err != ErrCode::Value::Success) { |
419 | 0 | spdlog::error("Compilation failed. Error code: {}, use " |
420 | 0 | "interpreter mode instead."sv, |
421 | 0 | Err); |
422 | 0 | } |
423 | 0 | return ErrCode::Value::Success; |
424 | 0 | }) |
425 | 0 | .and_then([&](auto LLModule) { |
426 | 0 | LLVM::JIT JIT(Conf); |
427 | 0 | return JIT.load(std::move(LLModule)); |
428 | 0 | }) |
429 | 0 | .map_error([](uint32_t Err) { |
430 | 0 | if (Err != ErrCode::Value::Success) { |
431 | 0 | spdlog::warn( |
432 | 0 | "JIT failed. Error code: {}, use interpreter mode instead."sv, |
433 | 0 | Err); |
434 | 0 | } |
435 | 0 | return ErrCode::Value::Success; |
436 | 0 | }) |
437 | 0 | .and_then([&](auto Module) { |
438 | 0 | return LoaderEngine.loadExecutable(*Mod, std::move(Module)); |
439 | 0 | }) |
440 | 0 | .map_error([](uint32_t Err) { |
441 | 0 | if (Err != ErrCode::Value::Success) { |
442 | 0 | spdlog::warn("Loader failed. Error code: {}, use interpreter " |
443 | 0 | "mode instead."sv, |
444 | 0 | Err); |
445 | 0 | } |
446 | 0 | return ErrCode::Value::Success; |
447 | 0 | }); |
448 | 0 | return {}; |
449 | | #else |
450 | | spdlog::warn("JIT was requested but WasmEdge was built without LLVM, " |
451 | | "falling back to interpreter."sv); |
452 | | return {}; |
453 | | #endif |
454 | 0 | } |
455 | | |
456 | 0 | Expect<void> VM::unsafeInstantiate() { |
457 | 0 | if (Stage < VMStage::Validated) { |
458 | | // Do not instantiate when the module is not validated. |
459 | 0 | spdlog::error(ErrCode::Value::WrongVMWorkflow); |
460 | 0 | return Unexpect(ErrCode::Value::WrongVMWorkflow); |
461 | 0 | } |
462 | 0 | if (Mod) { |
463 | 0 | EXPECTED_TRY(unsafeLoadJITExecutable()); |
464 | 0 | EXPECTED_TRY(auto NewModInst, |
465 | 0 | ExecutorEngine.instantiateModule(StoreRef, *Mod)); |
466 | |
|
467 | 0 | #ifdef WASMEDGE_USE_LLVM |
468 | 0 | if (LazyEngine) { |
469 | | // Rebind the lazy JIT state only after instantiation succeeds, so a |
470 | | // failed re-instantiation keeps the current instance bound. |
471 | 0 | if (ActiveModInst) { |
472 | 0 | LazyEngine->unregisterInstance(*ActiveModInst); |
473 | 0 | } |
474 | 0 | LazyEngine->registerInstance(*NewModInst, Mod); |
475 | 0 | } |
476 | 0 | #endif |
477 | 0 | ActiveModInst = std::move(NewModInst); |
478 | |
|
479 | 0 | Stage = VMStage::Instantiated; |
480 | 0 | return {}; |
481 | 0 | } |
482 | 0 | if (Comp) { |
483 | 0 | EXPECTED_TRY(ActiveCompInst, |
484 | 0 | ExecutorEngine.instantiateComponent(StoreRef, *Comp)); |
485 | 0 | Stage = VMStage::Instantiated; |
486 | 0 | return {}; |
487 | 0 | } |
488 | 0 | spdlog::error(ErrCode::Value::WrongVMWorkflow); |
489 | 0 | return Unexpect(ErrCode::Value::WrongVMWorkflow); |
490 | 0 | } |
491 | | |
492 | | Expect<std::vector<std::pair<ValVariant, ValType>>> |
493 | | VM::unsafeExecute(std::string_view Func, Span<const ValVariant> Params, |
494 | 0 | Span<const ValType> ParamTypes) { |
495 | 0 | if (unlikely(!ActiveModInst)) { |
496 | 0 | spdlog::error(ErrCode::Value::WrongInstanceAddress); |
497 | 0 | spdlog::error(ErrInfo::InfoExecuting("When invoking"sv, Func)); |
498 | 0 | return Unexpect(ErrCode::Value::WrongInstanceAddress); |
499 | 0 | } |
500 | | // Execute function and return values using the module instance. |
501 | 0 | return unsafeExecute(ActiveModInst.get(), Func, Params, ParamTypes); |
502 | 0 | } |
503 | | |
504 | | Expect<std::vector<std::pair<ValVariant, ValType>>> |
505 | | VM::unsafeExecute(std::string_view ModName, std::string_view Func, |
506 | | Span<const ValVariant> Params, |
507 | 0 | Span<const ValType> ParamTypes) { |
508 | | // Find module instance by name. |
509 | 0 | const auto *FindModInst = StoreRef.findModule(ModName); |
510 | 0 | if (unlikely(!FindModInst)) { |
511 | 0 | spdlog::error(ErrCode::Value::WrongInstanceAddress); |
512 | 0 | spdlog::error(ErrInfo::InfoExecuting(ModName, Func)); |
513 | 0 | return Unexpect(ErrCode::Value::WrongInstanceAddress); |
514 | 0 | } |
515 | | // Execute function and return values using the module instance. |
516 | 0 | return unsafeExecute(FindModInst, Func, Params, ParamTypes); |
517 | 0 | } |
518 | | |
519 | | Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>> |
520 | | VM::unsafeExecuteComponent(std::string_view Func, |
521 | | Span<const ComponentValVariant> Params, |
522 | 0 | Span<const ComponentValType> ParamTypes) { |
523 | 0 | if (unlikely(!ActiveCompInst)) { |
524 | 0 | spdlog::error(ErrCode::Value::WrongInstanceAddress); |
525 | 0 | spdlog::error(ErrInfo::InfoExecuting("When invoking"sv, Func)); |
526 | 0 | return Unexpect(ErrCode::Value::WrongInstanceAddress); |
527 | 0 | } |
528 | 0 | return unsafeExecuteComponent(ActiveCompInst.get(), Func, Params, ParamTypes); |
529 | 0 | } |
530 | | |
531 | | Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>> |
532 | | VM::unsafeExecuteComponent(std::string_view CompName, std::string_view Func, |
533 | | Span<const ComponentValVariant> Params, |
534 | 0 | Span<const ComponentValType> ParamTypes) { |
535 | | // Find module instance by name. |
536 | 0 | const auto *FindCompInst = StoreRef.findComponent(CompName); |
537 | 0 | if (unlikely(!FindCompInst)) { |
538 | 0 | spdlog::error(ErrCode::Value::WrongInstanceAddress); |
539 | 0 | spdlog::error(ErrInfo::InfoExecuting(CompName, Func)); |
540 | 0 | return Unexpect(ErrCode::Value::WrongInstanceAddress); |
541 | 0 | } |
542 | | // Execute function and return values using the component instance. |
543 | 0 | return unsafeExecuteComponent(FindCompInst, Func, Params, ParamTypes); |
544 | 0 | } |
545 | | |
546 | | Expect<std::vector<std::pair<ValVariant, ValType>>> |
547 | | VM::unsafeExecute(const Runtime::Instance::ModuleInstance *ModInst, |
548 | | std::string_view Func, Span<const ValVariant> Params, |
549 | 0 | Span<const ValType> ParamTypes) { |
550 | | // Find exported function by name. |
551 | 0 | Runtime::Instance::FunctionInstance *FuncInst = |
552 | 0 | ModInst->findFuncExports(Func); |
553 | |
|
554 | 0 | #ifdef WASMEDGE_USE_LLVM |
555 | | // Lazy JIT: compile the function on-demand if needed. |
556 | 0 | if (LazyEngine) { |
557 | 0 | EXPECTED_TRY(LazyEngine->compileOnDemand(FuncInst)); |
558 | 0 | } |
559 | 0 | #endif |
560 | | |
561 | | // Execute function. |
562 | 0 | return ExecutorEngine.invoke(FuncInst, Params, ParamTypes) |
563 | 0 | .map_error([&ModInst, &Func](auto E) { |
564 | 0 | if (E != ErrCode::Value::Terminated) { |
565 | 0 | spdlog::error(ErrInfo::InfoExecuting(ModInst->getModuleName(), Func)); |
566 | 0 | } |
567 | 0 | return E; |
568 | 0 | }); |
569 | 0 | } |
570 | | |
571 | | Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>> |
572 | | VM::unsafeExecuteComponent(const Runtime::Instance::ComponentInstance *CompInst, |
573 | | std::string_view Func, |
574 | | Span<const ComponentValVariant> Params, |
575 | 0 | Span<const ComponentValType> ParamTypes) { |
576 | | // Find exported function by name. |
577 | 0 | Runtime::Instance::Component::FunctionInstance *FuncInst = |
578 | 0 | CompInst->findFunction(Func); |
579 | | |
580 | | // Execute function. |
581 | 0 | return ExecutorEngine.invoke(FuncInst, Params, ParamTypes) |
582 | 0 | .map_error([&CompInst, &Func](auto E) { |
583 | 0 | if (E != ErrCode::Value::Terminated) { |
584 | 0 | spdlog::error( |
585 | 0 | ErrInfo::InfoExecuting(CompInst->getComponentName(), Func)); |
586 | 0 | } |
587 | 0 | return E; |
588 | 0 | }); |
589 | 0 | } |
590 | | |
591 | | Async<Expect<std::vector<std::pair<ValVariant, ValType>>>> |
592 | | VM::asyncExecute(std::string_view Func, Span<const ValVariant> Params, |
593 | 0 | Span<const ValType> ParamTypes) { |
594 | 0 | Expect<std::vector<std::pair<ValVariant, ValType>>> (VM::*FPtr)( |
595 | 0 | std::string_view, Span<const ValVariant>, Span<const ValType>) = |
596 | 0 | &VM::execute; |
597 | 0 | return {FPtr, *this, std::string(Func), |
598 | 0 | std::vector(Params.begin(), Params.end()), |
599 | 0 | std::vector(ParamTypes.begin(), ParamTypes.end())}; |
600 | 0 | } |
601 | | |
602 | | Async<Expect<std::vector<std::pair<ValVariant, ValType>>>> |
603 | | VM::asyncExecute(std::string_view ModName, std::string_view Func, |
604 | | Span<const ValVariant> Params, |
605 | 0 | Span<const ValType> ParamTypes) { |
606 | 0 | Expect<std::vector<std::pair<ValVariant, ValType>>> (VM::*FPtr)( |
607 | 0 | std::string_view, std::string_view, Span<const ValVariant>, |
608 | 0 | Span<const ValType>) = &VM::execute; |
609 | 0 | return {FPtr, |
610 | 0 | *this, |
611 | 0 | std::string(ModName), |
612 | 0 | std::string(Func), |
613 | 0 | std::vector(Params.begin(), Params.end()), |
614 | 0 | std::vector(ParamTypes.begin(), ParamTypes.end())}; |
615 | 0 | } |
616 | | |
617 | | Async<Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>> |
618 | | VM::asyncExecuteComponent(std::string_view Func, |
619 | | Span<const ComponentValVariant> Params, |
620 | 0 | Span<const ComponentValType> ParamTypes) { |
621 | 0 | Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>> ( |
622 | 0 | VM::*FPtr)(std::string_view, Span<const ComponentValVariant>, |
623 | 0 | Span<const ComponentValType>) = &VM::executeComponent; |
624 | 0 | return {FPtr, *this, std::string(Func), |
625 | 0 | std::vector(Params.begin(), Params.end()), |
626 | 0 | std::vector(ParamTypes.begin(), ParamTypes.end())}; |
627 | 0 | } |
628 | | |
629 | | Async<Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>> |
630 | | VM::asyncExecuteComponent(std::string_view CompName, std::string_view Func, |
631 | | Span<const ComponentValVariant> Params, |
632 | 0 | Span<const ComponentValType> ParamTypes) { |
633 | 0 | Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>> ( |
634 | 0 | VM::*FPtr)(std::string_view, std::string_view, |
635 | 0 | Span<const ComponentValVariant>, |
636 | 0 | Span<const ComponentValType>) = &VM::executeComponent; |
637 | 0 | return {FPtr, |
638 | 0 | *this, |
639 | 0 | std::string(CompName), |
640 | 0 | std::string(Func), |
641 | 0 | std::vector(Params.begin(), Params.end()), |
642 | 0 | std::vector(ParamTypes.begin(), ParamTypes.end())}; |
643 | 0 | } |
644 | | |
645 | 0 | void VM::unsafeCleanup() { |
646 | 0 | if (Mod) { |
647 | 0 | Mod.reset(); |
648 | 0 | } |
649 | 0 | if (Comp) { |
650 | 0 | Comp.reset(); |
651 | 0 | } |
652 | 0 | if (ActiveModInst) { |
653 | 0 | auto *RawMod = ActiveModInst.release(); |
654 | 0 | if (RawMod) { |
655 | 0 | RawMod->terminate(); |
656 | 0 | } |
657 | 0 | } |
658 | 0 | if (ActiveCompInst) { |
659 | 0 | ActiveCompInst.reset(); |
660 | 0 | } |
661 | 0 | StoreRef.reset(); |
662 | 0 | cleanupModInstContainer(RegModInsts); |
663 | 0 | Stat.clear(); |
664 | 0 | unsafeLoadBuiltInHosts(); |
665 | 0 | unsafeLoadPlugInHosts(); |
666 | 0 | unsafeRegisterBuiltInHosts(); |
667 | 0 | unsafeRegisterPlugInHosts(); |
668 | 0 | LoaderEngine.reset(); |
669 | 0 | Stage = VMStage::Inited; |
670 | 0 | #ifdef WASMEDGE_USE_LLVM |
671 | 0 | if (LazyEngine) { |
672 | 0 | LazyEngine->clear(); |
673 | 0 | } |
674 | 0 | #endif |
675 | 0 | } |
676 | | |
677 | | std::vector<std::pair<std::string, const AST::FunctionType &>> |
678 | 0 | VM::unsafeGetFunctionList() const { |
679 | 0 | std::vector<std::pair<std::string, const AST::FunctionType &>> Map; |
680 | 0 | if (ActiveModInst) { |
681 | 0 | ActiveModInst->getFuncExports([&](const auto &FuncExports) { |
682 | 0 | Map.reserve(FuncExports.size()); |
683 | 0 | for (auto &&Func : FuncExports) { |
684 | 0 | const auto &FuncType = (Func.second)->getFuncType(); |
685 | 0 | Map.emplace_back(Func.first, FuncType); |
686 | 0 | } |
687 | 0 | }); |
688 | 0 | } |
689 | 0 | return Map; |
690 | 0 | } |
691 | | |
692 | | std::vector<std::pair<std::string, const AST::Component::FuncType &>> |
693 | 0 | VM::unsafeGetComponentFunctionList() const { |
694 | 0 | std::vector<std::pair<std::string, const AST::Component::FuncType &>> Map; |
695 | 0 | if (ActiveCompInst) { |
696 | 0 | ActiveCompInst->getFuncExports([&](const auto &FuncExports) { |
697 | 0 | Map.reserve(FuncExports.size()); |
698 | 0 | for (auto &&Func : FuncExports) { |
699 | 0 | const auto &FuncType = (Func.second)->getFuncType(); |
700 | 0 | Map.emplace_back(Func.first, FuncType); |
701 | 0 | } |
702 | 0 | }); |
703 | 0 | } |
704 | 0 | return Map; |
705 | 0 | } |
706 | | |
707 | | Runtime::Instance::ModuleInstance * |
708 | 0 | VM::unsafeGetImportModule(const HostRegistration Type) const { |
709 | 0 | if (auto Iter = BuiltInModInsts.find(Type); Iter != BuiltInModInsts.cend()) { |
710 | 0 | return Iter->second.get(); |
711 | 0 | } |
712 | 0 | return nullptr; |
713 | 0 | } |
714 | | |
715 | 0 | const Runtime::Instance::ModuleInstance *VM::unsafeGetActiveModule() const { |
716 | 0 | if (ActiveModInst) { |
717 | 0 | return ActiveModInst.get(); |
718 | 0 | } |
719 | 0 | return nullptr; |
720 | 0 | }; |
721 | | |
722 | | } // namespace VM |
723 | | } // namespace WasmEdge |