/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 < : 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 < : 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 < : 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 < : 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 < : 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 < : 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 < : 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 < : 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 |