Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/vm/vm.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- wasmedge/vm/vm.h - VM execution flow class definition -------------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file defines the VM class.
12
///
13
//===----------------------------------------------------------------------===//
14
#pragma once
15
16
#include "common/async.h"
17
#include "common/configure.h"
18
#include "common/errcode.h"
19
#include "common/filesystem.h"
20
#include "common/types.h"
21
22
#include "executor/executor.h"
23
#include "loader/loader.h"
24
#include "validator/validator.h"
25
26
#include "runtime/instance/module.h"
27
#include "runtime/storemgr.h"
28
29
#ifdef WASMEDGE_USE_LLVM
30
#include "llvm/lazyjit.h"
31
#endif
32
33
#include <cstdint>
34
#include <memory>
35
#include <shared_mutex>
36
#include <string>
37
#include <string_view>
38
#include <type_traits>
39
#include <unordered_map>
40
#include <utility>
41
#include <variant>
42
#include <vector>
43
44
namespace WasmEdge {
45
namespace VM {
46
47
/// VM execution flow class
48
class VM {
49
public:
50
  VM() = delete;
51
  VM(const Configure &Conf);
52
  VM(const Configure &Conf, Runtime::StoreManager &S);
53
0
  ~VM() {
54
0
    if (ActiveModInst) {
55
0
      auto *RawMod = ActiveModInst.release();
56
0
      if (RawMod) {
57
0
        RawMod->terminate();
58
0
      }
59
0
    }
60
0
    cleanupModInstContainer(RegModInsts);
61
0
    cleanupModInstContainer(BuiltInModInsts);
62
0
    cleanupModInstContainer(PlugInModInsts);
63
0
  }
64
65
  /// ======= Functions can be called before the instantiated stage. =======
66
  /// Register wasm modules and host modules.
67
  Expect<void> registerModule(std::string_view Name,
68
0
                              const std::filesystem::path &Path) {
69
0
    std::unique_lock Lock(Mutex);
70
0
    return unsafeRegisterModule(Name, Path);
71
0
  }
72
0
  Expect<void> registerModule(std::string_view Name, Span<const Byte> Code) {
73
0
    std::unique_lock Lock(Mutex);
74
0
    return unsafeRegisterModule(Name, Code);
75
0
  }
76
  Expect<void> registerModule(std::string_view Name,
77
0
                              const AST::Module &Module) {
78
0
    std::unique_lock Lock(Mutex);
79
0
    return unsafeRegisterModule(Name, Module);
80
0
  }
81
  Expect<void>
82
0
  registerModule(const Runtime::Instance::ModuleInstance &ModInst) {
83
0
    return registerModule(ModInst.getModuleName(), ModInst);
84
0
  }
85
  Expect<void>
86
  registerModule(std::string_view Name,
87
0
                 const Runtime::Instance::ModuleInstance &ModInst) {
88
0
    std::unique_lock Lock(Mutex);
89
0
    return unsafeRegisterModule(Name, ModInst);
90
0
  }
91
92
  /// Unregister a named module instance.
93
0
  Expect<void> unregisterModule(std::string_view Name) {
94
0
    std::unique_lock Lock(Mutex);
95
0
    return unsafeUnregisterModule(Name);
96
0
  }
97
98
  /// Rapidly load, validate, instantiate, and run wasm function.
99
  Expect<std::vector<std::pair<ValVariant, ValType>>>
100
  runWasmFile(const std::filesystem::path &Path, std::string_view Func,
101
              Span<const ValVariant> Params = {},
102
0
              Span<const ValType> ParamTypes = {}) {
103
0
    std::unique_lock Lock(Mutex);
104
0
    return unsafeRunWasmFile(Path, Func, Params, ParamTypes);
105
0
  }
106
  Expect<std::vector<std::pair<ValVariant, ValType>>>
107
  runWasmFile(Span<const Byte> Code, std::string_view Func,
108
              Span<const ValVariant> Params = {},
109
0
              Span<const ValType> ParamTypes = {}) {
110
0
    std::unique_lock Lock(Mutex);
111
0
    return unsafeRunWasmFile(Code, Func, Params, ParamTypes);
112
0
  }
113
  Expect<std::vector<std::pair<ValVariant, ValType>>>
114
  runWasmFile(const AST::Module &Module, std::string_view Func,
115
              Span<const ValVariant> Params = {},
116
0
              Span<const ValType> ParamTypes = {}) {
117
0
    std::unique_lock Lock(Mutex);
118
0
    return unsafeRunWasmFile(Module, Func, Params, ParamTypes);
119
0
  }
120
121
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
122
  asyncRunWasmFile(const std::filesystem::path &Path, std::string_view Func,
123
                   Span<const ValVariant> Params = {},
124
                   Span<const ValType> ParamTypes = {});
125
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
126
  asyncRunWasmFile(Span<const Byte> Code, std::string_view Func,
127
                   Span<const ValVariant> Params = {},
128
                   Span<const ValType> ParamTypes = {});
129
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
130
  asyncRunWasmFile(const AST::Module &Module, std::string_view Func,
131
                   Span<const ValVariant> Params = {},
132
                   Span<const ValType> ParamTypes = {});
133
134
  /// Let runtimeTool check which arguments should be prepared.
135
0
  bool holdsModule() {
136
0
    if (ActiveModInst) {
137
0
      return true;
138
0
    }
139
0
    return false;
140
0
  }
141
0
  bool holdsComponent() {
142
0
    if (ActiveCompInst) {
143
0
      return true;
144
0
    }
145
0
    return false;
146
0
  }
147
148
  /// Load given wasm file, wasm bytecode, or wasm module.
149
0
  Expect<void> loadWasm(const std::filesystem::path &Path) {
150
0
    std::unique_lock Lock(Mutex);
151
0
    return unsafeLoadWasm(Path);
152
0
  }
153
0
  Expect<void> loadWasm(Span<const Byte> Code) {
154
0
    std::unique_lock Lock(Mutex);
155
0
    return unsafeLoadWasm(Code);
156
0
  }
157
0
  Expect<void> loadWasm(const AST::Module &Module) {
158
0
    std::unique_lock Lock(Mutex);
159
0
    return unsafeLoadWasm(Module);
160
0
  }
161
162
  /// ======= Functions can be called after the loaded stage. =======
163
  /// Validate loaded wasm module.
164
0
  Expect<void> validate() {
165
0
    std::unique_lock Lock(Mutex);
166
0
    return unsafeValidate();
167
0
  }
168
169
  /// Force-set the VM stage to Validated for a loaded component without
170
  /// actually running validation. Only used in spec tests and will be removed
171
  /// when component-model is fully supported.
172
  /// Returns failure if no component is loaded.
173
0
  Expect<void> forceValidateForComponent() {
174
0
    std::unique_lock Lock(Mutex);
175
0
    if (Stage < VMStage::Loaded || !Comp) {
176
0
      return Unexpect(ErrCode::Value::WrongVMWorkflow);
177
0
    }
178
0
    Comp->setIsValidated();
179
0
    Stage = VMStage::Validated;
180
0
    return {};
181
0
  }
182
183
  /// ======= Functions can be called after the validated stage. =======
184
  /// Instantiate validated wasm module.
185
0
  Expect<void> instantiate() {
186
0
    std::unique_lock Lock(Mutex);
187
0
    return unsafeInstantiate();
188
0
  }
189
190
  /// ======= Functions can be called after the instantiated stage. =======
191
  /// Execute wasm with given input.
192
  Expect<std::vector<std::pair<ValVariant, ValType>>>
193
  execute(std::string_view Func, Span<const ValVariant> Params = {},
194
0
          Span<const ValType> ParamTypes = {}) {
195
0
    std::shared_lock Lock(Mutex);
196
0
    return unsafeExecute(Func, Params, ParamTypes);
197
0
  }
198
199
  /// Execute a function of a registered module with the given input.
200
  Expect<std::vector<std::pair<ValVariant, ValType>>>
201
  execute(std::string_view ModName, std::string_view Func,
202
          Span<const ValVariant> Params = {},
203
0
          Span<const ValType> ParamTypes = {}) {
204
0
    std::shared_lock Lock(Mutex);
205
0
    return unsafeExecute(ModName, Func, Params, ParamTypes);
206
0
  }
207
208
  /// Execute a component function with the given input.
209
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
210
  executeComponent(std::string_view Func,
211
                   Span<const ComponentValVariant> Params = {},
212
0
                   Span<const ComponentValType> ParamTypes = {}) {
213
0
    std::shared_lock Lock(Mutex);
214
0
    return unsafeExecuteComponent(Func, Params, ParamTypes);
215
0
  }
216
217
  /// Execute a function of a registered component with the given input.
218
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
219
  executeComponent(std::string_view CompName, std::string_view Func,
220
                   Span<const ComponentValVariant> Params = {},
221
0
                   Span<const ComponentValType> ParamTypes = {}) {
222
0
    std::shared_lock Lock(Mutex);
223
0
    return unsafeExecuteComponent(CompName, Func, Params, ParamTypes);
224
0
  }
225
226
  /// Asynchronously execute Wasm with the given input.
227
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
228
  asyncExecute(std::string_view Func, Span<const ValVariant> Params = {},
229
               Span<const ValType> ParamTypes = {});
230
231
  /// Asynchronously execute a function of a registered module with the given
232
  /// input.
233
  Async<Expect<std::vector<std::pair<ValVariant, ValType>>>>
234
  asyncExecute(std::string_view ModName, std::string_view Func,
235
               Span<const ValVariant> Params = {},
236
               Span<const ValType> ParamTypes = {});
237
238
  /// Asynchronously execute a component function with the given input.
239
  Async<Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>>
240
  asyncExecuteComponent(std::string_view Func,
241
                        Span<const ComponentValVariant> Params = {},
242
                        Span<const ComponentValType> ParamTypes = {});
243
244
  /// Asynchronously execute a function of a registered component with the given
245
  /// input.
246
  Async<Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>>
247
  asyncExecuteComponent(std::string_view ModName, std::string_view Func,
248
                        Span<const ComponentValVariant> Params = {},
249
                        Span<const ComponentValType> ParamTypes = {});
250
251
  /// Stop execution
252
0
  void stop() noexcept { ExecutorEngine.stop(); }
253
254
  /// Snapshot VM-owned core modules at an invocation boundary. An empty path
255
  /// selects the default coredump filename. Externally registered modules are
256
  /// included only through state imported by a VM-owned module.
257
  Expect<std::filesystem::path>
258
  snapshot(const std::filesystem::path &Path = {});
259
  /// Restore the same ordered VM-owned module set. Component instances and
260
  /// restoring dropped segments to live segments are unsupported.
261
  Expect<void> restore(const std::filesystem::path &Path);
262
263
  /// ======= Functions which are stageless. =======
264
  /// Clean up VM status
265
0
  void cleanup() {
266
0
    std::unique_lock Lock(Mutex);
267
0
    return unsafeCleanup();
268
0
  }
269
270
  /// Get list of callable functions and corresponding function types.
271
  std::vector<std::pair<std::string, const AST::FunctionType &>>
272
0
  getFunctionList() const {
273
0
    std::shared_lock Lock(Mutex);
274
0
    return unsafeGetFunctionList();
275
0
  }
276
277
  /// Get list of callable component functions and corresponding function types.
278
  std::vector<std::pair<std::string, const AST::Component::FuncType &>>
279
0
  getComponentFunctionList() const {
280
0
    std::shared_lock Lock(Mutex);
281
0
    return unsafeGetComponentFunctionList();
282
0
  }
283
284
  /// Get pre-registered module instance by configuration.
285
  Runtime::Instance::ModuleInstance *
286
0
  getImportModule(const HostRegistration Type) const {
287
0
    std::shared_lock Lock(Mutex);
288
0
    return unsafeGetImportModule(Type);
289
0
  }
290
291
  /// Get current instantiated module instance.
292
0
  const Runtime::Instance::ModuleInstance *getActiveModule() const {
293
0
    std::shared_lock Lock(Mutex);
294
0
    return unsafeGetActiveModule();
295
0
  }
296
297
  /// Getter for the store set in the VM.
298
0
  Runtime::StoreManager &getStoreManager() noexcept { return StoreRef; }
299
0
  const Runtime::StoreManager &getStoreManager() const noexcept {
300
0
    return StoreRef;
301
0
  }
302
303
  /// Getter for the loader in the VM.
304
0
  Loader::Loader &getLoader() noexcept { return LoaderEngine; }
305
306
  /// Getter for the validator in the VM.
307
0
  Validator::Validator &getValidator() noexcept { return ValidatorEngine; }
308
309
  /// Getter for the executor in the VM.
310
0
  Executor::Executor &getExecutor() noexcept { return ExecutorEngine; }
311
312
  /// Getter for statistics.
313
0
  Statistics::Statistics &getStatistics() noexcept { return Stat; }
314
315
#ifdef WASMEDGE_USE_LLVM
316
  /// Getter for the number of lazily compiled functions.
317
0
  uint32_t getLazyCompiledFuncCount() const noexcept {
318
0
    return LazyEngine ? LazyEngine->compiledFunctionCount() : 0;
319
0
  }
320
#endif
321
322
private:
323
  std::vector<Runtime::Instance::ModuleInstance *> collectModuleInstances();
324
325
  /// Release and terminate all module instances in a sequence or map
326
  /// container, then clear the container.
327
  template <typename ContainerT>
328
0
  void cleanupModInstContainer(ContainerT &Container) {
329
0
    for (auto &Item : Container) {
330
0
      Runtime::Instance::ModuleInstance *ModInst;
331
      if constexpr (std::is_same_v<
332
                        typename ContainerT::value_type,
333
0
                        std::unique_ptr<Runtime::Instance::ModuleInstance>>) {
334
0
        ModInst = Item.release();
335
0
      } else {
336
0
        ModInst = Item.second.release();
337
0
      }
338
0
      if (ModInst) {
339
0
        ModInst->terminate();
340
0
      }
341
0
    }
342
0
    Container.clear();
343
0
  }
Unexecuted instantiation: void WasmEdge::VM::VM::cleanupModInstContainer<std::__1::vector<std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> >, std::__1::allocator<std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> > > > >(std::__1::vector<std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> >, std::__1::allocator<std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> > > >&)
Unexecuted instantiation: void WasmEdge::VM::VM::cleanupModInstContainer<std::__1::unordered_map<WasmEdge::HostRegistration, std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> >, std::__1::hash<WasmEdge::HostRegistration>, std::__1::equal_to<WasmEdge::HostRegistration>, std::__1::allocator<std::__1::pair<WasmEdge::HostRegistration const, std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> > > > > >(std::__1::unordered_map<WasmEdge::HostRegistration, std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> >, std::__1::hash<WasmEdge::HostRegistration>, std::__1::equal_to<WasmEdge::HostRegistration>, std::__1::allocator<std::__1::pair<WasmEdge::HostRegistration const, std::__1::unique_ptr<WasmEdge::Runtime::Instance::ModuleInstance, std::__1::default_delete<WasmEdge::Runtime::Instance::ModuleInstance> > > > >&)
344
345
  Expect<void> unsafeRegisterModule(std::string_view Name,
346
                                    const std::filesystem::path &Path);
347
  Expect<void> unsafeRegisterModule(std::string_view Name,
348
                                    Span<const Byte> Code);
349
  Expect<void> unsafeRegisterModule(std::string_view Name,
350
                                    const AST::Module &Module);
351
  Expect<void> unsafeRegisterModule(std::string_view Name,
352
                                    std::shared_ptr<AST::Module> Module);
353
  Expect<void>
354
  unsafeRegisterModule(std::string_view Name,
355
                       const Runtime::Instance::ModuleInstance &ModInst);
356
357
  Expect<void> unsafeUnregisterModule(std::string_view Name);
358
359
  Expect<std::vector<std::pair<ValVariant, ValType>>>
360
  unsafeRunWasmFile(const std::filesystem::path &Path, std::string_view Func,
361
                    Span<const ValVariant> Params = {},
362
                    Span<const ValType> ParamTypes = {});
363
  Expect<std::vector<std::pair<ValVariant, ValType>>>
364
  unsafeRunWasmFile(Span<const Byte> Code, std::string_view Func,
365
                    Span<const ValVariant> Params = {},
366
                    Span<const ValType> ParamTypes = {});
367
  Expect<std::vector<std::pair<ValVariant, ValType>>>
368
  unsafeRunWasmFile(const AST::Module &Module, std::string_view Func,
369
                    Span<const ValVariant> Params = {},
370
                    Span<const ValType> ParamTypes = {});
371
  Expect<std::vector<std::pair<ValVariant, ValType>>>
372
  unsafeRunWasmFile(const AST::Component::Component &Component,
373
                    std::string_view Func, Span<const ValVariant> Params = {},
374
                    Span<const ValType> ParamTypes = {});
375
376
  Expect<void> unsafeLoadWasm(const std::filesystem::path &Path);
377
  Expect<void> unsafeLoadWasm(Span<const Byte> Code);
378
  Expect<void> unsafeLoadWasm(const AST::Module &Module);
379
380
  Expect<void> unsafeValidate();
381
382
  Expect<void> unsafeInstantiate();
383
384
  /// In JIT or lazy JIT mode, compile and attach an executable to the loaded
385
  /// module if it does not carry one yet. Eager JIT compilation failures fall
386
  /// back to the interpreter; without LLVM support this only logs a warning.
387
  Expect<void> unsafeLoadJITExecutable();
388
389
  Expect<std::vector<std::pair<ValVariant, ValType>>>
390
  unsafeExecute(std::string_view Func, Span<const ValVariant> Params = {},
391
                Span<const ValType> ParamTypes = {});
392
  Expect<std::vector<std::pair<ValVariant, ValType>>>
393
  unsafeExecute(std::string_view Mod, std::string_view Func,
394
                Span<const ValVariant> Params = {},
395
                Span<const ValType> ParamTypes = {});
396
397
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
398
  unsafeExecuteComponent(std::string_view Func,
399
                         Span<const ComponentValVariant> Params = {},
400
                         Span<const ComponentValType> ParamTypes = {});
401
402
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
403
  unsafeExecuteComponent(std::string_view Comp, std::string_view Func,
404
                         Span<const ComponentValVariant> Params = {},
405
                         Span<const ComponentValType> ParamTypes = {});
406
407
  void unsafeCleanup();
408
409
  std::vector<std::pair<std::string, const AST::FunctionType &>>
410
  unsafeGetFunctionList() const;
411
412
  std::vector<std::pair<std::string, const AST::Component::FuncType &>>
413
  unsafeGetComponentFunctionList() const;
414
415
  Runtime::Instance::ModuleInstance *
416
  unsafeGetImportModule(const HostRegistration Type) const;
417
418
  const Runtime::Instance::ModuleInstance *unsafeGetActiveModule() const;
419
420
  enum class VMStage : uint8_t { Inited, Loaded, Validated, Instantiated };
421
  enum class WasmUnitKind : uint8_t { Module, Component };
422
423
  /// Store a parsed wasm unit into the matching slot and report its kind.
424
  /// The slot for the other kind keeps its previous content.
425
  WasmUnitKind
426
  unsafeStoreWasmUnit(std::variant<std::unique_ptr<AST::Component::Component>,
427
                                   std::unique_ptr<AST::Module>> &&Unit);
428
429
  /// Registering a module or running another wasm unit resets the active
430
  /// instantiation in the store, so the stage falls back to Validated and
431
  /// the instantiation must restart.
432
0
  void unsafeRevertStageToValidated() {
433
0
    if (Stage == VMStage::Instantiated) {
434
0
      Stage = VMStage::Validated;
435
0
    }
436
0
  }
437
438
  void unsafeInitVM();
439
  void unsafeLoadBuiltInHosts();
440
  void unsafeLoadPlugInHosts();
441
  void unsafeRegisterBuiltInHosts();
442
  void unsafeRegisterPlugInHosts();
443
444
  /// Helper function for execution.
445
  Expect<std::vector<std::pair<ValVariant, ValType>>>
446
  unsafeExecute(const Runtime::Instance::ModuleInstance *ModInst,
447
                std::string_view Func, Span<const ValVariant> Params = {},
448
                Span<const ValType> ParamTypes = {});
449
450
  Expect<std::vector<std::pair<ComponentValVariant, ComponentValType>>>
451
  unsafeExecuteComponent(const Runtime::Instance::ComponentInstance *CompInst,
452
                         std::string_view Func,
453
                         Span<const ComponentValVariant> Params = {},
454
                         Span<const ComponentValType> ParamTypes = {});
455
456
  /// \name VM environment.
457
  /// @{
458
  const Configure Conf;
459
  Statistics::Statistics Stat;
460
  VMStage Stage;
461
  mutable std::shared_mutex Mutex;
462
  /// @}
463
464
  /// \name VM components.
465
  /// @{
466
  Loader::Loader LoaderEngine;
467
  Validator::Validator ValidatorEngine;
468
#ifdef WASMEDGE_USE_LLVM
469
  /// Lazy JIT engine. Created only when the run mode is LazyJIT. Declared
470
  /// before the executor so it outlives the executor-registered lazy
471
  /// compilation callback that references it.
472
  std::unique_ptr<LLVM::LazyJITEngine> LazyEngine;
473
#endif
474
  Executor::Executor ExecutorEngine;
475
  /// @}
476
477
  /// \name VM Storage.
478
  /// @{
479
  /// Loaded AST module.
480
  std::shared_ptr<AST::Module> Mod;
481
  std::unique_ptr<AST::Component::Component> Comp;
482
  /// Active module instance.
483
  std::unique_ptr<Runtime::Instance::ModuleInstance> ActiveModInst;
484
  std::unique_ptr<Runtime::Instance::ComponentInstance> ActiveCompInst;
485
  /// Registered module instances by user.
486
  std::vector<std::unique_ptr<Runtime::Instance::ModuleInstance>> RegModInsts;
487
  /// Built-in module instances mapped to the configurations. For WASI.
488
  std::unordered_map<HostRegistration,
489
                     std::unique_ptr<Runtime::Instance::ModuleInstance>>
490
      BuiltInModInsts;
491
  /// Loaded module instances from plug-ins.
492
  std::vector<std::unique_ptr<Runtime::Instance::ModuleInstance>>
493
      PlugInModInsts;
494
  std::vector<std::unique_ptr<Runtime::Instance::ComponentInstance>>
495
      PlugInCompInsts;
496
  /// Self-owned store (nullptr if an outside store is assigned in constructor).
497
  std::unique_ptr<Runtime::StoreManager> Store;
498
  /// Reference to the store.
499
  Runtime::StoreManager &StoreRef;
500
  /// @}
501
};
502
503
} // namespace VM
504
} // namespace WasmEdge