Coverage Report

Created: 2026-06-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/validator/component_context.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#pragma once
5
6
#include "ast/component/component.h"
7
#include "ast/module.h"
8
#include "validator/component_name.h"
9
10
#include <deque>
11
#include <optional>
12
#include <string>
13
#include <unordered_map>
14
#include <unordered_set>
15
#include <vector>
16
17
namespace WasmEdge {
18
namespace Validator {
19
20
class ComponentContext {
21
public:
22
  // ==========================================================================
23
  // Validation context (one per component scope)
24
  // ==========================================================================
25
26
  struct Context {
27
    Context(const AST::Component::Component *C,
28
            const Context *P = nullptr) noexcept
29
0
        : Component(C), Parent(P) {}
30
31
    // ---- Nested types ----
32
    // Per-sort slot structs bundling body + externdesc type ascription.
33
    // Exactly one of {Body, Type} is non-null per slot (Body for inline,
34
    // Type for imported / outer-aliased).
35
    struct CoreModuleSlot {
36
      const AST::Module *Body;
37
      const AST::Component::CoreDefType *Type;
38
0
      CoreModuleSlot() noexcept : Body(nullptr), Type(nullptr) {}
39
0
      CoreModuleSlot(const AST::Module &B) noexcept : Body(&B), Type(nullptr) {}
40
      CoreModuleSlot(const AST::Component::CoreDefType *T) noexcept
41
0
          : Body(nullptr), Type(T) {}
42
    };
43
    struct ComponentSlot {
44
      const AST::Component::Component *Body;
45
      const AST::Component::ComponentType *Type;
46
0
      ComponentSlot() noexcept : Body(nullptr), Type(nullptr) {}
47
      ComponentSlot(const AST::Component::Component &B) noexcept
48
0
          : Body(&B), Type(nullptr) {}
49
      ComponentSlot(const AST::Component::ComponentType *T) noexcept
50
0
          : Body(nullptr), Type(T) {}
51
    };
52
    // Per-export entry inside an instance's export table.
53
    // ResourceId is set when ST == Type and the exported type is a resource
54
    // (so an alias-export onto a new type slot can carry the same identity).
55
    struct InstanceExport {
56
      AST::Component::Sort::SortType ST;
57
      const AST::Component::InstanceType *IT;
58
      std::optional<uint32_t> NestedInstIdx;
59
      std::optional<uint64_t> ResourceId;
60
    };
61
    // Instance slot. Type is set only when bound via
62
    // validate(ExternDesc::InstanceType) (GAP-I-5b follow-up otherwise).
63
    struct InstanceSlot {
64
      std::unordered_map<std::string, InstanceExport> Exports;
65
      const AST::Component::InstanceType *Type;
66
0
      InstanceSlot() : Type(nullptr) {}
67
0
      InstanceSlot(const AST::Component::InstanceType *T) : Type(T) {}
68
    };
69
    // Per-resource bookkeeping. "Key present in Resources" means resource.
70
    // The resource's AST body lives on ComponentContext::ResourceRegistry[Id].
71
    struct ResourceInfo {
72
      // Canonical identity. Two indices share a resource iff ids match.
73
      uint64_t Id = 0;
74
      // True for validate(DefType) in this scope. Gates resource.new/.rep.
75
      bool LocallyDefined = false;
76
    };
77
78
    // ---- Scope identity ----
79
    const AST::Component::Component *Component;
80
    const Context *Parent;
81
82
    // ---- Core sort index spaces ----
83
    std::vector<CoreModuleSlot> CoreModules; // core:module
84
    std::vector<std::unordered_map<std::string, ExternalType>>
85
        CoreInstances;                                 // core:instance
86
    std::vector<const AST::SubType *> CoreTypes;       // core:type
87
    std::vector<const AST::SubType *> CoreFuncs;       // core:func
88
    std::vector<const AST::TableType *> CoreTables;    // core:table
89
    std::vector<const AST::MemoryType *> CoreMemories; // core:memory
90
    std::vector<const AST::GlobalType *> CoreGlobals;  // core:global
91
    uint32_t CoreTagCount = 0;                         // core:tag
92
93
    // ---- Component sort index spaces ----
94
    std::vector<ComponentSlot> Components;               // component
95
    std::vector<InstanceSlot> Instances;                 // instance
96
    std::vector<const AST::Component::DefType *> Types;  // type
97
    std::vector<const AST::Component::FuncType *> Funcs; // func (i may be null)
98
    uint32_t ValueCount = 0;                             // value
99
100
    // ---- Type annotations (keyed by type index) ----
101
    // ResourceType bodies live on Resources[i].Body (see below).
102
    std::unordered_map<uint32_t, const AST::Component::InstanceType *>
103
        InstanceTypes;
104
    std::unordered_map<uint32_t, const AST::Component::ComponentType *>
105
        ComponentTypes;
106
    // CoreDefType (moduletype) bodies, keyed by core:type-idx.
107
    std::unordered_map<uint32_t, const AST::Component::CoreDefType *>
108
        CoreModuleTypes;
109
110
    // ---- Resource state (keyed by type index) ----
111
    std::unordered_map<uint32_t, ResourceInfo> Resources;
112
113
    // ---- Validation state ----
114
    std::unordered_map<std::string, uint32_t> TypeSubstitutions;
115
    std::unordered_set<std::string> ImportedNames;
116
    std::unordered_set<std::string> ExportedNames;
117
    // Kebab-case resource name → type-idx; consumed by annotated-name
118
    // validation ([constructor]R / [method]R.f / [static]R.f).
119
    std::unordered_map<std::string, uint32_t> ResourceLabels;
120
121
    // ---- Size queries (used by outer-alias validation on parent ctxs) ----
122
    uint32_t getSortIndexSize(AST::Component::Sort::SortType ST) const noexcept;
123
    uint32_t
124
    getCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) const noexcept;
125
126
    bool AddImportedName(const ComponentName &Name) noexcept;
127
    bool AddExportedName(const ComponentName &Name) noexcept;
128
  };
129
130
  // Per-id row of the session-global resource registry. Held by
131
  // ComponentContext::ResourceRegistry; vector index IS the resource id.
132
  struct ResourceRegistryEntry {
133
    const AST::Component::ResourceType *Body = nullptr;
134
  };
135
136
  // ==========================================================================
137
  // Context stack management
138
  // ==========================================================================
139
140
0
  void reset() noexcept {
141
0
    CompCtxs.clear();
142
0
    ResourceRegistry.clear();
143
0
  }
144
145
  /// Push a new validation scope for a real component.
146
0
  void enterComponent(const AST::Component::Component *C) noexcept {
147
0
    const Context *Parent = CompCtxs.empty() ? nullptr : &CompCtxs.back();
148
0
    CompCtxs.emplace_back(C, Parent);
149
0
  }
150
151
  /// Push a new validation scope for a type definition
152
  /// (componenttype, instancetype, or moduletype).
153
0
  void enterTypeDefinition() noexcept {
154
0
    const Context *Parent = CompCtxs.empty() ? nullptr : &CompCtxs.back();
155
0
    CompCtxs.emplace_back(nullptr, Parent);
156
0
  }
157
158
0
  void exitComponent() noexcept {
159
0
    assuming(!CompCtxs.empty());
160
0
    CompCtxs.pop_back();
161
0
  }
162
163
  /// Returns true if the current scope is a type definition scope
164
  /// (componenttype or instancetype), not a real component scope.
165
0
  bool isTypeDefinitionScope() const noexcept {
166
0
    return !CompCtxs.empty() && CompCtxs.back().Component == nullptr;
167
0
  }
168
169
0
  Context &getCurrentContext() noexcept {
170
0
    assuming(!CompCtxs.empty());
171
0
    return CompCtxs.back();
172
0
  }
173
0
  const Context &getCurrentContext() const noexcept {
174
0
    assuming(!CompCtxs.empty());
175
0
    return CompCtxs.back();
176
0
  }
177
178
  // ==========================================================================
179
  // Index space size queries (generic dispatch by sort enum)
180
  // ==========================================================================
181
182
0
  uint32_t getSortIndexSize(AST::Component::Sort::SortType ST) const noexcept {
183
0
    return getCurrentContext().getSortIndexSize(ST);
184
0
  }
185
  uint32_t
186
0
  getCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) const noexcept {
187
0
    return getCurrentContext().getCoreSortIndexSize(ST);
188
0
  }
189
190
  // ==========================================================================
191
  // Generic index space increment (for dynamic sort values)
192
  // ==========================================================================
193
194
  uint32_t incSortIndexSize(AST::Component::Sort::SortType ST) noexcept;
195
  uint32_t incCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) noexcept;
196
197
  // ==========================================================================
198
  // core:module
199
  // ==========================================================================
200
201
  /// Append a core-module slot. Slot's implicit constructors accept
202
  /// `const AST::Module &` (inline body), `const CoreDefType *` (typed
203
  /// import / alias), or nothing (empty slot, used by outer-alias
204
  /// validation and incCoreSortIndexSize).
205
0
  uint32_t addCoreModule(Context::CoreModuleSlot S = {}) noexcept {
206
0
    auto &Ctx = getCurrentContext();
207
0
    uint32_t Idx = static_cast<uint32_t>(Ctx.CoreModules.size());
208
0
    Ctx.CoreModules.push_back(std::move(S));
209
0
    return Idx;
210
0
  }
211
212
  /// Read a core-module slot. Callers access `.Body` (inline body) or
213
  /// `.Type` (externdesc-bound moduletype) as needed.
214
0
  const Context::CoreModuleSlot &getCoreModule(uint32_t Idx) const noexcept {
215
0
    return getCurrentContext().CoreModules.at(Idx);
216
0
  }
217
218
  /// Returns the CoreDefType (a moduletype) stored at a core:type index, or
219
  /// nullptr if the core type is not a ModuleType (or its body is not
220
  /// visible here).
221
  const AST::Component::CoreDefType *
222
0
  getCoreModuleType(uint32_t TypeIdx) const noexcept {
223
0
    const auto &Ctx = getCurrentContext();
224
0
    auto It = Ctx.CoreModuleTypes.find(TypeIdx);
225
0
    return It != Ctx.CoreModuleTypes.end() ? It->second : nullptr;
226
0
  }
227
228
  /// Bind a CoreDefType (a moduletype) to a core:type index. Called by
229
  /// validate(CoreDefType) when adding a moduletype to the core:type space.
230
  void setCoreModuleType(uint32_t TypeIdx,
231
0
                         const AST::Component::CoreDefType *CT) noexcept {
232
0
    getCurrentContext().CoreModuleTypes[TypeIdx] = CT;
233
0
  }
234
235
  // ==========================================================================
236
  // core:instance
237
  // ==========================================================================
238
239
0
  uint32_t addCoreInstance() noexcept {
240
0
    auto &V = getCurrentContext().CoreInstances;
241
0
    uint32_t Idx = static_cast<uint32_t>(V.size());
242
0
    V.emplace_back();
243
0
    return Idx;
244
0
  }
245
246
  const std::unordered_map<std::string, ExternalType> &
247
0
  getCoreInstance(uint32_t Idx) const noexcept {
248
0
    return getCurrentContext().CoreInstances.at(Idx);
249
0
  }
250
251
  void addCoreInstanceExport(uint32_t InstIdx, std::string_view Name,
252
0
                             ExternalType ET) {
253
0
    getCurrentContext().CoreInstances.at(InstIdx)[std::string(Name)] = ET;
254
0
  }
255
256
  // ==========================================================================
257
  // core:type / core:func / core:table / core:memory / core:global / core:tag
258
  // ==========================================================================
259
260
0
  uint32_t addCoreType(const AST::SubType *ST = nullptr) noexcept {
261
0
    auto &V = getCurrentContext().CoreTypes;
262
0
    uint32_t Idx = static_cast<uint32_t>(V.size());
263
0
    V.push_back(ST);
264
0
    return Idx;
265
0
  }
266
0
  uint32_t addCoreFunc(const AST::SubType *ST = nullptr) noexcept {
267
0
    auto &V = getCurrentContext().CoreFuncs;
268
0
    uint32_t Idx = static_cast<uint32_t>(V.size());
269
0
    V.push_back(ST);
270
0
    return Idx;
271
0
  }
272
0
  const AST::SubType *getCoreFunc(uint32_t Idx) const noexcept {
273
0
    const auto &V = getCurrentContext().CoreFuncs;
274
0
    return Idx < V.size() ? V[Idx] : nullptr;
275
0
  }
276
277
0
  uint32_t addCoreTable(const AST::TableType *TT = nullptr) noexcept {
278
0
    auto &V = getCurrentContext().CoreTables;
279
0
    uint32_t Idx = static_cast<uint32_t>(V.size());
280
0
    V.push_back(TT);
281
0
    return Idx;
282
0
  }
283
0
  uint32_t addCoreMemory(const AST::MemoryType *MT = nullptr) noexcept {
284
0
    auto &V = getCurrentContext().CoreMemories;
285
0
    uint32_t Idx = static_cast<uint32_t>(V.size());
286
0
    V.push_back(MT);
287
0
    return Idx;
288
0
  }
289
0
  uint32_t addCoreGlobal(const AST::GlobalType *GT = nullptr) noexcept {
290
0
    auto &V = getCurrentContext().CoreGlobals;
291
0
    uint32_t Idx = static_cast<uint32_t>(V.size());
292
0
    V.push_back(GT);
293
0
    return Idx;
294
0
  }
295
0
  uint32_t addCoreTag() noexcept { return getCurrentContext().CoreTagCount++; }
296
297
  // ==========================================================================
298
  // component
299
  // ==========================================================================
300
301
  /// Append a component slot. Slot's implicit constructors accept
302
  /// `const Component &` (inline body), `const ComponentType *` (typed
303
  /// import / alias), or nothing (empty slot).
304
0
  uint32_t addComponent(Context::ComponentSlot S = {}) noexcept {
305
0
    auto &Ctx = getCurrentContext();
306
0
    uint32_t Idx = static_cast<uint32_t>(Ctx.Components.size());
307
0
    Ctx.Components.push_back(std::move(S));
308
0
    return Idx;
309
0
  }
310
311
  /// Read a component slot. Callers access `.Body` (inline body) or
312
  /// `.Type` (externdesc-bound ComponentType) as needed.
313
0
  const Context::ComponentSlot &getComponent(uint32_t Idx) const noexcept {
314
0
    return getCurrentContext().Components.at(Idx);
315
0
  }
316
317
  /// Returns the ComponentType stored at a type index, or nullptr if the
318
  /// type is not a ComponentType (or its body is not visible here).
319
  const AST::Component::ComponentType *
320
0
  getComponentType(uint32_t TypeIdx) const noexcept {
321
0
    const auto &Ctx = getCurrentContext();
322
0
    auto It = Ctx.ComponentTypes.find(TypeIdx);
323
0
    return It != Ctx.ComponentTypes.end() ? It->second : nullptr;
324
0
  }
325
326
  // The scope an outer alias targets: Ct parent hops up. nullptr if Ct
327
  // exceeds the enclosing depth.
328
0
  const Context *resolveOuterContext(uint32_t Ct) const noexcept {
329
0
    uint32_t Hops = 0;
330
0
    const Context *T = &getCurrentContext();
331
0
    while (Ct > Hops && T != nullptr) {
332
0
      T = T->Parent;
333
0
      ++Hops;
334
0
    }
335
0
    return T;
336
0
  }
337
338
  // Reproduce an outer-aliased core module's slot into the alias's slot
339
  // DstIdx, so its exports stay enumerable when the alias is instantiated.
340
  void carryOuterCoreModule(uint32_t DstIdx, uint32_t Ct,
341
0
                            uint32_t SrcIdx) noexcept {
342
0
    const Context *O = resolveOuterContext(Ct);
343
0
    auto &Dst = getCurrentContext().CoreModules;
344
0
    if (O != nullptr && SrcIdx < O->CoreModules.size() && DstIdx < Dst.size()) {
345
0
      Dst[DstIdx] = O->CoreModules[SrcIdx];
346
0
    }
347
0
  }
348
349
  // Component analogue of carryOuterCoreModule.
350
  void carryOuterComponent(uint32_t DstIdx, uint32_t Ct,
351
0
                           uint32_t SrcIdx) noexcept {
352
0
    const Context *O = resolveOuterContext(Ct);
353
0
    auto &Dst = getCurrentContext().Components;
354
0
    if (O != nullptr && SrcIdx < O->Components.size() && DstIdx < Dst.size()) {
355
0
      Dst[DstIdx] = O->Components[SrcIdx];
356
0
    }
357
0
  }
358
359
  // Inherit an outer-aliased resource type's identity into the alias's type
360
  // slot DstIdx, so own/borrow checks and TypeBound (eq i) propagation in this
361
  // scope still recognise the aliased type as a resource. The alias does not
362
  // locally define the resource, so LocallyDefined stays false (it must not
363
  // gate resource.new/.rep here).
364
  void carryOuterResource(uint32_t DstIdx, uint32_t Ct,
365
0
                          uint32_t SrcIdx) noexcept {
366
0
    const Context *O = resolveOuterContext(Ct);
367
0
    if (O == nullptr) {
368
0
      return;
369
0
    }
370
0
    auto It = O->Resources.find(SrcIdx);
371
0
    if (It != O->Resources.end()) {
372
0
      getCurrentContext().Resources[DstIdx] = {It->second.Id,
373
0
                                               /*LocallyDefined=*/false};
374
0
    }
375
0
  }
376
377
  // ==========================================================================
378
  // instance
379
  // ==========================================================================
380
381
  /// Append an instance slot. Slot's implicit constructor accepts
382
  /// `const InstanceType *` (typed source) or nothing (untyped — used by
383
  /// inline-export / (instantiate ...) sources).
384
0
  uint32_t addInstance(Context::InstanceSlot S = {}) {
385
0
    auto &Ctx = getCurrentContext();
386
0
    uint32_t Idx = static_cast<uint32_t>(Ctx.Instances.size());
387
0
    Ctx.Instances.push_back(std::move(S));
388
0
    return Idx;
389
0
  }
390
391
  using InstanceExport = Context::InstanceExport;
392
393
  /// Read an instance slot. Callers access `.Exports` (export table) or
394
  /// `.Type` (externdesc-bound InstanceType) as needed.
395
0
  const Context::InstanceSlot &getInstance(uint32_t Idx) const noexcept {
396
0
    return getCurrentContext().Instances.at(Idx);
397
0
  }
398
399
  void addInstanceExport(
400
      uint32_t InstIdx, std::string_view Name,
401
      AST::Component::Sort::SortType ST,
402
      const AST::Component::InstanceType *IT = nullptr,
403
      std::optional<uint32_t> NestedInstIdx = std::nullopt,
404
0
      std::optional<uint64_t> ResourceId = std::nullopt) noexcept {
405
0
    getCurrentContext().Instances.at(InstIdx).Exports[std::string(Name)] = {
406
0
        ST, IT, NestedInstIdx, ResourceId};
407
0
  }
408
409
  // ==========================================================================
410
  // type
411
  // ==========================================================================
412
413
  /// Append a type slot. IsLocal=false for resource type imports and
414
  /// outer-alias resources, true otherwise.
415
  uint32_t addType(const AST::Component::DefType *DT = nullptr,
416
0
                   bool IsLocal = true) noexcept {
417
0
    return addTypeImpl(DT, IsLocal);
418
0
  }
419
420
0
  const AST::Component::DefType *getDefType(uint32_t Idx) const noexcept {
421
0
    const auto &Ctx = getCurrentContext();
422
0
    if (Idx < Ctx.Types.size()) {
423
0
      return Ctx.Types[Idx];
424
0
    }
425
0
    return nullptr;
426
0
  }
427
428
  const AST::Component::InstanceType *
429
0
  getInstanceType(uint32_t Idx) const noexcept {
430
0
    const auto &Ctx = getCurrentContext();
431
0
    auto It = Ctx.InstanceTypes.find(Idx);
432
0
    return It != Ctx.InstanceTypes.end() ? It->second : nullptr;
433
0
  }
434
435
  // ==========================================================================
436
  // resource
437
  // ==========================================================================
438
439
  /// Allocate a fresh resource id, pushing a new registry row. Body is
440
  /// nullptr for (sub resource) imports.
441
  uint64_t allocateFreshResourceId(
442
0
      const AST::Component::ResourceType *Body = nullptr) noexcept {
443
0
    uint64_t Id = ResourceRegistry.size();
444
0
    ResourceRegistry.push_back({Body});
445
0
    return Id;
446
0
  }
447
448
  /// Bind a ResourceInfo to a type index in the current scope.
449
0
  void addResource(uint32_t TypeIdx, Context::ResourceInfo Info) noexcept {
450
0
    getCurrentContext().Resources[TypeIdx] = Info;
451
0
  }
452
453
  /// ResourceInfo at this type index, or nullptr if not a resource.
454
0
  const Context::ResourceInfo *getResource(uint32_t Idx) const noexcept {
455
0
    const auto &R = getCurrentContext().Resources;
456
0
    auto It = R.find(Idx);
457
0
    return It != R.end() ? &It->second : nullptr;
458
0
  }
459
460
  /// Register a kebab-case resource name (from a TypeBound import / export)
461
  /// so annotated names ([constructor]R / [method]R.f / [static]R.f) resolve.
462
0
  void addResourceLabel(std::string_view Name, uint32_t TypeIdx) noexcept {
463
0
    getCurrentContext().ResourceLabels.emplace(std::string(Name), TypeIdx);
464
0
  }
465
466
0
  bool hasResourceLabel(std::string_view Name) const noexcept {
467
0
    return getCurrentContext().ResourceLabels.find(std::string(Name)) !=
468
0
           getCurrentContext().ResourceLabels.end();
469
0
  }
470
471
  // ==========================================================================
472
  // func / value
473
  // ==========================================================================
474
475
0
  uint32_t addFunc(const AST::Component::FuncType *FT = nullptr) noexcept {
476
0
    auto &V = getCurrentContext().Funcs;
477
0
    uint32_t Idx = static_cast<uint32_t>(V.size());
478
0
    V.push_back(FT);
479
0
    return Idx;
480
0
  }
481
0
  const AST::Component::FuncType *getFunc(uint32_t Idx) const noexcept {
482
0
    const auto &V = getCurrentContext().Funcs;
483
0
    return Idx < V.size() ? V[Idx] : nullptr;
484
0
  }
485
0
  uint32_t addValue() noexcept { return getCurrentContext().ValueCount++; }
486
487
  // ==========================================================================
488
  // Validation state
489
  // ==========================================================================
490
491
  void substituteTypeImport(const std::string &ImportName,
492
0
                            uint32_t TypeIdx) noexcept {
493
0
    getCurrentContext().TypeSubstitutions[ImportName] = TypeIdx;
494
0
  }
495
496
  std::optional<uint32_t>
497
0
  getSubstitutedType(const std::string &ImportName) const {
498
0
    const auto &Ctx = getCurrentContext();
499
0
    auto It = Ctx.TypeSubstitutions.find(ImportName);
500
0
    if (It != Ctx.TypeSubstitutions.end()) {
501
0
      return It->second;
502
0
    }
503
0
    return std::nullopt;
504
0
  }
505
506
0
  bool addImportedName(const ComponentName &Name) noexcept {
507
0
    return getCurrentContext().AddImportedName(Name);
508
0
  }
509
510
  /// Returns false if the export name violates strong-uniqueness.
511
0
  bool addExportedName(const ComponentName &Name) noexcept {
512
0
    return getCurrentContext().AddExportedName(Name);
513
0
  }
514
515
private:
516
  uint32_t addTypeImpl(const AST::Component::DefType *DT,
517
0
                       bool IsLocal) noexcept {
518
0
    auto &Ctx = getCurrentContext();
519
0
    uint32_t Idx = static_cast<uint32_t>(Ctx.Types.size());
520
0
    Ctx.Types.push_back(DT);
521
0
    if (DT != nullptr) {
522
0
      if (DT->isInstanceType()) {
523
0
        Ctx.InstanceTypes[Idx] = &DT->getInstanceType();
524
0
      } else if (DT->isResourceType()) {
525
        // Locally-defined: body goes to the registry; IsLocal sets locality.
526
0
        Ctx.Resources[Idx] = {allocateFreshResourceId(&DT->getResourceType()),
527
0
                              IsLocal};
528
0
      } else if (DT->isComponentType()) {
529
0
        Ctx.ComponentTypes[Idx] = &DT->getComponentType();
530
0
      }
531
0
    }
532
0
    return Idx;
533
0
  }
534
535
  std::deque<Context> CompCtxs;
536
537
  // Session-global resource registry; vector index IS the resource id.
538
  std::vector<ResourceRegistryEntry> ResourceRegistry;
539
};
540
541
} // namespace Validator
542
} // namespace WasmEdge