/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 | | #pragma once |
5 | | |
6 | | #include "ast/component/component.h" |
7 | | #include "ast/module.h" |
8 | | #include "validator/component_name.h" |
9 | | |
10 | | #include <deque> |
11 | | #include <optional> |
12 | | #include <string> |
13 | | #include <unordered_map> |
14 | | #include <unordered_set> |
15 | | #include <vector> |
16 | | |
17 | | namespace WasmEdge { |
18 | | namespace Validator { |
19 | | |
20 | | class ComponentContext { |
21 | | public: |
22 | | // ========================================================================== |
23 | | // Validation context (one per component scope) |
24 | | // ========================================================================== |
25 | | |
26 | | struct Context { |
27 | | Context(const AST::Component::Component *C, |
28 | | const Context *P = nullptr) noexcept |
29 | 0 | : Component(C), Parent(P) {} |
30 | | |
31 | | // ---- Nested types ---- |
32 | | // Per-sort slot structs bundling body + externdesc type ascription. |
33 | | // Exactly one of {Body, Type} is non-null per slot (Body for inline, |
34 | | // Type for imported / outer-aliased). |
35 | | struct CoreModuleSlot { |
36 | | const AST::Module *Body; |
37 | | const AST::Component::CoreDefType *Type; |
38 | 0 | CoreModuleSlot() noexcept : Body(nullptr), Type(nullptr) {} |
39 | 0 | CoreModuleSlot(const AST::Module &B) noexcept : Body(&B), Type(nullptr) {} |
40 | | CoreModuleSlot(const AST::Component::CoreDefType *T) noexcept |
41 | 0 | : Body(nullptr), Type(T) {} |
42 | | }; |
43 | | struct ComponentSlot { |
44 | | const AST::Component::Component *Body; |
45 | | const AST::Component::ComponentType *Type; |
46 | 0 | ComponentSlot() noexcept : Body(nullptr), Type(nullptr) {} |
47 | | ComponentSlot(const AST::Component::Component &B) noexcept |
48 | 0 | : Body(&B), Type(nullptr) {} |
49 | | ComponentSlot(const AST::Component::ComponentType *T) noexcept |
50 | 0 | : Body(nullptr), Type(T) {} |
51 | | }; |
52 | | // Per-export entry inside an instance's export table. |
53 | | // ResourceId is set when ST == Type and the exported type is a resource |
54 | | // (so an alias-export onto a new type slot can carry the same identity). |
55 | | struct InstanceExport { |
56 | | AST::Component::Sort::SortType ST; |
57 | | const AST::Component::InstanceType *IT; |
58 | | std::optional<uint32_t> NestedInstIdx; |
59 | | std::optional<uint64_t> ResourceId; |
60 | | }; |
61 | | // Instance slot. Type is set only when bound via |
62 | | // validate(ExternDesc::InstanceType) (GAP-I-5b follow-up otherwise). |
63 | | struct InstanceSlot { |
64 | | std::unordered_map<std::string, InstanceExport> Exports; |
65 | | const AST::Component::InstanceType *Type; |
66 | 0 | InstanceSlot() : Type(nullptr) {} |
67 | 0 | InstanceSlot(const AST::Component::InstanceType *T) : Type(T) {} |
68 | | }; |
69 | | // Per-resource bookkeeping. "Key present in Resources" means resource. |
70 | | // The resource's AST body lives on ComponentContext::ResourceRegistry[Id]. |
71 | | struct ResourceInfo { |
72 | | // Canonical identity. Two indices share a resource iff ids match. |
73 | | uint64_t Id = 0; |
74 | | // True for validate(DefType) in this scope. Gates resource.new/.rep. |
75 | | bool LocallyDefined = false; |
76 | | }; |
77 | | |
78 | | // ---- Scope identity ---- |
79 | | const AST::Component::Component *Component; |
80 | | const Context *Parent; |
81 | | |
82 | | // ---- Core sort index spaces ---- |
83 | | std::vector<CoreModuleSlot> CoreModules; // core:module |
84 | | std::vector<std::unordered_map<std::string, ExternalType>> |
85 | | CoreInstances; // core:instance |
86 | | std::vector<const AST::SubType *> CoreTypes; // core:type |
87 | | std::vector<const AST::SubType *> CoreFuncs; // core:func |
88 | | std::vector<const AST::TableType *> CoreTables; // core:table |
89 | | std::vector<const AST::MemoryType *> CoreMemories; // core:memory |
90 | | std::vector<const AST::GlobalType *> CoreGlobals; // core:global |
91 | | uint32_t CoreTagCount = 0; // core:tag |
92 | | |
93 | | // ---- Component sort index spaces ---- |
94 | | std::vector<ComponentSlot> Components; // component |
95 | | std::vector<InstanceSlot> Instances; // instance |
96 | | std::vector<const AST::Component::DefType *> Types; // type |
97 | | std::vector<const AST::Component::FuncType *> Funcs; // func (i may be null) |
98 | | uint32_t ValueCount = 0; // value |
99 | | |
100 | | // ---- Type annotations (keyed by type index) ---- |
101 | | // ResourceType bodies live on Resources[i].Body (see below). |
102 | | std::unordered_map<uint32_t, const AST::Component::InstanceType *> |
103 | | InstanceTypes; |
104 | | std::unordered_map<uint32_t, const AST::Component::ComponentType *> |
105 | | ComponentTypes; |
106 | | // CoreDefType (moduletype) bodies, keyed by core:type-idx. |
107 | | std::unordered_map<uint32_t, const AST::Component::CoreDefType *> |
108 | | CoreModuleTypes; |
109 | | |
110 | | // ---- Resource state (keyed by type index) ---- |
111 | | std::unordered_map<uint32_t, ResourceInfo> Resources; |
112 | | |
113 | | // ---- Validation state ---- |
114 | | std::unordered_map<std::string, uint32_t> TypeSubstitutions; |
115 | | std::unordered_set<std::string> ImportedNames; |
116 | | std::unordered_set<std::string> ExportedNames; |
117 | | // Kebab-case resource name → type-idx; consumed by annotated-name |
118 | | // validation ([constructor]R / [method]R.f / [static]R.f). |
119 | | std::unordered_map<std::string, uint32_t> ResourceLabels; |
120 | | |
121 | | // ---- Size queries (used by outer-alias validation on parent ctxs) ---- |
122 | | uint32_t getSortIndexSize(AST::Component::Sort::SortType ST) const noexcept; |
123 | | uint32_t |
124 | | getCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) const noexcept; |
125 | | |
126 | | bool AddImportedName(const ComponentName &Name) noexcept; |
127 | | bool AddExportedName(const ComponentName &Name) noexcept; |
128 | | }; |
129 | | |
130 | | // Per-id row of the session-global resource registry. Held by |
131 | | // ComponentContext::ResourceRegistry; vector index IS the resource id. |
132 | | struct ResourceRegistryEntry { |
133 | | const AST::Component::ResourceType *Body = nullptr; |
134 | | }; |
135 | | |
136 | | // ========================================================================== |
137 | | // Context stack management |
138 | | // ========================================================================== |
139 | | |
140 | 0 | void reset() noexcept { |
141 | 0 | CompCtxs.clear(); |
142 | 0 | ResourceRegistry.clear(); |
143 | 0 | } |
144 | | |
145 | | /// Push a new validation scope for a real component. |
146 | 0 | void enterComponent(const AST::Component::Component *C) noexcept { |
147 | 0 | const Context *Parent = CompCtxs.empty() ? nullptr : &CompCtxs.back(); |
148 | 0 | CompCtxs.emplace_back(C, Parent); |
149 | 0 | } |
150 | | |
151 | | /// Push a new validation scope for a type definition |
152 | | /// (componenttype, instancetype, or moduletype). |
153 | 0 | void enterTypeDefinition() noexcept { |
154 | 0 | const Context *Parent = CompCtxs.empty() ? nullptr : &CompCtxs.back(); |
155 | 0 | CompCtxs.emplace_back(nullptr, Parent); |
156 | 0 | } |
157 | | |
158 | 0 | void exitComponent() noexcept { |
159 | 0 | assuming(!CompCtxs.empty()); |
160 | 0 | CompCtxs.pop_back(); |
161 | 0 | } |
162 | | |
163 | | /// Returns true if the current scope is a type definition scope |
164 | | /// (componenttype or instancetype), not a real component scope. |
165 | 0 | bool isTypeDefinitionScope() const noexcept { |
166 | 0 | return !CompCtxs.empty() && CompCtxs.back().Component == nullptr; |
167 | 0 | } |
168 | | |
169 | 0 | Context &getCurrentContext() noexcept { |
170 | 0 | assuming(!CompCtxs.empty()); |
171 | 0 | return CompCtxs.back(); |
172 | 0 | } |
173 | 0 | const Context &getCurrentContext() const noexcept { |
174 | 0 | assuming(!CompCtxs.empty()); |
175 | 0 | return CompCtxs.back(); |
176 | 0 | } |
177 | | |
178 | | // ========================================================================== |
179 | | // Index space size queries (generic dispatch by sort enum) |
180 | | // ========================================================================== |
181 | | |
182 | 0 | uint32_t getSortIndexSize(AST::Component::Sort::SortType ST) const noexcept { |
183 | 0 | return getCurrentContext().getSortIndexSize(ST); |
184 | 0 | } |
185 | | uint32_t |
186 | 0 | getCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) const noexcept { |
187 | 0 | return getCurrentContext().getCoreSortIndexSize(ST); |
188 | 0 | } |
189 | | |
190 | | // ========================================================================== |
191 | | // Generic index space increment (for dynamic sort values) |
192 | | // ========================================================================== |
193 | | |
194 | | uint32_t incSortIndexSize(AST::Component::Sort::SortType ST) noexcept; |
195 | | uint32_t incCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) noexcept; |
196 | | |
197 | | // ========================================================================== |
198 | | // core:module |
199 | | // ========================================================================== |
200 | | |
201 | | /// Append a core-module slot. Slot's implicit constructors accept |
202 | | /// `const AST::Module &` (inline body), `const CoreDefType *` (typed |
203 | | /// import / alias), or nothing (empty slot, used by outer-alias |
204 | | /// validation and incCoreSortIndexSize). |
205 | 0 | uint32_t addCoreModule(Context::CoreModuleSlot S = {}) noexcept { |
206 | 0 | auto &Ctx = getCurrentContext(); |
207 | 0 | uint32_t Idx = static_cast<uint32_t>(Ctx.CoreModules.size()); |
208 | 0 | Ctx.CoreModules.push_back(std::move(S)); |
209 | 0 | return Idx; |
210 | 0 | } |
211 | | |
212 | | /// Read a core-module slot. Callers access `.Body` (inline body) or |
213 | | /// `.Type` (externdesc-bound moduletype) as needed. |
214 | 0 | const Context::CoreModuleSlot &getCoreModule(uint32_t Idx) const noexcept { |
215 | 0 | return getCurrentContext().CoreModules.at(Idx); |
216 | 0 | } |
217 | | |
218 | | /// Returns the CoreDefType (a moduletype) stored at a core:type index, or |
219 | | /// nullptr if the core type is not a ModuleType (or its body is not |
220 | | /// visible here). |
221 | | const AST::Component::CoreDefType * |
222 | 0 | getCoreModuleType(uint32_t TypeIdx) const noexcept { |
223 | 0 | const auto &Ctx = getCurrentContext(); |
224 | 0 | auto It = Ctx.CoreModuleTypes.find(TypeIdx); |
225 | 0 | return It != Ctx.CoreModuleTypes.end() ? It->second : nullptr; |
226 | 0 | } |
227 | | |
228 | | /// Bind a CoreDefType (a moduletype) to a core:type index. Called by |
229 | | /// validate(CoreDefType) when adding a moduletype to the core:type space. |
230 | | void setCoreModuleType(uint32_t TypeIdx, |
231 | 0 | const AST::Component::CoreDefType *CT) noexcept { |
232 | 0 | getCurrentContext().CoreModuleTypes[TypeIdx] = CT; |
233 | 0 | } |
234 | | |
235 | | // ========================================================================== |
236 | | // core:instance |
237 | | // ========================================================================== |
238 | | |
239 | 0 | uint32_t addCoreInstance() noexcept { |
240 | 0 | auto &V = getCurrentContext().CoreInstances; |
241 | 0 | uint32_t Idx = static_cast<uint32_t>(V.size()); |
242 | 0 | V.emplace_back(); |
243 | 0 | return Idx; |
244 | 0 | } |
245 | | |
246 | | const std::unordered_map<std::string, ExternalType> & |
247 | 0 | getCoreInstance(uint32_t Idx) const noexcept { |
248 | 0 | return getCurrentContext().CoreInstances.at(Idx); |
249 | 0 | } |
250 | | |
251 | | void addCoreInstanceExport(uint32_t InstIdx, std::string_view Name, |
252 | 0 | ExternalType ET) { |
253 | 0 | getCurrentContext().CoreInstances.at(InstIdx)[std::string(Name)] = ET; |
254 | 0 | } |
255 | | |
256 | | // ========================================================================== |
257 | | // core:type / core:func / core:table / core:memory / core:global / core:tag |
258 | | // ========================================================================== |
259 | | |
260 | 0 | uint32_t addCoreType(const AST::SubType *ST = nullptr) noexcept { |
261 | 0 | auto &V = getCurrentContext().CoreTypes; |
262 | 0 | uint32_t Idx = static_cast<uint32_t>(V.size()); |
263 | 0 | V.push_back(ST); |
264 | 0 | return Idx; |
265 | 0 | } |
266 | 0 | uint32_t addCoreFunc(const AST::SubType *ST = nullptr) noexcept { |
267 | 0 | auto &V = getCurrentContext().CoreFuncs; |
268 | 0 | uint32_t Idx = static_cast<uint32_t>(V.size()); |
269 | 0 | V.push_back(ST); |
270 | 0 | return Idx; |
271 | 0 | } |
272 | 0 | const AST::SubType *getCoreFunc(uint32_t Idx) const noexcept { |
273 | 0 | const auto &V = getCurrentContext().CoreFuncs; |
274 | 0 | return Idx < V.size() ? V[Idx] : nullptr; |
275 | 0 | } |
276 | | |
277 | 0 | uint32_t addCoreTable(const AST::TableType *TT = nullptr) noexcept { |
278 | 0 | auto &V = getCurrentContext().CoreTables; |
279 | 0 | uint32_t Idx = static_cast<uint32_t>(V.size()); |
280 | 0 | V.push_back(TT); |
281 | 0 | return Idx; |
282 | 0 | } |
283 | 0 | uint32_t addCoreMemory(const AST::MemoryType *MT = nullptr) noexcept { |
284 | 0 | auto &V = getCurrentContext().CoreMemories; |
285 | 0 | uint32_t Idx = static_cast<uint32_t>(V.size()); |
286 | 0 | V.push_back(MT); |
287 | 0 | return Idx; |
288 | 0 | } |
289 | 0 | uint32_t addCoreGlobal(const AST::GlobalType *GT = nullptr) noexcept { |
290 | 0 | auto &V = getCurrentContext().CoreGlobals; |
291 | 0 | uint32_t Idx = static_cast<uint32_t>(V.size()); |
292 | 0 | V.push_back(GT); |
293 | 0 | return Idx; |
294 | 0 | } |
295 | 0 | uint32_t addCoreTag() noexcept { return getCurrentContext().CoreTagCount++; } |
296 | | |
297 | | // ========================================================================== |
298 | | // component |
299 | | // ========================================================================== |
300 | | |
301 | | /// Append a component slot. Slot's implicit constructors accept |
302 | | /// `const Component &` (inline body), `const ComponentType *` (typed |
303 | | /// import / alias), or nothing (empty slot). |
304 | 0 | uint32_t addComponent(Context::ComponentSlot S = {}) noexcept { |
305 | 0 | auto &Ctx = getCurrentContext(); |
306 | 0 | uint32_t Idx = static_cast<uint32_t>(Ctx.Components.size()); |
307 | 0 | Ctx.Components.push_back(std::move(S)); |
308 | 0 | return Idx; |
309 | 0 | } |
310 | | |
311 | | /// Read a component slot. Callers access `.Body` (inline body) or |
312 | | /// `.Type` (externdesc-bound ComponentType) as needed. |
313 | 0 | const Context::ComponentSlot &getComponent(uint32_t Idx) const noexcept { |
314 | 0 | return getCurrentContext().Components.at(Idx); |
315 | 0 | } |
316 | | |
317 | | /// Returns the ComponentType stored at a type index, or nullptr if the |
318 | | /// type is not a ComponentType (or its body is not visible here). |
319 | | const AST::Component::ComponentType * |
320 | 0 | getComponentType(uint32_t TypeIdx) const noexcept { |
321 | 0 | const auto &Ctx = getCurrentContext(); |
322 | 0 | auto It = Ctx.ComponentTypes.find(TypeIdx); |
323 | 0 | return It != Ctx.ComponentTypes.end() ? It->second : nullptr; |
324 | 0 | } |
325 | | |
326 | | // The scope an outer alias targets: Ct parent hops up. nullptr if Ct |
327 | | // exceeds the enclosing depth. |
328 | 0 | const Context *resolveOuterContext(uint32_t Ct) const noexcept { |
329 | 0 | uint32_t Hops = 0; |
330 | 0 | const Context *T = &getCurrentContext(); |
331 | 0 | while (Ct > Hops && T != nullptr) { |
332 | 0 | T = T->Parent; |
333 | 0 | ++Hops; |
334 | 0 | } |
335 | 0 | return T; |
336 | 0 | } |
337 | | |
338 | | // Reproduce an outer-aliased core module's slot into the alias's slot |
339 | | // DstIdx, so its exports stay enumerable when the alias is instantiated. |
340 | | void carryOuterCoreModule(uint32_t DstIdx, uint32_t Ct, |
341 | 0 | uint32_t SrcIdx) noexcept { |
342 | 0 | const Context *O = resolveOuterContext(Ct); |
343 | 0 | auto &Dst = getCurrentContext().CoreModules; |
344 | 0 | if (O != nullptr && SrcIdx < O->CoreModules.size() && DstIdx < Dst.size()) { |
345 | 0 | Dst[DstIdx] = O->CoreModules[SrcIdx]; |
346 | 0 | } |
347 | 0 | } |
348 | | |
349 | | // Component analogue of carryOuterCoreModule. |
350 | | void carryOuterComponent(uint32_t DstIdx, uint32_t Ct, |
351 | 0 | uint32_t SrcIdx) noexcept { |
352 | 0 | const Context *O = resolveOuterContext(Ct); |
353 | 0 | auto &Dst = getCurrentContext().Components; |
354 | 0 | if (O != nullptr && SrcIdx < O->Components.size() && DstIdx < Dst.size()) { |
355 | 0 | Dst[DstIdx] = O->Components[SrcIdx]; |
356 | 0 | } |
357 | 0 | } |
358 | | |
359 | | // Inherit an outer-aliased resource type's identity into the alias's type |
360 | | // slot DstIdx, so own/borrow checks and TypeBound (eq i) propagation in this |
361 | | // scope still recognise the aliased type as a resource. The alias does not |
362 | | // locally define the resource, so LocallyDefined stays false (it must not |
363 | | // gate resource.new/.rep here). |
364 | | void carryOuterResource(uint32_t DstIdx, uint32_t Ct, |
365 | 0 | uint32_t SrcIdx) noexcept { |
366 | 0 | const Context *O = resolveOuterContext(Ct); |
367 | 0 | if (O == nullptr) { |
368 | 0 | return; |
369 | 0 | } |
370 | 0 | auto It = O->Resources.find(SrcIdx); |
371 | 0 | if (It != O->Resources.end()) { |
372 | 0 | getCurrentContext().Resources[DstIdx] = {It->second.Id, |
373 | 0 | /*LocallyDefined=*/false}; |
374 | 0 | } |
375 | 0 | } |
376 | | |
377 | | // ========================================================================== |
378 | | // instance |
379 | | // ========================================================================== |
380 | | |
381 | | /// Append an instance slot. Slot's implicit constructor accepts |
382 | | /// `const InstanceType *` (typed source) or nothing (untyped — used by |
383 | | /// inline-export / (instantiate ...) sources). |
384 | 0 | uint32_t addInstance(Context::InstanceSlot S = {}) { |
385 | 0 | auto &Ctx = getCurrentContext(); |
386 | 0 | uint32_t Idx = static_cast<uint32_t>(Ctx.Instances.size()); |
387 | 0 | Ctx.Instances.push_back(std::move(S)); |
388 | 0 | return Idx; |
389 | 0 | } |
390 | | |
391 | | using InstanceExport = Context::InstanceExport; |
392 | | |
393 | | /// Read an instance slot. Callers access `.Exports` (export table) or |
394 | | /// `.Type` (externdesc-bound InstanceType) as needed. |
395 | 0 | const Context::InstanceSlot &getInstance(uint32_t Idx) const noexcept { |
396 | 0 | return getCurrentContext().Instances.at(Idx); |
397 | 0 | } |
398 | | |
399 | | void addInstanceExport( |
400 | | uint32_t InstIdx, std::string_view Name, |
401 | | AST::Component::Sort::SortType ST, |
402 | | const AST::Component::InstanceType *IT = nullptr, |
403 | | std::optional<uint32_t> NestedInstIdx = std::nullopt, |
404 | 0 | std::optional<uint64_t> ResourceId = std::nullopt) noexcept { |
405 | 0 | getCurrentContext().Instances.at(InstIdx).Exports[std::string(Name)] = { |
406 | 0 | ST, IT, NestedInstIdx, ResourceId}; |
407 | 0 | } |
408 | | |
409 | | // ========================================================================== |
410 | | // type |
411 | | // ========================================================================== |
412 | | |
413 | | /// Append a type slot. IsLocal=false for resource type imports and |
414 | | /// outer-alias resources, true otherwise. |
415 | | uint32_t addType(const AST::Component::DefType *DT = nullptr, |
416 | 0 | bool IsLocal = true) noexcept { |
417 | 0 | return addTypeImpl(DT, IsLocal); |
418 | 0 | } |
419 | | |
420 | 0 | const AST::Component::DefType *getDefType(uint32_t Idx) const noexcept { |
421 | 0 | const auto &Ctx = getCurrentContext(); |
422 | 0 | if (Idx < Ctx.Types.size()) { |
423 | 0 | return Ctx.Types[Idx]; |
424 | 0 | } |
425 | 0 | return nullptr; |
426 | 0 | } |
427 | | |
428 | | const AST::Component::InstanceType * |
429 | 0 | getInstanceType(uint32_t Idx) const noexcept { |
430 | 0 | const auto &Ctx = getCurrentContext(); |
431 | 0 | auto It = Ctx.InstanceTypes.find(Idx); |
432 | 0 | return It != Ctx.InstanceTypes.end() ? It->second : nullptr; |
433 | 0 | } |
434 | | |
435 | | // ========================================================================== |
436 | | // resource |
437 | | // ========================================================================== |
438 | | |
439 | | /// Allocate a fresh resource id, pushing a new registry row. Body is |
440 | | /// nullptr for (sub resource) imports. |
441 | | uint64_t allocateFreshResourceId( |
442 | 0 | const AST::Component::ResourceType *Body = nullptr) noexcept { |
443 | 0 | uint64_t Id = ResourceRegistry.size(); |
444 | 0 | ResourceRegistry.push_back({Body}); |
445 | 0 | return Id; |
446 | 0 | } |
447 | | |
448 | | /// Bind a ResourceInfo to a type index in the current scope. |
449 | 0 | void addResource(uint32_t TypeIdx, Context::ResourceInfo Info) noexcept { |
450 | 0 | getCurrentContext().Resources[TypeIdx] = Info; |
451 | 0 | } |
452 | | |
453 | | /// ResourceInfo at this type index, or nullptr if not a resource. |
454 | 0 | const Context::ResourceInfo *getResource(uint32_t Idx) const noexcept { |
455 | 0 | const auto &R = getCurrentContext().Resources; |
456 | 0 | auto It = R.find(Idx); |
457 | 0 | return It != R.end() ? &It->second : nullptr; |
458 | 0 | } |
459 | | |
460 | | /// Register a kebab-case resource name (from a TypeBound import / export) |
461 | | /// so annotated names ([constructor]R / [method]R.f / [static]R.f) resolve. |
462 | 0 | void addResourceLabel(std::string_view Name, uint32_t TypeIdx) noexcept { |
463 | 0 | getCurrentContext().ResourceLabels.emplace(std::string(Name), TypeIdx); |
464 | 0 | } |
465 | | |
466 | 0 | bool hasResourceLabel(std::string_view Name) const noexcept { |
467 | 0 | return getCurrentContext().ResourceLabels.find(std::string(Name)) != |
468 | 0 | getCurrentContext().ResourceLabels.end(); |
469 | 0 | } |
470 | | |
471 | | // ========================================================================== |
472 | | // func / value |
473 | | // ========================================================================== |
474 | | |
475 | 0 | uint32_t addFunc(const AST::Component::FuncType *FT = nullptr) noexcept { |
476 | 0 | auto &V = getCurrentContext().Funcs; |
477 | 0 | uint32_t Idx = static_cast<uint32_t>(V.size()); |
478 | 0 | V.push_back(FT); |
479 | 0 | return Idx; |
480 | 0 | } |
481 | 0 | const AST::Component::FuncType *getFunc(uint32_t Idx) const noexcept { |
482 | 0 | const auto &V = getCurrentContext().Funcs; |
483 | 0 | return Idx < V.size() ? V[Idx] : nullptr; |
484 | 0 | } |
485 | 0 | uint32_t addValue() noexcept { return getCurrentContext().ValueCount++; } |
486 | | |
487 | | // ========================================================================== |
488 | | // Validation state |
489 | | // ========================================================================== |
490 | | |
491 | | void substituteTypeImport(const std::string &ImportName, |
492 | 0 | uint32_t TypeIdx) noexcept { |
493 | 0 | getCurrentContext().TypeSubstitutions[ImportName] = TypeIdx; |
494 | 0 | } |
495 | | |
496 | | std::optional<uint32_t> |
497 | 0 | getSubstitutedType(const std::string &ImportName) const { |
498 | 0 | const auto &Ctx = getCurrentContext(); |
499 | 0 | auto It = Ctx.TypeSubstitutions.find(ImportName); |
500 | 0 | if (It != Ctx.TypeSubstitutions.end()) { |
501 | 0 | return It->second; |
502 | 0 | } |
503 | 0 | return std::nullopt; |
504 | 0 | } |
505 | | |
506 | 0 | bool addImportedName(const ComponentName &Name) noexcept { |
507 | 0 | return getCurrentContext().AddImportedName(Name); |
508 | 0 | } |
509 | | |
510 | | /// Returns false if the export name violates strong-uniqueness. |
511 | 0 | bool addExportedName(const ComponentName &Name) noexcept { |
512 | 0 | return getCurrentContext().AddExportedName(Name); |
513 | 0 | } |
514 | | |
515 | | private: |
516 | | uint32_t addTypeImpl(const AST::Component::DefType *DT, |
517 | 0 | bool IsLocal) noexcept { |
518 | 0 | auto &Ctx = getCurrentContext(); |
519 | 0 | uint32_t Idx = static_cast<uint32_t>(Ctx.Types.size()); |
520 | 0 | Ctx.Types.push_back(DT); |
521 | 0 | if (DT != nullptr) { |
522 | 0 | if (DT->isInstanceType()) { |
523 | 0 | Ctx.InstanceTypes[Idx] = &DT->getInstanceType(); |
524 | 0 | } else if (DT->isResourceType()) { |
525 | | // Locally-defined: body goes to the registry; IsLocal sets locality. |
526 | 0 | Ctx.Resources[Idx] = {allocateFreshResourceId(&DT->getResourceType()), |
527 | 0 | IsLocal}; |
528 | 0 | } else if (DT->isComponentType()) { |
529 | 0 | Ctx.ComponentTypes[Idx] = &DT->getComponentType(); |
530 | 0 | } |
531 | 0 | } |
532 | 0 | return Idx; |
533 | 0 | } |
534 | | |
535 | | std::deque<Context> CompCtxs; |
536 | | |
537 | | // Session-global resource registry; vector index IS the resource id. |
538 | | std::vector<ResourceRegistryEntry> ResourceRegistry; |
539 | | }; |
540 | | |
541 | | } // namespace Validator |
542 | | } // namespace WasmEdge |