Coverage Report

Created: 2026-11-09 06:49

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
//===-- wasmedge/validator/component_context.h - Component checker --------===//
5
//
6
// Part of the WasmEdge Project.
7
//
8
//===----------------------------------------------------------------------===//
9
///
10
/// \file
11
/// This file contains the checker of a component under validation: the scope
12
/// stack with its index spaces, the type views it owns, and every check over
13
/// them, as FormChecker holds and checks the context of a core module.
14
///
15
//===----------------------------------------------------------------------===//
16
#pragma once
17
18
#include "ast/component/canonical.h"
19
#include "ast/component/instance.h"
20
#include "ast/component/sort.h"
21
#include "ast/component/type.h"
22
#include "ast/module.h"
23
#include "ast/type.h"
24
#include "common/component_valtype.h"
25
#include "common/errcode.h"
26
#include "common/span.h"
27
#include "validator/component_name.h"
28
#include "validator/component_types.h"
29
30
#include <cstdint>
31
#include <deque>
32
#include <map>
33
#include <memory>
34
#include <optional>
35
#include <string>
36
#include <string_view>
37
#include <unordered_map>
38
#include <unordered_set>
39
#include <utility>
40
#include <vector>
41
42
namespace WasmEdge {
43
namespace Validator {
44
namespace Component {
45
46
class Context {
47
public:
48
14.7k
  Context() = default;
49
50
  // ==========================================================================
51
  // The scope stack. Scopes stay owned after they pop; validate() resets it.
52
  // ==========================================================================
53
54
3.33M
  Scope &pushScope(ScopeKind K) noexcept {
55
3.33M
    const Scope *Parent = Stack.empty() ? nullptr : Stack.back();
56
3.33M
    OwnedScopes.emplace_back(K, Parent);
57
3.33M
    Stack.push_back(&OwnedScopes.back());
58
3.33M
    return OwnedScopes.back();
59
3.33M
  }
60
61
3.32M
  void popScope() noexcept {
62
3.32M
    assuming(!Stack.empty());
63
3.32M
    Stack.pop_back();
64
3.32M
  }
65
66
17.9M
  Scope &getTop() noexcept {
67
17.9M
    assuming(!Stack.empty());
68
17.9M
    return *Stack.back();
69
17.9M
  }
70
1.09M
  const Scope &getTop() const noexcept {
71
1.09M
    assuming(!Stack.empty());
72
1.09M
    return *Stack.back();
73
1.09M
  }
74
75
  /// The scope Levels hops up from the current one; nullptr if out of range.
76
79.5k
  Scope *getScope(uint32_t Levels) noexcept {
77
79.5k
    if (Levels >= Stack.size()) {
78
28
      return nullptr;
79
28
    }
80
79.5k
    return Stack[Stack.size() - 1 - Levels];
81
79.5k
  }
82
83
  // ==========================================================================
84
  // Index-space registration and resolution.
85
  // ==========================================================================
86
87
  /// Push the entity described by a resolved view into its index space.
88
  void addExtern(const ExternInfo &Info) noexcept;
89
  /// The typed view of a sortidx in the current scope.
90
  Expect<ExternInfo> getExtern(const AST::Component::SortIndex &SI) noexcept;
91
  /// A valtype in the current scope: its type index must name a defvaltype.
92
  Expect<void> validate(const ComponentValType &VT) const noexcept;
93
94
  // ==========================================================================
95
  // Naming checks and the named-types rule; the only writer of NameSide.
96
  // ==========================================================================
97
98
  /// Extern-name grammar checks; IsImport only selects the log prefix.
99
  Expect<ExternName> parseExternName(std::string_view Name,
100
                                     bool IsImport) const noexcept;
101
  /// Append N to Names, or diagnose the clash (exact or strong-uniqueness).
102
  Expect<void> addUniqueName(std::vector<NameRecord> &Names,
103
                             const NameRecord &N, bool IsImport) const noexcept;
104
  /// Name attributes: a valid versionsuffix, and `implements` only on a
105
  /// plain, instance-typed name.
106
  Expect<void> checkNameAttributes(const ExternName &CN,
107
                                   Span<const std::string> Impls,
108
                                   Span<const std::string> VSuffixes,
109
                                   bool IsInstance) const noexcept;
110
  /// Annotated plainname rules ([constructor]/[method]/[static]).
111
  Expect<void> checkAnnotatedName(const ExternName &Name,
112
                                  const ExternInfo &Info,
113
                                  bool IsImport) noexcept;
114
  /// Track plain resource labels for later annotated-name checks.
115
  void addResourceLabel(const ExternName &Name, const ExternInfo &Info,
116
                        bool IsImport) noexcept;
117
  /// Named-types rule: an earlier extern must introduce each named type used.
118
  Expect<void> checkNamedTypesRule(const ExternInfo &Info,
119
                                   bool IsImport) noexcept;
120
121
  // ==========================================================================
122
  // Declaring an import or an export; name errors precede ascription errors.
123
  // ==========================================================================
124
125
  /// Check an import's name and add the resolved entity it introduces.
126
  Expect<ExternInfo> addImport(std::string_view Name,
127
                               const ExternInfo &Resolved,
128
                               Span<const std::string> Impls = {},
129
                               Span<const std::string> VSuffixes = {}) noexcept;
130
  /// Check and record an export's name; addExport then adds the entity.
131
  Expect<ExternName>
132
  registerExportName(std::string_view Name, bool IsInstance,
133
                     Span<const std::string> Impls = {},
134
                     Span<const std::string> VSuffixes = {}) noexcept;
135
  /// Apply the optional ascription and add the re-exported index.
136
  Expect<ExternInfo>
137
  addExport(const ExternName &CN, const ExternInfo &Inferred,
138
            const std::optional<ExternInfo> &Ascribed) noexcept;
139
140
  // ==========================================================================
141
  // Canonical options. They resolve core index spaces.
142
  // ==========================================================================
143
144
  /// The index type of the selected canonical memory.
145
  ValType
146
  getCanonPtrType(const AST::Component::Canonical &Canon) const noexcept;
147
  /// canonopt rules: duplicates, indices, core signatures, per-site whitelist.
148
  Expect<void> checkOptions(const AST::Component::Canonical &Canon,
149
                            bool IsLift) const noexcept;
150
  /// The memory and realloc options a definition (What) needs.
151
  Expect<void> checkRequiredOptions(const AST::Component::Canonical &Canon,
152
                                    bool NeedMemory, bool NeedRealloc,
153
                                    std::string_view What) const noexcept;
154
155
  // ==========================================================================
156
  // Instantiation and the substitution applied to the views it creates.
157
  // ==========================================================================
158
159
  /// Match args against CI.Imports and produce the freshened export view.
160
  Expect<const Shape *> instantiateComponentShape(
161
      const Shape &CI,
162
      Span<const AST::Component::InstantiateArg<AST::Component::SortIndex>>
163
          Args) noexcept;
164
  /// Copy an instance view with fresh getTop()-owned ids for its resources.
165
  const Shape *copyDeclaredResources(const Shape *Inst,
166
                                     bool FromImport) noexcept;
167
  /// The export view an instantiation produces: CI's exports copied under Node.
168
  const Shape *copyInstanceExports(const Shape &CI,
169
                                   const ResourceMap *Node) noexcept;
170
171
  // ==========================================================================
172
  // Resource registry: index is the identity.
173
  // ==========================================================================
174
175
2.19M
  uint32_t nextNameId() noexcept { return NextNameId++; }
176
177
  uint32_t addResource(const AST::Component::ResourceType *RT,
178
7.93k
                       const Scope *Origin, bool FromImport) noexcept {
179
7.93k
    uint32_t Id = static_cast<uint32_t>(Resources.size());
180
7.93k
    Resources.push_back({RT, Origin, FromImport, nextNameId()});
181
7.93k
    return Id;
182
7.93k
  }
183
184
9.37k
  const ResourceEntry &getResource(uint32_t Id) const noexcept {
185
9.37k
    assuming(Id < Resources.size());
186
9.37k
    return Resources[Id];
187
9.37k
  }
188
189
  // ==========================================================================
190
  // Storage the checker owns. Every view holds raw pointers into it.
191
  // ==========================================================================
192
193
  /// Compose two remaps, Inner first; a leaf table is filled before composed.
194
  const ResourceMap *composeRemap(const ResourceMap *Outer,
195
3.37M
                                  const ResourceMap *Inner) noexcept {
196
3.37M
    if (Outer == nullptr) {
197
3.37M
      return Inner;
198
3.37M
    }
199
0
    if (Inner == nullptr) {
200
0
      return Outer;
201
0
    }
202
0
    auto Key = std::make_pair(Outer, Inner);
203
0
    auto It = ComposedRemaps.find(Key);
204
0
    if (It != ComposedRemaps.end()) {
205
0
      return It->second;
206
0
    }
207
0
    auto *Node = &OwnedRemaps.emplace_back();
208
    // Inner's moves land on their Outer image; Outer-only entries keep theirs.
209
0
    for (const auto &[From, To] : Inner->Map) {
210
0
      Node->Map.emplace(From, Outer->apply(To));
211
0
    }
212
0
    for (const auto &[From, To] : Outer->Map) {
213
0
      Node->Map.emplace(From, To);
214
0
    }
215
0
    ComposedRemaps.emplace(Key, Node);
216
0
    return Node;
217
0
  }
218
219
  /// Resource id denoted by M. If M is absent, Id denotes itself.
220
33
  uint32_t applyRemap(const ResourceMap *M, uint32_t Id) const noexcept {
221
33
    return M != nullptr ? M->apply(Id) : Id;
222
33
  }
223
224
254k
  CoreShape *addCoreShape() noexcept { return &OwnedCoreShapes.emplace_back(); }
225
5.27M
  Shape *addShape() noexcept { return &OwnedShapes.emplace_back(); }
226
975k
  ResourceMap *addResourceMap() noexcept { return &OwnedRemaps.emplace_back(); }
227
228
  /// An owned core function type for canon lower and resource built-in funcs.
229
  const AST::SubType *addCoreFuncType(Span<const ValType> Params,
230
244k
                                      Span<const ValType> Results) noexcept {
231
244k
    OwnedCoreTypes.push_back(
232
244k
        std::make_unique<AST::SubType>(AST::FunctionType(Params, Results)));
233
244k
    return OwnedCoreTypes.back().get();
234
244k
  }
235
236
  // ==========================================================================
237
  // Resolution: the shared substrate of every walk below.
238
  // ==========================================================================
239
240
  /// The entry a valtype's index names, written to Storage; nullptr if none.
241
  const TypeEntry *getTypeEntry(const QualValType &Q,
242
                                TypeEntry &Storage) noexcept;
243
  /// The primitive a valtype denotes through aliases; nullopt for composites.
244
  std::optional<PrimValType> getPrimValType(const QualValType &Q) noexcept;
245
  /// Effective resource id behind an own/borrow handle index.
246
  std::optional<uint32_t> getResourceId(const Scope *Home,
247
                                        const ResourceMap *Remap,
248
                                        uint32_t Idx) const noexcept;
249
250
  /// Calls Func on each nested value type; stream and future payloads excluded.
251
  template <typename F>
252
5.28M
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
5.28M
    if (D.isRecordTy()) {
254
3.22k
      for (const auto &LT : D.getRecord().LabelTypes) {
255
3.22k
        Func(LT.getValType());
256
3.22k
      }
257
5.28M
    } else if (D.isVariantTy()) {
258
19.3k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
19.3k
        if (Ty.has_value()) {
260
18.8k
          Func(*Ty);
261
18.8k
        }
262
19.3k
      }
263
5.26M
    } else if (D.isListTy()) {
264
316k
      Func(D.getList().ValTy);
265
4.94M
    } else if (D.isTupleTy()) {
266
35.0k
      for (const auto &Ty : D.getTuple().Types) {
267
35.0k
        Func(Ty);
268
35.0k
      }
269
4.93M
    } else if (D.isMapTy()) {
270
2.96M
      Func(D.getMap().KeyTy);
271
2.96M
      Func(D.getMap().ValTy);
272
2.96M
    } else if (D.isOptionTy()) {
273
9.55k
      Func(D.getOption().ValTy);
274
1.95M
    } else if (D.isResultTy()) {
275
1.73M
      const auto &R = D.getResult();
276
1.73M
      if (R.ValTy.has_value()) {
277
646k
        Func(*R.ValTy);
278
646k
      }
279
1.73M
      if (R.ErrTy.has_value()) {
280
1.09M
        Func(*R.ErrTy);
281
1.09M
      }
282
1.73M
    }
283
5.28M
  }
component_context.cpp:void WasmEdge::Validator::Component::Context::forEachValType<WasmEdge::Validator::Component::Context::hasBorrow(WasmEdge::Validator::Component::QualValType const&)::$_0>(WasmEdge::AST::Component::DefValType const&, WasmEdge::Validator::Component::Context::hasBorrow(WasmEdge::Validator::Component::QualValType const&)::$_0&&) const
Line
Count
Source
252
955k
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
955k
    if (D.isRecordTy()) {
254
225
      for (const auto &LT : D.getRecord().LabelTypes) {
255
225
        Func(LT.getValType());
256
225
      }
257
955k
    } else if (D.isVariantTy()) {
258
2.89k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
2.89k
        if (Ty.has_value()) {
260
2.77k
          Func(*Ty);
261
2.77k
        }
262
2.89k
      }
263
952k
    } else if (D.isListTy()) {
264
250k
      Func(D.getList().ValTy);
265
701k
    } else if (D.isTupleTy()) {
266
8.44k
      for (const auto &Ty : D.getTuple().Types) {
267
8.44k
        Func(Ty);
268
8.44k
      }
269
697k
    } else if (D.isMapTy()) {
270
165k
      Func(D.getMap().KeyTy);
271
165k
      Func(D.getMap().ValTy);
272
531k
    } else if (D.isOptionTy()) {
273
116
      Func(D.getOption().ValTy);
274
531k
    } else if (D.isResultTy()) {
275
530k
      const auto &R = D.getResult();
276
530k
      if (R.ValTy.has_value()) {
277
204k
        Func(*R.ValTy);
278
204k
      }
279
530k
      if (R.ErrTy.has_value()) {
280
326k
        Func(*R.ErrTy);
281
326k
      }
282
530k
    }
283
955k
  }
component_context.cpp:void WasmEdge::Validator::Component::Context::forEachValType<WasmEdge::Validator::Component::Context::hasHandle(WasmEdge::Validator::Component::QualValType const&)::$_0>(WasmEdge::AST::Component::DefValType const&, WasmEdge::Validator::Component::Context::hasHandle(WasmEdge::Validator::Component::QualValType const&)::$_0&&) const
Line
Count
Source
252
15.5k
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
15.5k
    if (D.isRecordTy()) {
254
1.60k
      for (const auto &LT : D.getRecord().LabelTypes) {
255
1.60k
        Func(LT.getValType());
256
1.60k
      }
257
13.9k
    } else if (D.isVariantTy()) {
258
1.71k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
1.71k
        if (Ty.has_value()) {
260
1.63k
          Func(*Ty);
261
1.63k
        }
262
1.71k
      }
263
12.2k
    } else if (D.isListTy()) {
264
979
      Func(D.getList().ValTy);
265
11.2k
    } else if (D.isTupleTy()) {
266
570
      for (const auto &Ty : D.getTuple().Types) {
267
570
        Func(Ty);
268
570
      }
269
10.8k
    } else if (D.isMapTy()) {
270
6.66k
      Func(D.getMap().KeyTy);
271
6.66k
      Func(D.getMap().ValTy);
272
6.66k
    } else if (D.isOptionTy()) {
273
2.00k
      Func(D.getOption().ValTy);
274
2.16k
    } else if (D.isResultTy()) {
275
1.01k
      const auto &R = D.getResult();
276
1.01k
      if (R.ValTy.has_value()) {
277
470
        Func(*R.ValTy);
278
470
      }
279
1.01k
      if (R.ErrTy.has_value()) {
280
546
        Func(*R.ErrTy);
281
546
      }
282
1.01k
    }
283
15.5k
  }
component_context.cpp:void WasmEdge::Validator::Component::Context::forEachValType<WasmEdge::Validator::Component::Context::needsMemory(WasmEdge::Validator::Component::QualValType const&)::$_0>(WasmEdge::AST::Component::DefValType const&, WasmEdge::Validator::Component::Context::needsMemory(WasmEdge::Validator::Component::QualValType const&)::$_0&&) const
Line
Count
Source
252
6.06k
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
6.06k
    if (D.isRecordTy()) {
254
74
      for (const auto &LT : D.getRecord().LabelTypes) {
255
74
        Func(LT.getValType());
256
74
      }
257
5.99k
    } else if (D.isVariantTy()) {
258
192
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
192
        if (Ty.has_value()) {
260
126
          Func(*Ty);
261
126
        }
262
192
      }
263
5.80k
    } else if (D.isListTy()) {
264
0
      Func(D.getList().ValTy);
265
5.80k
    } else if (D.isTupleTy()) {
266
5.94k
      for (const auto &Ty : D.getTuple().Types) {
267
5.94k
        Func(Ty);
268
5.94k
      }
269
2.97k
    } else if (D.isMapTy()) {
270
0
      Func(D.getMap().KeyTy);
271
0
      Func(D.getMap().ValTy);
272
2.82k
    } else if (D.isOptionTy()) {
273
71
      Func(D.getOption().ValTy);
274
2.75k
    } else if (D.isResultTy()) {
275
1.98k
      const auto &R = D.getResult();
276
1.98k
      if (R.ValTy.has_value()) {
277
1.43k
        Func(*R.ValTy);
278
1.43k
      }
279
1.98k
      if (R.ErrTy.has_value()) {
280
1.58k
        Func(*R.ErrTy);
281
1.58k
      }
282
1.98k
    }
283
6.06k
  }
component_context.cpp:void WasmEdge::Validator::Component::Context::forEachValType<WasmEdge::Validator::Component::Context::isIntroduced(WasmEdge::Validator::Component::TypeEntry const&, bool)::$_1>(WasmEdge::AST::Component::DefValType const&, WasmEdge::Validator::Component::Context::isIntroduced(WasmEdge::Validator::Component::TypeEntry const&, bool)::$_1&&) const
Line
Count
Source
252
268
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
268
    if (D.isRecordTy()) {
254
0
      for (const auto &LT : D.getRecord().LabelTypes) {
255
0
        Func(LT.getValType());
256
0
      }
257
268
    } else if (D.isVariantTy()) {
258
0
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
0
        if (Ty.has_value()) {
260
0
          Func(*Ty);
261
0
        }
262
0
      }
263
268
    } else if (D.isListTy()) {
264
60
      Func(D.getList().ValTy);
265
208
    } else if (D.isTupleTy()) {
266
255
      for (const auto &Ty : D.getTuple().Types) {
267
255
        Func(Ty);
268
255
      }
269
109
    } else if (D.isMapTy()) {
270
26
      Func(D.getMap().KeyTy);
271
26
      Func(D.getMap().ValTy);
272
73
    } else if (D.isOptionTy()) {
273
20
      Func(D.getOption().ValTy);
274
53
    } else if (D.isResultTy()) {
275
53
      const auto &R = D.getResult();
276
53
      if (R.ValTy.has_value()) {
277
40
        Func(*R.ValTy);
278
40
      }
279
53
      if (R.ErrTy.has_value()) {
280
13
        Func(*R.ErrTy);
281
13
      }
282
53
    }
283
268
  }
component_context.cpp:void WasmEdge::Validator::Component::Context::forEachValType<WasmEdge::Validator::Component::Context::areInnerTypesIntroduced(WasmEdge::Validator::Component::TypeEntry const&, bool)::$_1>(WasmEdge::AST::Component::DefValType const&, WasmEdge::Validator::Component::Context::areInnerTypesIntroduced(WasmEdge::Validator::Component::TypeEntry const&, bool)::$_1&&) const
Line
Count
Source
252
965
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
965
    if (D.isRecordTy()) {
254
45
      for (const auto &LT : D.getRecord().LabelTypes) {
255
45
        Func(LT.getValType());
256
45
      }
257
920
    } else if (D.isVariantTy()) {
258
25
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
25
        if (Ty.has_value()) {
260
22
          Func(*Ty);
261
22
        }
262
25
      }
263
895
    } else if (D.isListTy()) {
264
34
      Func(D.getList().ValTy);
265
861
    } else if (D.isTupleTy()) {
266
112
      for (const auto &Ty : D.getTuple().Types) {
267
112
        Func(Ty);
268
112
      }
269
814
    } else if (D.isMapTy()) {
270
737
      Func(D.getMap().KeyTy);
271
737
      Func(D.getMap().ValTy);
272
737
    } else if (D.isOptionTy()) {
273
30
      Func(D.getOption().ValTy);
274
47
    } else if (D.isResultTy()) {
275
47
      const auto &R = D.getResult();
276
47
      if (R.ValTy.has_value()) {
277
25
        Func(*R.ValTy);
278
25
      }
279
47
      if (R.ErrTy.has_value()) {
280
28
        Func(*R.ErrTy);
281
28
      }
282
47
    }
283
965
  }
Unexecuted instantiation: component_context.cpp:void WasmEdge::Validator::Component::Context::forEachValType<WasmEdge::Validator::Component::Context::collectResources(WasmEdge::Validator::Component::TypeEntry const&, std::__1::unordered_set<unsigned int, std::__1::hash<unsigned int>, std::__1::equal_to<unsigned int>, std::__1::allocator<unsigned int> >&)::$_0&>(WasmEdge::AST::Component::DefValType const&, WasmEdge::Validator::Component::Context::collectResources(WasmEdge::Validator::Component::TypeEntry const&, std::__1::unordered_set<unsigned int, std::__1::hash<unsigned int>, std::__1::equal_to<unsigned int>, std::__1::allocator<unsigned int> >&)::$_0&) const
component_context.cpp:void WasmEdge::Validator::Component::Context::forEachValType<WasmEdge::Validator::Component::Context::getTypeSize(WasmEdge::Validator::Component::TypeEntry const&)::$_0>(WasmEdge::AST::Component::DefValType const&, WasmEdge::Validator::Component::Context::getTypeSize(WasmEdge::Validator::Component::TypeEntry const&)::$_0&&) const
Line
Count
Source
252
2.15M
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
2.15M
    if (D.isRecordTy()) {
254
637
      for (const auto &LT : D.getRecord().LabelTypes) {
255
637
        Func(LT.getValType());
256
637
      }
257
2.15M
    } else if (D.isVariantTy()) {
258
7.25k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
7.25k
        if (Ty.has_value()) {
260
7.15k
          Func(*Ty);
261
7.15k
        }
262
7.25k
      }
263
2.14M
    } else if (D.isListTy()) {
264
32.1k
      Func(D.getList().ValTy);
265
2.11M
    } else if (D.isTupleTy()) {
266
9.86k
      for (const auto &Ty : D.getTuple().Types) {
267
9.86k
        Func(Ty);
268
9.86k
      }
269
2.10M
    } else if (D.isMapTy()) {
270
1.39M
      Func(D.getMap().KeyTy);
271
1.39M
      Func(D.getMap().ValTy);
272
1.39M
    } else if (D.isOptionTy()) {
273
3.65k
      Func(D.getOption().ValTy);
274
711k
    } else if (D.isResultTy()) {
275
602k
      const auto &R = D.getResult();
276
602k
      if (R.ValTy.has_value()) {
277
219k
        Func(*R.ValTy);
278
219k
      }
279
602k
      if (R.ErrTy.has_value()) {
280
383k
        Func(*R.ErrTy);
281
383k
      }
282
602k
    }
283
2.15M
  }
component_context.cpp:void WasmEdge::Validator::Component::Context::forEachValType<WasmEdge::Validator::Component::Context::getTypeDepth(WasmEdge::Validator::Component::TypeEntry const&)::$_0>(WasmEdge::AST::Component::DefValType const&, WasmEdge::Validator::Component::Context::getTypeDepth(WasmEdge::Validator::Component::TypeEntry const&)::$_0&&) const
Line
Count
Source
252
2.15M
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
2.15M
    if (D.isRecordTy()) {
254
637
      for (const auto &LT : D.getRecord().LabelTypes) {
255
637
        Func(LT.getValType());
256
637
      }
257
2.15M
    } else if (D.isVariantTy()) {
258
7.25k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
7.25k
        if (Ty.has_value()) {
260
7.15k
          Func(*Ty);
261
7.15k
        }
262
7.25k
      }
263
2.14M
    } else if (D.isListTy()) {
264
32.1k
      Func(D.getList().ValTy);
265
2.11M
    } else if (D.isTupleTy()) {
266
9.86k
      for (const auto &Ty : D.getTuple().Types) {
267
9.86k
        Func(Ty);
268
9.86k
      }
269
2.10M
    } else if (D.isMapTy()) {
270
1.39M
      Func(D.getMap().KeyTy);
271
1.39M
      Func(D.getMap().ValTy);
272
1.39M
    } else if (D.isOptionTy()) {
273
3.65k
      Func(D.getOption().ValTy);
274
711k
    } else if (D.isResultTy()) {
275
602k
      const auto &R = D.getResult();
276
602k
      if (R.ValTy.has_value()) {
277
219k
        Func(*R.ValTy);
278
219k
      }
279
602k
      if (R.ErrTy.has_value()) {
280
383k
        Func(*R.ErrTy);
281
383k
      }
282
602k
    }
283
2.15M
  }
284
285
  // ==========================================================================
286
  // Resource-id walks.
287
  // ==========================================================================
288
289
  /// Transitive borrow check on value types.
290
  bool hasBorrow(const QualValType &Q) noexcept;
291
  /// Transitive handle check on value types: own, borrow, stream, future and
292
  /// error-context.
293
  bool hasHandle(const QualValType &Q) noexcept;
294
  /// Collect resource ids reachable from a view (for free-variable rules).
295
  void collectResources(const ExternInfo &Info,
296
                        std::unordered_set<uint32_t> &Out) noexcept;
297
  void collectResources(const QualValType &Q,
298
                        std::unordered_set<uint32_t> &Out) noexcept;
299
  /// True iff the id is declared in S or one of its descendants.
300
  bool isDeclaredIn(uint32_t Id, const Scope &S) const noexcept;
301
302
  // ==========================================================================
303
  // Effective type size and nesting depth.
304
  // ==========================================================================
305
306
  static inline constexpr const uint64_t MaxTypeSize = 1000000;
307
  /// The reference engine bounds value-type nesting at 100.
308
  static inline constexpr const uint64_t MaxTypeDepth = 100;
309
  uint64_t getTypeSize(const ExternInfo &Info) noexcept;
310
  uint64_t getTypeDepth(const ExternInfo &Info) noexcept;
311
  /// Both limits over one extern, the pairing every call site needs.
312
  Expect<void> checkTypeLimits(const ExternInfo &Info) noexcept;
313
314
  // ==========================================================================
315
  // Canonical ABI layout (spec `elem_size` and `alignment`, 64-bit pointers).
316
  // ==========================================================================
317
318
  /// Every defvaltype's element size must stay below this bound.
319
  static inline constexpr const uint64_t MaxElemSize = UINT64_C(1) << 28;
320
  /// The element size and alignment of a value type.
321
  std::pair<uint64_t, uint64_t> getElemLayout(const QualValType &Q) noexcept;
322
  std::pair<uint64_t, uint64_t>
323
  getElemLayout(const AST::Component::DefValType &D, const Scope *Home,
324
                const ResourceMap *Remap) noexcept;
325
326
  // ==========================================================================
327
  // Canonical ABI flattening (spec `flatten_functype`).
328
  // ==========================================================================
329
330
  static inline constexpr const uint32_t MaxFlatParams = 16;
331
  static inline constexpr const uint32_t MaxFlatAsyncParams = 4;
332
  static inline constexpr const uint32_t MaxFlatResults = 1;
333
  /// Flattening ceiling; past the largest limit every consumer replaces it.
334
  static inline constexpr const uint32_t MaxFlatExpand = MaxFlatParams + 1;
335
  /// Thread-local slots addressable by context.get/context.set.
336
  static inline constexpr const uint32_t MaxContextSlots = 2;
337
  /// Elements a fixed-length list may declare, as the reference validator.
338
  static inline constexpr const uint32_t MaxFixedListElems = 1U << 30;
339
340
  /// Appends Q's flat core types to Out, false if invalid; Ptr indexes memory.
341
  bool flattenValType(const QualValType &Q, std::vector<ValType> &Out,
342
                      const ValType &Ptr) noexcept;
343
  /// True iff the type transitively contains a list or string.
344
  bool needsMemory(const QualValType &Q) noexcept;
345
  /// Flatten a function type; the flags report which side needs a memory.
346
  Expect<AST::FunctionType> flattenFuncType(const FuncInfo &FI,
347
                                            const ValType &Ptr,
348
                                            bool &ParamsNeedMemory,
349
                                            bool &ResultsNeedMemory) noexcept;
350
351
6.53k
  void reset() noexcept {
352
6.53k
    Stack.clear();
353
6.53k
    OwnedScopes.clear();
354
6.53k
    NextNameId = 0;
355
6.53k
    Resources.clear();
356
6.53k
    OwnedCoreShapes.clear();
357
6.53k
    OwnedShapes.clear();
358
6.53k
    OwnedRemaps.clear();
359
6.53k
    ComposedRemaps.clear();
360
6.53k
    OwnedCoreTypes.clear();
361
6.53k
    TypeSizes.clear();
362
6.53k
    TypeDepths.clear();
363
6.53k
    ElemLayouts.clear();
364
6.53k
  }
365
366
private:
367
  // ==========================================================================
368
  // The named-types rule: introduceExternTypes checks and records an extern.
369
  // ==========================================================================
370
371
  bool introduceExternTypes(const ExternInfo &Info, bool IsImport) noexcept;
372
  bool isIntroduced(const QualValType &Q, bool IsImport) noexcept;
373
  bool isIntroduced(const TypeEntry &E, bool IsImport) noexcept;
374
  // The immediate components of the type. The extern names the type itself.
375
  bool areInnerTypesIntroduced(const TypeEntry &E, bool IsImport) noexcept;
376
377
  // ==========================================================================
378
  // The leaves of the walks above.
379
  // ==========================================================================
380
381
  void collectResources(const TypeEntry &E,
382
                        std::unordered_set<uint32_t> &Out) noexcept;
383
  uint64_t getTypeSize(const QualValType &Q) noexcept;
384
  uint64_t getTypeSize(const TypeEntry &E) noexcept;
385
  uint64_t getTypeDepth(const QualValType &Q) noexcept;
386
  uint64_t getTypeDepth(const TypeEntry &E) noexcept;
387
388
  // ==========================================================================
389
  // Copies of views under a remap; Copies maps each shape met to its copy.
390
  // ==========================================================================
391
392
  ExternInfo
393
  copyExtern(const ExternInfo &E, const ResourceMap *Node,
394
             std::unordered_map<const Shape *, const Shape *> &Copies) noexcept;
395
  TypeEntry copyTypeEntry(
396
      const TypeEntry &E, const ResourceMap *Node,
397
      std::unordered_map<const Shape *, const Shape *> &Copies) noexcept;
398
  const Shape *
399
  copyShape(const Shape *S, const ResourceMap *Node,
400
            std::unordered_map<const Shape *, const Shape *> &Copies) noexcept;
401
402
  std::vector<Scope *> Stack;
403
  std::deque<Scope> OwnedScopes;
404
  uint32_t NextNameId = 0;
405
  std::vector<ResourceEntry> Resources;
406
  std::deque<CoreShape> OwnedCoreShapes;
407
  std::deque<Shape> OwnedShapes;
408
  std::deque<ResourceMap> OwnedRemaps;
409
  std::map<std::pair<const ResourceMap *, const ResourceMap *>,
410
           const ResourceMap *>
411
      ComposedRemaps;
412
  std::vector<std::unique_ptr<AST::SubType>> OwnedCoreTypes;
413
  std::unordered_map<const void *, uint64_t> TypeSizes;
414
  std::unordered_map<const void *, uint64_t> TypeDepths;
415
  std::unordered_map<const void *, std::pair<uint64_t, uint64_t>> ElemLayouts;
416
};
417
418
} // namespace Component
419
} // namespace Validator
420
} // namespace WasmEdge