/src/WasmEdge/include/validator/component_context.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | //===-- wasmedge/validator/component_context.h - Component state ----------===// |
5 | | // |
6 | | // Part of the WasmEdge Project. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | /// |
10 | | /// \file |
11 | | /// This file contains the state of one component under validation: the scope |
12 | | /// stack, its index spaces, and everything that reads them. An operation that |
13 | | /// reads an index space lives here. Every other type operation lives in |
14 | | /// TypeSystem (component_types.h). |
15 | | /// |
16 | | //===----------------------------------------------------------------------===// |
17 | | #pragma once |
18 | | |
19 | | #include "ast/component/canonical.h" |
20 | | #include "ast/component/instance.h" |
21 | | #include "ast/component/sort.h" |
22 | | #include "ast/module.h" |
23 | | #include "common/errcode.h" |
24 | | #include "common/span.h" |
25 | | #include "validator/component_name.h" |
26 | | #include "validator/component_types.h" |
27 | | #include "validator/formchecker.h" |
28 | | |
29 | | #include <deque> |
30 | | #include <optional> |
31 | | #include <string> |
32 | | #include <string_view> |
33 | | #include <utility> |
34 | | #include <vector> |
35 | | |
36 | | namespace WasmEdge { |
37 | | namespace Validator { |
38 | | namespace Component { |
39 | | |
40 | | class Context { |
41 | | public: |
42 | 13.6k | explicit Context(TypeSystem &Types) noexcept : Types(Types) {} |
43 | | |
44 | | // ========================================================================== |
45 | | // The scope stack. Scopes stay owned after they pop; validate() resets it. |
46 | | // ========================================================================== |
47 | | |
48 | 1.24M | Scope &enterScope(ScopeKind K) noexcept { |
49 | 1.24M | const Scope *Parent = Stack.empty() ? nullptr : Stack.back(); |
50 | 1.24M | OwnedScopes.emplace_back(K, Parent); |
51 | 1.24M | Stack.push_back(&OwnedScopes.back()); |
52 | 1.24M | return OwnedScopes.back(); |
53 | 1.24M | } |
54 | | |
55 | 1.24M | void exitScope() noexcept { |
56 | 1.24M | assuming(!Stack.empty()); |
57 | 1.24M | Stack.pop_back(); |
58 | 1.24M | } |
59 | | |
60 | 9.74M | Scope &top() noexcept { |
61 | 9.74M | assuming(!Stack.empty()); |
62 | 9.74M | return *Stack.back(); |
63 | 9.74M | } |
64 | 16.9k | const Scope &top() const noexcept { |
65 | 16.9k | assuming(!Stack.empty()); |
66 | 16.9k | return *Stack.back(); |
67 | 16.9k | } |
68 | | |
69 | | /// The scope Levels hops up from the current one; nullptr if out of range. |
70 | 5.50k | Scope *scopeUp(uint32_t Levels) noexcept { |
71 | 5.50k | if (Levels >= Stack.size()) { |
72 | 33 | return nullptr; |
73 | 33 | } |
74 | 5.46k | return Stack[Stack.size() - 1 - Levels]; |
75 | 5.50k | } |
76 | | |
77 | | /// The scope inside the outer-alias target; a component there is a crossing. |
78 | 2.44k | const Scope *scopeInsideTarget(uint32_t Levels) const noexcept { |
79 | 2.44k | if (Levels == 0 || Levels > Stack.size()) { |
80 | 1.93k | return nullptr; |
81 | 1.93k | } |
82 | 508 | return Stack[Stack.size() - Levels]; |
83 | 2.44k | } |
84 | | |
85 | | // ========================================================================== |
86 | | // Index-space registration and resolution. |
87 | | // ========================================================================== |
88 | | |
89 | | /// Push the entity described by a resolved view into its index space. |
90 | | void defineExtern(const ExternInfo &Info) noexcept; |
91 | | /// Resolve a sortidx to its typed view in the current scope. |
92 | | Expect<ExternInfo> |
93 | | resolveSortIndex(const AST::Component::SortIndex &SI) noexcept; |
94 | | /// Build the external view of an inline core module. |
95 | | Expect<const CoreShape *> buildCoreShape(const AST::Module &Mod) noexcept; |
96 | | |
97 | | // ========================================================================== |
98 | | // Naming checks and the named-types rule; the only writer of NameSide. |
99 | | // ========================================================================== |
100 | | |
101 | | /// Extern-name grammar checks; an export rejects the import-only name kinds. |
102 | | Expect<ExternName> parseExternName(std::string_view Name, |
103 | | bool IsImport) const noexcept; |
104 | | /// Build the comparison record for a parsed name. |
105 | | NameRecord makeNameRecord(const ExternName &Name) const noexcept; |
106 | | /// Append N to Names, or diagnose the clash (exact or strong-uniqueness). |
107 | | Expect<void> addUniqueName(std::vector<NameRecord> &Names, |
108 | | const NameRecord &N, bool IsImport) const noexcept; |
109 | | /// Name attributes: each kind at most once, on a plain, instance-typed name. |
110 | | Expect<void> checkNameAttributes(const ExternName &CN, |
111 | | Span<const std::string> Impls, |
112 | | Span<const std::string> ExtIds, |
113 | | Span<const std::string> VSuffixes, |
114 | | bool IsInstance) const noexcept; |
115 | | /// Annotated plainname rules ([constructor]/[method]/[static]). |
116 | | Expect<void> checkAnnotatedName(const ExternName &Name, |
117 | | const ExternInfo &Info, |
118 | | bool IsImport) noexcept; |
119 | | /// Track plain resource labels for later annotated-name checks. |
120 | | void recordResourceLabel(const ExternName &Name, const ExternInfo &Info, |
121 | | bool IsImport) noexcept; |
122 | | /// Named-types rule: an earlier extern must introduce each named type used. |
123 | | Expect<void> checkNamedTypesRule(const ExternInfo &Info, |
124 | | bool IsImport) noexcept; |
125 | | |
126 | | // ========================================================================== |
127 | | // Declaring an import or an export; name errors precede ascription errors. |
128 | | // ========================================================================== |
129 | | |
130 | | /// Check an import's name and define the resolved entity it introduces. |
131 | | Expect<ExternInfo> |
132 | | defineImport(std::string_view Name, const ExternInfo &Resolved, |
133 | | Span<const std::string> Impls = {}, |
134 | | Span<const std::string> ExtIds = {}, |
135 | | Span<const std::string> VSuffixes = {}) noexcept; |
136 | | /// Check and record an export's name; defineExport then defines the entity. |
137 | | Expect<ExternName> |
138 | | registerExportName(std::string_view Name, bool IsInstance, |
139 | | Span<const std::string> Impls = {}, |
140 | | Span<const std::string> ExtIds = {}, |
141 | | Span<const std::string> VSuffixes = {}) noexcept; |
142 | | /// Apply the optional ascription and define the re-exported index. |
143 | | Expect<ExternInfo> |
144 | | defineExport(const ExternName &CN, const ExternInfo &Inferred, |
145 | | const std::optional<ExternInfo> &Ascribed) noexcept; |
146 | | |
147 | | /// Mint fresh identities for the resources Inst declares; top() owns them. |
148 | | const Shape *freshenDeclaredResources(const Shape *Inst, |
149 | 153 | bool FromImport) noexcept { |
150 | 153 | return Types.freshenDeclaredResources(Inst, top(), FromImport); |
151 | 153 | } |
152 | | |
153 | | // ========================================================================== |
154 | | // Canonical options. They resolve core index spaces, so they live here. |
155 | | // ========================================================================== |
156 | | |
157 | | /// The index type of the selected canonical memory. |
158 | | ValType |
159 | | getCanonPtrType(const AST::Component::Canonical &Canon) const noexcept; |
160 | | /// canonopt rules: duplicates, indices, core signatures, per-site whitelist. |
161 | | Expect<void> checkOptions(const AST::Component::Canonical &Canon, |
162 | | bool IsLift) const noexcept; |
163 | | /// The memory and realloc options a definition (What) needs. |
164 | | Expect<void> requireOptions(const AST::Component::Canonical &Canon, |
165 | | bool NeedMemory, bool NeedRealloc, |
166 | | std::string_view What) const noexcept; |
167 | | |
168 | | // ========================================================================== |
169 | | // Instantiation. |
170 | | // ========================================================================== |
171 | | |
172 | | /// Match args against CI.Imports and produce the freshened export view. |
173 | | Expect<const Shape *> instantiateComponentShape( |
174 | | const Shape &CI, |
175 | | Span<const AST::Component::InstantiateArg<AST::Component::SortIndex>> |
176 | | Args) noexcept; |
177 | | |
178 | | /// Core-module code sections deferred to the end of the root component. |
179 | | std::vector<std::pair<const AST::Module *, FormChecker>> DeferredModules; |
180 | | |
181 | 5.98k | void reset() noexcept { |
182 | 5.98k | DeferredModules.clear(); |
183 | 5.98k | Stack.clear(); |
184 | 5.98k | OwnedScopes.clear(); |
185 | 5.98k | Types.reset(); |
186 | 5.98k | } |
187 | | |
188 | | private: |
189 | | // Named-types rule: introduceExternTypes checks (false if unmet) and records. |
190 | | bool introduceExternTypes(const ExternInfo &Info, bool IsImport) noexcept; |
191 | | bool isIntroduced(const QualValType &Q, bool IsImport) noexcept; |
192 | | bool isIntroduced(const TypeEntry &E, bool IsImport) noexcept; |
193 | | // The immediate components of the type. The extern names the type itself. |
194 | | bool areInnerTypesIntroduced(const TypeEntry &E, bool IsImport) noexcept; |
195 | | |
196 | | TypeSystem &Types; |
197 | | std::vector<Scope *> Stack; |
198 | | std::deque<Scope> OwnedScopes; |
199 | | }; |
200 | | |
201 | | } // namespace Component |
202 | | } // namespace Validator |
203 | | } // namespace WasmEdge |