/src/WasmEdge/include/validator/validator_component.h
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: 2019-2024 Second State INC |
3 | | #pragma once |
4 | | |
5 | | #include "common/errinfo.h" |
6 | | #include "validator/context.h" |
7 | | #include "validator/validator.h" |
8 | | |
9 | | namespace WasmEdge { |
10 | | namespace Validator { |
11 | | |
12 | | using namespace std::literals; |
13 | | using namespace AST::Component; |
14 | | |
15 | | // Helper func for better logging |
16 | 0 | inline std::string toString(const SortCase &SC) { |
17 | 0 | switch (SC) { |
18 | 0 | case SortCase::Func: |
19 | 0 | return "Func"; |
20 | 0 | case SortCase::Value: |
21 | 0 | return "Value"; |
22 | 0 | case SortCase::Type: |
23 | 0 | return "Type"; |
24 | 0 | case SortCase::Component: |
25 | 0 | return "Component"; |
26 | 0 | case SortCase::Instance: |
27 | 0 | return "Instance"; |
28 | 0 | default: |
29 | 0 | return "Unknown SortCase"; |
30 | 0 | } |
31 | 0 | } |
32 | | |
33 | 0 | inline std::string toString(const CoreSort &CS) { |
34 | 0 | switch (CS) { |
35 | 0 | case CoreSort::Func: |
36 | 0 | return "Func"; |
37 | 0 | case CoreSort::Table: |
38 | 0 | return "Table"; |
39 | 0 | case CoreSort::Memory: |
40 | 0 | return "Memory"; |
41 | 0 | case CoreSort::Global: |
42 | 0 | return "Global"; |
43 | 0 | case CoreSort::Type: |
44 | 0 | return "Type"; |
45 | 0 | case CoreSort::Module: |
46 | 0 | return "Module"; |
47 | 0 | case CoreSort::Instance: |
48 | 0 | return "Instance"; |
49 | 0 | default: |
50 | 0 | return "Unknown CoreSort"; |
51 | 0 | } |
52 | 0 | } |
53 | | |
54 | 0 | inline std::string toString(const Sort &S) { |
55 | 0 | return std::visit( |
56 | 0 | [](const auto &value) -> std::string { return toString(value); }, S); Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > WasmEdge::Validator::toString(std::__1::variant<WasmEdge::AST::Component::CoreSort, WasmEdge::AST::Component::SortCase> const&)::{lambda(auto:1 const&)#1}::operator()<WasmEdge::AST::Component::CoreSort>(WasmEdge::AST::Component::CoreSort const&) const Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > WasmEdge::Validator::toString(std::__1::variant<WasmEdge::AST::Component::CoreSort, WasmEdge::AST::Component::SortCase> const&)::{lambda(auto:1 const&)#1}::operator()<WasmEdge::AST::Component::SortCase>(WasmEdge::AST::Component::SortCase const&) const |
57 | 0 | } |
58 | | |
59 | 0 | inline std::string toString(const IndexKind &IK) { |
60 | 0 | switch (IK) { |
61 | 0 | case IndexKind::CoreType: |
62 | 0 | return "CoreType"; |
63 | 0 | case IndexKind::FuncType: |
64 | 0 | return "FuncType"; |
65 | 0 | case IndexKind::ComponentType: |
66 | 0 | return "ComponentType"; |
67 | 0 | case IndexKind::InstanceType: |
68 | 0 | return "InstanceType"; |
69 | 0 | default: |
70 | 0 | return "Unknown IndexKind (" + std::to_string(static_cast<int>(IK)) + ")"; |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | struct ExternDescVisitor { |
75 | 0 | ExternDescVisitor(Context &Ctx) : Ctx(Ctx) {} |
76 | | |
77 | 0 | Expect<void> operator()(const DescTypeIndex &DTI) { |
78 | 0 | auto Idx = DTI.getIndex(); |
79 | 0 | switch (DTI.getKind()) { |
80 | 0 | case IndexKind::CoreType: |
81 | 0 | Ctx.incCoreIndexSize(CoreSort::Type); |
82 | 0 | break; |
83 | 0 | case IndexKind::FuncType: |
84 | 0 | Ctx.incComponentIndexSize(SortCase::Func); |
85 | 0 | break; |
86 | 0 | case IndexKind::ComponentType: |
87 | 0 | Ctx.incComponentIndexSize(SortCase::Component); |
88 | 0 | break; |
89 | 0 | case IndexKind::InstanceType: |
90 | 0 | Ctx.incComponentIndexSize(SortCase::Instance); |
91 | 0 | const auto *IT = Ctx.getComponentInstanceType(Idx); |
92 | 0 | if (IT != nullptr) { |
93 | 0 | const auto &InstanceDecls = IT->getContent(); |
94 | 0 | for (auto &InstanceDecl : InstanceDecls) { |
95 | 0 | if (std::holds_alternative<CoreType>(InstanceDecl)) { |
96 | 0 | spdlog::debug("Core Type found"sv); |
97 | 0 | } else if (std::holds_alternative<std::shared_ptr<Type>>( |
98 | 0 | InstanceDecl)) { |
99 | 0 | spdlog::debug("Def Type found"sv); |
100 | 0 | } else if (std::holds_alternative<Alias>(InstanceDecl)) { |
101 | 0 | spdlog::debug("Alias found"sv); |
102 | 0 | } else if (std::holds_alternative<ExportDecl>(InstanceDecl)) { |
103 | 0 | auto &ED = std::get<ExportDecl>(InstanceDecl); |
104 | 0 | uint32_t InstanceIdx = static_cast<uint32_t>( |
105 | 0 | Ctx.getComponentIndexSize(SortCase::Instance) - 1); |
106 | 0 | Ctx.addComponentInstanceExport(InstanceIdx, ED.getExportName(), |
107 | 0 | ED.getExternDesc()); |
108 | 0 | spdlog::debug("Export Decl found"sv); |
109 | 0 | } else { |
110 | 0 | assumingUnreachable(); |
111 | 0 | } |
112 | 0 | } |
113 | 0 | } else { |
114 | 0 | assumingUnreachable(); |
115 | 0 | } |
116 | 0 | break; |
117 | 0 | } |
118 | 0 | return {}; |
119 | 0 | } |
120 | 0 | Expect<void> operator()(const TypeBound &) { |
121 | | // TypeBound == std::optional<TypeIndex> |
122 | 0 | Ctx.incComponentIndexSize(SortCase::Type); |
123 | 0 | return {}; |
124 | 0 | } |
125 | 0 | Expect<void> operator()(const ValueType &) { |
126 | 0 | Ctx.incComponentIndexSize(SortCase::Type); |
127 | 0 | return {}; |
128 | 0 | } |
129 | | |
130 | | private: |
131 | | Context &Ctx; |
132 | | }; |
133 | | |
134 | | struct CoreInstanceExprVisitor { |
135 | 0 | CoreInstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {} |
136 | | |
137 | 0 | Expect<void> operator()(const CoreInstantiate &Inst) { |
138 | 0 | const uint32_t ModuleIdx = Inst.getModuleIdx(); |
139 | 0 | if (ModuleIdx >= Ctx.getCoreModuleCount()) { |
140 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
141 | 0 | spdlog::error( |
142 | 0 | "CoreInstanceSection: Module index {} exceeds available core modules {}"sv, |
143 | 0 | ModuleIdx, Ctx.getCoreModuleCount()); |
144 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
145 | 0 | } |
146 | 0 | auto Args = Inst.getArgs(); |
147 | 0 | auto ImportsList = getImports(Inst); |
148 | 0 | for (auto Import : ImportsList) { |
149 | 0 | auto ArgIt = std::find_if(Args.begin(), Args.end(), [&](const auto &Arg) { |
150 | 0 | return Arg.getName() == Import; |
151 | 0 | }); |
152 | |
|
153 | 0 | if (ArgIt == Args.end()) { |
154 | 0 | spdlog::error(ErrCode::Value::MissingArgument); |
155 | 0 | spdlog::error("Module[{}]: Missing argument for import '{}'"sv, |
156 | 0 | Inst.getModuleIdx(), Import); |
157 | 0 | return Unexpect(ErrCode::Value::MissingArgument); |
158 | 0 | } |
159 | 0 | } |
160 | 0 | Ctx.incCoreIndexSize(CoreSort::Instance); |
161 | 0 | const auto &Mod = Ctx.getCoreModule(ModuleIdx); |
162 | 0 | const auto &ExportDescs = Mod.getExportSection().getContent(); |
163 | 0 | uint32_t InstanceIdx = |
164 | 0 | static_cast<uint32_t>(Ctx.getCoreIndexSize(CoreSort::Instance) - 1); |
165 | 0 | for (const auto &ExportDesc : ExportDescs) { |
166 | 0 | Ctx.addCoreInstanceExport(InstanceIdx, ExportDesc.getExternalName(), |
167 | 0 | ExportDesc.getExternalType()); |
168 | 0 | } |
169 | 0 | return {}; |
170 | 0 | } |
171 | | |
172 | 0 | Expect<void> operator()(const CoreInlineExports &Exports) { |
173 | 0 | for (const auto &Export : Exports.getExports()) { |
174 | 0 | auto ExportName = Export.getName(); |
175 | 0 | auto SortIdx = Export.getSortIdx(); |
176 | 0 | auto Sort = SortIdx.getSort(); |
177 | 0 | uint32_t Idx = SortIdx.getSortIdx(); |
178 | |
|
179 | 0 | if (!isValidArgumentIndex(Sort, Idx)) { |
180 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
181 | 0 | spdlog::error("Core: Inline export '{}' refers to invalid index {}"sv, |
182 | 0 | ExportName, Idx); |
183 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
184 | 0 | } |
185 | 0 | } |
186 | 0 | Ctx.incCoreIndexSize(CoreSort::Instance); |
187 | 0 | return {}; |
188 | 0 | } |
189 | | |
190 | | private: |
191 | | Context &Ctx; |
192 | | |
193 | 0 | std::vector<std::string> getImports(const CoreInstantiate &Inst) { |
194 | 0 | const uint32_t Index = Inst.getModuleIdx(); |
195 | 0 | std::vector<std::string> ImportsList; |
196 | |
|
197 | 0 | const auto &Mod = Ctx.getCoreModule(Index); |
198 | 0 | const auto &ImportDesc = Mod.getImportSection().getContent(); |
199 | |
|
200 | 0 | for (const auto &Import : ImportDesc) { |
201 | 0 | ImportsList.emplace_back(std::string(Import.getModuleName())); |
202 | 0 | } |
203 | 0 | return ImportsList; |
204 | 0 | } |
205 | | |
206 | 0 | bool isValidArgumentIndex(const CoreSort &ArgSort, const uint32_t Idx) { |
207 | 0 | if (Ctx.getCoreIndexSize(ArgSort) > Idx) { |
208 | 0 | return true; |
209 | 0 | } |
210 | 0 | return false; |
211 | 0 | } |
212 | | }; |
213 | | |
214 | | struct InstanceExprVisitor { |
215 | 0 | InstanceExprVisitor(Context &Ctx) : Ctx(Ctx) {} |
216 | | |
217 | 0 | Expect<void> operator()(const Instantiate &Inst) { |
218 | 0 | auto Args = Inst.getArgs(); |
219 | 0 | auto ImportMap = getImports(Inst.getComponentIdx()); |
220 | |
|
221 | 0 | for (auto It = ImportMap.begin(); It != ImportMap.end(); ++It) { |
222 | 0 | const auto &ImportName = It->first; |
223 | 0 | const auto &ImportDesc = It->second; |
224 | 0 | auto ArgIt = std::find_if(Args.begin(), Args.end(), [&](const auto &Arg) { |
225 | 0 | return Arg.getName() == ImportName; |
226 | 0 | }); |
227 | |
|
228 | 0 | if (ArgIt == Args.end()) { |
229 | 0 | spdlog::error(ErrCode::Value::MissingArgument); |
230 | 0 | spdlog::error("Component[{}]: Missing argument for import '{}'"sv, |
231 | 0 | Inst.getComponentIdx(), ImportName); |
232 | 0 | return Unexpect(ErrCode::Value::MissingArgument); |
233 | 0 | } |
234 | | |
235 | 0 | const auto &ArgSortIndex = ArgIt->getIndex(); |
236 | 0 | const auto &ArgSort = ArgSortIndex.getSort(); |
237 | 0 | const uint32_t ArgIdx = ArgSortIndex.getSortIdx(); |
238 | |
|
239 | 0 | if (!matchImportAndArgTypes(ImportDesc, ArgSort)) { |
240 | 0 | spdlog::error(ErrCode::Value::ArgTypeMismatch); |
241 | 0 | spdlog::error("Component[{}]: Argument '{}' type mismatch"sv, |
242 | 0 | Inst.getComponentIdx(), ImportName); |
243 | 0 | return Unexpect(ErrCode::Value::ArgTypeMismatch); |
244 | 0 | } |
245 | | |
246 | 0 | if (!isValidArgumentIndex(ArgSort, ArgIdx)) { |
247 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
248 | 0 | spdlog::error( |
249 | 0 | "Component[{}]: Argument '{}' refers to invalid index {}"sv, |
250 | 0 | Inst.getComponentIdx(), ArgIt->getName(), ArgIdx); |
251 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
252 | 0 | } |
253 | | |
254 | 0 | if (std::holds_alternative<SortCase>(ArgSort) && |
255 | 0 | std::get<SortCase>(ArgSort) == SortCase::Type && |
256 | 0 | std::holds_alternative<TypeBound>(ImportDesc)) { |
257 | 0 | Ctx.substituteTypeImport(ImportName, ArgIdx); |
258 | 0 | } |
259 | 0 | } |
260 | 0 | Ctx.incComponentIndexSize(SortCase::Instance); |
261 | 0 | return {}; |
262 | 0 | } |
263 | 0 | Expect<void> operator()(const InlineExports &Exports) { |
264 | 0 | for (const auto &Export : Exports.getExports()) { |
265 | 0 | auto ExportName = Export.getName(); |
266 | 0 | auto SortIdx = Export.getSortIdx(); |
267 | 0 | auto Sort = SortIdx.getSort(); |
268 | 0 | uint32_t Idx = SortIdx.getSortIdx(); |
269 | |
|
270 | 0 | if (!isValidArgumentIndex(Sort, Idx)) { |
271 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
272 | 0 | spdlog::error( |
273 | 0 | "Component: Inline export '{}' refers to invalid index {}"sv, |
274 | 0 | ExportName, Idx); |
275 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
276 | 0 | } |
277 | | |
278 | 0 | if (std::holds_alternative<SortCase>(Sort) && |
279 | 0 | std::get<SortCase>(Sort) == SortCase::Type) { |
280 | 0 | auto SubstitutedIdx = Ctx.getSubstitutedType(std::string(ExportName)); |
281 | 0 | if (SubstitutedIdx.has_value() && Idx != SubstitutedIdx.value()) { |
282 | 0 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
283 | 0 | spdlog::error( |
284 | 0 | "Component: Inline export '{}' type index {} does not match substituted type index {}"sv, |
285 | 0 | ExportName, Idx, SubstitutedIdx.value()); |
286 | 0 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
287 | 0 | } |
288 | 0 | } |
289 | 0 | } |
290 | 0 | Ctx.incComponentIndexSize(SortCase::Instance); |
291 | 0 | return {}; |
292 | 0 | } |
293 | | |
294 | | private: |
295 | | Context &Ctx; |
296 | | |
297 | 0 | std::unordered_map<std::string, ExternDesc> getImports(uint32_t Index) { |
298 | 0 | std::unordered_map<std::string, ExternDesc> ImportMap; |
299 | |
|
300 | 0 | if (Index >= Ctx.getComponentCount()) { |
301 | 0 | spdlog::error("Unreachable State: Index {} exceeds Component Count {}"sv, |
302 | 0 | Index, Ctx.getComponentCount()); |
303 | 0 | spdlog::error(WasmEdge::ErrInfo::InfoBoundary( |
304 | 0 | Index, 0, static_cast<uint32_t>(Ctx.getComponentCount()))); |
305 | |
|
306 | 0 | return ImportMap; |
307 | 0 | } |
308 | | |
309 | 0 | auto &Comp = Ctx.getComponent(Index); |
310 | |
|
311 | 0 | for (const auto &Sec : Comp.getSections()) { |
312 | 0 | if (std::holds_alternative<ImportSection>(Sec)) { |
313 | 0 | const auto &ImportSec = std::get<ImportSection>(Sec); |
314 | |
|
315 | 0 | for (const auto &Import : ImportSec.getContent()) { |
316 | 0 | ImportMap[std::string(Import.getName())] = Import.getDesc(); |
317 | 0 | } |
318 | 0 | } |
319 | 0 | } |
320 | |
|
321 | 0 | return ImportMap; |
322 | 0 | } |
323 | | |
324 | | // https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md |
325 | | bool matchImportAndArgTypes(const ExternDesc &ImportType, |
326 | 0 | const Sort &ArgSort) { |
327 | 0 | if (std::holds_alternative<CoreSort>(ArgSort)) { |
328 | 0 | CoreSort ArgCoreSort = std::get<CoreSort>(ArgSort); |
329 | |
|
330 | 0 | if (std::holds_alternative<DescTypeIndex>(ImportType)) { |
331 | 0 | const auto &Desc = std::get<DescTypeIndex>(ImportType); |
332 | 0 | IndexKind Kind = Desc.getKind(); |
333 | |
|
334 | 0 | if ((Kind == IndexKind::CoreType && ArgCoreSort == CoreSort::Type) || |
335 | 0 | (Kind == IndexKind::FuncType && ArgCoreSort == CoreSort::Func) || |
336 | 0 | (Kind == IndexKind::ComponentType && |
337 | 0 | ArgCoreSort == CoreSort::Module) || |
338 | 0 | (Kind == IndexKind::InstanceType && |
339 | 0 | ArgCoreSort == CoreSort::Instance)) { |
340 | 0 | return true; |
341 | 0 | } |
342 | 0 | spdlog::error("[Core Sort] Type mismatch: Expected '{}' but got '{}'"sv, |
343 | 0 | WasmEdge::Validator::toString(Kind), |
344 | 0 | WasmEdge::Validator::toString(ArgCoreSort)); |
345 | |
|
346 | 0 | return false; |
347 | 0 | } else if (std::holds_alternative<ValueType>(ImportType)) { |
348 | 0 | if (ArgCoreSort == CoreSort::Func || ArgCoreSort == CoreSort::Table || |
349 | 0 | ArgCoreSort == CoreSort::Memory || |
350 | 0 | ArgCoreSort == CoreSort::Global) { |
351 | 0 | return true; |
352 | 0 | } |
353 | 0 | spdlog::error( |
354 | 0 | "[Core Sort] Type mismatch: Expected 'Func', 'Table', 'Memory', or 'Global' but got '{}'"sv, |
355 | 0 | WasmEdge::Validator::toString(ArgCoreSort)); |
356 | 0 | return false; |
357 | 0 | } else if (std::holds_alternative<TypeBound>(ImportType)) { |
358 | 0 | if (ArgCoreSort == CoreSort::Module || |
359 | 0 | ArgCoreSort == CoreSort::Instance) { |
360 | 0 | return true; |
361 | 0 | } |
362 | 0 | spdlog::error( |
363 | 0 | "[Core Sort] Type mismatch: Expected 'Module' or 'Instance' but got '{}'"sv, |
364 | 0 | WasmEdge::Validator::toString(ArgCoreSort)); |
365 | 0 | return false; |
366 | 0 | } |
367 | 0 | } else if (std::holds_alternative<SortCase>(ArgSort)) { |
368 | 0 | SortCase ArgSortCase = std::get<SortCase>(ArgSort); |
369 | |
|
370 | 0 | if (std::holds_alternative<TypeBound>(ImportType)) { |
371 | 0 | if (ArgSortCase == SortCase::Type) { |
372 | 0 | return true; |
373 | 0 | } |
374 | 0 | spdlog::error( |
375 | 0 | "[Sort Case] Type mismatch: Expected 'Type' but got '{}'"sv, |
376 | 0 | WasmEdge::Validator::toString(ArgSortCase)); |
377 | 0 | return false; |
378 | 0 | } else if (std::holds_alternative<ValueType>(ImportType)) { |
379 | 0 | if (ArgSortCase == SortCase::Value) { |
380 | 0 | return true; |
381 | 0 | } |
382 | 0 | spdlog::error( |
383 | 0 | "[Sort Case] Type mismatch: Expected 'Value' but got '{}'"sv, |
384 | 0 | WasmEdge::Validator::toString(ArgSortCase)); |
385 | 0 | return false; |
386 | 0 | } else if (std::holds_alternative<DescTypeIndex>(ImportType)) { |
387 | 0 | const auto &Desc = std::get<DescTypeIndex>(ImportType); |
388 | 0 | IndexKind Kind = Desc.getKind(); |
389 | |
|
390 | 0 | if ((Kind == IndexKind::ComponentType && |
391 | 0 | ArgSortCase == SortCase::Component) || |
392 | 0 | (Kind == IndexKind::InstanceType && |
393 | 0 | ArgSortCase == SortCase::Instance) || |
394 | 0 | (Kind == IndexKind::FuncType && ArgSortCase == SortCase::Func) || |
395 | 0 | (Kind == IndexKind::CoreType && ArgSortCase == SortCase::Type)) { |
396 | 0 | return true; |
397 | 0 | } |
398 | | |
399 | 0 | spdlog::error("[Sort Case] Type mismatch: Expected '{}' but got '{}'"sv, |
400 | 0 | WasmEdge::Validator::toString(Kind), |
401 | 0 | WasmEdge::Validator::toString(ArgSortCase)); |
402 | 0 | return false; |
403 | 0 | } |
404 | 0 | } |
405 | | |
406 | 0 | spdlog::error( |
407 | 0 | "Unhandled type comparison: ImportType and ArgSort do not match any known case."sv); |
408 | 0 | return false; |
409 | 0 | } |
410 | | |
411 | 0 | bool isValidArgumentIndex(const Sort &ArgSort, const uint32_t Idx) { |
412 | 0 | if (std::holds_alternative<SortCase>(ArgSort)) { |
413 | 0 | auto ArgSortCase = std::get<SortCase>(ArgSort); |
414 | 0 | if (Ctx.getComponentIndexSize(ArgSortCase) > Idx) { |
415 | 0 | return true; |
416 | 0 | } |
417 | 0 | } else { |
418 | 0 | auto ArgSortCase = std::get<CoreSort>(ArgSort); |
419 | 0 | if (Ctx.getCoreIndexSize(ArgSortCase) > Idx) { |
420 | 0 | return true; |
421 | 0 | } |
422 | 0 | } |
423 | 0 | return false; |
424 | 0 | } |
425 | | }; |
426 | | |
427 | | struct AliasTargetVisitor { |
428 | 0 | AliasTargetVisitor(const Sort &S, Context &Ctx) : S{S}, Ctx(Ctx) {} |
429 | | |
430 | 0 | Expect<void> operator()(const AliasTargetExport &ATE) { |
431 | 0 | auto Idx = ATE.getInstanceIdx(); |
432 | 0 | auto Name = ATE.getName(); |
433 | |
|
434 | 0 | if (std::holds_alternative<CoreSort>(S)) { |
435 | 0 | if (Idx >= Ctx.getCoreInstanceExportsSize()) { |
436 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
437 | 0 | spdlog::error( |
438 | 0 | "AliasTargetExport: Export index {} exceeds available core instance index {}"sv, |
439 | 0 | Idx, Ctx.getCoreInstanceExportsSize() - 1); |
440 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
441 | 0 | } |
442 | 0 | const auto &CoreExports = Ctx.getCoreInstanceExports(Idx); |
443 | 0 | auto CoreS = std::get<CoreSort>(S); |
444 | |
|
445 | 0 | auto It = CoreExports.find(Name); |
446 | 0 | if (It == CoreExports.end()) { |
447 | 0 | spdlog::error(ErrCode::Value::ExportNotFound); |
448 | 0 | spdlog::error( |
449 | 0 | "AliasTargetExport: No matching export '{}' found in core instance index {}"sv, |
450 | 0 | Name, Idx); |
451 | 0 | return Unexpect(ErrCode::Value::ExportNotFound); |
452 | 0 | } |
453 | | |
454 | 0 | const auto &ExternTy = It->second; |
455 | 0 | std::optional<CoreSort> MappedSort = mapExternalTypeToCoreSort(ExternTy); |
456 | |
|
457 | 0 | if (MappedSort && *MappedSort == CoreS) { |
458 | 0 | return {}; |
459 | 0 | } else { |
460 | 0 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
461 | 0 | spdlog::error( |
462 | 0 | "AliasTargetExport: Type mapping mismatch for export '{}': expected {}, got {}"sv, |
463 | 0 | Name, toString(CoreS), |
464 | 0 | MappedSort ? toString(*MappedSort) : "none"sv); |
465 | 0 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
466 | 0 | } |
467 | 0 | } else if (std::holds_alternative<SortCase>(S)) { |
468 | 0 | if (Idx >= Ctx.getComponentInstanceExportsSize()) { |
469 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
470 | 0 | spdlog::error( |
471 | 0 | "AliasTargetExport: Export index {} exceeds available component instance index {}"sv, |
472 | 0 | Idx, Ctx.getComponentInstanceExportsSize() - 1); |
473 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
474 | 0 | } |
475 | 0 | const auto &ComponentExports = Ctx.getComponentInstanceExports(Idx); |
476 | 0 | auto SortC = std::get<SortCase>(S); |
477 | |
|
478 | 0 | auto It = ComponentExports.find(Name); |
479 | 0 | if (It == ComponentExports.end()) { |
480 | 0 | spdlog::error(ErrCode::Value::ExportNotFound); |
481 | 0 | spdlog::error( |
482 | 0 | "AliasTargetExport: No matching export '{}' found in component instance index {}"sv, |
483 | 0 | Name, Idx); |
484 | 0 | return Unexpect(ErrCode::Value::ExportNotFound); |
485 | 0 | } |
486 | | |
487 | 0 | const auto &ExternDesc = It->second; |
488 | 0 | std::optional<SortCase> MappedSort = mapExternDescToSortCase(ExternDesc); |
489 | |
|
490 | 0 | if (MappedSort && *MappedSort == SortC) { |
491 | 0 | return {}; |
492 | 0 | } else { |
493 | 0 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
494 | 0 | spdlog::error( |
495 | 0 | "AliasTargetExport: Type mapping mismatch for export '{}': expected {}, got {}"sv, |
496 | 0 | Name, toString(SortC), |
497 | 0 | MappedSort ? toString(*MappedSort) : "none"sv); |
498 | 0 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
499 | 0 | } |
500 | 0 | } else { |
501 | 0 | assumingUnreachable(); |
502 | 0 | } |
503 | 0 | return {}; |
504 | 0 | } |
505 | | |
506 | 0 | Expect<void> operator()(const AliasTargetOuter &ATO) { |
507 | 0 | const auto &ComponentIdx = ATO.getComponent(); |
508 | 0 | const auto &Idx = ATO.getIndex(); |
509 | |
|
510 | 0 | uint32_t EnclosingComponentCount = 0; |
511 | 0 | const auto *CurrentContext = &Ctx.getCurrentContext(); |
512 | 0 | while (CurrentContext->Parent.has_value()) { |
513 | 0 | EnclosingComponentCount++; |
514 | 0 | CurrentContext = CurrentContext->Parent.value(); |
515 | 0 | } |
516 | |
|
517 | 0 | if (ComponentIdx > EnclosingComponentCount) { |
518 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
519 | 0 | spdlog::error( |
520 | 0 | "AliasTargetOuter: ComponentIdx {} is exceeding the enclosing component count {}"sv, |
521 | 0 | ComponentIdx, EnclosingComponentCount); |
522 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
523 | 0 | } |
524 | | |
525 | 0 | const Context::ComponentContext *TargetContext = &Ctx.getCurrentContext(); |
526 | 0 | uint32_t Steps = ComponentIdx; |
527 | 0 | while (Steps > 0 && TargetContext != nullptr) { |
528 | 0 | if (TargetContext->Parent.has_value()) { |
529 | 0 | TargetContext = TargetContext->Parent.value(); |
530 | 0 | --Steps; |
531 | 0 | } else { |
532 | 0 | assumingUnreachable(); |
533 | 0 | } |
534 | 0 | } |
535 | | |
536 | 0 | if (std::holds_alternative<SortCase>(S)) { |
537 | 0 | auto &Sort = std::get<SortCase>(S); |
538 | 0 | auto It = TargetContext->getComponentIndexSize(Sort); |
539 | 0 | spdlog::debug("{}", toString(Sort)); |
540 | 0 | if (Idx >= It) { |
541 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
542 | 0 | spdlog::error( |
543 | 0 | "AliasTargetOuter: Index {} invalid for SortCase in component context"sv, |
544 | 0 | ATO.getIndex()); |
545 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
546 | 0 | } |
547 | 0 | } else if (std::holds_alternative<CoreSort>(S)) { |
548 | 0 | auto &Sort = std::get<CoreSort>(S); |
549 | 0 | auto It = TargetContext->getCoreIndexSize(Sort); |
550 | 0 | if (Idx >= It) { |
551 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
552 | 0 | spdlog::error( |
553 | 0 | "AliasTargetOuter: Index {} invalid for CoreSort in component context"sv, |
554 | 0 | Idx); |
555 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
556 | 0 | } |
557 | 0 | } else { |
558 | 0 | assumingUnreachable(); |
559 | 0 | } |
560 | | |
561 | 0 | if (std::holds_alternative<SortCase>(S)) { |
562 | 0 | auto Sort = std::get<SortCase>(S); |
563 | |
|
564 | 0 | if (Sort != SortCase::Type && Sort != SortCase::Component) { |
565 | 0 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
566 | 0 | spdlog::error( |
567 | 0 | "AliasTargetOuter: Invalid sort for outer alias: {}. Only type, module, or component are allowed."sv, |
568 | 0 | toString(Sort)); |
569 | 0 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
570 | 0 | } |
571 | | |
572 | 0 | if (Sort == SortCase::Type) { |
573 | 0 | if (TargetContext->ComponentResourceTypes.find(Idx) != |
574 | 0 | TargetContext->ComponentResourceTypes.end()) { |
575 | 0 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
576 | 0 | spdlog::error( |
577 | 0 | "AliasTargetOuter: Cannot outer-alias a resource type at index {}. Resource types are generative."sv, |
578 | 0 | Idx); |
579 | 0 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
580 | 0 | } |
581 | 0 | } |
582 | |
|
583 | 0 | } else if (std::holds_alternative<CoreSort>(S)) { |
584 | 0 | auto Sort = std::get<CoreSort>(S); |
585 | |
|
586 | 0 | if (Sort != CoreSort::Module && Sort != CoreSort::Type) { |
587 | 0 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
588 | 0 | spdlog::error( |
589 | 0 | "AliasTargetOuter: Invalid sort for outer alias: {}. Only type, module, or component are allowed."sv, |
590 | 0 | toString(Sort)); |
591 | 0 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
592 | 0 | } |
593 | 0 | } |
594 | | |
595 | 0 | return {}; |
596 | 0 | } |
597 | | |
598 | | private: |
599 | | const Sort &S; |
600 | | Context &Ctx; |
601 | | |
602 | | static inline std::optional<CoreSort> |
603 | 0 | mapExternalTypeToCoreSort(WasmEdge::ExternalType ExtType) { |
604 | 0 | using WasmEdge::ExternalType; |
605 | 0 | switch (ExtType) { |
606 | 0 | case ExternalType::Function: |
607 | 0 | return CoreSort::Func; |
608 | 0 | case ExternalType::Table: |
609 | 0 | return CoreSort::Table; |
610 | 0 | case ExternalType::Memory: |
611 | 0 | return CoreSort::Memory; |
612 | 0 | case ExternalType::Global: |
613 | 0 | return CoreSort::Global; |
614 | 0 | default: |
615 | 0 | return std::nullopt; |
616 | 0 | } |
617 | 0 | } |
618 | | |
619 | | static inline std::optional<SortCase> |
620 | 0 | mapExternDescToSortCase(const ExternDesc &Desc) { |
621 | 0 | if (std::holds_alternative<DescTypeIndex>(Desc)) { |
622 | 0 | const auto &DTI = std::get<DescTypeIndex>(Desc); |
623 | 0 | switch (DTI.getKind()) { |
624 | 0 | case IndexKind::FuncType: |
625 | 0 | return SortCase::Func; |
626 | 0 | case IndexKind::ComponentType: |
627 | 0 | return SortCase::Component; |
628 | 0 | case IndexKind::InstanceType: |
629 | 0 | return SortCase::Instance; |
630 | 0 | default: |
631 | 0 | return std::nullopt; |
632 | 0 | } |
633 | 0 | } else if (std::holds_alternative<TypeBound>(Desc)) { |
634 | 0 | return SortCase::Type; |
635 | 0 | } else if (std::holds_alternative<ValueType>(Desc)) { |
636 | 0 | return SortCase::Type; |
637 | 0 | } |
638 | 0 | return std::nullopt; |
639 | 0 | } |
640 | | }; |
641 | | |
642 | | struct CoreModuleDeclVisitor { |
643 | | // TODO: Validation of core:moduledecl rejects core:moduletype |
644 | | // definitions and outer aliases of core:moduletype definitions inside |
645 | | // type declarators. Thus, as an invariant, when validating a |
646 | | // core:moduletype, the core type index space will not contain any |
647 | | // core module types. |
648 | 0 | Expect<void> operator()(const AST::ImportDesc &) { return {}; } |
649 | 0 | Expect<void> operator()(const std::shared_ptr<CoreType> &) { return {}; } |
650 | 0 | Expect<void> operator()(const Alias &) { return {}; } |
651 | 0 | Expect<void> operator()(const CoreExportDecl &) { return {}; } |
652 | | }; |
653 | | struct CoreDefTypeVisitor { |
654 | 0 | CoreDefTypeVisitor(Context &Ctx) : Ctx(Ctx) {} |
655 | | |
656 | 0 | Expect<void> operator()(const AST::FunctionType &) { |
657 | 0 | Ctx.incCoreIndexSize(CoreSort::Type); |
658 | 0 | return {}; |
659 | 0 | } |
660 | 0 | Expect<void> operator()(const CoreModuleType &Mod) { |
661 | 0 | for (const CoreModuleDecl &D : Mod.getContent()) { |
662 | 0 | EXPECTED_TRY(std::visit(CoreModuleDeclVisitor{}, D)); |
663 | 0 | } |
664 | 0 | return {}; |
665 | 0 | } |
666 | | |
667 | | private: |
668 | | Context &Ctx; |
669 | | }; |
670 | | |
671 | | struct DefTypeVisitor { |
672 | 0 | DefTypeVisitor(Context &Ctx) : Ctx(Ctx) {} |
673 | | |
674 | 0 | Expect<void> operator()(const DefValType &) { |
675 | | // TODO: Validation of valtype requires the typeidx to refer to a |
676 | | // defvaltype. |
677 | | |
678 | | // TODO: Validation of own and borrow requires the typeidx to refer to a |
679 | | // resource type. |
680 | 0 | Ctx.incComponentIndexSize(SortCase::Type); |
681 | 0 | return {}; |
682 | 0 | } |
683 | 0 | Expect<void> operator()(const FuncType &) { |
684 | | // TODO: Validation of functype rejects any transitive use of borrow in |
685 | | // a result type. Similarly, validation of components and component |
686 | | // types rejects any transitive use of borrow in an exported value type. |
687 | 0 | Ctx.incComponentIndexSize(SortCase::Type); |
688 | 0 | return {}; |
689 | 0 | } |
690 | 0 | Expect<void> operator()(const ComponentType &CT) { |
691 | 0 | for (auto &Decl : CT.getContent()) { |
692 | 0 | if (std::holds_alternative<ImportDecl>(Decl)) { |
693 | 0 | auto &I = std::get<ImportDecl>(Decl); |
694 | 0 | check(I.getExternDesc()); |
695 | 0 | } else if (std::holds_alternative<InstanceDecl>(Decl)) { |
696 | 0 | check(std::get<InstanceDecl>(Decl)); |
697 | 0 | } |
698 | 0 | Ctx.incComponentIndexSize(SortCase::Type); |
699 | 0 | } |
700 | | // TODO: Validation rejects resourcetype type definitions inside |
701 | | // componenttype and instancettype. Thus, handle types inside a |
702 | | // componenttype can only refer to resource types that are imported or |
703 | | // exported. |
704 | | |
705 | | // TODO: As described in the explainer, each component and instance type |
706 | | // is validated with an initially-empty type index space. Outer aliases |
707 | | // can be used to pull in type definitions from containing components. |
708 | |
|
709 | 0 | return {}; |
710 | 0 | } |
711 | 0 | Expect<void> operator()(const InstanceType &IT) { |
712 | 0 | Ctx.incComponentIndexSize(SortCase::Type); |
713 | 0 | Ctx.addComponentInstanceType( |
714 | 0 | static_cast<uint32_t>(Ctx.getComponentIndexSize(SortCase::Type) - 1), |
715 | 0 | IT); |
716 | 0 | return {}; |
717 | 0 | } |
718 | 0 | Expect<void> operator()(const ResourceType &RT) { |
719 | 0 | Ctx.incComponentIndexSize(SortCase::Type); |
720 | 0 | Ctx.addComponentResourceType( |
721 | 0 | static_cast<uint32_t>(Ctx.getComponentIndexSize(SortCase::Type) - 1), |
722 | 0 | RT); |
723 | 0 | return {}; |
724 | 0 | } |
725 | | |
726 | 0 | void check(const InstanceDecl &) { |
727 | | // TODO: Validation of instancedecl (currently) only allows the type and |
728 | | // instance sorts in alias declarators. |
729 | 0 | } |
730 | | |
731 | 0 | void check(const ExternDesc &) { |
732 | | // TODO: Validation of externdesc requires the various typeidx type |
733 | | // constructors to match the preceding sort. |
734 | 0 | } |
735 | | |
736 | | private: |
737 | | Context &Ctx; |
738 | | }; |
739 | | struct CanonVisitor { |
740 | 0 | CanonVisitor(Context &Ctx) : Ctx(Ctx) {} |
741 | | |
742 | 0 | Expect<void> operator()(const Lift &) { |
743 | | // TODO: validation specifies |
744 | | // = $callee must have type flatten_functype($opts, $ft, 'lift') |
745 | | // = $f is given type $ft |
746 | | // = a memory is present if required by lifting and is a subtype of |
747 | | // (memory 1) |
748 | | // = a realloc is present if required by lifting and has type |
749 | | // (func (param i32 i32 i32 i32) (result i32)) |
750 | | // = if a post-return is present, it has type |
751 | | // (func (param flatten_functype({}, $ft, 'lift').results)) |
752 | 0 | Ctx.incComponentIndexSize(SortCase::Func); |
753 | 0 | return {}; |
754 | 0 | } |
755 | 0 | Expect<void> operator()(const Lower &) { |
756 | | // TODO: where $callee has type $ft, validation specifies |
757 | | // = $f is given type flatten_functype($opts, $ft, 'lower') |
758 | | // = a memory is present if required by lifting and is a subtype of |
759 | | // (memory 1) |
760 | | // = a realloc is present if required by lifting and has type |
761 | | // (func (param i32 i32 i32 i32) (result i32)) |
762 | | // = there is no post-return in $opts |
763 | 0 | Ctx.incCoreIndexSize(CoreSort::Func); |
764 | 0 | return {}; |
765 | 0 | } |
766 | 0 | Expect<void> operator()(const ResourceNew &) { |
767 | | // TODO: validation specifies |
768 | | // = $rt must refer to locally-defined (not imported) resource type |
769 | | // = $f is given type (func (param $rt.rep) (result i32)), where $rt.rep is |
770 | | // currently fixed to be i32. |
771 | 0 | Ctx.incCoreIndexSize(CoreSort::Func); |
772 | 0 | return {}; |
773 | 0 | } |
774 | 0 | Expect<void> operator()(const ResourceDrop &) { |
775 | | // TODO: validation specifies |
776 | | // = $rt must refer to resource type |
777 | | // = $f is given type (func (param i32)) |
778 | 0 | Ctx.incCoreIndexSize(CoreSort::Func); |
779 | 0 | return {}; |
780 | 0 | } |
781 | 0 | Expect<void> operator()(const ResourceRep &) { |
782 | | // TODO: validation specifies |
783 | | // = $rt must refer to a locally-defined (not imported) resource type |
784 | | // = $f is given type (func (param i32) (result $rt.rep)), where $rt.rep is |
785 | | // currently fixed to be i32. |
786 | 0 | Ctx.incCoreIndexSize(CoreSort::Func); |
787 | 0 | return {}; |
788 | 0 | } |
789 | | // TODO: The following are not yet exists in WasmEdge, so just list entries |
790 | | // 1. canon task.backpressure |
791 | | // 2. canon task.start |
792 | | // 3. canon task.return |
793 | | // 4. canon task.wait |
794 | | // 5. canon task.poll |
795 | | // 6. canon task.yield |
796 | | // 7. canon thread.spawn |
797 | | // 8. canon thread.hw_concurrency |
798 | | private: |
799 | | Context &Ctx; |
800 | | }; |
801 | | |
802 | | struct SectionVisitor { |
803 | 0 | SectionVisitor(Validator &V, Context &Ctx) : V(V), Ctx(Ctx) {} |
804 | | |
805 | 0 | Expect<void> operator()(const AST::CustomSection &) { |
806 | 0 | spdlog::debug("Custom Section"sv); |
807 | 0 | return {}; |
808 | 0 | } |
809 | 0 | Expect<void> operator()(const CoreModuleSection &Sec) { |
810 | 0 | spdlog::debug("CoreModule Section"sv); |
811 | 0 | auto &Mod = Sec.getContent(); |
812 | 0 | V.validate(Mod); |
813 | 0 | Ctx.addCoreModule(Mod); |
814 | 0 | Ctx.incCoreIndexSize(CoreSort::Module); |
815 | 0 | return {}; |
816 | 0 | } |
817 | 0 | Expect<void> operator()(const ComponentSection &Sec) { |
818 | 0 | spdlog::debug("Component Section"sv); |
819 | 0 | auto &C = Sec.getContent(); |
820 | 0 | V.validate(C); |
821 | 0 | Ctx.incComponentIndexSize(SortCase::Component); |
822 | 0 | return {}; |
823 | 0 | } |
824 | 0 | Expect<void> operator()(const CoreInstanceSection &Sec) { |
825 | 0 | spdlog::debug("CoreInstance Section"sv); |
826 | 0 | for (const CoreInstanceExpr &E : Sec.getContent()) { |
827 | 0 | CoreInstanceExprVisitor Visitor{Ctx}; |
828 | 0 | EXPECTED_TRY(std::visit(Visitor, E)); |
829 | 0 | } |
830 | | // NOTE: refers below InstanceSection, and copy the similar structure |
831 | | |
832 | | // TODO: Validation of core:instantiatearg initially only allows the |
833 | | // instance sort, but would be extended to accept other sorts as core wasm |
834 | | // is extended. |
835 | 0 | return {}; |
836 | 0 | } |
837 | 0 | Expect<void> operator()(const InstanceSection &Sec) { |
838 | 0 | spdlog::debug("Instance Section"sv); |
839 | 0 | for (const InstanceExpr &E : Sec.getContent()) { |
840 | 0 | InstanceExprVisitor Visitor{Ctx}; |
841 | 0 | EXPECTED_TRY(std::visit(Visitor, E)); |
842 | 0 | } |
843 | 0 | return {}; |
844 | 0 | } |
845 | 0 | Expect<void> operator()(const AliasSection &Sec) { |
846 | 0 | spdlog::debug("Alias Section"sv); |
847 | 0 | for (const Alias &A : Sec.getContent()) { |
848 | 0 | EXPECTED_TRY( |
849 | 0 | std::visit(AliasTargetVisitor{A.getSort(), Ctx}, A.getTarget())); |
850 | 0 | auto Sort = A.getSort(); |
851 | 0 | if (std::holds_alternative<SortCase>(Sort)) { |
852 | 0 | Ctx.incComponentIndexSize(std::get<SortCase>(Sort)); |
853 | 0 | } else if (std::holds_alternative<CoreSort>(Sort)) { |
854 | 0 | Ctx.incCoreIndexSize(std::get<CoreSort>(Sort)); |
855 | 0 | } |
856 | 0 | } |
857 | 0 | return {}; |
858 | 0 | } |
859 | 0 | Expect<void> operator()(const CoreTypeSection &Sec) { |
860 | 0 | spdlog::debug("CoreType Section"sv); |
861 | | // TODO: As described in the explainer, each module type is validated with |
862 | | // an initially-empty type index space. |
863 | 0 | for (const CoreDefType &T : Sec.getContent()) { |
864 | 0 | CoreDefTypeVisitor Visitor{Ctx}; |
865 | 0 | EXPECTED_TRY(std::visit(Visitor, T)); |
866 | 0 | } |
867 | 0 | return {}; |
868 | 0 | } |
869 | 0 | Expect<void> operator()(const TypeSection &Sec) { |
870 | 0 | spdlog::debug("Type Section"sv); |
871 | 0 | for (const DefType &T : Sec.getContent()) { |
872 | 0 | DefTypeVisitor Visitor{Ctx}; |
873 | 0 | EXPECTED_TRY(std::visit(Visitor, T)); |
874 | 0 | } |
875 | | // TODO: Validation of resourcetype requires the destructor (if present) to |
876 | | // have type [i32] -> []. |
877 | | |
878 | 0 | return {}; |
879 | 0 | } |
880 | 0 | Expect<void> operator()(const CanonSection &Sec) { |
881 | 0 | spdlog::debug("Canon Section"sv); |
882 | | // TODO: Validation prevents duplicate or conflicting canonopt. |
883 | 0 | for (const Canon &C : Sec.getContent()) { |
884 | 0 | CanonVisitor Visitor{Ctx}; |
885 | 0 | EXPECTED_TRY(std::visit(Visitor, C)); |
886 | 0 | } |
887 | | |
888 | 0 | return {}; |
889 | 0 | } |
890 | 0 | Expect<void> operator()(const StartSection &) { |
891 | 0 | spdlog::debug("Start Section"sv); |
892 | | // API: |
893 | | // const Start &S = Sec.getContent(); |
894 | | // S.getFunctionIndex(); |
895 | | // S.getArguments(); |
896 | | // S.getResult(); |
897 | | |
898 | | // TODO: Validation requires f have functype with param arity and types |
899 | | // matching arg* and result arity r. |
900 | | |
901 | | // TODO: Validation appends the result types of f to the value index space |
902 | | // (making them available for reference by subsequent definitions). |
903 | | |
904 | | // TODO: In addition to the type-compatibility checks mentioned above, the |
905 | | // validation rules for value definitions additionally require that each |
906 | | // value is consumed exactly once. Thus, during validation, each value has |
907 | | // an associated "consumed" boolean flag. When a value is first added to |
908 | | // the value index space (via import, instance, alias or start), the flag |
909 | | // is clear. When a value is used (via export, instantiate or start), the |
910 | | // flag is set. After validating the last definition of a component, |
911 | | // validation requires all values' flags are set. |
912 | |
|
913 | 0 | return {}; |
914 | 0 | } |
915 | 0 | Expect<void> operator()(const ImportSection &Sec) { |
916 | 0 | spdlog::debug("Import Section"sv); |
917 | | // NOTE: This section share the validation rules with export section, one |
918 | | // must share the implementation as much as possible. |
919 | 0 | for (const Import &I : Sec.getContent()) { |
920 | | // TODO: Validation requires that annotated plainnames only occur on func |
921 | | // imports or exports and that the first label of a [constructor], |
922 | | // [method] or [static] matches the plainname of a preceding resource |
923 | | // import or export, respectively, in the same scope (component, component |
924 | | // type or instance type). |
925 | | |
926 | | // TODO: Validation of [constructor] names requires that the func returns |
927 | | // a (result (own $R)), where $R is the resource labeled r. |
928 | | |
929 | | // TODO: Validation of [method] names requires the first parameter of the |
930 | | // function to be (param "self" (borrow $R)), where $R is the resource |
931 | | // labeled r. |
932 | | |
933 | | // TODO: Validation of [method] and [static] names ensures that all field |
934 | | // names are disjoint. |
935 | 0 | I.getName(); |
936 | |
|
937 | 0 | ExternDescVisitor Visitor{Ctx}; |
938 | 0 | EXPECTED_TRY(std::visit(Visitor, I.getDesc())); |
939 | 0 | } |
940 | | // TODO: Validation requires that all resource types transitively used in |
941 | | // the type of an export are introduced by a preceding importdecl or |
942 | | // exportdecl. |
943 | | |
944 | 0 | return {}; |
945 | 0 | } |
946 | 0 | Expect<void> operator()(const ExportSection &Sec) { |
947 | 0 | spdlog::debug("Export Section"sv); |
948 | 0 | for (const Export &E : Sec.getContent()) { |
949 | 0 | auto SI = E.getSortIndex(); |
950 | 0 | auto Sort = SI.getSort(); |
951 | 0 | SI.getSortIdx(); |
952 | 0 | if (E.getDesc().has_value()) { |
953 | | // TODO: Validation requires any exported sortidx to have a valid |
954 | | // externdesc (which disallows core sorts other than core module). When |
955 | | // the optional externdesc immediate is present, validation requires it |
956 | | // to be a supertype of the inferred externdesc of the sortidx. |
957 | 0 | ExternDescVisitor Visitor{Ctx}; |
958 | 0 | EXPECTED_TRY(std::visit(Visitor, *E.getDesc())); |
959 | 0 | } else if (std::holds_alternative<SortCase>(Sort)) { |
960 | 0 | auto SC = std::get<SortCase>(Sort); |
961 | 0 | Ctx.incComponentIndexSize(SC); |
962 | 0 | } |
963 | 0 | } |
964 | | |
965 | 0 | return {}; |
966 | 0 | } |
967 | | |
968 | | private: |
969 | | Validator &V; |
970 | | Context &Ctx; |
971 | | }; |
972 | | |
973 | | } // namespace Validator |
974 | | } // namespace WasmEdge |