Coverage Report

Created: 2026-06-30 06:10

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 "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