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