Coverage Report

Created: 2026-11-12 06:35

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