/src/WasmEdge/lib/validator/component_validator.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | //===-- component_validator.cpp - Component definition validation ---------===// |
5 | | // |
6 | | // The component-model validation entry point and the per-section rules. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | |
10 | | #include "common/errinfo.h" |
11 | | #include "common/spdlog.h" |
12 | | #include "validator/component_value_decode.h" |
13 | | #include "validator/validator.h" |
14 | | |
15 | | #include <optional> |
16 | | #include <string> |
17 | | #include <unordered_set> |
18 | | #include <variant> |
19 | | |
20 | | namespace WasmEdge { |
21 | | namespace Validator { |
22 | | |
23 | | using namespace std::literals; |
24 | | |
25 | | Expect<void> |
26 | 7.37k | Validator::validate(const AST::Component::Component &Comp) noexcept { |
27 | 7.37k | CompCtx.reset(); |
28 | 7.37k | DeferredModules.clear(); |
29 | 7.37k | EXPECTED_TRY(validate(Comp, *CompCtx.addShape())); |
30 | | // Deferred function-body validation on the checker state saved per module. |
31 | 4.77k | for (auto &[Mod, Saved] : DeferredModules) { |
32 | 4.77k | Checker = std::move(Saved); |
33 | 4.77k | EXPECTED_TRY(validate(Mod->getCodeSection()).map_error([](auto E) { |
34 | 4.76k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Code)); |
35 | 4.76k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
36 | 4.76k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod)); |
37 | 4.76k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); |
38 | 4.76k | return E; |
39 | 4.76k | })); |
40 | 4.76k | const_cast<AST::Module &>(*Mod).setIsValidated(); |
41 | 4.76k | } |
42 | 3.52k | const_cast<AST::Component::Component &>(Comp).setIsValidated(); |
43 | 3.52k | return {}; |
44 | 3.53k | } |
45 | | |
46 | | Expect<void> Validator::validate(const AST::Component::Component &Comp, |
47 | 71.5k | Component::Shape &Out) noexcept { |
48 | | // Walk the sections in binary order; a reference sees only earlier entries. |
49 | 71.5k | auto &S = CompCtx.pushScope(Component::ScopeKind::Component); |
50 | 71.5k | Out.DeclScope = &S; |
51 | | |
52 | 71.5k | auto ReportError = [](auto E) { |
53 | 3.39k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); |
54 | 3.39k | return E; |
55 | 3.39k | }; |
56 | 13.1M | for (const auto &Sec : Comp.getSections()) { |
57 | 13.1M | auto Visitor = [&](auto &&Section) -> Expect<void> { |
58 | 13.1M | using T = std::decay_t<decltype(Section)>; |
59 | 13.1M | if constexpr (std::is_same_v<T, AST::CustomSection>) { |
60 | 4.12M | return {}; |
61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || |
62 | 110k | std::is_same_v<T, AST::Component::ExportSection>) { |
63 | | // These two accumulate into the component's own external type. |
64 | 110k | return validate(Section, Out).map_error(ReportError); |
65 | 8.90M | } else { |
66 | 8.90M | return validate(Section).map_error(ReportError); |
67 | 8.90M | } |
68 | 13.1M | }; component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::CustomSection const&>(WasmEdge::AST::CustomSection const&) const Line | Count | Source | 57 | 4.12M | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 4.12M | using T = std::decay_t<decltype(Section)>; | 59 | 4.12M | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | 4.12M | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | | } else { | 66 | | return validate(Section).map_error(ReportError); | 67 | | } | 68 | 4.12M | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::CoreModuleSection const&>(WasmEdge::AST::Component::CoreModuleSection const&) const Line | Count | Source | 57 | 6.59k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 6.59k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 6.59k | } else { | 66 | 6.59k | return validate(Section).map_error(ReportError); | 67 | 6.59k | } | 68 | 6.59k | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::CoreInstanceSection const&>(WasmEdge::AST::Component::CoreInstanceSection const&) const Line | Count | Source | 57 | 84.4k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 84.4k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 84.4k | } else { | 66 | 84.4k | return validate(Section).map_error(ReportError); | 67 | 84.4k | } | 68 | 84.4k | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::CoreTypeSection const&>(WasmEdge::AST::Component::CoreTypeSection const&) const Line | Count | Source | 57 | 188k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 188k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 188k | } else { | 66 | 188k | return validate(Section).map_error(ReportError); | 67 | 188k | } | 68 | 188k | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::ComponentSection const&>(WasmEdge::AST::Component::ComponentSection const&) const Line | Count | Source | 57 | 64.1k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 64.1k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 64.1k | } else { | 66 | 64.1k | return validate(Section).map_error(ReportError); | 67 | 64.1k | } | 68 | 64.1k | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::InstanceSection const&>(WasmEdge::AST::Component::InstanceSection const&) const Line | Count | Source | 57 | 2.12M | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 2.12M | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 2.12M | } else { | 66 | 2.12M | return validate(Section).map_error(ReportError); | 67 | 2.12M | } | 68 | 2.12M | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::AliasSection const&>(WasmEdge::AST::Component::AliasSection const&) const Line | Count | Source | 57 | 69.4k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 69.4k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 69.4k | } else { | 66 | 69.4k | return validate(Section).map_error(ReportError); | 67 | 69.4k | } | 68 | 69.4k | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::TypeSection const&>(WasmEdge::AST::Component::TypeSection const&) const Line | Count | Source | 57 | 6.07M | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 6.07M | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 6.07M | } else { | 66 | 6.07M | return validate(Section).map_error(ReportError); | 67 | 6.07M | } | 68 | 6.07M | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::CanonSection const&>(WasmEdge::AST::Component::CanonSection const&) const Line | Count | Source | 57 | 272k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 272k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 272k | } else { | 66 | 272k | return validate(Section).map_error(ReportError); | 67 | 272k | } | 68 | 272k | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::StartSection const&>(WasmEdge::AST::Component::StartSection const&) const Line | Count | Source | 57 | 674 | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 674 | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 674 | } else { | 66 | 674 | return validate(Section).map_error(ReportError); | 67 | 674 | } | 68 | 674 | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::ImportSection const&>(WasmEdge::AST::Component::ImportSection const&) const Line | Count | Source | 57 | 97.8k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 97.8k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | 97.8k | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | 97.8k | return validate(Section, Out).map_error(ReportError); | 65 | | } else { | 66 | | return validate(Section).map_error(ReportError); | 67 | | } | 68 | 97.8k | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::ExportSection const&>(WasmEdge::AST::Component::ExportSection const&) const Line | Count | Source | 57 | 13.0k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 13.0k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | 13.0k | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | 13.0k | return validate(Section, Out).map_error(ReportError); | 65 | | } else { | 66 | | return validate(Section).map_error(ReportError); | 67 | | } | 68 | 13.0k | }; |
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::ValueSection const&>(WasmEdge::AST::Component::ValueSection const&) const Line | Count | Source | 57 | 13.9k | auto Visitor = [&](auto &&Section) -> Expect<void> { | 58 | 13.9k | using T = std::decay_t<decltype(Section)>; | 59 | | if constexpr (std::is_same_v<T, AST::CustomSection>) { | 60 | | return {}; | 61 | | } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> || | 62 | | std::is_same_v<T, AST::Component::ExportSection>) { | 63 | | // These two accumulate into the component's own external type. | 64 | | return validate(Section, Out).map_error(ReportError); | 65 | 13.9k | } else { | 66 | 13.9k | return validate(Section).map_error(ReportError); | 67 | 13.9k | } | 68 | 13.9k | }; |
|
69 | 13.1M | EXPECTED_TRY(std::visit(Visitor, Sec)); |
70 | 13.1M | } |
71 | | // Value linearity. Every value must have exactly one consumer. |
72 | 68.1k | const auto &Values = S.Values; |
73 | 68.2k | for (uint32_t I = 0; I < Values.size(); ++I) { |
74 | 484 | if (!Values[I].Consumed) { |
75 | 448 | spdlog::error(ErrCode::Value::ComponentValueNotConsumed); |
76 | 448 | spdlog::error(" Value index {} was not consumed before the end of the " |
77 | 448 | "component."sv, |
78 | 448 | I); |
79 | 448 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component)); |
80 | 448 | return Unexpect(ErrCode::Value::ComponentValueNotConsumed); |
81 | 448 | } |
82 | 484 | } |
83 | 67.7k | CompCtx.popScope(); |
84 | 67.7k | return {}; |
85 | 68.1k | } |
86 | | |
87 | | Expect<void> |
88 | 6.59k | Validator::validate(const AST::Component::CoreModuleSection &ModSec) noexcept { |
89 | | // Validate every section but the function bodies, which defer to the end. |
90 | 6.59k | const auto &Mod = ModSec.getContent(); |
91 | 6.59k | Checker.reset(true); |
92 | 72.1k | auto ReportError = [](ASTNodeAttr Attr) { |
93 | 72.1k | return [Attr](auto E) { |
94 | 67 | spdlog::error(ErrInfo::InfoAST(Attr)); |
95 | 67 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
96 | 67 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod)); |
97 | 67 | return E; |
98 | 67 | }; |
99 | 72.1k | }; |
100 | 6.59k | EXPECTED_TRY(validate(Mod.getTypeSection()) |
101 | 6.59k | .map_error(ReportError(ASTNodeAttr::Sec_Type))); |
102 | 6.59k | EXPECTED_TRY(validate(Mod.getImportSection()) |
103 | 6.57k | .map_error(ReportError(ASTNodeAttr::Sec_Import))); |
104 | 6.57k | EXPECTED_TRY(validate(Mod.getFunctionSection()) |
105 | 6.57k | .map_error(ReportError(ASTNodeAttr::Sec_Function))); |
106 | 6.57k | EXPECTED_TRY(validate(Mod.getTableSection()) |
107 | 6.55k | .map_error(ReportError(ASTNodeAttr::Sec_Table))); |
108 | 6.55k | EXPECTED_TRY(validate(Mod.getMemorySection()) |
109 | 6.55k | .map_error(ReportError(ASTNodeAttr::Sec_Memory))); |
110 | 6.55k | EXPECTED_TRY(validate(Mod.getGlobalSection()) |
111 | 6.54k | .map_error(ReportError(ASTNodeAttr::Sec_Global))); |
112 | 6.54k | EXPECTED_TRY(validate(Mod.getTagSection()) |
113 | 6.54k | .map_error(ReportError(ASTNodeAttr::Sec_Tag))); |
114 | 6.54k | EXPECTED_TRY(validate(Mod.getExportSection()) |
115 | 6.54k | .map_error(ReportError(ASTNodeAttr::Sec_Export))); |
116 | 6.54k | EXPECTED_TRY(validate(Mod.getStartSection()) |
117 | 6.53k | .map_error(ReportError(ASTNodeAttr::Sec_Start))); |
118 | 6.53k | EXPECTED_TRY(validate(Mod.getElementSection()) |
119 | 6.53k | .map_error(ReportError(ASTNodeAttr::Sec_Element))); |
120 | 6.53k | EXPECTED_TRY(validate(Mod.getDataSection()) |
121 | 6.53k | .map_error(ReportError(ASTNodeAttr::Sec_Data))); |
122 | 6.53k | if (Checker.getTables().size() > 1 && |
123 | 1.56k | !Conf.hasProposal(Proposal::ReferenceTypes)) { |
124 | 0 | spdlog::error(ErrCode::Value::MultiTables); |
125 | 0 | spdlog::error(ErrInfo::InfoProposal(Proposal::ReferenceTypes)); |
126 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
127 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod)); |
128 | 0 | return Unexpect(ErrCode::Value::MultiTables); |
129 | 0 | } |
130 | 6.53k | if (Checker.getMemories().size() > 1 && |
131 | 1.07k | !Conf.hasProposal(Proposal::MultiMemories)) { |
132 | 0 | spdlog::error(ErrCode::Value::MultiMemories); |
133 | 0 | spdlog::error(ErrInfo::InfoProposal(Proposal::MultiMemories)); |
134 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module)); |
135 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod)); |
136 | 0 | return Unexpect(ErrCode::Value::MultiMemories); |
137 | 0 | } |
138 | 6.53k | DeferredModules.emplace_back(&Mod, Checker); |
139 | 6.53k | auto *Shape = CompCtx.addCoreShape(); |
140 | 6.53k | EXPECTED_TRY(validate(Mod, *Shape)); |
141 | 6.52k | CompCtx.getTop().addCoreModule(Shape); |
142 | 6.52k | return {}; |
143 | 6.53k | } |
144 | | |
145 | | // External view of an inline core module: its imports and export types. |
146 | | Expect<void> Validator::validate(const AST::Module &Mod, |
147 | 6.53k | Component::CoreShape &Out) noexcept { |
148 | 6.53k | const auto &ModTypes = Mod.getTypeSection().getContent(); |
149 | | |
150 | 6.53k | auto GetSubType = [&ModTypes](uint32_t Idx) noexcept -> const AST::SubType * { |
151 | 2.32k | return Idx < ModTypes.size() ? &ModTypes[Idx] : nullptr; |
152 | 2.32k | }; |
153 | | |
154 | | // Core index spaces: imports first, then definitions. |
155 | 6.53k | std::vector<Component::CoreExternInfo> Funcs, Tables, Memories, Globals, Tags; |
156 | 6.53k | for (const auto &Imp : Mod.getImportSection().getContent()) { |
157 | 1.90k | Component::CoreExternInfo Ext; |
158 | 1.90k | switch (Imp.getExternalType()) { |
159 | 404 | case ExternalType::Function: |
160 | 404 | Ext = Component::CoreExternInfo(ExternalType::Function, |
161 | 404 | GetSubType(Imp.getExternalFuncTypeIdx())); |
162 | 404 | Funcs.push_back(Ext); |
163 | 404 | break; |
164 | 26 | case ExternalType::Table: |
165 | 26 | Ext = Component::CoreExternInfo(&Imp.getExternalTableType()); |
166 | 26 | Tables.push_back(Ext); |
167 | 26 | break; |
168 | 1.23k | case ExternalType::Memory: |
169 | 1.23k | Ext = Component::CoreExternInfo(&Imp.getExternalMemoryType()); |
170 | 1.23k | Memories.push_back(Ext); |
171 | 1.23k | break; |
172 | 156 | case ExternalType::Global: |
173 | 156 | Ext = Component::CoreExternInfo(&Imp.getExternalGlobalType()); |
174 | 156 | Globals.push_back(Ext); |
175 | 156 | break; |
176 | 85 | case ExternalType::Tag: |
177 | 85 | Ext = Component::CoreExternInfo( |
178 | 85 | ExternalType::Tag, GetSubType(Imp.getExternalTagType().getTypeIdx())); |
179 | 85 | Tags.push_back(Ext); |
180 | 85 | break; |
181 | 0 | default: |
182 | 0 | break; |
183 | 1.90k | } |
184 | 1.90k | for (const auto &[ModName, Name, Prev] : Out.Imports) { |
185 | 641 | if (ModName == Imp.getModuleName() && Name == Imp.getExternalName()) { |
186 | 10 | spdlog::error(ErrCode::Value::ComponentDuplicateImportName); |
187 | 10 | spdlog::error(" Module import '{}'.'{}' name conflict."sv, ModName, |
188 | 10 | Name); |
189 | 10 | return Unexpect(ErrCode::Value::ComponentDuplicateImportName); |
190 | 10 | } |
191 | 641 | } |
192 | 1.89k | Out.Imports.emplace_back(std::string(Imp.getModuleName()), |
193 | 1.89k | std::string(Imp.getExternalName()), Ext); |
194 | 1.89k | } |
195 | 6.52k | for (const auto TIdx : Mod.getFunctionSection().getContent()) { |
196 | 122 | Funcs.emplace_back(ExternalType::Function, GetSubType(TIdx)); |
197 | 122 | } |
198 | 6.52k | for (const auto &Seg : Mod.getTableSection().getContent()) { |
199 | 3.26k | Tables.emplace_back(&Seg.getTableType()); |
200 | 3.26k | } |
201 | 6.52k | for (const auto &MT : Mod.getMemorySection().getContent()) { |
202 | 2.68k | Memories.emplace_back(&MT); |
203 | 2.68k | } |
204 | 6.52k | for (const auto &Seg : Mod.getGlobalSection().getContent()) { |
205 | 613 | Globals.emplace_back(&Seg.getGlobalType()); |
206 | 613 | } |
207 | 6.52k | for (const auto &TT : Mod.getTagSection().getContent()) { |
208 | 1.71k | Tags.emplace_back(ExternalType::Tag, GetSubType(TT.getTypeIdx())); |
209 | 1.71k | } |
210 | | |
211 | 6.52k | for (const auto &Exp : Mod.getExportSection().getContent()) { |
212 | 73 | const uint32_t Idx = Exp.getExternalIndex(); |
213 | 73 | Component::CoreExternInfo Ext; |
214 | 73 | switch (Exp.getExternalType()) { |
215 | 0 | case ExternalType::Function: |
216 | 0 | if (Idx >= Funcs.size()) { |
217 | 0 | continue; |
218 | 0 | } |
219 | 0 | Ext = Funcs[Idx]; |
220 | 0 | break; |
221 | 0 | case ExternalType::Table: |
222 | 0 | if (Idx >= Tables.size()) { |
223 | 0 | continue; |
224 | 0 | } |
225 | 0 | Ext = Tables[Idx]; |
226 | 0 | break; |
227 | 0 | case ExternalType::Memory: |
228 | 0 | if (Idx >= Memories.size()) { |
229 | 0 | continue; |
230 | 0 | } |
231 | 0 | Ext = Memories[Idx]; |
232 | 0 | break; |
233 | 73 | case ExternalType::Global: |
234 | 73 | if (Idx >= Globals.size()) { |
235 | 0 | continue; |
236 | 0 | } |
237 | 73 | Ext = Globals[Idx]; |
238 | 73 | break; |
239 | 0 | case ExternalType::Tag: |
240 | 0 | if (Idx >= Tags.size()) { |
241 | 0 | continue; |
242 | 0 | } |
243 | 0 | Ext = Tags[Idx]; |
244 | 0 | break; |
245 | 0 | default: |
246 | 0 | continue; |
247 | 73 | } |
248 | 73 | Out.Exports.emplace(std::string(Exp.getExternalName()), Ext); |
249 | 73 | } |
250 | 6.52k | return {}; |
251 | 6.52k | } |
252 | | |
253 | | Expect<void> Validator::validate( |
254 | 84.4k | const AST::Component::CoreInstanceSection &InstSec) noexcept { |
255 | 84.4k | for (const auto &Inst : InstSec.getContent()) { |
256 | 82.3k | EXPECTED_TRY(validate(Inst).map_error([](auto E) { |
257 | 82.3k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreInstance)); |
258 | 82.3k | return E; |
259 | 82.3k | })); |
260 | 82.3k | } |
261 | 84.3k | return {}; |
262 | 84.4k | } |
263 | | |
264 | | Expect<void> |
265 | 82.3k | Validator::validate(const AST::Component::CoreInstance &Inst) noexcept { |
266 | 82.3k | auto &S = CompCtx.getTop(); |
267 | 82.3k | if (Inst.isInstantiateModule()) { |
268 | 688 | const auto *Mod = S.getCoreModule(Inst.getModuleIndex()); |
269 | 688 | if (Mod == nullptr) { |
270 | 22 | spdlog::error(ErrCode::Value::ComponentUnknownModule); |
271 | 22 | spdlog::error(" Core module index {} out of bounds (size {})."sv, |
272 | 22 | Inst.getModuleIndex(), S.CoreModules.size()); |
273 | 22 | return Unexpect(ErrCode::Value::ComponentUnknownModule); |
274 | 22 | } |
275 | | // Collect the named argument instances. |
276 | 666 | std::unordered_map<std::string_view, const Component::CoreShape *> Args; |
277 | 666 | for (const auto &Arg : Inst.getInstantiateArgs()) { |
278 | 0 | const auto *AI = S.getCoreInstance(Arg.getIndex()); |
279 | 0 | if (AI == nullptr) { |
280 | 0 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
281 | 0 | spdlog::error(" Core instance index {} out of bounds (size {})."sv, |
282 | 0 | Arg.getIndex(), S.CoreInstances.size()); |
283 | 0 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
284 | 0 | } |
285 | 0 | if (!Args.emplace(Arg.getName(), AI).second) { |
286 | 0 | spdlog::error(ErrCode::Value::ComponentDuplicateModuleArg); |
287 | 0 | spdlog::error(" Duplicate instantiation argument '{}'."sv, |
288 | 0 | Arg.getName()); |
289 | 0 | return Unexpect(ErrCode::Value::ComponentDuplicateModuleArg); |
290 | 0 | } |
291 | 0 | } |
292 | | // Every module import must be satisfied by the matching argument. |
293 | 666 | for (const auto &[ModName, Name, Required] : Mod->Imports) { |
294 | 0 | auto It = Args.find(ModName); |
295 | 0 | if (It == Args.end()) { |
296 | 0 | spdlog::error(ErrCode::Value::ComponentMissingModuleArg); |
297 | 0 | spdlog::error(" Missing instantiation argument '{}'."sv, ModName); |
298 | 0 | return Unexpect(ErrCode::Value::ComponentMissingModuleArg); |
299 | 0 | } |
300 | 0 | auto ExpIt = It->second->Exports.find(Name); |
301 | 0 | if (ExpIt == It->second->Exports.end()) { |
302 | 0 | spdlog::error(ErrCode::Value::ComponentUnknownExport); |
303 | 0 | spdlog::error( |
304 | 0 | " Instance argument '{}' does not export '{}' required by " |
305 | 0 | "the module."sv, |
306 | 0 | ModName, Name); |
307 | 0 | return Unexpect(ErrCode::Value::ComponentUnknownExport); |
308 | 0 | } |
309 | 0 | const auto &Provided = ExpIt->second; |
310 | 0 | if (Provided.Kind != Required.Kind) { |
311 | 0 | ErrCode::Value Code = ErrCode::Value::ArgTypeMismatch; |
312 | 0 | if (Required.Kind == ExternalType::Global) { |
313 | 0 | Code = ErrCode::Value::ComponentExpectedGlobal; |
314 | 0 | } else if (Required.Kind == ExternalType::Function) { |
315 | 0 | Code = ErrCode::Value::ComponentExpectedFunc; |
316 | 0 | } |
317 | 0 | spdlog::error(Code); |
318 | 0 | spdlog::error(" Import '{}'.'{}' kind mismatch."sv, ModName, Name); |
319 | 0 | return Unexpect(Code); |
320 | 0 | } |
321 | 0 | if (!Component::Matcher::matchCoreExtern(Provided, Required)) { |
322 | | // Distinguish the mismatch class for diagnostics. |
323 | 0 | ErrCode::Value Code = ErrCode::Value::ArgTypeMismatch; |
324 | 0 | switch (Required.Kind) { |
325 | 0 | case ExternalType::Function: |
326 | | // A trivial expected signature is reported as `expected: (func)`. |
327 | 0 | if (Required.Func != nullptr && |
328 | 0 | Required.Func->getCompositeType().isFunc() && |
329 | 0 | Required.Func->getCompositeType() |
330 | 0 | .getFuncType() |
331 | 0 | .getParamTypes() |
332 | 0 | .empty() && |
333 | 0 | Required.Func->getCompositeType() |
334 | 0 | .getFuncType() |
335 | 0 | .getReturnTypes() |
336 | 0 | .empty()) { |
337 | 0 | Code = ErrCode::Value::ComponentExpectedFuncParen; |
338 | 0 | } |
339 | 0 | break; |
340 | 0 | case ExternalType::Memory: |
341 | 0 | if (Provided.Memory != nullptr && Required.Memory != nullptr) { |
342 | 0 | const auto &LP = Provided.Memory->getLimit(); |
343 | 0 | const auto &LR = Required.Memory->getLimit(); |
344 | 0 | if (LP.isShared() != LR.isShared()) { |
345 | 0 | Code = ErrCode::Value::ComponentMemorySharedMismatch; |
346 | 0 | } else if (LP.is64() != LR.is64()) { |
347 | 0 | Code = ErrCode::Value::ComponentMemoryIndexTypeMismatch; |
348 | 0 | } else { |
349 | 0 | Code = ErrCode::Value::ComponentMemoryLimitsMismatch; |
350 | 0 | } |
351 | 0 | } |
352 | 0 | break; |
353 | 0 | case ExternalType::Global: |
354 | 0 | Code = ErrCode::Value::ArgTypeMismatch; |
355 | 0 | break; |
356 | 0 | case ExternalType::Table: |
357 | 0 | if (Provided.Table != nullptr && Required.Table != nullptr && |
358 | 0 | !(Provided.Table->getRefType() == Required.Table->getRefType())) { |
359 | 0 | Code = ErrCode::Value::ArgTypeMismatch; |
360 | 0 | } else { |
361 | 0 | Code = ErrCode::Value::ComponentTableLimitsMismatch; |
362 | 0 | } |
363 | 0 | break; |
364 | 0 | default: |
365 | 0 | break; |
366 | 0 | } |
367 | 0 | spdlog::error(Code); |
368 | 0 | spdlog::error(" Import '{}'.'{}' type mismatch."sv, ModName, Name); |
369 | 0 | return Unexpect(Code); |
370 | 0 | } |
371 | 0 | } |
372 | | // The new core instance exposes the module's exports. |
373 | 666 | auto *Result = CompCtx.addCoreShape(); |
374 | 666 | Result->Exports = Mod->Exports; |
375 | 666 | S.addCoreInstance(Result); |
376 | 666 | return {}; |
377 | 666 | } |
378 | | |
379 | | // Inline exports project index-space entries into a fresh core instance. |
380 | 81.6k | auto *Result = CompCtx.addCoreShape(); |
381 | 81.6k | for (const auto &Exp : Inst.getInlineExports()) { |
382 | 3.46k | const auto &SI = Exp.getSortIdx(); |
383 | 3.46k | const uint32_t Idx = SI.getIdx(); |
384 | 3.46k | if (!SI.getSort().isCore()) { |
385 | 0 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
386 | 0 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
387 | 0 | } |
388 | 3.46k | Component::CoreExternInfo Ext; |
389 | 3.46k | switch (SI.getSort().getCoreSortType()) { |
390 | 3.40k | case AST::Component::Sort::CoreSortType::Func: { |
391 | 3.40k | const auto *F = S.getCoreFunc(Idx); |
392 | 3.40k | if (F == nullptr) { |
393 | 33 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
394 | 33 | spdlog::error(" Core function index {} out of bounds."sv, Idx); |
395 | 33 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
396 | 33 | } |
397 | 3.37k | Ext = Component::CoreExternInfo(ExternalType::Function, F); |
398 | 3.37k | break; |
399 | 3.40k | } |
400 | 4 | case AST::Component::Sort::CoreSortType::Table: { |
401 | 4 | if (Idx >= S.CoreTables.size()) { |
402 | 4 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
403 | 4 | spdlog::error(" Core table index {} out of bounds."sv, Idx); |
404 | 4 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
405 | 4 | } |
406 | 0 | Ext = Component::CoreExternInfo(S.CoreTables[Idx]); |
407 | 0 | break; |
408 | 4 | } |
409 | 13 | case AST::Component::Sort::CoreSortType::Memory: { |
410 | 13 | if (Idx >= S.CoreMemories.size()) { |
411 | 13 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
412 | 13 | spdlog::error(" Core memory index {} out of bounds."sv, Idx); |
413 | 13 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
414 | 13 | } |
415 | 0 | Ext = Component::CoreExternInfo(S.CoreMemories[Idx]); |
416 | 0 | break; |
417 | 13 | } |
418 | 20 | case AST::Component::Sort::CoreSortType::Global: { |
419 | 20 | if (Idx >= S.CoreGlobals.size()) { |
420 | 20 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
421 | 20 | spdlog::error(" Core global index {} out of bounds."sv, Idx); |
422 | 20 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
423 | 20 | } |
424 | 0 | Ext = Component::CoreExternInfo(S.CoreGlobals[Idx]); |
425 | 0 | break; |
426 | 20 | } |
427 | 21 | case AST::Component::Sort::CoreSortType::Tag: { |
428 | 21 | if (Idx >= S.CoreTags.size()) { |
429 | 21 | spdlog::error(ErrCode::Value::UnknownCoreTag); |
430 | 21 | spdlog::error(" Core tag index {} out of bounds."sv, Idx); |
431 | 21 | return Unexpect(ErrCode::Value::UnknownCoreTag); |
432 | 21 | } |
433 | 0 | Ext = Component::CoreExternInfo(ExternalType::Tag, S.CoreTags[Idx]); |
434 | 0 | break; |
435 | 21 | } |
436 | 2 | default: |
437 | 2 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
438 | 2 | spdlog::error( |
439 | 2 | " Core instances can only export functions, tables, memories, " |
440 | 2 | "globals, and tags."sv); |
441 | 2 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
442 | 3.46k | } |
443 | 3.37k | if (!Result->Exports.emplace(std::string(Exp.getName()), Ext).second) { |
444 | 13 | spdlog::error(ErrCode::Value::DupExportName); |
445 | 13 | spdlog::error(" Duplicate inline export name '{}'."sv, Exp.getName()); |
446 | 13 | return Unexpect(ErrCode::Value::DupExportName); |
447 | 13 | } |
448 | 3.37k | } |
449 | 81.5k | S.addCoreInstance(Result); |
450 | 81.5k | return {}; |
451 | 81.6k | } |
452 | | |
453 | | Expect<void> |
454 | 188k | Validator::validate(const AST::Component::CoreTypeSection &TypeSec) noexcept { |
455 | 188k | for (const auto &Type : TypeSec.getContent()) { |
456 | 142k | EXPECTED_TRY(validate(Type).map_error([](auto E) { |
457 | 142k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreType)); |
458 | 142k | return E; |
459 | 142k | })); |
460 | 142k | } |
461 | 188k | return {}; |
462 | 188k | } |
463 | | |
464 | | Expect<void> |
465 | 64.1k | Validator::validate(const AST::Component::ComponentSection &CompSec) noexcept { |
466 | 64.1k | auto *Shape = CompCtx.addShape(); |
467 | 64.1k | EXPECTED_TRY(validate(CompSec.getContent(), *Shape).map_error([](auto E) { |
468 | 64.1k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Component)); |
469 | 64.1k | return E; |
470 | 64.1k | })); |
471 | 64.1k | CompCtx.getTop().addComponent(Shape); |
472 | 64.1k | return {}; |
473 | 64.1k | } |
474 | | |
475 | | Expect<void> |
476 | 2.12M | Validator::validate(const AST::Component::InstanceSection &InstSec) noexcept { |
477 | 2.12M | for (const auto &Inst : InstSec.getContent()) { |
478 | 2.12M | EXPECTED_TRY(validate(Inst).map_error([](auto E) { |
479 | 2.12M | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Instance)); |
480 | 2.12M | return E; |
481 | 2.12M | })); |
482 | 2.12M | } |
483 | 2.12M | return {}; |
484 | 2.12M | } |
485 | | |
486 | | Expect<void> |
487 | 2.12M | Validator::validate(const AST::Component::Instance &Inst) noexcept { |
488 | 2.12M | auto &S = CompCtx.getTop(); |
489 | 2.12M | if (Inst.isInstantiateModule()) { |
490 | 1.16M | const auto *CI = S.getComponent(Inst.getComponentIndex()); |
491 | 1.16M | if (CI == nullptr) { |
492 | 45 | spdlog::error(ErrCode::Value::ComponentUnknownComponent); |
493 | 45 | spdlog::error(" Component index {} out of bounds (size {})."sv, |
494 | 45 | Inst.getComponentIndex(), S.Components.size()); |
495 | 45 | return Unexpect(ErrCode::Value::ComponentUnknownComponent); |
496 | 45 | } |
497 | 1.16M | EXPECTED_TRY(const auto *Result, CompCtx.instantiateComponentShape( |
498 | 1.16M | *CI, Inst.getInstantiateArgs())); |
499 | 1.16M | CompCtx.getTop().addInstance(Result); |
500 | 1.16M | return {}; |
501 | 1.16M | } |
502 | | |
503 | | // Inline exports. Index validity is checked before the export name. |
504 | 960k | auto *Result = CompCtx.addShape(); |
505 | 960k | Result->DeclScope = &S; |
506 | 960k | std::vector<Component::NameRecord> Names; |
507 | 960k | for (const auto &Exp : Inst.getInlineExports()) { |
508 | | // Function indices get their own diagnostic here. |
509 | 567 | if (!Exp.getSortIdx().getSort().isCore() && |
510 | 562 | Exp.getSortIdx().getSort().getSortType() == |
511 | 562 | AST::Component::Sort::SortType::Func && |
512 | 93 | S.getFunc(Exp.getSortIdx().getIdx()) == nullptr) { |
513 | 12 | spdlog::error(ErrCode::Value::ComponentFunctionIndexOutOfBounds); |
514 | 12 | spdlog::error(" Function index {} out of bounds (size {})."sv, |
515 | 12 | Exp.getSortIdx().getIdx(), S.Funcs.size()); |
516 | 12 | return Unexpect(ErrCode::Value::ComponentFunctionIndexOutOfBounds); |
517 | 12 | } |
518 | 1.09k | EXPECTED_TRY(auto Info, CompCtx.getExtern(Exp.getSortIdx())); |
519 | 1.09k | EXPECTED_TRY(Component::ExternName CN, |
520 | 516 | CompCtx.parseExternName(Exp.getName(), false)); |
521 | 516 | EXPECTED_TRY( |
522 | 516 | CompCtx.addUniqueName(Names, Component::NameRecord(CN), false)); |
523 | 516 | EXPECTED_TRY(CompCtx.checkAnnotatedName(CN, Info, false)); |
524 | 511 | EXPECTED_TRY(CompCtx.checkNameAttributes( |
525 | 510 | CN, Exp.getImplements(), Exp.getVersionSuffixes(), |
526 | 510 | Info.Kind == Component::ExternKind::InstanceType)); |
527 | 510 | if (!Exp.getSortIdx().getSort().isCore() && |
528 | 510 | Exp.getSortIdx().getSort().getSortType() == |
529 | 510 | AST::Component::Sort::SortType::Value) { |
530 | 28 | EXPECTED_TRY(CompCtx.getTop().consumeValue(Exp.getSortIdx().getIdx())); |
531 | 28 | } |
532 | 507 | Result->Exports.emplace(std::string(Exp.getName()), Info); |
533 | 507 | Result->ExportOrder.emplace_back(Exp.getName()); |
534 | 507 | } |
535 | | // An inline instance nests re-exported shapes, so it is bounded like a type. |
536 | 960k | Component::ExternInfo Probe; |
537 | 960k | Probe.Kind = Component::ExternKind::InstanceType; |
538 | 960k | Probe.Shape = Result; |
539 | 960k | EXPECTED_TRY(CompCtx.checkTypeLimits(Probe)); |
540 | 960k | CompCtx.getTop().addInstance(Result); |
541 | 960k | return {}; |
542 | 960k | } |
543 | | |
544 | | Expect<void> |
545 | 69.4k | Validator::validate(const AST::Component::AliasSection &AliasSec) noexcept { |
546 | 69.4k | for (const auto &Alias : AliasSec.getContent()) { |
547 | 64.9k | EXPECTED_TRY(validate(Alias).map_error([](auto E) { |
548 | 64.9k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Alias)); |
549 | 64.9k | return E; |
550 | 64.9k | })); |
551 | 64.9k | } |
552 | 69.3k | return {}; |
553 | 69.4k | } |
554 | | |
555 | 66.0k | Expect<void> Validator::validate(const AST::Component::Alias &Alias) noexcept { |
556 | 66.0k | auto &S = CompCtx.getTop(); |
557 | 66.0k | const auto &Sort = Alias.getSort(); |
558 | 66.0k | const bool InTypeDecl = S.Kind == Component::ScopeKind::ComponentType || |
559 | 65.5k | S.Kind == Component::ScopeKind::InstanceType; |
560 | | |
561 | 66.0k | switch (Alias.getTargetType()) { |
562 | 36 | case AST::Component::Alias::TargetType::Export: { |
563 | 36 | if (Sort.isCore() && |
564 | 11 | Sort.getCoreSortType() != AST::Component::Sort::CoreSortType::Module) { |
565 | 6 | spdlog::error(ErrCode::Value::MalformedAliasTarget); |
566 | 6 | return Unexpect(ErrCode::Value::MalformedAliasTarget); |
567 | 6 | } |
568 | 30 | const bool WantCoreModule = Sort.isCore(); |
569 | 30 | if (InTypeDecl && |
570 | 7 | (WantCoreModule || |
571 | 6 | (Sort.getSortType() != AST::Component::Sort::SortType::Type && |
572 | 4 | Sort.getSortType() != AST::Component::Sort::SortType::Instance))) { |
573 | 4 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
574 | 4 | spdlog::error(" Aliases in a component or instance type may only " |
575 | 4 | "refer to types or instances."sv); |
576 | 4 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
577 | 4 | } |
578 | 26 | const auto &[InstIdx, Name] = Alias.getExport(); |
579 | 26 | const auto *Inst = S.getInstance(InstIdx); |
580 | 26 | if (Inst == nullptr) { |
581 | 8 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
582 | 8 | spdlog::error(" Instance index {} out of bounds (size {})."sv, InstIdx, |
583 | 8 | S.Instances.size()); |
584 | 8 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
585 | 8 | } |
586 | 18 | auto It = Inst->Exports.find(Name); |
587 | 18 | if (WantCoreModule) { |
588 | | // Core-module exports of component instances. |
589 | 3 | if (It == Inst->Exports.end() || |
590 | 3 | It->second.Kind != Component::ExternKind::CoreType) { |
591 | 3 | spdlog::error(ErrCode::Value::ComponentExportNotAModule); |
592 | 3 | spdlog::error(" Export '{}' of instance {} is not a core module."sv, |
593 | 3 | Name, InstIdx); |
594 | 3 | return Unexpect(ErrCode::Value::ComponentExportNotAModule); |
595 | 3 | } |
596 | 0 | CompCtx.addExtern(It->second); |
597 | 0 | return {}; |
598 | 3 | } |
599 | 15 | if (It == Inst->Exports.end()) { |
600 | 15 | spdlog::error(ErrCode::Value::ComponentUnknownExport); |
601 | 15 | spdlog::error(" Instance {} has no export named '{}'."sv, InstIdx, |
602 | 15 | Name); |
603 | 15 | return Unexpect(ErrCode::Value::ComponentUnknownExport); |
604 | 15 | } |
605 | 0 | const auto ST = Sort.getSortType(); |
606 | 0 | const auto &Info = It->second; |
607 | 0 | const bool KindOk = (ST == AST::Component::Sort::SortType::Func && |
608 | 0 | Info.Kind == Component::ExternKind::FuncType) || |
609 | 0 | (ST == AST::Component::Sort::SortType::Value && |
610 | 0 | Info.Kind == Component::ExternKind::ValueBound) || |
611 | 0 | (ST == AST::Component::Sort::SortType::Type && |
612 | 0 | Info.Kind == Component::ExternKind::TypeBound) || |
613 | 0 | (ST == AST::Component::Sort::SortType::Component && |
614 | 0 | Info.Kind == Component::ExternKind::ComponentType) || |
615 | 0 | (ST == AST::Component::Sort::SortType::Instance && |
616 | 0 | Info.Kind == Component::ExternKind::InstanceType); |
617 | 0 | if (!KindOk) { |
618 | 0 | spdlog::error(ErrCode::Value::ComponentUnknownExport); |
619 | 0 | spdlog::error(" Export '{}' of instance {} does not match the " |
620 | 0 | "alias sort."sv, |
621 | 0 | Name, InstIdx); |
622 | 0 | return Unexpect(ErrCode::Value::ComponentUnknownExport); |
623 | 0 | } |
624 | 0 | CompCtx.addExtern(Info); |
625 | 0 | return {}; |
626 | 0 | } |
627 | 330 | case AST::Component::Alias::TargetType::CoreExport: { |
628 | 330 | if (!Sort.isCore()) { |
629 | 2 | spdlog::error(ErrCode::Value::MalformedAliasTarget); |
630 | 2 | return Unexpect(ErrCode::Value::MalformedAliasTarget); |
631 | 2 | } |
632 | 328 | if (InTypeDecl) { |
633 | 1 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
634 | 1 | spdlog::error(" Aliases in a component or instance type may only " |
635 | 1 | "refer to types or instances."sv); |
636 | 1 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
637 | 1 | } |
638 | 327 | const auto &[InstIdx, Name] = Alias.getExport(); |
639 | 327 | const auto *Inst = S.getCoreInstance(InstIdx); |
640 | 327 | if (Inst == nullptr) { |
641 | 1 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
642 | 1 | spdlog::error(" Core instance index {} out of bounds (size {})."sv, |
643 | 1 | InstIdx, S.CoreInstances.size()); |
644 | 1 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
645 | 1 | } |
646 | 326 | auto It = Inst->Exports.find(Name); |
647 | 326 | const auto CS = Sort.getCoreSortType(); |
648 | 326 | if (It == Inst->Exports.end()) { |
649 | 10 | const auto Code = CS == AST::Component::Sort::CoreSortType::Tag |
650 | 10 | ? ErrCode::Value::UnknownCoreTag |
651 | 10 | : ErrCode::Value::ComponentUnknownExport; |
652 | 10 | spdlog::error(Code); |
653 | 10 | spdlog::error(" Core instance {} has no export named '{}'."sv, InstIdx, |
654 | 10 | Name); |
655 | 10 | return Unexpect(Code); |
656 | 10 | } |
657 | 316 | const auto &Ext = It->second; |
658 | 316 | const bool KindOk = (CS == AST::Component::Sort::CoreSortType::Func && |
659 | 308 | Ext.Kind == ExternalType::Function) || |
660 | 8 | (CS == AST::Component::Sort::CoreSortType::Table && |
661 | 1 | Ext.Kind == ExternalType::Table) || |
662 | 8 | (CS == AST::Component::Sort::CoreSortType::Memory && |
663 | 1 | Ext.Kind == ExternalType::Memory) || |
664 | 8 | (CS == AST::Component::Sort::CoreSortType::Global && |
665 | 1 | Ext.Kind == ExternalType::Global) || |
666 | 8 | (CS == AST::Component::Sort::CoreSortType::Tag && |
667 | 1 | Ext.Kind == ExternalType::Tag); |
668 | 316 | if (!KindOk) { |
669 | 8 | const auto Code = CS == AST::Component::Sort::CoreSortType::Tag |
670 | 8 | ? ErrCode::Value::UnknownCoreTag |
671 | 8 | : ErrCode::Value::InvalidTypeReference; |
672 | 8 | spdlog::error(Code); |
673 | 8 | spdlog::error(" Core export '{}' does not match the alias sort."sv, |
674 | 8 | Name); |
675 | 8 | return Unexpect(Code); |
676 | 8 | } |
677 | 308 | S.addCoreExtern(Ext); |
678 | 308 | return {}; |
679 | 316 | } |
680 | 65.7k | case AST::Component::Alias::TargetType::Outer: { |
681 | 65.7k | const auto &[Ct, Idx] = Alias.getOuter(); |
682 | 65.7k | auto *Target = CompCtx.getScope(Ct); |
683 | 65.7k | if (Target == nullptr) { |
684 | 31 | spdlog::error(ErrCode::Value::ComponentInvalidOuterAliasCount); |
685 | 31 | spdlog::error(" Outer alias count {} exceeds enclosing scopes."sv, Ct); |
686 | 31 | return Unexpect(ErrCode::Value::ComponentInvalidOuterAliasCount); |
687 | 31 | } |
688 | 65.6k | if (Sort.isCore()) { |
689 | 61.7k | switch (Sort.getCoreSortType()) { |
690 | 60.5k | case AST::Component::Sort::CoreSortType::Module: { |
691 | 60.5k | if (InTypeDecl) { |
692 | 1 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
693 | 1 | spdlog::error(" Aliases in a component or instance type may " |
694 | 1 | "only refer to types or instances."sv); |
695 | 1 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
696 | 1 | } |
697 | 60.5k | const auto *Mod = Target->getCoreModule(Idx); |
698 | 60.5k | if (Mod == nullptr) { |
699 | 21 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
700 | 21 | spdlog::error(" Aliased core module index {} out of bounds."sv, |
701 | 21 | Idx); |
702 | 21 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
703 | 21 | } |
704 | 60.5k | S.addCoreModule(Mod); |
705 | 60.5k | return {}; |
706 | 60.5k | } |
707 | 1.19k | case AST::Component::Sort::CoreSortType::Type: { |
708 | 1.19k | const auto *Entry = Target->getCoreType(Idx); |
709 | 1.19k | if (Entry == nullptr) { |
710 | 21 | spdlog::error(ErrCode::Value::ComponentTypeIndexOutOfBounds); |
711 | 21 | spdlog::error(" Aliased core type index {} out of bounds."sv, Idx); |
712 | 21 | return Unexpect(ErrCode::Value::ComponentTypeIndexOutOfBounds); |
713 | 21 | } |
714 | 1.17k | S.addCoreType(*Entry); |
715 | 1.17k | return {}; |
716 | 1.19k | } |
717 | 0 | default: |
718 | 0 | spdlog::error(ErrCode::Value::MalformedAliasTarget); |
719 | 0 | spdlog::error( |
720 | 0 | " Outer aliases may only target module, type, component."sv); |
721 | 0 | return Unexpect(ErrCode::Value::MalformedAliasTarget); |
722 | 61.7k | } |
723 | 61.7k | } |
724 | 3.90k | switch (Sort.getSortType()) { |
725 | 3.28k | case AST::Component::Sort::SortType::Type: { |
726 | 3.28k | const auto *Entry = Target->getType(Idx); |
727 | 3.28k | if (Entry == nullptr) { |
728 | 5 | spdlog::error(ErrCode::Value::ComponentTypeIndexOutOfBounds); |
729 | 5 | spdlog::error(" Aliased type index {} out of bounds."sv, Idx); |
730 | 5 | return Unexpect(ErrCode::Value::ComponentTypeIndexOutOfBounds); |
731 | 5 | } |
732 | | // A type crossing a component boundary must carry no free resource id. |
733 | 3.28k | const auto *Inside = Ct == 0 ? nullptr : CompCtx.getScope(Ct - 1); |
734 | 3.28k | if (Inside != nullptr && |
735 | 955 | Inside->Kind == Component::ScopeKind::Component) { |
736 | 0 | std::unordered_set<uint32_t> Ids; |
737 | 0 | Component::ExternInfo Probe; |
738 | 0 | Probe.Kind = Component::ExternKind::TypeBound; |
739 | 0 | Probe.Type = *Entry; |
740 | 0 | CompCtx.collectResources(Probe, Ids); |
741 | | // Ids bound by the aliased type itself are not free. |
742 | 0 | const Component::Scope *Binder = nullptr; |
743 | 0 | if (Entry->Inst != nullptr) { |
744 | 0 | Binder = Entry->Inst->DeclScope; |
745 | 0 | } else if (Entry->Comp != nullptr) { |
746 | 0 | Binder = Entry->Comp->DeclScope; |
747 | 0 | } |
748 | 0 | bool HasFree = false; |
749 | 0 | for (const uint32_t Id : Ids) { |
750 | 0 | if (Binder == nullptr || !CompCtx.isDeclaredIn(Id, *Binder)) { |
751 | 0 | HasFree = true; |
752 | 0 | break; |
753 | 0 | } |
754 | 0 | } |
755 | 0 | if (HasFree) { |
756 | 0 | spdlog::error(ErrCode::Value::ComponentAliasResourceLeak); |
757 | 0 | spdlog::error( |
758 | 0 | " Cannot alias an outer type which transitively refers to " |
759 | 0 | "resources not defined in the current component."sv); |
760 | 0 | return Unexpect(ErrCode::Value::ComponentAliasResourceLeak); |
761 | 0 | } |
762 | 0 | } |
763 | 3.28k | S.addType(*Entry); |
764 | 3.28k | return {}; |
765 | 3.28k | } |
766 | 613 | case AST::Component::Sort::SortType::Component: { |
767 | 613 | if (InTypeDecl) { |
768 | 1 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
769 | 1 | spdlog::error(" Aliases in a component or instance type may only " |
770 | 1 | "refer to types or instances."sv); |
771 | 1 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
772 | 1 | } |
773 | 612 | const auto *Comp = Target->getComponent(Idx); |
774 | 612 | if (Comp == nullptr) { |
775 | 26 | spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds); |
776 | 26 | spdlog::error(" Aliased component index {} out of bounds."sv, Idx); |
777 | 26 | return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds); |
778 | 26 | } |
779 | 586 | S.addComponent(Comp); |
780 | 586 | return {}; |
781 | 612 | } |
782 | 0 | default: |
783 | 0 | spdlog::error(ErrCode::Value::MalformedAliasTarget); |
784 | 0 | spdlog::error( |
785 | 0 | " Outer aliases may only target module, type, component."sv); |
786 | 0 | return Unexpect(ErrCode::Value::MalformedAliasTarget); |
787 | 3.90k | } |
788 | 3.90k | } |
789 | 0 | default: |
790 | 0 | spdlog::error(ErrCode::Value::MalformedAliasTarget); |
791 | 0 | return Unexpect(ErrCode::Value::MalformedAliasTarget); |
792 | 66.0k | } |
793 | 66.0k | } |
794 | | |
795 | | Expect<void> |
796 | 6.07M | Validator::validate(const AST::Component::TypeSection &TypeSec) noexcept { |
797 | 6.07M | for (const auto &Type : TypeSec.getContent()) { |
798 | 5.80M | EXPECTED_TRY(validate(Type).map_error([](auto E) { |
799 | 5.80M | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Type)); |
800 | 5.80M | return E; |
801 | 5.80M | })); |
802 | 5.80M | } |
803 | 6.07M | return {}; |
804 | 6.07M | } |
805 | | |
806 | | Expect<void> |
807 | 272k | Validator::validate(const AST::Component::CanonSection &CanonSec) noexcept { |
808 | 275k | for (const auto &Canon : CanonSec.getContent()) { |
809 | 275k | EXPECTED_TRY(validate(Canon).map_error([](auto E) { |
810 | 275k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Canon)); |
811 | 275k | return E; |
812 | 275k | })); |
813 | 275k | } |
814 | 271k | return {}; |
815 | 272k | } |
816 | | |
817 | | Expect<void> |
818 | 674 | Validator::validate(const AST::Component::StartSection &StartSec) noexcept { |
819 | 674 | const auto &Start = StartSec.getContent(); |
820 | 674 | auto &S = CompCtx.getTop(); |
821 | 674 | const auto *FI = S.getFunc(Start.getFunctionIndex()); |
822 | 674 | if (FI == nullptr || FI->FT == nullptr) { |
823 | 20 | spdlog::error(ErrCode::Value::ComponentFunctionIndexOutOfBounds); |
824 | 20 | spdlog::error(" Start function index {} out of bounds (size {})."sv, |
825 | 20 | Start.getFunctionIndex(), S.Funcs.size()); |
826 | 20 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start)); |
827 | 20 | return Unexpect(ErrCode::Value::ComponentFunctionIndexOutOfBounds); |
828 | 20 | } |
829 | 654 | const auto Params = FI->FT->getParamList(); |
830 | 654 | const auto Args = Start.getArguments(); |
831 | 654 | if (Params.size() != Args.size()) { |
832 | 1 | spdlog::error(ErrCode::Value::ArgTypeMismatch); |
833 | 1 | spdlog::error(" Start takes {} arguments but the function has {} " |
834 | 1 | "parameters."sv, |
835 | 1 | Args.size(), Params.size()); |
836 | 1 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start)); |
837 | 1 | return Unexpect(ErrCode::Value::ArgTypeMismatch); |
838 | 1 | } |
839 | 653 | for (size_t I = 0; I < Args.size(); ++I) { |
840 | 0 | const uint32_t ValIdx = Args[I]; |
841 | 0 | if (ValIdx >= S.Values.size()) { |
842 | 0 | spdlog::error(ErrCode::Value::InvalidIndex); |
843 | 0 | spdlog::error(" Start argument value index {} out of bounds."sv, |
844 | 0 | ValIdx); |
845 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start)); |
846 | 0 | return Unexpect(ErrCode::Value::InvalidIndex); |
847 | 0 | } |
848 | 0 | EXPECTED_TRY(S.consumeValue(ValIdx).map_error([ValIdx](auto E) { |
849 | 0 | spdlog::error(" Start argument value {} was already consumed."sv, |
850 | 0 | ValIdx); |
851 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start)); |
852 | 0 | return E; |
853 | 0 | })); |
854 | 0 | Component::ResourceMap Subst; |
855 | 0 | if (!Component::Matcher::matchValType( |
856 | 0 | CompCtx, S.Values[ValIdx].Type, |
857 | 0 | {Params[I].getValType(), FI->Home, FI->Remap}, Subst)) { |
858 | 0 | spdlog::error(ErrCode::Value::ArgTypeMismatch); |
859 | 0 | spdlog::error(" Start argument {} type mismatch."sv, I); |
860 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start)); |
861 | 0 | return Unexpect(ErrCode::Value::ArgTypeMismatch); |
862 | 0 | } |
863 | 0 | } |
864 | 653 | const auto &Result = FI->FT->getResult(); |
865 | 653 | if (Start.getResult() != FI->FT->getResultArity()) { |
866 | 4 | spdlog::error(ErrCode::Value::ArgTypeMismatch); |
867 | 4 | spdlog::error(" Start declares {} results but the function has {}."sv, |
868 | 4 | Start.getResult(), FI->FT->getResultArity()); |
869 | 4 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start)); |
870 | 4 | return Unexpect(ErrCode::Value::ArgTypeMismatch); |
871 | 4 | } |
872 | 649 | if (Result.has_value()) { |
873 | 330 | S.addValue({*Result, FI->Home, FI->Remap}); |
874 | 330 | } |
875 | 649 | return {}; |
876 | 653 | } |
877 | | |
878 | | Expect<void> Validator::validate(const AST::Component::ImportSection &ImpSec, |
879 | 97.8k | Component::Shape &Out) noexcept { |
880 | 97.8k | for (const auto &Import : ImpSec.getContent()) { |
881 | 8.27k | EXPECTED_TRY(validate(Import, Out).map_error([](auto E) { |
882 | 8.27k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Import)); |
883 | 8.27k | return E; |
884 | 8.27k | })); |
885 | 8.27k | } |
886 | 97.5k | return {}; |
887 | 97.8k | } |
888 | | |
889 | | Expect<void> Validator::validate(const AST::Component::Import &Im, |
890 | 8.27k | Component::Shape &Out) noexcept { |
891 | | // The descriptor is checked before the import name. |
892 | 8.27k | Component::ExternInfo Resolved; |
893 | 8.27k | EXPECTED_TRY(validate(Im.getDesc(), true, Resolved)); |
894 | 8.16k | EXPECTED_TRY(auto Info, |
895 | 7.92k | CompCtx.addImport(Im.getName(), Resolved, Im.getImplements(), |
896 | 7.92k | Im.getVersionSuffixes())); |
897 | 7.92k | Out.Imports.emplace_back(std::string(Im.getName()), Info); |
898 | 7.92k | return {}; |
899 | 8.16k | } |
900 | | |
901 | | Expect<void> Validator::validate(const AST::Component::ExportSection &ExpSec, |
902 | 13.0k | Component::Shape &Out) noexcept { |
903 | 13.0k | for (const auto &Export : ExpSec.getContent()) { |
904 | 3.01k | EXPECTED_TRY(validate(Export, Out).map_error([](auto E) { |
905 | 3.01k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Export)); |
906 | 3.01k | return E; |
907 | 3.01k | })); |
908 | 3.01k | } |
909 | 12.5k | return {}; |
910 | 13.0k | } |
911 | | |
912 | | Expect<void> Validator::validate(const AST::Component::Export &Ex, |
913 | 3.01k | Component::Shape &Out) noexcept { |
914 | 3.01k | auto &S = CompCtx.getTop(); |
915 | | // Index bounds are diagnosed before the name; a valid name refines the code. |
916 | 3.01k | { |
917 | 3.01k | const auto &SI = Ex.getSortIndex(); |
918 | 3.01k | Component::ExternName CN; |
919 | 3.01k | const bool NameOk = CN.parse(Ex.getName()).has_value(); |
920 | 3.01k | const uint32_t Idx = SI.getIdx(); |
921 | 3.01k | bool OOB = false; |
922 | 3.01k | ErrCode::Value Code = ErrCode::Value::DefTypeIndexOutOfBounds; |
923 | 3.01k | if (SI.getSort().isCore()) { |
924 | 25 | if (SI.getSort().getCoreSortType() == |
925 | 25 | AST::Component::Sort::CoreSortType::Module && |
926 | 22 | S.getCoreModule(Idx) == nullptr) { |
927 | 22 | OOB = true; |
928 | 22 | if (NameOk) { |
929 | 1 | Code = ErrCode::Value::ComponentModuleIndexOutOfBounds; |
930 | 1 | } |
931 | 22 | } |
932 | 2.99k | } else { |
933 | 2.99k | switch (SI.getSort().getSortType()) { |
934 | 117 | case AST::Component::Sort::SortType::Func: |
935 | 117 | if (S.getFunc(Idx) == nullptr) { |
936 | 40 | OOB = true; |
937 | 40 | if (NameOk) { |
938 | 7 | Code = ErrCode::Value::ComponentFunctionIndexOutOfBounds; |
939 | 7 | } |
940 | 40 | } |
941 | 117 | break; |
942 | 401 | case AST::Component::Sort::SortType::Instance: |
943 | 401 | if (S.getInstance(Idx) == nullptr) { |
944 | 110 | OOB = true; |
945 | 110 | if (NameOk) { |
946 | 8 | Code = ErrCode::Value::ComponentInstanceIndexOutOfBounds; |
947 | 8 | } |
948 | 110 | } |
949 | 401 | break; |
950 | 2.47k | default: |
951 | 2.47k | break; |
952 | 2.99k | } |
953 | 2.99k | } |
954 | 3.01k | if (OOB) { |
955 | 172 | spdlog::error(Code); |
956 | 172 | spdlog::error(" Export index {} out of bounds."sv, Idx); |
957 | 172 | return Unexpect(Code); |
958 | 172 | } |
959 | 3.01k | } |
960 | 5.55k | EXPECTED_TRY(auto Inferred, CompCtx.getExtern(Ex.getSortIndex())); |
961 | | // Exporting a value consumes it. |
962 | 5.55k | if (!Ex.getSortIndex().getSort().isCore() && |
963 | 2.71k | Ex.getSortIndex().getSort().getSortType() == |
964 | 2.71k | AST::Component::Sort::SortType::Value) { |
965 | 77 | const uint32_t ValIdx = Ex.getSortIndex().getIdx(); |
966 | 77 | EXPECTED_TRY(S.consumeValue(ValIdx).map_error([ValIdx](auto E) { |
967 | 76 | spdlog::error(" Exported value {} was already consumed."sv, ValIdx); |
968 | 76 | return E; |
969 | 76 | })); |
970 | | // Exported values must not transitively contain borrow handles. |
971 | 76 | if (CompCtx.hasBorrow(S.Values[ValIdx].Type)) { |
972 | 0 | spdlog::error(ErrCode::Value::InvalidTypeReference); |
973 | 0 | spdlog::error(" Exported value types cannot contain borrows."sv); |
974 | 0 | return Unexpect(ErrCode::Value::InvalidTypeReference); |
975 | 0 | } |
976 | 76 | } |
977 | 5.25k | EXPECTED_TRY(Component::ExternName CN, |
978 | 5.25k | CompCtx.registerExportName( |
979 | 5.25k | Ex.getName(), |
980 | 5.25k | Inferred.Kind == Component::ExternKind::InstanceType, |
981 | 5.25k | Ex.getImplements(), Ex.getVersionSuffixes())); |
982 | 5.25k | std::optional<Component::ExternInfo> Ascribed; |
983 | 5.25k | if (Ex.getDesc().has_value()) { |
984 | 82 | EXPECTED_TRY(validate(*Ex.getDesc(), false, Ascribed.emplace())); |
985 | 82 | } |
986 | 2.54k | EXPECTED_TRY(auto Result, CompCtx.addExport(CN, Inferred, Ascribed)); |
987 | | // The re-exported value index is born consumed. |
988 | 2.49k | if (Result.Kind == Component::ExternKind::ValueBound) { |
989 | 14 | CompCtx.getTop().Values.back().Consumed = true; |
990 | 14 | } |
991 | 2.49k | Out.Exports.emplace(std::string(Ex.getName()), Result); |
992 | 2.49k | return {}; |
993 | 2.54k | } |
994 | | |
995 | | Expect<void> |
996 | 13.9k | Validator::validate(const AST::Component::ValueSection &ValSec) noexcept { |
997 | 14.6k | for (const auto &Value : ValSec.getContent()) { |
998 | 14.6k | EXPECTED_TRY(CompCtx.validate(Value.getType()).map_error([](auto E) { |
999 | 14.6k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value)); |
1000 | 14.6k | return E; |
1001 | 14.6k | })); |
1002 | 14.6k | if (CompCtx.hasHandle({Value.getType(), &CompCtx.getTop(), nullptr})) { |
1003 | 8 | spdlog::error(ErrCode::Value::ComponentValueHandleType); |
1004 | 8 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value)); |
1005 | 8 | return Unexpect(ErrCode::Value::ComponentValueHandleType); |
1006 | 8 | } |
1007 | 14.6k | Component::ValueDecoder Decoder(Value.getData(), CompCtx.getTop()); |
1008 | 14.6k | auto Decoded = Decoder.decode(Value.getType()); |
1009 | 14.6k | if (!Decoded) { |
1010 | 956 | spdlog::error(ErrCode::Value::ComponentMalformedValue); |
1011 | 956 | spdlog::error(" Value definition payload does not match its type."sv); |
1012 | 956 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value)); |
1013 | 956 | return Unexpect(ErrCode::Value::ComponentMalformedValue); |
1014 | 956 | } |
1015 | 13.6k | Value.setDecoded(std::move(*Decoded)); |
1016 | 13.6k | CompCtx.getTop().addValue({Value.getType(), &CompCtx.getTop(), nullptr}); |
1017 | 13.6k | } |
1018 | 12.9k | return {}; |
1019 | 13.9k | } |
1020 | | |
1021 | | } // namespace Validator |
1022 | | } // namespace WasmEdge |