Coverage Report

Created: 2026-11-12 06:35

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
16.1k
  Context() = default;
49
50
  // ==========================================================================
51
  // The scope stack. Scopes stay owned after they pop; validate() resets it.
52
  // ==========================================================================
53
54
2.51M
  Scope &pushScope(ScopeKind K) noexcept {
55
2.51M
    const Scope *Parent = Stack.empty() ? nullptr : Stack.back();
56
2.51M
    OwnedScopes.emplace_back(K, Parent);
57
2.51M
    Stack.push_back(&OwnedScopes.back());
58
2.51M
    return OwnedScopes.back();
59
2.51M
  }
60
61
2.51M
  void popScope() noexcept {
62
2.51M
    assuming(!Stack.empty());
63
2.51M
    Stack.pop_back();
64
2.51M
  }
65
66
19.5M
  Scope &getTop() noexcept {
67
19.5M
    assuming(!Stack.empty());
68
19.5M
    return *Stack.back();
69
19.5M
  }
70
693k
  const Scope &getTop() const noexcept {
71
693k
    assuming(!Stack.empty());
72
693k
    return *Stack.back();
73
693k
  }
74
75
  /// The scope Levels hops up from the current one; nullptr if out of range.
76
66.7k
  Scope *getScope(uint32_t Levels) noexcept {
77
66.7k
    if (Levels >= Stack.size()) {
78
36
      return nullptr;
79
36
    }
80
66.6k
    return Stack[Stack.size() - 1 - Levels];
81
66.7k
  }
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
  /// The interface version with its `version-suffix`, and `implements` only
105
  /// on a 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
3.00M
  uint32_t nextNameId() noexcept { return NextNameId++; }
176
177
  uint32_t addResource(const AST::Component::ResourceType *RT,
178
8.73k
                       const Scope *Origin, bool FromImport) noexcept {
179
8.73k
    uint32_t Id = static_cast<uint32_t>(Resources.size());
180
8.73k
    Resources.push_back({RT, Origin, FromImport, nextNameId()});
181
8.73k
    return Id;
182
8.73k
  }
183
184
10.0k
  const ResourceEntry &getResource(uint32_t Id) const noexcept {
185
10.0k
    assuming(Id < Resources.size());
186
10.0k
    return Resources[Id];
187
10.0k
  }
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
2.05M
                                  const ResourceMap *Inner) noexcept {
196
2.05M
    if (Outer == nullptr) {
197
2.05M
      return Inner;
198
2.05M
    }
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
26
  uint32_t applyRemap(const ResourceMap *M, uint32_t Id) const noexcept {
221
26
    return M != nullptr ? M->apply(Id) : Id;
222
26
  }
223
224
181k
  CoreShape *addCoreShape() noexcept { return &OwnedCoreShapes.emplace_back(); }
225
4.54M
  Shape *addShape() noexcept { return &OwnedShapes.emplace_back(); }
226
1.16M
  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
266k
                                      Span<const ValType> Results) noexcept {
231
266k
    OwnedCoreTypes.push_back(
232
266k
        std::make_unique<AST::SubType>(AST::FunctionType(Params, Results)));
233
266k
    return OwnedCoreTypes.back().get();
234
266k
  }
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
6.48M
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
6.48M
    if (D.isRecordTy()) {
254
3.00k
      for (const auto &LT : D.getRecord().LabelTypes) {
255
3.00k
        Func(LT.getValType());
256
3.00k
      }
257
6.48M
    } else if (D.isVariantTy()) {
258
22.0k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
22.0k
        if (Ty.has_value()) {
260
21.5k
          Func(*Ty);
261
21.5k
        }
262
22.0k
      }
263
6.45M
    } else if (D.isListTy()) {
264
227k
      Func(D.getList().ValTy);
265
6.23M
    } else if (D.isTupleTy()) {
266
51.4k
      for (const auto &Ty : D.getTuple().Types) {
267
51.4k
        Func(Ty);
268
51.4k
      }
269
6.20M
    } else if (D.isMapTy()) {
270
5.08M
      Func(D.getMap().KeyTy);
271
5.08M
      Func(D.getMap().ValTy);
272
5.08M
    } else if (D.isOptionTy()) {
273
10.8k
      Func(D.getOption().ValTy);
274
1.11M
    } else if (D.isResultTy()) {
275
876k
      const auto &R = D.getResult();
276
876k
      if (R.ValTy.has_value()) {
277
339k
        Func(*R.ValTy);
278
339k
      }
279
876k
      if (R.ErrTy.has_value()) {
280
541k
        Func(*R.ErrTy);
281
541k
      }
282
876k
    }
283
6.48M
  }
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
507k
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
507k
    if (D.isRecordTy()) {
254
249
      for (const auto &LT : D.getRecord().LabelTypes) {
255
249
        Func(LT.getValType());
256
249
      }
257
507k
    } else if (D.isVariantTy()) {
258
3.52k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
3.52k
        if (Ty.has_value()) {
260
3.38k
          Func(*Ty);
261
3.38k
        }
262
3.52k
      }
263
503k
    } else if (D.isListTy()) {
264
146k
      Func(D.getList().ValTy);
265
357k
    } else if (D.isTupleTy()) {
266
14.0k
      for (const auto &Ty : D.getTuple().Types) {
267
14.0k
        Func(Ty);
268
14.0k
      }
269
349k
    } else if (D.isMapTy()) {
270
195k
      Func(D.getMap().KeyTy);
271
195k
      Func(D.getMap().ValTy);
272
195k
    } else if (D.isOptionTy()) {
273
134
      Func(D.getOption().ValTy);
274
153k
    } else if (D.isResultTy()) {
275
152k
      const auto &R = D.getResult();
276
152k
      if (R.ValTy.has_value()) {
277
60.1k
        Func(*R.ValTy);
278
60.1k
      }
279
152k
      if (R.ErrTy.has_value()) {
280
93.9k
        Func(*R.ErrTy);
281
93.9k
      }
282
152k
    }
283
507k
  }
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
44.5k
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
44.5k
    if (D.isRecordTy()) {
254
1.34k
      for (const auto &LT : D.getRecord().LabelTypes) {
255
1.34k
        Func(LT.getValType());
256
1.34k
      }
257
43.1k
    } else if (D.isVariantTy()) {
258
1.64k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
1.64k
        if (Ty.has_value()) {
260
1.57k
          Func(*Ty);
261
1.57k
        }
262
1.64k
      }
263
41.5k
    } else if (D.isListTy()) {
264
1.51k
      Func(D.getList().ValTy);
265
40.0k
    } else if (D.isTupleTy()) {
266
559
      for (const auto &Ty : D.getTuple().Types) {
267
559
        Func(Ty);
268
559
      }
269
39.6k
    } else if (D.isMapTy()) {
270
35.1k
      Func(D.getMap().KeyTy);
271
35.1k
      Func(D.getMap().ValTy);
272
35.1k
    } else if (D.isOptionTy()) {
273
2.62k
      Func(D.getOption().ValTy);
274
2.62k
    } else if (D.isResultTy()) {
275
744
      const auto &R = D.getResult();
276
744
      if (R.ValTy.has_value()) {
277
344
        Func(*R.ValTy);
278
344
      }
279
744
      if (R.ErrTy.has_value()) {
280
400
        Func(*R.ErrTy);
281
400
      }
282
744
    }
283
44.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
9.03k
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
9.03k
    if (D.isRecordTy()) {
254
92
      for (const auto &LT : D.getRecord().LabelTypes) {
255
92
        Func(LT.getValType());
256
92
      }
257
8.94k
    } else if (D.isVariantTy()) {
258
159
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
159
        if (Ty.has_value()) {
260
93
          Func(*Ty);
261
93
        }
262
159
      }
263
8.78k
    } else if (D.isListTy()) {
264
0
      Func(D.getList().ValTy);
265
8.78k
    } else if (D.isTupleTy()) {
266
9.95k
      for (const auto &Ty : D.getTuple().Types) {
267
9.95k
        Func(Ty);
268
9.95k
      }
269
4.97k
    } else if (D.isMapTy()) {
270
0
      Func(D.getMap().KeyTy);
271
0
      Func(D.getMap().ValTy);
272
3.81k
    } else if (D.isOptionTy()) {
273
97
      Func(D.getOption().ValTy);
274
3.71k
    } else if (D.isResultTy()) {
275
2.71k
      const auto &R = D.getResult();
276
2.71k
      if (R.ValTy.has_value()) {
277
2.30k
        Func(*R.ValTy);
278
2.30k
      }
279
2.71k
      if (R.ErrTy.has_value()) {
280
1.95k
        Func(*R.ErrTy);
281
1.95k
      }
282
2.71k
    }
283
9.03k
  }
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
285
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
285
    if (D.isRecordTy()) {
254
0
      for (const auto &LT : D.getRecord().LabelTypes) {
255
0
        Func(LT.getValType());
256
0
      }
257
285
    } 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
285
    } else if (D.isListTy()) {
264
76
      Func(D.getList().ValTy);
265
209
    } else if (D.isTupleTy()) {
266
247
      for (const auto &Ty : D.getTuple().Types) {
267
247
        Func(Ty);
268
247
      }
269
105
    } else if (D.isMapTy()) {
270
34
      Func(D.getMap().KeyTy);
271
34
      Func(D.getMap().ValTy);
272
70
    } else if (D.isOptionTy()) {
273
21
      Func(D.getOption().ValTy);
274
49
    } else if (D.isResultTy()) {
275
49
      const auto &R = D.getResult();
276
49
      if (R.ValTy.has_value()) {
277
30
        Func(*R.ValTy);
278
30
      }
279
49
      if (R.ErrTy.has_value()) {
280
19
        Func(*R.ErrTy);
281
19
      }
282
49
    }
283
285
  }
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
1.01k
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
1.01k
    if (D.isRecordTy()) {
254
48
      for (const auto &LT : D.getRecord().LabelTypes) {
255
48
        Func(LT.getValType());
256
48
      }
257
963
    } else if (D.isVariantTy()) {
258
31
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
31
        if (Ty.has_value()) {
260
25
          Func(*Ty);
261
25
        }
262
31
      }
263
932
    } else if (D.isListTy()) {
264
38
      Func(D.getList().ValTy);
265
894
    } else if (D.isTupleTy()) {
266
113
      for (const auto &Ty : D.getTuple().Types) {
267
113
        Func(Ty);
268
113
      }
269
848
    } else if (D.isMapTy()) {
270
781
      Func(D.getMap().KeyTy);
271
781
      Func(D.getMap().ValTy);
272
781
    } else if (D.isOptionTy()) {
273
32
      Func(D.getOption().ValTy);
274
35
    } else if (D.isResultTy()) {
275
35
      const auto &R = D.getResult();
276
35
      if (R.ValTy.has_value()) {
277
22
        Func(*R.ValTy);
278
22
      }
279
35
      if (R.ErrTy.has_value()) {
280
17
        Func(*R.ErrTy);
281
17
      }
282
35
    }
283
1.01k
  }
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.96M
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
2.96M
    if (D.isRecordTy()) {
254
635
      for (const auto &LT : D.getRecord().LabelTypes) {
255
635
        Func(LT.getValType());
256
635
      }
257
2.96M
    } else if (D.isVariantTy()) {
258
8.32k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
8.32k
        if (Ty.has_value()) {
260
8.21k
          Func(*Ty);
261
8.21k
        }
262
8.32k
      }
263
2.95M
    } else if (D.isListTy()) {
264
39.5k
      Func(D.getList().ValTy);
265
2.91M
    } else if (D.isTupleTy()) {
266
13.2k
      for (const auto &Ty : D.getTuple().Types) {
267
13.2k
        Func(Ty);
268
13.2k
      }
269
2.90M
    } else if (D.isMapTy()) {
270
2.42M
      Func(D.getMap().KeyTy);
271
2.42M
      Func(D.getMap().ValTy);
272
2.42M
    } else if (D.isOptionTy()) {
273
3.94k
      Func(D.getOption().ValTy);
274
476k
    } else if (D.isResultTy()) {
275
360k
      const auto &R = D.getResult();
276
360k
      if (R.ValTy.has_value()) {
277
138k
        Func(*R.ValTy);
278
138k
      }
279
360k
      if (R.ErrTy.has_value()) {
280
222k
        Func(*R.ErrTy);
281
222k
      }
282
360k
    }
283
2.96M
  }
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.96M
  void forEachValType(const AST::Component::DefValType &D, F &&Func) const {
253
2.96M
    if (D.isRecordTy()) {
254
635
      for (const auto &LT : D.getRecord().LabelTypes) {
255
635
        Func(LT.getValType());
256
635
      }
257
2.96M
    } else if (D.isVariantTy()) {
258
8.32k
      for (const auto &[Label, Ty] : D.getVariant().Cases) {
259
8.32k
        if (Ty.has_value()) {
260
8.21k
          Func(*Ty);
261
8.21k
        }
262
8.32k
      }
263
2.95M
    } else if (D.isListTy()) {
264
39.5k
      Func(D.getList().ValTy);
265
2.91M
    } else if (D.isTupleTy()) {
266
13.2k
      for (const auto &Ty : D.getTuple().Types) {
267
13.2k
        Func(Ty);
268
13.2k
      }
269
2.90M
    } else if (D.isMapTy()) {
270
2.42M
      Func(D.getMap().KeyTy);
271
2.42M
      Func(D.getMap().ValTy);
272
2.42M
    } else if (D.isOptionTy()) {
273
3.94k
      Func(D.getOption().ValTy);
274
476k
    } else if (D.isResultTy()) {
275
360k
      const auto &R = D.getResult();
276
360k
      if (R.ValTy.has_value()) {
277
138k
        Func(*R.ValTy);
278
138k
      }
279
360k
      if (R.ErrTy.has_value()) {
280
222k
        Func(*R.ErrTy);
281
222k
      }
282
360k
    }
283
2.96M
  }
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
  /// and IsLower lowers the values into this component.
342
  bool flattenValType(const QualValType &Q, std::vector<ValType> &Out,
343
                      const ValType &Ptr, bool IsLower) noexcept;
344
  /// The flat type of a borrow: the representation of a resource this
345
  /// component defines when lowered into it, else an i32 handle.
346
  ValType flattenBorrow(const Scope *Home, const ResourceMap *Remap,
347
                        uint32_t Idx, bool IsLower) const noexcept;
348
  /// True iff the type transitively contains a list or string.
349
  bool needsMemory(const QualValType &Q) noexcept;
350
  /// Flatten a function type lifted from or lowered into this component; the
351
  /// flags report which side needs a memory.
352
  Expect<AST::FunctionType> flattenFuncType(const FuncInfo &FI,
353
                                            const ValType &Ptr, bool IsLift,
354
                                            bool &ParamsNeedMemory,
355
                                            bool &ResultsNeedMemory) noexcept;
356
357
7.37k
  void reset() noexcept {
358
7.37k
    Stack.clear();
359
7.37k
    OwnedScopes.clear();
360
7.37k
    NextNameId = 0;
361
7.37k
    Resources.clear();
362
7.37k
    OwnedCoreShapes.clear();
363
7.37k
    OwnedShapes.clear();
364
7.37k
    OwnedRemaps.clear();
365
7.37k
    ComposedRemaps.clear();
366
7.37k
    OwnedCoreTypes.clear();
367
7.37k
    TypeSizes.clear();
368
7.37k
    TypeDepths.clear();
369
7.37k
    ElemLayouts.clear();
370
7.37k
  }
371
372
private:
373
  // ==========================================================================
374
  // The named-types rule: introduceExternTypes checks and records an extern.
375
  // ==========================================================================
376
377
  bool introduceExternTypes(const ExternInfo &Info, bool IsImport) noexcept;
378
  bool isIntroduced(const QualValType &Q, bool IsImport) noexcept;
379
  bool isIntroduced(const TypeEntry &E, bool IsImport) noexcept;
380
  // The immediate components of the type. The extern names the type itself.
381
  bool areInnerTypesIntroduced(const TypeEntry &E, bool IsImport) noexcept;
382
383
  // ==========================================================================
384
  // The leaves of the walks above.
385
  // ==========================================================================
386
387
  void collectResources(const TypeEntry &E,
388
                        std::unordered_set<uint32_t> &Out) noexcept;
389
  uint64_t getTypeSize(const QualValType &Q) noexcept;
390
  uint64_t getTypeSize(const TypeEntry &E) noexcept;
391
  uint64_t getTypeDepth(const QualValType &Q) noexcept;
392
  uint64_t getTypeDepth(const TypeEntry &E) noexcept;
393
394
  // ==========================================================================
395
  // Copies of views under a remap; Copies maps each shape met to its copy.
396
  // ==========================================================================
397
398
  ExternInfo
399
  copyExtern(const ExternInfo &E, const ResourceMap *Node,
400
             std::unordered_map<const Shape *, const Shape *> &Copies) noexcept;
401
  TypeEntry copyTypeEntry(
402
      const TypeEntry &E, const ResourceMap *Node,
403
      std::unordered_map<const Shape *, const Shape *> &Copies) noexcept;
404
  const Shape *
405
  copyShape(const Shape *S, const ResourceMap *Node,
406
            std::unordered_map<const Shape *, const Shape *> &Copies) noexcept;
407
408
  std::vector<Scope *> Stack;
409
  std::deque<Scope> OwnedScopes;
410
  uint32_t NextNameId = 0;
411
  std::vector<ResourceEntry> Resources;
412
  std::deque<CoreShape> OwnedCoreShapes;
413
  std::deque<Shape> OwnedShapes;
414
  std::deque<ResourceMap> OwnedRemaps;
415
  std::map<std::pair<const ResourceMap *, const ResourceMap *>,
416
           const ResourceMap *>
417
      ComposedRemaps;
418
  std::vector<std::unique_ptr<AST::SubType>> OwnedCoreTypes;
419
  std::unordered_map<const void *, uint64_t> TypeSizes;
420
  std::unordered_map<const void *, uint64_t> TypeDepths;
421
  std::unordered_map<const void *, std::pair<uint64_t, uint64_t>> ElemLayouts;
422
};
423
424
} // namespace Component
425
} // namespace Validator
426
} // namespace WasmEdge