Coverage Report

Created: 2026-07-19 07:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wasmparser/src/validator/component.rs
Line
Count
Source
1
//! State relating to validating a WebAssembly component.
2
3
use super::{
4
    check_max,
5
    component_types::{
6
        Abi, AliasableResourceId, ComponentAnyTypeId, ComponentCoreInstanceTypeId,
7
        ComponentCoreModuleTypeId, ComponentCoreTypeId, ComponentDefinedType,
8
        ComponentDefinedTypeId, ComponentEntityType, ComponentFuncType, ComponentFuncTypeId,
9
        ComponentInstanceType, ComponentInstanceTypeId, ComponentItem, ComponentType,
10
        ComponentTypeId, ComponentValType, Context, CoreInstanceTypeKind, InstanceType, ModuleType,
11
        RecordType, Remap, Remapping, ResourceId, SubtypeCx, TupleType, VariantCase, VariantType,
12
    },
13
    core::{InternRecGroup, Module},
14
    types::{CoreTypeId, EntityType, TypeAlloc, TypeData, TypeInfo, TypeList},
15
};
16
use crate::collections::index_map::Entry;
17
use crate::limits::*;
18
use crate::prelude::*;
19
use crate::validator::names::{ComponentName, ComponentNameKind, KebabStr, KebabString};
20
use crate::{
21
    CanonicalFunction, CanonicalOption, ComponentExternName, ComponentExternalKind,
22
    ComponentOuterAliasKind, ComponentTypeRef, CompositeInnerType, Error, ExternalKind, FuncType,
23
    GlobalType, InstantiationArgKind, MemoryType, PackedIndex, RefType, Result, SubType, TableType,
24
    TypeBounds, ValType, WasmFeatures, require_feature,
25
};
26
use core::mem;
27
28
797k
fn to_kebab_string<'a>(s: &'a str, desc: &str, offset: usize) -> Result<KebabString> {
29
797k
    match KebabString::new(s) {
30
797k
        Some(s) => Ok(s),
31
        None => {
32
0
            if s.is_empty() {
33
0
                bail!(offset, "{desc} name cannot be empty");
34
0
            }
35
36
0
            bail!(offset, "{desc} name `{s}` is not in kebab case");
37
        }
38
    }
39
797k
}
40
41
pub(crate) struct ComponentState {
42
    /// Whether this state is a concrete component, an instance type, or a
43
    /// component type.
44
    kind: ComponentKind,
45
    features: WasmFeatures,
46
47
    // Core index spaces
48
    pub core_types: Vec<ComponentCoreTypeId>,
49
    pub core_funcs: Vec<CoreTypeId>,
50
    pub core_tags: Vec<CoreTypeId>,
51
    pub core_modules: Vec<ComponentCoreModuleTypeId>,
52
    pub core_instances: Vec<ComponentCoreInstanceTypeId>,
53
    pub core_memories: Vec<MemoryType>,
54
    pub core_tables: Vec<TableType>,
55
    pub core_globals: Vec<GlobalType>,
56
57
    // Component index spaces
58
    pub types: Vec<ComponentAnyTypeId>,
59
    pub funcs: Vec<ComponentFuncTypeId>,
60
    pub values: Vec<(ComponentValType, bool)>,
61
    pub instances: Vec<ComponentInstanceTypeId>,
62
    pub components: Vec<ComponentTypeId>,
63
64
    pub imports: IndexMap<String, ComponentItem>,
65
    pub import_names: IndexSet<ComponentName>,
66
    pub exports: IndexMap<String, ComponentItem>,
67
    pub export_names: IndexSet<ComponentName>,
68
69
    has_start: bool,
70
    type_info: TypeInfo,
71
72
    /// A mapping of imported resources in this component.
73
    ///
74
    /// This mapping represents all "type variables" imported into the
75
    /// component, or resources. This could be resources imported directly as
76
    /// a top-level type import or additionally transitively through other
77
    /// imported instances.
78
    ///
79
    /// The mapping element here is a "path" which is a list of indexes into
80
    /// the import map that will be generated for this component. Each index
81
    /// is an index into an `IndexMap`, and each list is guaranteed to have at
82
    /// least one element.
83
    ///
84
    /// An example of this map is:
85
    ///
86
    /// ```wasm
87
    /// (component
88
    ///     ;; [0] - the first import
89
    ///     (import "r" (type (sub resource)))
90
    ///
91
    ///     ;; [1] - the second import
92
    ///     (import "r2" (type (sub resource)))
93
    ///
94
    ///     (import "i" (instance
95
    ///         ;; [2, 0] - the third import, and the first export the instance
96
    ///         (export "r3" (type (sub resource)))
97
    ///         ;; [2, 1] - the third import, and the second export the instance
98
    ///         (export "r4" (type (sub resource)))
99
    ///     ))
100
    ///
101
    ///     ;; ...
102
    /// )
103
    /// ```
104
    ///
105
    /// The `Vec<usize>` here can be thought of as `Vec<String>` but a
106
    /// (hopefully) more efficient representation.
107
    ///
108
    /// Finally note that this map is listed as an "append only" map because all
109
    /// insertions into it should always succeed. Any insertion which overlaps
110
    /// with a previous entry indicates a bug in the validator which needs to be
111
    /// corrected via other means.
112
    //
113
    // TODO: make these `SkolemResourceId` and then go fix all the compile
114
    // errors, don't add skolem things into the type area
115
    imported_resources: IndexMapAppendOnly<ResourceId, Vec<usize>>,
116
117
    /// A mapping of "defined" resources in this component, or those which
118
    /// are defined within the instantiation of this component.
119
    ///
120
    /// Defined resources, as the name implies, can sort of be thought of as
121
    /// "these are defined within the component". Note though that the means by
122
    /// which a local definition can occur are not simply those defined in the
123
    /// component but also in its transitively instantiated components
124
    /// internally. This means that this set closes over many transitive
125
    /// internal items in addition to those defined immediately in the component
126
    /// itself.
127
    ///
128
    /// The `Option<ValType>` in this mapping is whether or not the underlying
129
    /// representation of the resource is known to this component. Immediately
130
    /// defined resources, for example, will have `Some(I32)` here. Resources
131
    /// that come from transitively defined components, for example, will have
132
    /// `None`. In the type context all entries here are `None`.
133
    ///
134
    /// Note that like `imported_resources` all insertions into this map are
135
    /// expected to succeed to it's declared as append-only.
136
    defined_resources: IndexMapAppendOnly<ResourceId, Option<ValType>>,
137
138
    /// A mapping of explicitly exported resources from this component in
139
    /// addition to the path that they're exported at.
140
    ///
141
    /// For more information on the path here see the documentation for
142
    /// `imported_resources`. Note that the indexes here index into the
143
    /// list of exports of this component.
144
    explicit_resources: IndexMap<ResourceId, Vec<usize>>,
145
146
    /// The set of types which are considered "exported" from this component.
147
    ///
148
    /// This is added to whenever a type export is found, or an instance export
149
    /// which itself contains a type export. This additionally includes all
150
    /// imported types since those are suitable for export as well.
151
    ///
152
    /// This set is consulted whenever an exported item is added since all
153
    /// referenced types must be members of this set.
154
    exported_types: Set<ComponentAnyTypeId>,
155
156
    /// Same as `exported_types`, but for imports.
157
    imported_types: Set<ComponentAnyTypeId>,
158
159
    /// The set of top-level resource exports and their names.
160
    ///
161
    /// This context is used to validate method names such as `[method]foo.bar`
162
    /// to ensure that `foo` is an exported resource and that the type mentioned
163
    /// in a function type is actually named `foo`.
164
    ///
165
    /// Note that imports/exports have disjoint contexts to ensure that they're
166
    /// validated correctly. Namely you can't retroactively attach methods to an
167
    /// import, for example.
168
    toplevel_exported_resources: ComponentNameContext,
169
170
    /// Same as `toplevel_exported_resources`, but for imports.
171
    toplevel_imported_resources: ComponentNameContext,
172
173
    /// The type that's been assigned to slots of `context.{get,set}` by this
174
    /// component. This is `None` until the first intrinsic is seen.
175
    context_type: Option<ValType>,
176
}
177
178
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
179
pub enum ComponentKind {
180
    Component,
181
    InstanceType,
182
    ComponentType,
183
}
184
185
/// Helper context used to track information about resource names for method
186
/// name validation.
187
#[derive(Default)]
188
struct ComponentNameContext {
189
    /// A map from a resource type id to an index in the `all_resource_names`
190
    /// set for the name of that resource.
191
    resource_name_map: Map<AliasableResourceId, usize>,
192
193
    /// All known resource names in this context, used to validate static method
194
    /// names to by ensuring that static methods' resource names are somewhere
195
    /// in this set.
196
    all_resource_names: IndexSet<String>,
197
}
198
199
#[derive(Debug, Copy, Clone)]
200
pub enum ExternKind {
201
    Import,
202
    Export,
203
}
204
205
impl ExternKind {
206
0
    pub fn desc(&self) -> &'static str {
207
0
        match self {
208
0
            ExternKind::Import => "import",
209
0
            ExternKind::Export => "export",
210
        }
211
0
    }
212
}
213
214
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
215
pub(crate) enum StringEncoding {
216
    #[default]
217
    Utf8,
218
    Utf16,
219
    CompactUtf16,
220
}
221
222
impl core::fmt::Display for StringEncoding {
223
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
224
0
        f.write_str(match self {
225
0
            Self::Utf8 => "utf8",
226
0
            Self::Utf16 => "utf16",
227
0
            Self::CompactUtf16 => "latin1-utf16",
228
        })
229
0
    }
230
}
231
232
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
233
pub(crate) enum Concurrency {
234
    /// Synchronous.
235
    #[default]
236
    Sync,
237
238
    /// Asynchronous.
239
    Async {
240
        /// When present, this is the function index of the async callback. When
241
        /// omitted, we are either using stack-switching based asynchrony or are
242
        /// in an operation that does not support the `callback` option (like
243
        /// lowering).
244
        callback: Option<u32>,
245
    },
246
}
247
248
impl Concurrency {
249
24.9k
    pub(crate) fn is_sync(&self) -> bool {
250
24.9k
        matches!(self, Self::Sync)
251
24.9k
    }
252
253
21.8k
    pub(crate) fn is_async(&self) -> bool {
254
21.8k
        !self.is_sync()
255
21.8k
    }
256
}
257
258
#[derive(Clone, Copy)]
259
pub(crate) enum PtrSize {
260
    Ptr32,
261
    Ptr64,
262
}
263
264
impl PtrSize {
265
5.49k
    pub(crate) fn core_type(&self) -> ValType {
266
5.49k
        match self {
267
5.49k
            PtrSize::Ptr32 => ValType::I32,
268
0
            PtrSize::Ptr64 => ValType::I64,
269
        }
270
5.49k
    }
271
}
272
273
#[derive(Clone, Copy)]
274
pub(crate) struct CanonicalOptions {
275
    pub(crate) string_encoding: StringEncoding,
276
    pub(crate) memory: Option<(u32, PtrSize)>,
277
    pub(crate) realloc: Option<u32>,
278
    pub(crate) post_return: Option<u32>,
279
    pub(crate) concurrency: Concurrency,
280
    pub(crate) core_type: Option<CoreTypeId>,
281
    pub(crate) gc: bool,
282
}
283
284
impl CanonicalOptions {
285
2.82k
    pub(crate) fn require_sync(&self, offset: usize, where_: &str) -> Result<&Self> {
286
2.82k
        if !self.concurrency.is_sync() {
287
0
            bail!(offset, "cannot specify `async` option on `{where_}`")
288
2.82k
        }
289
2.82k
        Ok(self)
290
2.82k
    }
291
292
1.63k
    pub(crate) fn require_memory(&self, offset: usize) -> Result<&Self> {
293
1.63k
        if self.memory.is_none() {
294
0
            bail!(offset, "canonical option `memory` is required");
295
1.63k
        }
296
1.63k
        Ok(self)
297
1.63k
    }
298
299
186
    pub(crate) fn require_realloc(&self, offset: usize) -> Result<&Self> {
300
        // Memory is always required when `realloc` is required.
301
186
        self.require_memory(offset)?;
302
303
186
        if self.realloc.is_none() {
304
0
            bail!(offset, "canonical option `realloc` is required")
305
186
        }
306
307
186
        Ok(self)
308
186
    }
309
310
16.1k
    pub(crate) fn require_memory_if(
311
16.1k
        &self,
312
16.1k
        offset: usize,
313
16.1k
        when: impl Fn() -> bool,
314
16.1k
    ) -> Result<&Self> {
315
16.1k
        if self.memory.is_none() && when() {
316
0
            self.require_memory(offset)?;
317
16.1k
        }
318
16.1k
        Ok(self)
319
16.1k
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component::ComponentState>::future_read::{closure#0}>
Line
Count
Source
310
69
    pub(crate) fn require_memory_if(
311
69
        &self,
312
69
        offset: usize,
313
69
        when: impl Fn() -> bool,
314
69
    ) -> Result<&Self> {
315
69
        if self.memory.is_none() && when() {
316
0
            self.require_memory(offset)?;
317
69
        }
318
69
        Ok(self)
319
69
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component::ComponentState>::stream_read::{closure#0}>
Line
Count
Source
310
60
    pub(crate) fn require_memory_if(
311
60
        &self,
312
60
        offset: usize,
313
60
        when: impl Fn() -> bool,
314
60
    ) -> Result<&Self> {
315
60
        if self.memory.is_none() && when() {
316
0
            self.require_memory(offset)?;
317
60
        }
318
60
        Ok(self)
319
60
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component::ComponentState>::future_write::{closure#0}>
Line
Count
Source
310
69
    pub(crate) fn require_memory_if(
311
69
        &self,
312
69
        offset: usize,
313
69
        when: impl Fn() -> bool,
314
69
    ) -> Result<&Self> {
315
69
        if self.memory.is_none() && when() {
316
0
            self.require_memory(offset)?;
317
69
        }
318
69
        Ok(self)
319
69
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component::ComponentState>::stream_write::{closure#0}>
Line
Count
Source
310
60
    pub(crate) fn require_memory_if(
311
60
        &self,
312
60
        offset: usize,
313
60
        when: impl Fn() -> bool,
314
60
    ) -> Result<&Self> {
315
60
        if self.memory.is_none() && when() {
316
0
            self.require_memory(offset)?;
317
60
        }
318
60
        Ok(self)
319
60
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component_types::ComponentFuncType>::lower::{closure#0}>
Line
Count
Source
310
13.3k
    pub(crate) fn require_memory_if(
311
13.3k
        &self,
312
13.3k
        offset: usize,
313
13.3k
        when: impl Fn() -> bool,
314
13.3k
    ) -> Result<&Self> {
315
13.3k
        if self.memory.is_none() && when() {
316
0
            self.require_memory(offset)?;
317
13.3k
        }
318
13.3k
        Ok(self)
319
13.3k
    }
<wasmparser::validator::component::CanonicalOptions>::require_memory_if::<<wasmparser::validator::component_types::ComponentFuncType>::lower::{closure#3}>
Line
Count
Source
310
2.56k
    pub(crate) fn require_memory_if(
311
2.56k
        &self,
312
2.56k
        offset: usize,
313
2.56k
        when: impl Fn() -> bool,
314
2.56k
    ) -> Result<&Self> {
315
2.56k
        if self.memory.is_none() && when() {
316
0
            self.require_memory(offset)?;
317
2.56k
        }
318
2.56k
        Ok(self)
319
2.56k
    }
320
321
29.6k
    pub(crate) fn require_realloc_if(
322
29.6k
        &self,
323
29.6k
        offset: usize,
324
29.6k
        when: impl Fn() -> bool,
325
29.6k
    ) -> Result<&Self> {
326
29.6k
        if self.realloc.is_none() && when() {
327
0
            self.require_realloc(offset)?;
328
29.6k
        }
329
29.6k
        Ok(self)
330
29.6k
    }
<wasmparser::validator::component::CanonicalOptions>::require_realloc_if::<<wasmparser::validator::component::ComponentState>::future_read::{closure#1}>
Line
Count
Source
321
69
    pub(crate) fn require_realloc_if(
322
69
        &self,
323
69
        offset: usize,
324
69
        when: impl Fn() -> bool,
325
69
    ) -> Result<&Self> {
326
69
        if self.realloc.is_none() && when() {
327
0
            self.require_realloc(offset)?;
328
69
        }
329
69
        Ok(self)
330
69
    }
<wasmparser::validator::component::CanonicalOptions>::require_realloc_if::<<wasmparser::validator::component::ComponentState>::stream_read::{closure#1}>
Line
Count
Source
321
60
    pub(crate) fn require_realloc_if(
322
60
        &self,
323
60
        offset: usize,
324
60
        when: impl Fn() -> bool,
325
60
    ) -> Result<&Self> {
326
60
        if self.realloc.is_none() && when() {
327
0
            self.require_realloc(offset)?;
328
60
        }
329
60
        Ok(self)
330
60
    }
<wasmparser::validator::component::CanonicalOptions>::require_realloc_if::<<wasmparser::validator::component_types::ComponentFuncType>::lower::{closure#2}>
Line
Count
Source
321
12.1k
    pub(crate) fn require_realloc_if(
322
12.1k
        &self,
323
12.1k
        offset: usize,
324
12.1k
        when: impl Fn() -> bool,
325
12.1k
    ) -> Result<&Self> {
326
12.1k
        if self.realloc.is_none() && when() {
327
0
            self.require_realloc(offset)?;
328
12.1k
        }
329
12.1k
        Ok(self)
330
12.1k
    }
<wasmparser::validator::component::CanonicalOptions>::require_realloc_if::<<wasmparser::validator::component_types::ComponentFuncType>::lower::{closure#1}>
Line
Count
Source
321
17.3k
    pub(crate) fn require_realloc_if(
322
17.3k
        &self,
323
17.3k
        offset: usize,
324
17.3k
        when: impl Fn() -> bool,
325
17.3k
    ) -> Result<&Self> {
326
17.3k
        if self.realloc.is_none() && when() {
327
0
            self.require_realloc(offset)?;
328
17.3k
        }
329
17.3k
        Ok(self)
330
17.3k
    }
331
332
7.95k
    pub(crate) fn check_lower(&self, offset: usize) -> Result<&Self> {
333
7.95k
        if self.post_return.is_some() {
334
0
            bail!(
335
0
                offset,
336
                "canonical option `post-return` cannot be specified for lowerings"
337
            );
338
7.95k
        }
339
340
459
        if let Concurrency::Async { callback: Some(_) } = self.concurrency {
341
0
            bail!(
342
0
                offset,
343
                "canonical option `callback` cannot be specified for lowerings"
344
            );
345
7.95k
        }
346
347
7.95k
        if self.gc && self.core_type.is_none() {
348
0
            bail!(
349
0
                offset,
350
                "cannot specify `gc` without also specifying a `core-type` for lowerings"
351
            )
352
7.95k
        }
353
354
7.95k
        Ok(self)
355
7.95k
    }
356
357
9.12k
    pub(crate) fn check_lift(
358
9.12k
        &mut self,
359
9.12k
        types: &TypeList,
360
9.12k
        state: &ComponentState,
361
9.12k
        core_ty_id: CoreTypeId,
362
9.12k
        offset: usize,
363
9.12k
    ) -> Result<&Self> {
364
9.12k
        debug_assert!(matches!(
365
0
            types[core_ty_id].composite_type.inner,
366
            CompositeInnerType::Func(_)
367
        ));
368
369
9.12k
        if let Some(idx) = self.post_return {
370
6.53k
            let post_return_func_ty = types[state.core_function_at(idx, offset)?].unwrap_func();
371
6.53k
            let core_ty = types[core_ty_id].unwrap_func();
372
6.53k
            if post_return_func_ty.params() != core_ty.results()
373
6.53k
                || !post_return_func_ty.results().is_empty()
374
            {
375
0
                bail!(
376
0
                    offset,
377
                    "canonical option `post-return` uses a core function with an incorrect signature"
378
                );
379
6.53k
            }
380
2.59k
        }
381
382
2.59k
        match self.concurrency {
383
6.53k
            Concurrency::Sync => {}
384
385
            Concurrency::Async { callback: None } => {
386
66
                require_feature::cm_async_stackful(
387
66
                    state.features,
388
                    "requires the component model async stackful feature",
389
66
                    offset,
390
0
                )?;
391
            }
392
393
            Concurrency::Async {
394
2.53k
                callback: Some(idx),
395
            } => {
396
2.53k
                let func_ty = types[state.core_function_at(idx, offset)?].unwrap_func();
397
2.53k
                if func_ty.params() != [ValType::I32; 3] && func_ty.params() != [ValType::I32] {
398
0
                    return Err(Error::new(
399
0
                        "canonical option `callback` uses a core function with an incorrect signature",
400
0
                        offset,
401
0
                    ));
402
2.53k
                }
403
            }
404
        }
405
406
9.12k
        if self.core_type.is_some() {
407
0
            bail!(
408
0
                offset,
409
                "canonical option `core-type` is not allowed in `canon lift`"
410
            )
411
9.12k
        }
412
9.12k
        self.core_type = Some(core_ty_id);
413
414
9.12k
        Ok(self)
415
9.12k
    }
416
417
14.0k
    fn check_asyncness(&self, ty: &ComponentFuncType, offset: usize) -> Result<()> {
418
        // The `async` canonical ABI option is only allowed with `async`-typed
419
        // functions.
420
14.0k
        if self.concurrency.is_async() && !ty.async_ {
421
0
            bail!(
422
0
                offset,
423
                "the `async` canonical option requires an async function type",
424
            );
425
14.0k
        }
426
14.0k
        Ok(())
427
14.0k
    }
428
429
258
    pub(crate) fn check_core_type(
430
258
        &self,
431
258
        types: &mut TypeAlloc,
432
258
        actual: FuncType,
433
258
        offset: usize,
434
258
    ) -> Result<CoreTypeId> {
435
258
        if let Some(declared_id) = self.core_type {
436
0
            let declared = types[declared_id].unwrap_func();
437
438
0
            if actual.params() != declared.params() {
439
0
                bail!(
440
0
                    offset,
441
                    "declared core type has `{:?}` parameter types, but actual lowering has \
442
                     `{:?}` parameter types",
443
0
                    declared.params(),
444
0
                    actual.params(),
445
                );
446
0
            }
447
448
0
            if actual.results() != declared.results() {
449
0
                bail!(
450
0
                    offset,
451
                    "declared core type has `{:?}` result types, but actual lowering has \
452
                     `{:?}` result types",
453
0
                    declared.results(),
454
0
                    actual.results(),
455
                );
456
0
            }
457
458
0
            Ok(declared_id)
459
        } else {
460
258
            Ok(types.intern_func_type(actual, offset))
461
        }
462
258
    }
463
}
464
465
impl ComponentState {
466
139k
    pub fn new(kind: ComponentKind, features: WasmFeatures) -> Self {
467
139k
        Self {
468
139k
            kind,
469
139k
            features,
470
139k
            core_types: Default::default(),
471
139k
            core_modules: Default::default(),
472
139k
            core_instances: Default::default(),
473
139k
            core_funcs: Default::default(),
474
139k
            core_memories: Default::default(),
475
139k
            core_tables: Default::default(),
476
139k
            core_globals: Default::default(),
477
139k
            core_tags: Default::default(),
478
139k
            types: Default::default(),
479
139k
            funcs: Default::default(),
480
139k
            values: Default::default(),
481
139k
            instances: Default::default(),
482
139k
            components: Default::default(),
483
139k
            imports: Default::default(),
484
139k
            exports: Default::default(),
485
139k
            import_names: Default::default(),
486
139k
            export_names: Default::default(),
487
139k
            has_start: Default::default(),
488
139k
            type_info: TypeInfo::new(),
489
139k
            imported_resources: Default::default(),
490
139k
            defined_resources: Default::default(),
491
139k
            explicit_resources: Default::default(),
492
139k
            exported_types: Default::default(),
493
139k
            imported_types: Default::default(),
494
139k
            toplevel_exported_resources: Default::default(),
495
139k
            toplevel_imported_resources: Default::default(),
496
139k
            context_type: None,
497
139k
        }
498
139k
    }
499
500
328k
    pub fn type_count(&self) -> usize {
501
328k
        self.core_types.len() + self.types.len()
502
328k
    }
503
504
86.2k
    pub fn instance_count(&self) -> usize {
505
86.2k
        self.core_instances.len() + self.instances.len()
506
86.2k
    }
507
508
111k
    pub fn function_count(&self) -> usize {
509
111k
        self.core_funcs.len() + self.funcs.len()
510
111k
    }
511
512
0
    pub fn add_core_type(
513
0
        components: &mut [Self],
514
0
        ty: crate::CoreType,
515
0
        types: &mut TypeAlloc,
516
0
        offset: usize,
517
0
        check_limit: bool,
518
0
    ) -> Result<()> {
519
0
        let current = components.last_mut().unwrap();
520
0
        if check_limit {
521
0
            check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
522
0
        }
523
0
        match ty {
524
0
            crate::CoreType::Rec(rec) => {
525
0
                current.canonicalize_and_intern_rec_group(types, rec, offset)?;
526
            }
527
0
            crate::CoreType::Module(decls) => {
528
0
                let mod_ty = Self::create_module_type(components, decls.into_vec(), types, offset)?;
529
0
                let id = ComponentCoreTypeId::Module(types.push_ty(mod_ty));
530
0
                components.last_mut().unwrap().core_types.push(id);
531
            }
532
        }
533
534
0
        Ok(())
535
0
    }
536
537
21.7k
    pub fn add_core_module(
538
21.7k
        &mut self,
539
21.7k
        module: &Module,
540
21.7k
        types: &mut TypeAlloc,
541
21.7k
        offset: usize,
542
21.7k
    ) -> Result<()> {
543
21.7k
        let imports = module.imports_for_module_type(offset)?;
544
545
        // We have to clone the module's imports and exports here
546
        // because we cannot take the data out of the `MaybeOwned`
547
        // as it might be shared with a function validator.
548
21.7k
        let mod_ty = ModuleType {
549
21.7k
            info: TypeInfo::core(module.type_size),
550
21.7k
            imports,
551
21.7k
            exports: module.exports.clone(),
552
21.7k
        };
553
554
21.7k
        let mod_id = types.push_ty(mod_ty);
555
21.7k
        self.core_modules.push(mod_id);
556
557
21.7k
        Ok(())
558
21.7k
    }
559
560
38.5k
    pub fn add_core_instance(
561
38.5k
        &mut self,
562
38.5k
        instance: crate::Instance,
563
38.5k
        types: &mut TypeAlloc,
564
38.5k
        offset: usize,
565
38.5k
    ) -> Result<()> {
566
38.5k
        let instance = match instance {
567
21.7k
            crate::Instance::Instantiate { module_index, args } => {
568
21.7k
                self.instantiate_core_module(module_index, args.into_vec(), types, offset)?
569
            }
570
16.7k
            crate::Instance::FromExports(exports) => {
571
16.7k
                self.instantiate_core_exports(exports.into_vec(), types, offset)?
572
            }
573
        };
574
575
38.5k
        self.core_instances.push(instance);
576
577
38.5k
        Ok(())
578
38.5k
    }
579
580
379k
    pub fn add_type(
581
379k
        components: &mut Vec<Self>,
582
379k
        ty: crate::ComponentType,
583
379k
        types: &mut TypeAlloc,
584
379k
        offset: usize,
585
379k
        check_limit: bool,
586
379k
    ) -> Result<()> {
587
379k
        assert!(!components.is_empty());
588
589
644k
        fn current(components: &mut Vec<ComponentState>) -> &mut ComponentState {
590
644k
            components.last_mut().unwrap()
591
644k
        }
592
593
379k
        let id = match ty {
594
227k
            crate::ComponentType::Defined(ty) => {
595
227k
                let ty = current(components).create_defined_type(ty, types, offset)?;
596
227k
                let depth = ty.type_info(types).depth();
597
227k
                if depth > MAX_WASM_COMPONENT_TYPE_DEPTH {
598
0
                    bail!(offset, "type nesting is too deep");
599
227k
                }
600
227k
                types.push(ty).into()
601
            }
602
37.2k
            crate::ComponentType::Func(ty) => {
603
37.2k
                let ty = current(components).create_function_type(ty, types, offset)?;
604
37.2k
                types.push(ty).into()
605
            }
606
63.1k
            crate::ComponentType::Component(decls) => {
607
63.1k
                let ty = Self::create_component_type(components, decls.into_vec(), types, offset)?;
608
63.0k
                types.push(ty).into()
609
            }
610
51.3k
            crate::ComponentType::Instance(decls) => {
611
51.3k
                let ty = Self::create_instance_type(components, decls.into_vec(), types, offset)?;
612
51.3k
                types.push(ty).into()
613
            }
614
636
            crate::ComponentType::Resource { rep, dtor } => {
615
636
                let component = current(components);
616
617
                // Resource types cannot be declared in a type context, only
618
                // within a component context.
619
636
                if component.kind != ComponentKind::Component {
620
0
                    bail!(
621
0
                        offset,
622
                        "resources can only be defined within a concrete component"
623
                    );
624
636
                }
625
626
                // Current MVP restriction of the component model.
627
636
                if rep == ValType::I64 {
628
0
                    require_feature::cm64(
629
0
                        component.features,
630
                        "resources with `i64` require the `cm64` feature to be enabled",
631
0
                        offset,
632
0
                    )?;
633
636
                }
634
636
                if rep != ValType::I32 && rep != ValType::I64 {
635
0
                    bail!(
636
0
                        offset,
637
                        "resources can only be represented by `i32` or `i64`"
638
                    );
639
636
                }
640
641
                // If specified validate that the destructor is both a valid
642
                // function and has the correct signature.
643
636
                if let Some(dtor) = dtor {
644
636
                    let ty = component.core_function_at(dtor, offset)?;
645
636
                    let ty = types[ty].composite_type.unwrap_func();
646
636
                    if ty.params() != [rep] || ty.results() != [] {
647
0
                        bail!(
648
0
                            offset,
649
                            "core function {dtor} has wrong signature for a destructor"
650
                        );
651
636
                    }
652
0
                }
653
654
                // As this is the introduction of a resource create a fresh new
655
                // identifier for the resource. This is then added into the
656
                // list of defined resources for this component, notably with a
657
                // rep listed to enable getting access to various intrinsics
658
                // such as `resource.rep`.
659
636
                let id = types.alloc_resource_id();
660
636
                component.defined_resources.insert(id.resource(), Some(rep));
661
636
                id.into()
662
            }
663
        };
664
665
379k
        let current = current(components);
666
379k
        if check_limit {
667
222k
            check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
668
156k
        }
669
379k
        current.types.push(id);
670
671
379k
        Ok(())
672
379k
    }
673
674
33.8k
    pub fn add_import(
675
33.8k
        &mut self,
676
33.8k
        import: crate::ComponentImport<'_>,
677
33.8k
        types: &mut TypeAlloc,
678
33.8k
        offset: usize,
679
33.8k
    ) -> Result<()> {
680
33.8k
        let mut entity = self.check_type_ref(&import.ty, types, offset)?;
681
33.8k
        self.add_entity(
682
33.8k
            &mut entity,
683
33.8k
            Some((import.name.name, ExternKind::Import)),
684
33.8k
            types,
685
33.8k
            offset,
686
0
        )?;
687
33.8k
        self.toplevel_imported_resources.validate_extern(
688
33.8k
            &import.name,
689
33.8k
            ExternKind::Import,
690
33.8k
            &entity,
691
33.8k
            types,
692
33.8k
            offset,
693
33.8k
            &mut self.import_names,
694
33.8k
            &mut self.imports,
695
33.8k
            &mut self.type_info,
696
33.8k
            &self.features,
697
0
        )?;
698
33.8k
        Ok(())
699
33.8k
    }
700
701
306k
    fn add_entity(
702
306k
        &mut self,
703
306k
        ty: &mut ComponentEntityType,
704
306k
        name_and_kind: Option<(&str, ExternKind)>,
705
306k
        types: &mut TypeAlloc,
706
306k
        offset: usize,
707
306k
    ) -> Result<()> {
708
306k
        let kind = name_and_kind.map(|(_, k)| k);
709
306k
        let (len, max, desc) = match ty {
710
0
            ComponentEntityType::Module(id) => {
711
0
                self.core_modules.push(*id);
712
0
                (self.core_modules.len(), MAX_WASM_MODULES, "modules")
713
            }
714
13.6k
            ComponentEntityType::Component(id) => {
715
13.6k
                self.components.push(*id);
716
13.6k
                (self.components.len(), MAX_WASM_COMPONENTS, "components")
717
            }
718
56.5k
            ComponentEntityType::Instance(id) => {
719
56.5k
                match kind {
720
8.31k
                    Some(ExternKind::Import) => self.prepare_instance_import(id, types),
721
48.2k
                    Some(ExternKind::Export) => self.prepare_instance_export(id, types),
722
0
                    None => {}
723
                }
724
56.5k
                self.instances.push(*id);
725
56.5k
                (self.instance_count(), MAX_WASM_INSTANCES, "instances")
726
            }
727
56.0k
            ComponentEntityType::Func(id) => {
728
56.0k
                self.funcs.push(*id);
729
56.0k
                (self.function_count(), MAX_WASM_FUNCTIONS, "functions")
730
            }
731
0
            ComponentEntityType::Value(ty) => {
732
0
                self.check_value_support(offset)?;
733
0
                let value_used = match kind {
734
0
                    Some(ExternKind::Import) | None => false,
735
0
                    Some(ExternKind::Export) => true,
736
                };
737
0
                self.values.push((*ty, value_used));
738
0
                (self.values.len(), MAX_WASM_VALUES, "values")
739
            }
740
            ComponentEntityType::Type {
741
180k
                created,
742
180k
                referenced,
743
            } => {
744
180k
                self.types.push(*created);
745
746
                // Extra logic here for resources being imported and exported.
747
                // Note that if `created` is the same as `referenced` then this
748
                // is the original introduction of the resource which is where
749
                // `self.{imported,defined}_resources` are updated.
750
180k
                if let ComponentAnyTypeId::Resource(id) = *created {
751
5.54k
                    match kind {
752
                        Some(ExternKind::Import) => {
753
                            // A fresh new resource is being imported into a
754
                            // component. This arises from the import section of
755
                            // a component or from the import declaration in a
756
                            // component type. In both cases a new imported
757
                            // resource is injected with a fresh new identifier
758
                            // into our state.
759
1.53k
                            if created == referenced {
760
1.42k
                                self.imported_resources
761
1.42k
                                    .insert(id.resource(), vec![self.imports.len()]);
762
1.42k
                            }
763
                        }
764
765
                        Some(ExternKind::Export) => {
766
                            // A fresh resource is being exported from this
767
                            // component. This arises as part of the
768
                            // declaration of a component type, for example. In
769
                            // this situation brand new resource identifier is
770
                            // allocated and a definition is added, unlike the
771
                            // import case where an imported resource is added.
772
                            // Notably the representation of this new resource
773
                            // is unknown so it's listed as `None`.
774
4.01k
                            if created == referenced {
775
2.69k
                                self.defined_resources.insert(id.resource(), None);
776
2.69k
                            }
777
778
                            // If this is a type export of a resource type then
779
                            // update the `explicit_resources` list. A new
780
                            // export path is about to be created for this
781
                            // resource and this keeps track of that.
782
4.01k
                            self.explicit_resources
783
4.01k
                                .insert(id.resource(), vec![self.exports.len()]);
784
                        }
785
786
766
                        None => {}
787
                    }
788
174k
                }
789
180k
                (self.types.len(), MAX_WASM_TYPES, "types")
790
            }
791
        };
792
793
306k
        check_max(len, 0, max, desc, offset)?;
794
795
        // Before returning perform the final validation of the type of the item
796
        // being imported/exported. This will ensure that everything is
797
        // appropriately named with respect to type definitions, resources, etc.
798
306k
        if let Some((name, kind)) = name_and_kind {
799
295k
            if !self.validate_and_register_named_types(Some(name), kind, ty, types) {
800
0
                bail!(
801
0
                    offset,
802
                    "{} not valid to be used as {}",
803
0
                    ty.desc(),
804
0
                    kind.desc()
805
                );
806
295k
            }
807
11.3k
        }
808
306k
        Ok(())
809
306k
    }
810
811
    /// Validates that the `ty` referenced only refers to named types internally
812
    /// and then inserts anything necessary, if applicable, to the defined sets
813
    /// within this component.
814
    ///
815
    /// This function will validate that `ty` only refers to named types. For
816
    /// example if it's a record then all of its fields must refer to named
817
    /// types. This consults either `self.imported_types` or
818
    /// `self.exported_types` as specified by `kind`. Note that this is not
819
    /// inherently recursive itself but it ends up being recursive since if
820
    /// recursive members were named then all their components must also be
821
    /// named. Consequently this check stops at the "one layer deep" position,
822
    /// or more accurately the position where types must be named (e.g. tuples
823
    /// aren't required to be named).
824
444k
    fn validate_and_register_named_types(
825
444k
        &mut self,
826
444k
        toplevel_name: Option<&str>,
827
444k
        kind: ExternKind,
828
444k
        ty: &ComponentEntityType,
829
444k
        types: &TypeAlloc,
830
444k
    ) -> bool {
831
444k
        if let ComponentEntityType::Type { created, .. } = ty {
832
            // If this is a top-level resource then register it in the
833
            // appropriate context so later validation of method-like-names
834
            // works out.
835
283k
            if let Some(name) = toplevel_name {
836
172k
                if let ComponentAnyTypeId::Resource(id) = *created {
837
5.54k
                    let cx = match kind {
838
1.53k
                        ExternKind::Import => &mut self.toplevel_imported_resources,
839
4.01k
                        ExternKind::Export => &mut self.toplevel_exported_resources,
840
                    };
841
5.54k
                    cx.register(name, id);
842
166k
                }
843
110k
            }
844
161k
        }
845
846
444k
        match self.kind {
847
328k
            ComponentKind::Component | ComponentKind::ComponentType => {}
848
115k
            ComponentKind::InstanceType => return true,
849
        }
850
328k
        let set = match kind {
851
78.1k
            ExternKind::Import => &self.imported_types,
852
250k
            ExternKind::Export => &self.exported_types,
853
        };
854
328k
        match ty {
855
            // When a type is imported or exported than any recursive type
856
            // referred to by that import/export must additionally be exported
857
            // or imported. Here this walks the "first layer" of the type which
858
            // delegates to `TypeAlloc::type_named_type_id` to determine whether
859
            // the components of the type being named here are indeed all they
860
            // themselves named.
861
            ComponentEntityType::Type {
862
196k
                created,
863
196k
                referenced,
864
            } => {
865
196k
                if !self.all_valtypes_named(types, *referenced, set) {
866
0
                    return false;
867
196k
                }
868
196k
                match kind {
869
                    // Imported types are both valid for import and valid for
870
                    // export.
871
49.4k
                    ExternKind::Import => {
872
49.4k
                        self.imported_types.insert(*created);
873
49.4k
                        self.exported_types.insert(*created);
874
49.4k
                    }
875
147k
                    ExternKind::Export => {
876
147k
                        self.exported_types.insert(*created);
877
147k
                    }
878
                }
879
880
196k
                true
881
            }
882
883
            // Instances are slightly nuanced here. The general idea is that if
884
            // an instance is imported, then any type exported by the instance
885
            // is then also exported. Additionally for exports. To get this to
886
            // work out this arm will recursively call
887
            // `validate_and_register_named_types` which means that types are
888
            // inserted into `self.{imported,exported}_types` as-we-go rather
889
            // than all at once.
890
            //
891
            // This then recursively validates that all items in the instance
892
            // itself are valid to import/export, recursive instances are
893
            // captured, and everything is appropriately added to the right
894
            // imported/exported set.
895
148k
            ComponentEntityType::Instance(i) => types[*i].exports.iter().all(|(_name, ty)| {
896
148k
                self.validate_and_register_named_types(None, kind, &ty.ty, types)
897
148k
            }),
898
899
            // All types referred to by a function must be named.
900
61.5k
            ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, *id, set),
901
902
0
            ComponentEntityType::Value(ty) => types.type_named_valtype(ty, set),
903
904
            // Components/modules are always "closed" or "standalone" and don't
905
            // need validation with respect to their named types.
906
13.6k
            ComponentEntityType::Component(_) | ComponentEntityType::Module(_) => true,
907
        }
908
444k
    }
909
910
196k
    fn all_valtypes_named(
911
196k
        &self,
912
196k
        types: &TypeAlloc,
913
196k
        id: ComponentAnyTypeId,
914
196k
        set: &Set<ComponentAnyTypeId>,
915
196k
    ) -> bool {
916
196k
        match id {
917
            // Resource types, in isolation, are always valid to import or
918
            // export since they're either attached to an import or being
919
            // exported.
920
            //
921
            // Note that further validation of this happens in `finish`, too.
922
6.19k
            ComponentAnyTypeId::Resource(_) => true,
923
924
            // Component types are validated as they are constructed,
925
            // so all component types are valid to export if they've
926
            // already been constructed.
927
49.4k
            ComponentAnyTypeId::Component(_) => true,
928
929
141k
            ComponentAnyTypeId::Defined(id) => self.all_valtypes_named_in_defined(types, id, set),
930
0
            ComponentAnyTypeId::Func(id) => self.all_valtypes_named_in_func(types, id, set),
931
0
            ComponentAnyTypeId::Instance(id) => self.all_valtypes_named_in_instance(types, id, set),
932
        }
933
196k
    }
934
935
0
    fn all_valtypes_named_in_instance(
936
0
        &self,
937
0
        types: &TypeAlloc,
938
0
        id: ComponentInstanceTypeId,
939
0
        set: &Set<ComponentAnyTypeId>,
940
0
    ) -> bool {
941
        // Instances must recursively have all referenced types named.
942
0
        let ty = &types[id];
943
0
        ty.exports.values().all(|ty| match ty.ty {
944
0
            ComponentEntityType::Module(_) => true,
945
0
            ComponentEntityType::Func(id) => self.all_valtypes_named_in_func(types, id, set),
946
0
            ComponentEntityType::Type { created: id, .. } => {
947
0
                self.all_valtypes_named(types, id, set)
948
            }
949
0
            ComponentEntityType::Value(ComponentValType::Type(id)) => {
950
0
                self.all_valtypes_named_in_defined(types, id, set)
951
            }
952
0
            ComponentEntityType::Instance(id) => {
953
0
                self.all_valtypes_named_in_instance(types, id, set)
954
            }
955
            ComponentEntityType::Component(_)
956
0
            | ComponentEntityType::Value(ComponentValType::Primitive(_)) => return true,
957
0
        })
958
0
    }
959
960
141k
    fn all_valtypes_named_in_defined(
961
141k
        &self,
962
141k
        types: &TypeAlloc,
963
141k
        id: ComponentDefinedTypeId,
964
141k
        set: &Set<ComponentAnyTypeId>,
965
141k
    ) -> bool {
966
141k
        let ty = &types[id];
967
141k
        match ty {
968
            // These types do not contain anything which must be
969
            // named.
970
            ComponentDefinedType::Primitive(_)
971
            | ComponentDefinedType::Flags(_)
972
100k
            | ComponentDefinedType::Enum(_) => true,
973
974
            // Referenced types of all these aggregates must all be
975
            // named.
976
15.8k
            ComponentDefinedType::Record(r) => {
977
62.4k
                r.fields.values().all(|t| types.type_named_valtype(t, set))
978
            }
979
589
            ComponentDefinedType::Tuple(r) => {
980
1.07k
                r.types.iter().all(|t| types.type_named_valtype(t, set))
981
            }
982
23.1k
            ComponentDefinedType::Variant(r) => r
983
23.1k
                .cases
984
23.1k
                .values()
985
85.9k
                .filter_map(|t| t.ty.as_ref())
986
69.9k
                .all(|t| types.type_named_valtype(t, set)),
987
231
            ComponentDefinedType::Result { ok, err, .. } => {
988
231
                ok.as_ref()
989
231
                    .map(|t| types.type_named_valtype(t, set))
990
231
                    .unwrap_or(true)
991
231
                    && err
992
231
                        .as_ref()
993
231
                        .map(|t| types.type_named_valtype(t, set))
994
231
                        .unwrap_or(true)
995
            }
996
189
            ComponentDefinedType::List { element: ty, .. }
997
23
            | ComponentDefinedType::FixedLengthList { element: ty, .. }
998
902
            | ComponentDefinedType::Option { ty, .. } => types.type_named_valtype(ty, set),
999
0
            ComponentDefinedType::Map { key, value, .. } => {
1000
0
                types.type_named_valtype(key, set) && types.type_named_valtype(value, set)
1001
            }
1002
1003
            // The resource referred to by own/borrow must be named.
1004
0
            ComponentDefinedType::Own(id) | ComponentDefinedType::Borrow(id) => {
1005
0
                set.contains(&ComponentAnyTypeId::from(*id))
1006
            }
1007
1008
49
            ComponentDefinedType::Future { ty, .. } | ComponentDefinedType::Stream { ty, .. } => ty
1009
49
                .as_ref()
1010
49
                .map(|ty| types.type_named_valtype(ty, set))
1011
49
                .unwrap_or(true),
1012
        }
1013
141k
    }
1014
1015
61.5k
    fn all_valtypes_named_in_func(
1016
61.5k
        &self,
1017
61.5k
        types: &TypeAlloc,
1018
61.5k
        id: ComponentFuncTypeId,
1019
61.5k
        set: &Set<ComponentAnyTypeId>,
1020
61.5k
    ) -> bool {
1021
61.5k
        let ty = &types[id];
1022
        // Function types must have all their parameters/results named.
1023
61.5k
        ty.params
1024
61.5k
            .iter()
1025
61.5k
            .map(|(_, ty)| ty)
1026
61.5k
            .chain(&ty.result)
1027
181k
            .all(|ty| types.type_named_valtype(ty, set))
1028
61.5k
    }
1029
1030
    /// Updates the type `id` specified, an identifier for a component instance
1031
    /// type, to be imported into this component.
1032
    ///
1033
    /// Importing an instance type into a component specially handles the
1034
    /// defined resources registered in the instance type. Notably all
1035
    /// defined resources are "freshened" into brand new type variables and
1036
    /// these new variables are substituted within the type. This is what
1037
    /// creates a new `TypeId` and may update the `id` specified.
1038
    ///
1039
    /// One side effect of this operation, for example, is that if an instance
1040
    /// type is used twice to import two different instances then the instances
1041
    /// do not share resource types despite sharing the same original instance
1042
    /// type.
1043
8.31k
    fn prepare_instance_import(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
1044
8.31k
        let ty = &types[*id];
1045
1046
        // No special treatment for imports of instances which themselves have
1047
        // no defined resources
1048
8.31k
        if ty.defined_resources.is_empty() {
1049
7.42k
            return;
1050
886
        }
1051
1052
886
        let mut new_ty = ComponentInstanceType {
1053
886
            // Copied from the input verbatim
1054
886
            info: ty.info,
1055
886
1056
886
            // Copied over as temporary storage for now, and both of these are
1057
886
            // filled out and expanded below.
1058
886
            exports: ty.exports.clone(),
1059
886
            explicit_resources: ty.explicit_resources.clone(),
1060
886
1061
886
            // Explicitly discard this field since the
1062
886
            // defined resources are lifted into `self`
1063
886
            defined_resources: Default::default(),
1064
886
        };
1065
1066
        // Create brand new resources for all defined ones in the instance.
1067
886
        let resources = (0..ty.defined_resources.len())
1068
1.07k
            .map(|_| types.alloc_resource_id())
1069
886
            .collect::<IndexSet<_>>();
1070
1071
        // Build a map from the defined resources in `ty` to those in `new_ty`.
1072
        //
1073
        // As part of this same loop the new resources, which were previously
1074
        // defined in `ty`, now become imported variables in `self`. Their
1075
        // path for where they're imported is updated as well with
1076
        // `self.next_import_index` as the import-to-be soon.
1077
886
        let mut mapping = Remapping::default();
1078
886
        let ty = &types[*id];
1079
1.07k
        for (old, new) in ty.defined_resources.iter().zip(&resources) {
1080
1.07k
            let prev = mapping.resources.insert(*old, new.resource());
1081
1.07k
            assert!(prev.is_none());
1082
1083
1.07k
            let mut base = vec![self.imports.len()];
1084
1.07k
            base.extend(ty.explicit_resources[old].iter().copied());
1085
1.07k
            self.imported_resources.insert(new.resource(), base);
1086
        }
1087
1088
        // Using the old-to-new resource mapping perform a substitution on
1089
        // the `exports` and `explicit_resources` fields of `new_ty`
1090
5.74k
        for ty in new_ty.exports.values_mut() {
1091
5.74k
            types.remap_component_entity(&mut ty.ty, &mut mapping);
1092
5.74k
        }
1093
1.11k
        for (id, path) in mem::take(&mut new_ty.explicit_resources) {
1094
1.11k
            let id = *mapping.resources.get(&id).unwrap_or(&id);
1095
1.11k
            new_ty.explicit_resources.insert(id, path);
1096
1.11k
        }
1097
1098
        // Now that `new_ty` is complete finish its registration and then
1099
        // update `id` on the way out.
1100
886
        *id = types.push_ty(new_ty);
1101
8.31k
    }
1102
1103
    /// Prepares an instance type, pointed to `id`, for being exported as a
1104
    /// concrete instance from `self`.
1105
    ///
1106
    /// This will internally perform any resource "freshening" as required and
1107
    /// then additionally update metadata within `self` about resources being
1108
    /// exported or defined.
1109
48.2k
    fn prepare_instance_export(&mut self, id: &mut ComponentInstanceTypeId, types: &mut TypeAlloc) {
1110
        // Exports of an instance mean that the enclosing context
1111
        // is inheriting the resources that the instance
1112
        // encapsulates. This means that the instance type
1113
        // recorded for this export will itself have no
1114
        // defined resources.
1115
48.2k
        let ty = &types[*id];
1116
1117
        // Check to see if `defined_resources` is non-empty, and if so then
1118
        // "freshen" all the resources and inherit them to our own defined
1119
        // resources, updating `id` in the process.
1120
        //
1121
        // Note though that this specifically is not rewriting the resources of
1122
        // exported instances. The `defined_resources` set on instance types is
1123
        // a little subtle (see its documentation for more info), but the
1124
        // general idea is that for a concrete instance it's always empty. Only
1125
        // for instance type definitions does it ever have elements in it.
1126
        //
1127
        // That means that if this set is non-empty then what's happening is
1128
        // that we're in a type context an exporting an instance of a previously
1129
        // specified type. In this case all resources are required to be
1130
        // "freshened" to ensure that multiple exports of the same type all
1131
        // export different types of resources.
1132
        //
1133
        // And finally note that this operation empties out the
1134
        // `defined_resources` set of the type that is registered for the
1135
        // instance, as this export is modeled as producing a concrete instance.
1136
48.2k
        if !ty.defined_resources.is_empty() {
1137
1.43k
            let mut new_ty = ty.clone();
1138
1.43k
            let mut mapping = Remapping::default();
1139
1.61k
            for old in mem::take(&mut new_ty.defined_resources) {
1140
1.61k
                let new = types.alloc_resource_id();
1141
1.61k
                mapping.resources.insert(old, new.resource());
1142
1.61k
                self.defined_resources.insert(new.resource(), None);
1143
1.61k
            }
1144
12.0k
            for ty in new_ty.exports.values_mut() {
1145
12.0k
                types.remap_component_entity(&mut ty.ty, &mut mapping);
1146
12.0k
            }
1147
1.65k
            for (id, path) in mem::take(&mut new_ty.explicit_resources) {
1148
1.65k
                let id = mapping.resources.get(&id).copied().unwrap_or(id);
1149
1.65k
                new_ty.explicit_resources.insert(id, path);
1150
1.65k
            }
1151
1.43k
            *id = types.push_ty(new_ty);
1152
46.7k
        }
1153
1154
        // Any explicit resources in the instance are now additionally explicit
1155
        // in this component since it's exported.
1156
        //
1157
        // The path to each explicit resources gets one element prepended which
1158
        // is `self.next_export_index`, the index of the export about to be
1159
        // generated.
1160
48.2k
        let ty = &types[*id];
1161
48.2k
        for (id, path) in ty.explicit_resources.iter() {
1162
2.51k
            let mut new_path = vec![self.exports.len()];
1163
2.51k
            new_path.extend(path);
1164
2.51k
            self.explicit_resources.insert(*id, new_path);
1165
2.51k
        }
1166
48.2k
    }
1167
1168
261k
    pub fn add_export(
1169
261k
        &mut self,
1170
261k
        name: ComponentExternName<'_>,
1171
261k
        mut ty: ComponentEntityType,
1172
261k
        types: &mut TypeAlloc,
1173
261k
        offset: usize,
1174
261k
        check_limit: bool,
1175
261k
    ) -> Result<()> {
1176
261k
        if check_limit {
1177
173k
            check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?;
1178
88.4k
        }
1179
261k
        self.add_entity(
1180
261k
            &mut ty,
1181
261k
            Some((name.name, ExternKind::Export)),
1182
261k
            types,
1183
261k
            offset,
1184
0
        )?;
1185
261k
        self.toplevel_exported_resources.validate_extern(
1186
261k
            &name,
1187
261k
            ExternKind::Export,
1188
261k
            &ty,
1189
261k
            types,
1190
261k
            offset,
1191
261k
            &mut self.export_names,
1192
261k
            &mut self.exports,
1193
261k
            &mut self.type_info,
1194
261k
            &self.features,
1195
0
        )?;
1196
261k
        Ok(())
1197
261k
    }
1198
1199
42.9k
    pub fn canonical_function(
1200
42.9k
        &mut self,
1201
42.9k
        func: CanonicalFunction,
1202
42.9k
        types: &mut TypeAlloc,
1203
42.9k
        offset: usize,
1204
42.9k
    ) -> Result<()> {
1205
42.9k
        match func {
1206
            CanonicalFunction::Lift {
1207
9.12k
                core_func_index,
1208
9.12k
                type_index,
1209
9.12k
                options,
1210
9.12k
            } => self.lift_function(core_func_index, type_index, &options, types, offset),
1211
            CanonicalFunction::Lower {
1212
4.94k
                func_index,
1213
4.94k
                options,
1214
4.94k
            } => self.lower_function(func_index, &options, types, offset),
1215
636
            CanonicalFunction::ResourceNew { resource } => {
1216
636
                self.resource_new(resource, types, offset)
1217
            }
1218
1.23k
            CanonicalFunction::ResourceDrop { resource } => {
1219
1.23k
                self.resource_drop(resource, types, offset)
1220
            }
1221
636
            CanonicalFunction::ResourceRep { resource } => {
1222
636
                self.resource_rep(resource, types, offset)
1223
            }
1224
0
            CanonicalFunction::ThreadSpawnRef { func_ty_index } => {
1225
0
                self.thread_spawn_ref(func_ty_index, types, offset)
1226
            }
1227
            CanonicalFunction::ThreadSpawnIndirect {
1228
0
                func_ty_index,
1229
0
                table_index,
1230
0
            } => self.thread_spawn_indirect(func_ty_index, table_index, types, offset),
1231
            CanonicalFunction::ThreadAvailableParallelism => {
1232
0
                self.thread_available_parallelism(types, offset)
1233
            }
1234
1.54k
            CanonicalFunction::BackpressureInc => self.backpressure_inc(types, offset),
1235
1.54k
            CanonicalFunction::BackpressureDec => self.backpressure_dec(types, offset),
1236
2.82k
            CanonicalFunction::TaskReturn { result, options } => {
1237
2.82k
                self.task_return(&result, &options, types, offset)
1238
            }
1239
1.54k
            CanonicalFunction::TaskCancel => self.task_cancel(types, offset),
1240
1.54k
            CanonicalFunction::ContextGet { ty, slot } => self.context_get(ty, slot, types, offset),
1241
1.54k
            CanonicalFunction::ContextSet { ty, slot } => self.context_set(ty, slot, types, offset),
1242
1.54k
            CanonicalFunction::SubtaskDrop => self.subtask_drop(types, offset),
1243
1.54k
            CanonicalFunction::SubtaskCancel { async_ } => {
1244
1.54k
                self.subtask_cancel(async_, types, offset)
1245
            }
1246
60
            CanonicalFunction::StreamNew { ty } => self.stream_new(ty, types, offset),
1247
60
            CanonicalFunction::StreamRead { ty, options } => {
1248
60
                self.stream_read(ty, &options, types, offset)
1249
            }
1250
60
            CanonicalFunction::StreamWrite { ty, options } => {
1251
60
                self.stream_write(ty, &options, types, offset)
1252
            }
1253
60
            CanonicalFunction::StreamCancelRead { ty, async_ } => {
1254
60
                self.stream_cancel_read(ty, async_, types, offset)
1255
            }
1256
60
            CanonicalFunction::StreamCancelWrite { ty, async_ } => {
1257
60
                self.stream_cancel_write(ty, async_, types, offset)
1258
            }
1259
60
            CanonicalFunction::StreamDropReadable { ty } => {
1260
60
                self.stream_drop_readable(ty, types, offset)
1261
            }
1262
60
            CanonicalFunction::StreamDropWritable { ty } => {
1263
60
                self.stream_drop_writable(ty, types, offset)
1264
            }
1265
582
            CanonicalFunction::FutureNew { ty } => self.future_new(ty, types, offset),
1266
69
            CanonicalFunction::FutureRead { ty, options } => {
1267
69
                self.future_read(ty, &options, types, offset)
1268
            }
1269
69
            CanonicalFunction::FutureWrite { ty, options } => {
1270
69
                self.future_write(ty, &options, types, offset)
1271
            }
1272
582
            CanonicalFunction::FutureCancelRead { ty, async_ } => {
1273
582
                self.future_cancel_read(ty, async_, types, offset)
1274
            }
1275
582
            CanonicalFunction::FutureCancelWrite { ty, async_ } => {
1276
582
                self.future_cancel_write(ty, async_, types, offset)
1277
            }
1278
582
            CanonicalFunction::FutureDropReadable { ty } => {
1279
582
                self.future_drop_readable(ty, types, offset)
1280
            }
1281
582
            CanonicalFunction::FutureDropWritable { ty } => {
1282
582
                self.future_drop_writable(ty, types, offset)
1283
            }
1284
0
            CanonicalFunction::ErrorContextNew { options } => {
1285
0
                self.error_context_new(options.into_vec(), types, offset)
1286
            }
1287
0
            CanonicalFunction::ErrorContextDebugMessage { options } => {
1288
0
                self.error_context_debug_message(options.into_vec(), types, offset)
1289
            }
1290
0
            CanonicalFunction::ErrorContextDrop => self.error_context_drop(types, offset),
1291
1.54k
            CanonicalFunction::WaitableSetNew => self.waitable_set_new(types, offset),
1292
            CanonicalFunction::WaitableSetWait {
1293
                cancellable: _,
1294
1.54k
                memory,
1295
1.54k
            } => self.waitable_set_wait(memory, types, offset),
1296
            CanonicalFunction::WaitableSetPoll {
1297
                cancellable: _,
1298
1.54k
                memory,
1299
1.54k
            } => self.waitable_set_poll(memory, types, offset),
1300
1.54k
            CanonicalFunction::WaitableSetDrop => self.waitable_set_drop(types, offset),
1301
1.54k
            CanonicalFunction::WaitableJoin => self.waitable_join(types, offset),
1302
0
            CanonicalFunction::ThreadIndex => self.thread_index(types, offset),
1303
            CanonicalFunction::ThreadNewIndirect {
1304
0
                func_ty_index,
1305
0
                table_index,
1306
0
            } => self.thread_new_indirect(func_ty_index, table_index, types, offset),
1307
0
            CanonicalFunction::ThreadResumeLater => self.thread_resume_later(types, offset),
1308
0
            CanonicalFunction::ThreadSuspend { cancellable } => {
1309
0
                self.thread_suspend(cancellable, types, offset)
1310
            }
1311
1.54k
            CanonicalFunction::ThreadYield { cancellable: _ } => self.thread_yield(types, offset),
1312
0
            CanonicalFunction::ThreadSuspendThenResume { cancellable } => {
1313
0
                self.thread_suspend_then_resume(cancellable, types, offset)
1314
            }
1315
0
            CanonicalFunction::ThreadYieldThenResume { cancellable } => {
1316
0
                self.thread_yield_then_resume(cancellable, types, offset)
1317
            }
1318
0
            CanonicalFunction::ThreadSuspendThenPromote { cancellable } => {
1319
0
                self.thread_suspend_then_promote(cancellable, types, offset)
1320
            }
1321
0
            CanonicalFunction::ThreadYieldThenPromote { cancellable } => {
1322
0
                self.thread_yield_then_promote(cancellable, types, offset)
1323
            }
1324
        }
1325
42.9k
    }
1326
1327
9.12k
    fn lift_function(
1328
9.12k
        &mut self,
1329
9.12k
        core_func_index: u32,
1330
9.12k
        type_index: u32,
1331
9.12k
        options: &[CanonicalOption],
1332
9.12k
        types: &mut TypeAlloc,
1333
9.12k
        offset: usize,
1334
9.12k
    ) -> Result<()> {
1335
9.12k
        let ty = self.function_type_at(type_index, types, offset)?;
1336
9.12k
        let core_ty_id = self.core_function_at(core_func_index, offset)?;
1337
1338
        // Lifting a function is for an export, so match the expected canonical ABI
1339
        // export signature
1340
9.12k
        let mut options = self.check_options(types, options, offset)?;
1341
9.12k
        options.check_lift(types, self, core_ty_id, offset)?;
1342
9.12k
        options.check_asyncness(ty, offset)?;
1343
9.12k
        let func_ty = ty.lower(types, &options, Abi::Lift, offset)?;
1344
9.12k
        let lowered_core_ty_id = func_ty.intern(types, offset);
1345
1346
9.12k
        if core_ty_id == lowered_core_ty_id {
1347
9.12k
            self.funcs
1348
9.12k
                .push(self.types[type_index as usize].unwrap_func());
1349
9.12k
            return Ok(());
1350
0
        }
1351
1352
0
        let ty = types[core_ty_id].unwrap_func();
1353
0
        let lowered_ty = types[lowered_core_ty_id].unwrap_func();
1354
1355
0
        if lowered_ty.params() != ty.params() {
1356
0
            bail!(
1357
0
                offset,
1358
                "lowered parameter types `{:?}` do not match parameter types `{:?}` of \
1359
                     core function {core_func_index}",
1360
0
                lowered_ty.params(),
1361
0
                ty.params()
1362
            );
1363
0
        }
1364
1365
0
        if lowered_ty.results() != ty.results() {
1366
0
            bail!(
1367
0
                offset,
1368
                "lowered result types `{:?}` do not match result types `{:?}` of \
1369
                     core function {core_func_index}",
1370
0
                lowered_ty.results(),
1371
0
                ty.results()
1372
            );
1373
0
        }
1374
1375
        // Otherwise, must be different rec groups or subtyping (which isn't
1376
        // supported yet) or something.
1377
0
        bail!(
1378
0
            offset,
1379
            "lowered function type `{:?}` does not match type `{:?}` of \
1380
                 core function {core_func_index}",
1381
0
            types[lowered_core_ty_id],
1382
0
            types[core_ty_id],
1383
        );
1384
9.12k
    }
1385
1386
4.94k
    fn lower_function(
1387
4.94k
        &mut self,
1388
4.94k
        func_index: u32,
1389
4.94k
        options: &[CanonicalOption],
1390
4.94k
        types: &mut TypeAlloc,
1391
4.94k
        offset: usize,
1392
4.94k
    ) -> Result<()> {
1393
4.94k
        let ty = &types[self.function_at(func_index, offset)?];
1394
1395
        // Lowering a function is for an import, so use a function type that matches
1396
        // the expected canonical ABI import signature.
1397
4.94k
        let options = self.check_options(types, options, offset)?;
1398
4.94k
        options.check_lower(offset)?;
1399
4.94k
        options.check_asyncness(ty, offset)?;
1400
1401
4.94k
        let func_ty = ty.lower(types, &options, Abi::Lower, offset)?;
1402
4.94k
        let ty_id = func_ty.intern(types, offset);
1403
1404
4.94k
        self.core_funcs.push(ty_id);
1405
4.94k
        Ok(())
1406
4.94k
    }
1407
1408
636
    fn resource_new(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1409
636
        let rep = self.check_local_resource(resource, types, offset)?;
1410
636
        let id = types.intern_func_type(FuncType::new([rep], [ValType::I32]), offset);
1411
636
        self.core_funcs.push(id);
1412
636
        Ok(())
1413
636
    }
1414
1415
1.23k
    fn resource_drop(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1416
1.23k
        self.resource_at(resource, types, offset)?;
1417
1.23k
        let id = types.intern_func_type(FuncType::new([ValType::I32], []), offset);
1418
1.23k
        self.core_funcs.push(id);
1419
1.23k
        Ok(())
1420
1.23k
    }
1421
1422
636
    fn resource_rep(&mut self, resource: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1423
636
        let rep = self.check_local_resource(resource, types, offset)?;
1424
636
        let id = types.intern_func_type(FuncType::new([ValType::I32], [rep]), offset);
1425
636
        self.core_funcs.push(id);
1426
636
        Ok(())
1427
636
    }
1428
1429
1.54k
    fn backpressure_inc(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1430
1.54k
        require_feature::cm_async(
1431
1.54k
            self.features,
1432
            "`backpressure.inc` requires the component model async feature",
1433
1.54k
            offset,
1434
0
        )?;
1435
1436
1.54k
        self.core_funcs
1437
1.54k
            .push(types.intern_func_type(FuncType::new([], []), offset));
1438
1.54k
        Ok(())
1439
1.54k
    }
1440
1441
1.54k
    fn backpressure_dec(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1442
1.54k
        require_feature::cm_async(
1443
1.54k
            self.features,
1444
            "`backpressure.dec` requires the component model async feature",
1445
1.54k
            offset,
1446
0
        )?;
1447
1448
1.54k
        self.core_funcs
1449
1.54k
            .push(types.intern_func_type(FuncType::new([], []), offset));
1450
1.54k
        Ok(())
1451
1.54k
    }
1452
1453
2.82k
    fn task_return(
1454
2.82k
        &mut self,
1455
2.82k
        result: &Option<crate::ComponentValType>,
1456
2.82k
        options: &[CanonicalOption],
1457
2.82k
        types: &mut TypeAlloc,
1458
2.82k
        offset: usize,
1459
2.82k
    ) -> Result<()> {
1460
2.82k
        require_feature::cm_async(
1461
2.82k
            self.features,
1462
            "`task.return` requires the component model async feature",
1463
2.82k
            offset,
1464
0
        )?;
1465
1466
2.82k
        let func_ty = ComponentFuncType {
1467
            async_: false,
1468
2.82k
            info: TypeInfo::new(),
1469
2.82k
            params: result
1470
2.82k
                .iter()
1471
2.82k
                .map(|ty| {
1472
                    Ok((
1473
2.73k
                        KebabString::new("v").unwrap(),
1474
2.73k
                        match ty {
1475
2.72k
                            crate::ComponentValType::Primitive(ty) => {
1476
2.72k
                                ComponentValType::Primitive(*ty)
1477
                            }
1478
12
                            crate::ComponentValType::Type(index) => {
1479
12
                                ComponentValType::Type(self.defined_type_at(*index, offset)?)
1480
                            }
1481
                        },
1482
                    ))
1483
2.73k
                })
1484
2.82k
                .collect::<Result<_>>()?,
1485
2.82k
            result: None,
1486
        };
1487
1488
2.82k
        let options = self.check_options(types, options, offset)?;
1489
2.82k
        if options.realloc.is_some() {
1490
0
            bail!(offset, "cannot specify `realloc` option on `task.return`")
1491
2.82k
        }
1492
2.82k
        if options.post_return.is_some() {
1493
0
            bail!(
1494
0
                offset,
1495
                "cannot specify `post-return` option on `task.return`"
1496
            )
1497
2.82k
        }
1498
2.82k
        options.check_lower(offset)?;
1499
2.82k
        options.require_sync(offset, "task.return")?;
1500
1501
2.82k
        let func_ty = func_ty.lower(types, &options, Abi::Lower, offset)?;
1502
2.82k
        let ty_id = func_ty.intern(types, offset);
1503
1504
2.82k
        self.core_funcs.push(ty_id);
1505
2.82k
        Ok(())
1506
2.82k
    }
1507
1508
1.54k
    fn task_cancel(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1509
1.54k
        require_feature::cm_async(
1510
1.54k
            self.features,
1511
            "`task.cancel` requires the component model async feature",
1512
1.54k
            offset,
1513
0
        )?;
1514
1515
1.54k
        self.core_funcs
1516
1.54k
            .push(types.intern_func_type(FuncType::new([], []), offset));
1517
1.54k
        Ok(())
1518
1.54k
    }
1519
1520
3.09k
    fn validate_context_immediate(
1521
3.09k
        &self,
1522
3.09k
        immediate: u32,
1523
3.09k
        operation: &str,
1524
3.09k
        offset: usize,
1525
3.09k
    ) -> Result<()> {
1526
3.09k
        if immediate > 0 {
1527
0
            require_feature::cm_threading(
1528
0
                self.features,
1529
0
                format_args!("`{operation}` immediate must be zero: {immediate}"),
1530
0
                offset,
1531
0
            )?;
1532
0
            if immediate > 1 {
1533
0
                bail!(
1534
0
                    offset,
1535
                    "`{operation}` immediate must be zero or one: {immediate}"
1536
                )
1537
0
            }
1538
3.09k
        }
1539
3.09k
        Ok(())
1540
3.09k
    }
1541
1542
1.54k
    fn context_get(
1543
1.54k
        &mut self,
1544
1.54k
        ty: ValType,
1545
1.54k
        i: u32,
1546
1.54k
        types: &mut TypeAlloc,
1547
1.54k
        offset: usize,
1548
1.54k
    ) -> Result<()> {
1549
1.54k
        require_feature::cm_async(
1550
1.54k
            self.features,
1551
            "`context.get` requires the component model async feature",
1552
1.54k
            offset,
1553
0
        )?;
1554
1.54k
        self.validate_context_type(ty, "context.get", offset)?;
1555
1.54k
        self.validate_context_immediate(i, "context.get", offset)?;
1556
1557
1.54k
        self.core_funcs
1558
1.54k
            .push(types.intern_func_type(FuncType::new([], [ty]), offset));
1559
1.54k
        Ok(())
1560
1.54k
    }
1561
1562
1.54k
    fn context_set(
1563
1.54k
        &mut self,
1564
1.54k
        ty: ValType,
1565
1.54k
        i: u32,
1566
1.54k
        types: &mut TypeAlloc,
1567
1.54k
        offset: usize,
1568
1.54k
    ) -> Result<()> {
1569
1.54k
        require_feature::cm_async(
1570
1.54k
            self.features,
1571
            "`context.set` requires the component model async feature",
1572
1.54k
            offset,
1573
0
        )?;
1574
1.54k
        self.validate_context_type(ty, "context.set", offset)?;
1575
1.54k
        self.validate_context_immediate(i, "context.set", offset)?;
1576
1577
1.54k
        self.core_funcs
1578
1.54k
            .push(types.intern_func_type(FuncType::new([ty], []), offset));
1579
1.54k
        Ok(())
1580
1.54k
    }
1581
1582
3.09k
    fn validate_context_type(&mut self, ty: ValType, intrinsic: &str, offset: usize) -> Result<()> {
1583
3.09k
        match ty {
1584
3.09k
            ValType::I32 => {}
1585
            ValType::I64 => {
1586
0
                require_feature::cm64(
1587
0
                    self.features,
1588
0
                    format_args!(
1589
                        "64-bit `{intrinsic}` requires the component model 64-bit feature"
1590
                    ),
1591
0
                    offset,
1592
0
                )?;
1593
0
                {}
1594
            }
1595
0
            _ => bail!(offset, "`{intrinsic}` only supports `i32` or `i64`"),
1596
        }
1597
1598
3.09k
        match self.context_type {
1599
1.54k
            None => self.context_type = Some(ty),
1600
1.54k
            Some(other) => {
1601
1.54k
                if other != ty {
1602
0
                    bail!(
1603
0
                        offset,
1604
                        "`{intrinsic}` type must match previous context type"
1605
                    )
1606
1.54k
                }
1607
            }
1608
        }
1609
3.09k
        Ok(())
1610
3.09k
    }
1611
1612
1.54k
    fn subtask_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1613
1.54k
        require_feature::cm_async(
1614
1.54k
            self.features,
1615
            "`subtask.drop` requires the component model async feature",
1616
1.54k
            offset,
1617
0
        )?;
1618
1619
1.54k
        self.core_funcs
1620
1.54k
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1621
1.54k
        Ok(())
1622
1.54k
    }
1623
1624
1.54k
    fn subtask_cancel(&mut self, async_: bool, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1625
1.54k
        require_feature::cm_async(
1626
1.54k
            self.features,
1627
            "`subtask.cancel` requires the component model async feature",
1628
1.54k
            offset,
1629
0
        )?;
1630
1.54k
        if async_ {
1631
0
            require_feature::cm_more_async_builtins(
1632
0
                self.features,
1633
                "async `subtask.cancel` requires the component model more async builtins feature",
1634
0
                offset,
1635
0
            )?;
1636
1.54k
        }
1637
1638
1.54k
        self.core_funcs
1639
1.54k
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1640
1.54k
        Ok(())
1641
1.54k
    }
1642
1643
60
    fn stream_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1644
60
        require_feature::cm_async(
1645
60
            self.features,
1646
            "`stream.new` requires the component model async feature",
1647
60
            offset,
1648
0
        )?;
1649
1650
60
        let ty = self.defined_type_at(ty, offset)?;
1651
60
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1652
0
            bail!(offset, "`stream.new` requires a stream type")
1653
        };
1654
1655
60
        self.core_funcs
1656
60
            .push(types.intern_func_type(FuncType::new([], [ValType::I64]), offset));
1657
60
        Ok(())
1658
60
    }
1659
1660
60
    fn stream_read(
1661
60
        &mut self,
1662
60
        ty: u32,
1663
60
        options: &[CanonicalOption],
1664
60
        types: &mut TypeAlloc,
1665
60
        offset: usize,
1666
60
    ) -> Result<()> {
1667
60
        require_feature::cm_async(
1668
60
            self.features,
1669
            "`stream.read` requires the component model async feature",
1670
60
            offset,
1671
0
        )?;
1672
1673
60
        let ty = self.defined_type_at(ty, offset)?;
1674
60
        let ComponentDefinedType::Stream { ty: elem_ty, .. } = &types[ty] else {
1675
0
            bail!(offset, "`stream.read` requires a stream type")
1676
        };
1677
1678
60
        let options = self.check_options(types, options, offset)?;
1679
60
        if options.concurrency.is_sync() {
1680
0
            require_feature::cm_more_async_builtins(
1681
0
                self.features,
1682
                "synchronous `stream.read` requires the component model more async builtins feature",
1683
0
                offset,
1684
0
            )?;
1685
60
        }
1686
60
        let ty_id = options
1687
60
            .require_memory_if(offset, || elem_ty.is_some())?
1688
60
            .require_realloc_if(offset, || elem_ty.is_some_and(|ty| ty.contains_ptr(types)))?
1689
60
            .check_lower(offset)?
1690
60
            .check_core_type(
1691
60
                types,
1692
60
                FuncType::new([ValType::I32; 3], [ValType::I32]),
1693
60
                offset,
1694
0
            )?;
1695
1696
60
        self.core_funcs.push(ty_id);
1697
60
        Ok(())
1698
60
    }
1699
1700
60
    fn stream_write(
1701
60
        &mut self,
1702
60
        ty: u32,
1703
60
        options: &[CanonicalOption],
1704
60
        types: &mut TypeAlloc,
1705
60
        offset: usize,
1706
60
    ) -> Result<()> {
1707
60
        require_feature::cm_async(
1708
60
            self.features,
1709
            "`stream.write` requires the component model async feature",
1710
60
            offset,
1711
0
        )?;
1712
1713
60
        let ty = self.defined_type_at(ty, offset)?;
1714
60
        let ComponentDefinedType::Stream { ty: elem_ty, .. } = &types[ty] else {
1715
0
            bail!(offset, "`stream.write` requires a stream type")
1716
        };
1717
1718
60
        let options = self.check_options(types, options, offset)?;
1719
60
        if options.concurrency.is_sync() {
1720
0
            require_feature::cm_more_async_builtins(
1721
0
                self.features,
1722
                "synchronous `stream.write` requires the component model more async builtins feature",
1723
0
                offset,
1724
0
            )?;
1725
60
        }
1726
60
        let ty_id = options
1727
60
            .require_memory_if(offset, || elem_ty.is_some())?
1728
60
            .check_lower(offset)?
1729
60
            .check_core_type(
1730
60
                types,
1731
60
                FuncType::new([ValType::I32; 3], [ValType::I32]),
1732
60
                offset,
1733
0
            )?;
1734
1735
60
        self.core_funcs.push(ty_id);
1736
60
        Ok(())
1737
60
    }
1738
1739
60
    fn stream_cancel_read(
1740
60
        &mut self,
1741
60
        ty: u32,
1742
60
        cancellable: bool,
1743
60
        types: &mut TypeAlloc,
1744
60
        offset: usize,
1745
60
    ) -> Result<()> {
1746
60
        require_feature::cm_async(
1747
60
            self.features,
1748
            "`stream.cancel-read` requires the component model async feature",
1749
60
            offset,
1750
0
        )?;
1751
60
        if cancellable {
1752
0
            require_feature::cm_more_async_builtins(
1753
0
                self.features,
1754
                "async `stream.cancel-read` requires the component model more async builtins feature",
1755
0
                offset,
1756
0
            )?;
1757
60
        }
1758
1759
60
        let ty = self.defined_type_at(ty, offset)?;
1760
60
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1761
0
            bail!(offset, "`stream.cancel-read` requires a stream type")
1762
        };
1763
1764
60
        self.core_funcs
1765
60
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1766
60
        Ok(())
1767
60
    }
1768
1769
60
    fn stream_cancel_write(
1770
60
        &mut self,
1771
60
        ty: u32,
1772
60
        cancellable: bool,
1773
60
        types: &mut TypeAlloc,
1774
60
        offset: usize,
1775
60
    ) -> Result<()> {
1776
60
        require_feature::cm_async(
1777
60
            self.features,
1778
            "`stream.cancel-write` requires the component model async feature",
1779
60
            offset,
1780
0
        )?;
1781
60
        if cancellable {
1782
0
            require_feature::cm_more_async_builtins(
1783
0
                self.features,
1784
                "async `stream.cancel-write` requires the component model more async builtins feature",
1785
0
                offset,
1786
0
            )?;
1787
60
        }
1788
1789
60
        let ty = self.defined_type_at(ty, offset)?;
1790
60
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1791
0
            bail!(offset, "`stream.cancel-write` requires a stream type")
1792
        };
1793
1794
60
        self.core_funcs
1795
60
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1796
60
        Ok(())
1797
60
    }
1798
1799
60
    fn stream_drop_readable(
1800
60
        &mut self,
1801
60
        ty: u32,
1802
60
        types: &mut TypeAlloc,
1803
60
        offset: usize,
1804
60
    ) -> Result<()> {
1805
60
        require_feature::cm_async(
1806
60
            self.features,
1807
            "`stream.drop-readable` requires the component model async feature",
1808
60
            offset,
1809
0
        )?;
1810
1811
60
        let ty = self.defined_type_at(ty, offset)?;
1812
60
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1813
0
            bail!(offset, "`stream.drop-readable` requires a stream type")
1814
        };
1815
1816
60
        self.core_funcs
1817
60
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1818
60
        Ok(())
1819
60
    }
1820
1821
60
    fn stream_drop_writable(
1822
60
        &mut self,
1823
60
        ty: u32,
1824
60
        types: &mut TypeAlloc,
1825
60
        offset: usize,
1826
60
    ) -> Result<()> {
1827
60
        require_feature::cm_async(
1828
60
            self.features,
1829
            "`stream.drop-writable` requires the component model async feature",
1830
60
            offset,
1831
0
        )?;
1832
1833
60
        let ty = self.defined_type_at(ty, offset)?;
1834
60
        let ComponentDefinedType::Stream { .. } = &types[ty] else {
1835
0
            bail!(offset, "`stream.drop-writable` requires a stream type")
1836
        };
1837
1838
60
        self.core_funcs
1839
60
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
1840
60
        Ok(())
1841
60
    }
1842
1843
582
    fn future_new(&mut self, ty: u32, types: &mut TypeAlloc, offset: usize) -> Result<()> {
1844
582
        require_feature::cm_async(
1845
582
            self.features,
1846
            "`future.new` requires the component model async feature",
1847
582
            offset,
1848
0
        )?;
1849
1850
582
        let ty = self.defined_type_at(ty, offset)?;
1851
582
        let ComponentDefinedType::Future { .. } = &types[ty] else {
1852
0
            bail!(offset, "`future.new` requires a future type")
1853
        };
1854
1855
582
        self.core_funcs
1856
582
            .push(types.intern_func_type(FuncType::new([], [ValType::I64]), offset));
1857
582
        Ok(())
1858
582
    }
1859
1860
69
    fn future_read(
1861
69
        &mut self,
1862
69
        ty: u32,
1863
69
        options: &[CanonicalOption],
1864
69
        types: &mut TypeAlloc,
1865
69
        offset: usize,
1866
69
    ) -> Result<()> {
1867
69
        require_feature::cm_async(
1868
69
            self.features,
1869
            "`future.read` requires the component model async feature",
1870
69
            offset,
1871
0
        )?;
1872
1873
69
        let ty = self.defined_type_at(ty, offset)?;
1874
69
        let ComponentDefinedType::Future { ty: elem_ty, .. } = &types[ty] else {
1875
0
            bail!(offset, "`future.read` requires a future type")
1876
        };
1877
1878
69
        let options = self.check_options(types, options, offset)?;
1879
69
        if options.concurrency.is_sync() {
1880
0
            require_feature::cm_more_async_builtins(
1881
0
                self.features,
1882
                "synchronous `future.read` requires the component model more async builtins feature",
1883
0
                offset,
1884
0
            )?;
1885
69
        }
1886
69
        let ty_id = options
1887
69
            .require_memory_if(offset, || elem_ty.is_some())?
1888
69
            .require_realloc_if(offset, || elem_ty.is_some_and(|ty| ty.contains_ptr(types)))?
1889
69
            .check_lower(offset)?
1890
69
            .check_core_type(
1891
69
                types,
1892
69
                FuncType::new([ValType::I32; 2], [ValType::I32]),
1893
69
                offset,
1894
0
            )?;
1895
1896
69
        self.core_funcs.push(ty_id);
1897
69
        Ok(())
1898
69
    }
1899
1900
69
    fn future_write(
1901
69
        &mut self,
1902
69
        ty: u32,
1903
69
        options: &[CanonicalOption],
1904
69
        types: &mut TypeAlloc,
1905
69
        offset: usize,
1906
69
    ) -> Result<()> {
1907
69
        require_feature::cm_async(
1908
69
            self.features,
1909
            "`future.write` requires the component model async feature",
1910
69
            offset,
1911
0
        )?;
1912
1913
69
        let ty = self.defined_type_at(ty, offset)?;
1914
69
        let ComponentDefinedType::Future { ty: elem_ty, .. } = &types[ty] else {
1915
0
            bail!(offset, "`future.write` requires a future type")
1916
        };
1917
1918
69
        let options = self.check_options(types, &options, offset)?;
1919
69
        if options.concurrency.is_sync() {
1920
0
            require_feature::cm_more_async_builtins(
1921
0
                self.features,
1922
                "synchronous `future.write` requires the component model more async builtins feature",
1923
0
                offset,
1924
0
            )?;
1925
69
        }
1926
69
        let ty_id = options
1927
69
            .require_memory_if(offset, || elem_ty.is_some())?
1928
69
            .check_core_type(
1929
69
                types,
1930
69
                FuncType::new([ValType::I32; 2], [ValType::I32]),
1931
69
                offset,
1932
0
            )?;
1933
1934
69
        self.core_funcs.push(ty_id);
1935
69
        Ok(())
1936
69
    }
1937
1938
582
    fn future_cancel_read(
1939
582
        &mut self,
1940
582
        ty: u32,
1941
582
        cancellable: bool,
1942
582
        types: &mut TypeAlloc,
1943
582
        offset: usize,
1944
582
    ) -> Result<()> {
1945
582
        require_feature::cm_async(
1946
582
            self.features,
1947
            "`future.cancel-read` requires the component model async feature",
1948
582
            offset,
1949
0
        )?;
1950
582
        if cancellable {
1951
0
            require_feature::cm_more_async_builtins(
1952
0
                self.features,
1953
                "async `future.cancel-read` requires the component model more async builtins feature",
1954
0
                offset,
1955
0
            )?;
1956
582
        }
1957
1958
582
        let ty = self.defined_type_at(ty, offset)?;
1959
582
        let ComponentDefinedType::Future { .. } = &types[ty] else {
1960
0
            bail!(offset, "`future.cancel-read` requires a future type")
1961
        };
1962
1963
582
        self.core_funcs
1964
582
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1965
582
        Ok(())
1966
582
    }
1967
1968
582
    fn future_cancel_write(
1969
582
        &mut self,
1970
582
        ty: u32,
1971
582
        cancellable: bool,
1972
582
        types: &mut TypeAlloc,
1973
582
        offset: usize,
1974
582
    ) -> Result<()> {
1975
582
        require_feature::cm_async(
1976
582
            self.features,
1977
            "`future.cancel-write` requires the component model async feature",
1978
582
            offset,
1979
0
        )?;
1980
582
        if cancellable {
1981
0
            require_feature::cm_more_async_builtins(
1982
0
                self.features,
1983
                "async `future.cancel-write` requires the component model more async builtins feature",
1984
0
                offset,
1985
0
            )?;
1986
582
        }
1987
1988
582
        let ty = self.defined_type_at(ty, offset)?;
1989
582
        let ComponentDefinedType::Future { .. } = &types[ty] else {
1990
0
            bail!(offset, "`future.cancel-write` requires a future type")
1991
        };
1992
1993
582
        self.core_funcs
1994
582
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
1995
582
        Ok(())
1996
582
    }
1997
1998
582
    fn future_drop_readable(
1999
582
        &mut self,
2000
582
        ty: u32,
2001
582
        types: &mut TypeAlloc,
2002
582
        offset: usize,
2003
582
    ) -> Result<()> {
2004
582
        require_feature::cm_async(
2005
582
            self.features,
2006
            "`future.drop-readable` requires the component model async feature",
2007
582
            offset,
2008
0
        )?;
2009
2010
582
        let ty = self.defined_type_at(ty, offset)?;
2011
582
        let ComponentDefinedType::Future { .. } = &types[ty] else {
2012
0
            bail!(offset, "`future.drop-readable` requires a future type")
2013
        };
2014
2015
582
        self.core_funcs
2016
582
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2017
582
        Ok(())
2018
582
    }
2019
2020
582
    fn future_drop_writable(
2021
582
        &mut self,
2022
582
        ty: u32,
2023
582
        types: &mut TypeAlloc,
2024
582
        offset: usize,
2025
582
    ) -> Result<()> {
2026
582
        require_feature::cm_async(
2027
582
            self.features,
2028
            "`future.drop-writable` requires the component model async feature",
2029
582
            offset,
2030
0
        )?;
2031
2032
582
        let ty = self.defined_type_at(ty, offset)?;
2033
582
        let ComponentDefinedType::Future { .. } = &types[ty] else {
2034
0
            bail!(offset, "`future.drop-writable` requires a future type")
2035
        };
2036
2037
582
        self.core_funcs
2038
582
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2039
582
        Ok(())
2040
582
    }
2041
2042
0
    fn error_context_new(
2043
0
        &mut self,
2044
0
        options: Vec<CanonicalOption>,
2045
0
        types: &mut TypeAlloc,
2046
0
        offset: usize,
2047
0
    ) -> Result<()> {
2048
0
        require_feature::cm_error_context(
2049
0
            self.features,
2050
            "`error-context.new` requires the component model error-context feature",
2051
0
            offset,
2052
0
        )?;
2053
2054
0
        let ty_id = self
2055
0
            .check_options(types, &options, offset)?
2056
0
            .require_memory(offset)?
2057
0
            .require_sync(offset, "error-context.new")?
2058
0
            .check_lower(offset)?
2059
0
            .check_core_type(
2060
0
                types,
2061
0
                FuncType::new([ValType::I32; 2], [ValType::I32]),
2062
0
                offset,
2063
0
            )?;
2064
2065
0
        self.core_funcs.push(ty_id);
2066
0
        Ok(())
2067
0
    }
2068
2069
0
    fn error_context_debug_message(
2070
0
        &mut self,
2071
0
        options: Vec<CanonicalOption>,
2072
0
        types: &mut TypeAlloc,
2073
0
        offset: usize,
2074
0
    ) -> Result<()> {
2075
0
        require_feature::cm_error_context(
2076
0
            self.features,
2077
            "`error-context.debug-message` requires the component model error-context feature",
2078
0
            offset,
2079
0
        )?;
2080
2081
0
        let ty_id = self
2082
0
            .check_options(types, &options, offset)?
2083
0
            .require_memory(offset)?
2084
0
            .require_realloc(offset)?
2085
0
            .require_sync(offset, "error-context.debug-message")?
2086
0
            .check_lower(offset)?
2087
0
            .check_core_type(types, FuncType::new([ValType::I32; 2], []), offset)?;
2088
2089
0
        self.core_funcs.push(ty_id);
2090
0
        Ok(())
2091
0
    }
2092
2093
0
    fn error_context_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2094
0
        require_feature::cm_error_context(
2095
0
            self.features,
2096
            "`error-context.drop` requires the component model error-context feature",
2097
0
            offset,
2098
0
        )?;
2099
2100
0
        self.core_funcs
2101
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2102
0
        Ok(())
2103
0
    }
2104
2105
1.54k
    fn waitable_set_new(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2106
1.54k
        require_feature::cm_async(
2107
1.54k
            self.features,
2108
            "`waitable-set.new` requires the component model async feature",
2109
1.54k
            offset,
2110
0
        )?;
2111
2112
1.54k
        self.core_funcs
2113
1.54k
            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2114
1.54k
        Ok(())
2115
1.54k
    }
2116
2117
1.54k
    fn waitable_set_wait(
2118
1.54k
        &mut self,
2119
1.54k
        memory: u32,
2120
1.54k
        types: &mut TypeAlloc,
2121
1.54k
        offset: usize,
2122
1.54k
    ) -> Result<()> {
2123
1.54k
        require_feature::cm_async(
2124
1.54k
            self.features,
2125
            "`waitable-set.wait` requires the component model async feature",
2126
1.54k
            offset,
2127
0
        )?;
2128
2129
1.54k
        self.cabi_memory_at(memory, offset)?;
2130
1.54k
        let memory64 = self.memory_at(memory, offset)?.memory64;
2131
1.54k
        let ty = if memory64 { ValType::I64 } else { ValType::I32 };
2132
1.54k
        self.core_funcs.push(
2133
1.54k
            types.intern_func_type(FuncType::new([ValType::I32, ty], [ValType::I32]), offset),
2134
        );
2135
1.54k
        Ok(())
2136
1.54k
    }
2137
2138
1.54k
    fn waitable_set_poll(
2139
1.54k
        &mut self,
2140
1.54k
        memory: u32,
2141
1.54k
        types: &mut TypeAlloc,
2142
1.54k
        offset: usize,
2143
1.54k
    ) -> Result<()> {
2144
1.54k
        require_feature::cm_async(
2145
1.54k
            self.features,
2146
            "`waitable-set.poll` requires the component model async feature",
2147
1.54k
            offset,
2148
0
        )?;
2149
2150
1.54k
        self.cabi_memory_at(memory, offset)?;
2151
1.54k
        let memory64 = self.memory_at(memory, offset)?.memory64;
2152
1.54k
        let ty = if memory64 { ValType::I64 } else { ValType::I32 };
2153
1.54k
        self.core_funcs.push(
2154
1.54k
            types.intern_func_type(FuncType::new([ValType::I32, ty], [ValType::I32]), offset),
2155
        );
2156
1.54k
        Ok(())
2157
1.54k
    }
2158
2159
1.54k
    fn waitable_set_drop(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2160
1.54k
        require_feature::cm_async(
2161
1.54k
            self.features,
2162
            "`waitable-set.drop` requires the component model async feature",
2163
1.54k
            offset,
2164
0
        )?;
2165
2166
1.54k
        self.core_funcs
2167
1.54k
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2168
1.54k
        Ok(())
2169
1.54k
    }
2170
2171
1.54k
    fn waitable_join(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2172
1.54k
        require_feature::cm_async(
2173
1.54k
            self.features,
2174
            "`waitable.join` requires the component model async feature",
2175
1.54k
            offset,
2176
0
        )?;
2177
2178
1.54k
        self.core_funcs
2179
1.54k
            .push(types.intern_func_type(FuncType::new([ValType::I32; 2], []), offset));
2180
1.54k
        Ok(())
2181
1.54k
    }
2182
2183
0
    fn thread_index(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2184
0
        require_feature::cm_threading(
2185
0
            self.features,
2186
            "`thread.index` requires the component model threading feature",
2187
0
            offset,
2188
0
        )?;
2189
2190
0
        self.core_funcs
2191
0
            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2192
0
        Ok(())
2193
0
    }
2194
2195
0
    fn thread_new_indirect(
2196
0
        &mut self,
2197
0
        func_ty_index: u32,
2198
0
        table_index: u32,
2199
0
        types: &mut TypeAlloc,
2200
0
        offset: usize,
2201
0
    ) -> Result<()> {
2202
0
        require_feature::cm_threading(
2203
0
            self.features,
2204
            "`thread.new-indirect` requires the component model threading feature",
2205
0
            offset,
2206
0
        )?;
2207
2208
0
        let core_type_id = match self.core_type_at(func_ty_index, offset)? {
2209
0
            ComponentCoreTypeId::Sub(c) => c,
2210
0
            ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"),
2211
        };
2212
0
        let sub_ty = &types[core_type_id];
2213
0
        match &sub_ty.composite_type.inner {
2214
0
            CompositeInnerType::Func(func_ty) => {
2215
0
                if func_ty.params() != [ValType::I32] {
2216
0
                    bail!(
2217
0
                        offset,
2218
                        "start function must take a single `i32` argument (currently)"
2219
                    );
2220
0
                }
2221
0
                if func_ty.results() != [] {
2222
0
                    bail!(offset, "start function must not return any values");
2223
0
                }
2224
            }
2225
0
            _ => bail!(offset, "start type must be a function"),
2226
        }
2227
2228
0
        let table = self.table_at(table_index, offset)?;
2229
2230
0
        SubtypeCx::table_type(
2231
0
            table,
2232
0
            &TableType {
2233
0
                initial: 0,
2234
0
                maximum: None,
2235
0
                table64: false,
2236
0
                shared: false,
2237
0
                element_type: RefType::FUNCREF,
2238
0
            },
2239
0
            offset,
2240
        )
2241
0
        .map_err(|mut e| {
2242
0
            e.add_context("table is not a 32-bit table of (ref null (func))".into());
2243
0
            e
2244
0
        })?;
2245
2246
0
        self.core_funcs.push(types.intern_func_type(
2247
0
            FuncType::new([ValType::I32, ValType::I32], [ValType::I32]),
2248
0
            offset,
2249
0
        ));
2250
0
        Ok(())
2251
0
    }
2252
2253
0
    fn thread_resume_later(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2254
0
        require_feature::cm_threading(
2255
0
            self.features,
2256
            "`thread.resume-later` requires the component model threading feature",
2257
0
            offset,
2258
0
        )?;
2259
0
        self.core_funcs
2260
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], []), offset));
2261
0
        Ok(())
2262
0
    }
2263
2264
0
    fn thread_suspend(
2265
0
        &mut self,
2266
0
        _cancellable: bool,
2267
0
        types: &mut TypeAlloc,
2268
0
        offset: usize,
2269
0
    ) -> Result<()> {
2270
0
        require_feature::cm_threading(
2271
0
            self.features,
2272
            "`thread.suspend` requires the component model threading feature",
2273
0
            offset,
2274
0
        )?;
2275
0
        self.core_funcs
2276
0
            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2277
0
        Ok(())
2278
0
    }
2279
2280
1.54k
    fn thread_yield(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2281
1.54k
        require_feature::cm_async(
2282
1.54k
            self.features,
2283
            "`thread.yield` requires the component model async feature",
2284
1.54k
            offset,
2285
0
        )?;
2286
2287
1.54k
        self.core_funcs
2288
1.54k
            .push(types.intern_func_type(FuncType::new([], [ValType::I32]), offset));
2289
1.54k
        Ok(())
2290
1.54k
    }
2291
2292
0
    fn thread_suspend_then_resume(
2293
0
        &mut self,
2294
0
        _cancellable: bool,
2295
0
        types: &mut TypeAlloc,
2296
0
        offset: usize,
2297
0
    ) -> Result<()> {
2298
0
        require_feature::cm_threading(
2299
0
            self.features,
2300
            "`thread.suspend-then-resume` requires the component model threading feature",
2301
0
            offset,
2302
0
        )?;
2303
2304
0
        self.core_funcs
2305
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2306
0
        Ok(())
2307
0
    }
2308
2309
0
    fn thread_yield_then_resume(
2310
0
        &mut self,
2311
0
        _cancellable: bool,
2312
0
        types: &mut TypeAlloc,
2313
0
        offset: usize,
2314
0
    ) -> Result<()> {
2315
0
        require_feature::cm_threading(
2316
0
            self.features,
2317
            "`thread.yield-then-resume` requires the component model threading feature",
2318
0
            offset,
2319
0
        )?;
2320
0
        self.core_funcs
2321
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2322
0
        Ok(())
2323
0
    }
2324
2325
0
    fn thread_suspend_then_promote(
2326
0
        &mut self,
2327
0
        _cancellable: bool,
2328
0
        types: &mut TypeAlloc,
2329
0
        offset: usize,
2330
0
    ) -> Result<()> {
2331
0
        require_feature::cm_threading(
2332
0
            self.features,
2333
            "`thread.suspend-then-promote` requires the component model threading feature",
2334
0
            offset,
2335
0
        )?;
2336
0
        self.core_funcs
2337
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2338
0
        Ok(())
2339
0
    }
2340
2341
0
    fn thread_yield_then_promote(
2342
0
        &mut self,
2343
0
        _cancellable: bool,
2344
0
        types: &mut TypeAlloc,
2345
0
        offset: usize,
2346
0
    ) -> Result<()> {
2347
0
        require_feature::cm_threading(
2348
0
            self.features,
2349
            "`thread.yield-then-promote` requires the component model threading feature",
2350
0
            offset,
2351
0
        )?;
2352
0
        self.core_funcs
2353
0
            .push(types.intern_func_type(FuncType::new([ValType::I32], [ValType::I32]), offset));
2354
0
        Ok(())
2355
0
    }
2356
2357
1.27k
    fn check_local_resource(&self, idx: u32, types: &TypeList, offset: usize) -> Result<ValType> {
2358
1.27k
        let resource = self.resource_at(idx, types, offset)?;
2359
1.27k
        match self
2360
1.27k
            .defined_resources
2361
1.27k
            .get(&resource.resource())
2362
1.27k
            .and_then(|rep| *rep)
2363
        {
2364
1.27k
            Some(ty) => Ok(ty),
2365
0
            None => bail!(offset, "type {idx} is not a local resource"),
2366
        }
2367
1.27k
    }
2368
2369
6.53k
    fn resource_at<'a>(
2370
6.53k
        &self,
2371
6.53k
        idx: u32,
2372
6.53k
        _types: &'a TypeList,
2373
6.53k
        offset: usize,
2374
6.53k
    ) -> Result<AliasableResourceId> {
2375
6.53k
        if let ComponentAnyTypeId::Resource(id) = self.component_type_at(idx, offset)? {
2376
6.53k
            return Ok(id);
2377
0
        }
2378
0
        bail!(offset, "type index {} is not a resource type", idx)
2379
6.53k
    }
2380
2381
0
    fn thread_spawn_ref(
2382
0
        &mut self,
2383
0
        func_ty_index: u32,
2384
0
        types: &mut TypeAlloc,
2385
0
        offset: usize,
2386
0
    ) -> Result<()> {
2387
0
        require_feature::shared_everything_threads(
2388
0
            self.features,
2389
            "`thread.spawn-ref` requires the shared-everything-threads proposal",
2390
0
            offset,
2391
0
        )?;
2392
0
        let core_type_id = self.validate_spawn_type(func_ty_index, types, offset)?;
2393
2394
        // Insert the core function.
2395
0
        let packed_index = PackedIndex::from_id(core_type_id).ok_or_else(|| {
2396
0
            format_err!(offset, "implementation limit: too many types in `TypeList`")
2397
0
        })?;
2398
0
        let start_func_ref = RefType::concrete(true, packed_index);
2399
0
        let func_ty = FuncType::new([ValType::Ref(start_func_ref), ValType::I32], [ValType::I32]);
2400
0
        let core_ty = SubType::func(func_ty, true);
2401
0
        let id = types.intern_sub_type(core_ty, offset);
2402
0
        self.core_funcs.push(id);
2403
2404
0
        Ok(())
2405
0
    }
2406
2407
0
    fn thread_spawn_indirect(
2408
0
        &mut self,
2409
0
        func_ty_index: u32,
2410
0
        table_index: u32,
2411
0
        types: &mut TypeAlloc,
2412
0
        offset: usize,
2413
0
    ) -> Result<()> {
2414
0
        require_feature::shared_everything_threads(
2415
0
            self.features,
2416
            "`thread.spawn-indirect` requires the shared-everything-threads proposal",
2417
0
            offset,
2418
0
        )?;
2419
0
        let _ = self.validate_spawn_type(func_ty_index, types, offset)?;
2420
2421
        // Check this much like `call_indirect` (see
2422
        // `OperatorValidatorTemp::check_call_indirect_ty`), but loosen the
2423
        // table type restrictions to just a `funcref`. See the component model
2424
        // for more details:
2425
        // https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#-canon-threadspawn-indirect.
2426
0
        let table = self.table_at(table_index, offset)?;
2427
2428
0
        SubtypeCx::table_type(
2429
0
            table,
2430
0
            &TableType {
2431
0
                initial: 0,
2432
0
                maximum: None,
2433
0
                table64: false,
2434
0
                shared: true,
2435
0
                element_type: RefType::FUNCREF
2436
0
                    .shared()
2437
0
                    .expect("a funcref can always be shared"),
2438
0
            },
2439
0
            offset,
2440
        )
2441
0
        .map_err(|mut e| {
2442
0
            e.add_context("table is not a 32-bit shared table of (ref null (shared func))".into());
2443
0
            e
2444
0
        })?;
2445
2446
        // Insert the core function.
2447
0
        let func_ty = FuncType::new([ValType::I32, ValType::I32], [ValType::I32]);
2448
0
        let core_ty = SubType::func(func_ty, true);
2449
0
        let id = types.intern_sub_type(core_ty, offset);
2450
0
        self.core_funcs.push(id);
2451
2452
0
        Ok(())
2453
0
    }
2454
2455
    /// Validates the type of a `thread.spawn*` instruction.
2456
    ///
2457
    /// This is currently limited to shared functions with the signature `[i32]
2458
    /// -> []`. See component model [explanation] for more details.
2459
    ///
2460
    /// [explanation]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#-canon-threadspawn-ref
2461
0
    fn validate_spawn_type(
2462
0
        &self,
2463
0
        func_ty_index: u32,
2464
0
        types: &TypeAlloc,
2465
0
        offset: usize,
2466
0
    ) -> Result<CoreTypeId> {
2467
0
        let core_type_id = match self.core_type_at(func_ty_index, offset)? {
2468
0
            ComponentCoreTypeId::Sub(c) => c,
2469
0
            ComponentCoreTypeId::Module(_) => bail!(offset, "expected a core function type"),
2470
        };
2471
0
        let sub_ty = &types[core_type_id];
2472
0
        if !sub_ty.composite_type.shared {
2473
0
            bail!(offset, "spawn type must be shared");
2474
0
        }
2475
0
        match &sub_ty.composite_type.inner {
2476
0
            CompositeInnerType::Func(func_ty) => {
2477
0
                if func_ty.params() != [ValType::I32] {
2478
0
                    bail!(
2479
0
                        offset,
2480
                        "spawn function must take a single `i32` argument (currently)"
2481
                    );
2482
0
                }
2483
0
                if func_ty.results() != [] {
2484
0
                    bail!(offset, "spawn function must not return any values");
2485
0
                }
2486
            }
2487
0
            _ => bail!(offset, "spawn type must be a function"),
2488
        }
2489
0
        Ok(core_type_id)
2490
0
    }
2491
2492
0
    fn thread_available_parallelism(&mut self, types: &mut TypeAlloc, offset: usize) -> Result<()> {
2493
0
        require_feature::shared_everything_threads(
2494
0
            self.features,
2495
            "`thread.available_parallelism` requires the shared-everything-threads proposal",
2496
0
            offset,
2497
0
        )?;
2498
2499
0
        let func_ty = FuncType::new([], [ValType::I32]);
2500
0
        let core_ty = SubType::func(func_ty, true);
2501
0
        let id = types.intern_sub_type(core_ty, offset);
2502
0
        self.core_funcs.push(id);
2503
2504
0
        Ok(())
2505
0
    }
2506
2507
5.16k
    pub fn add_component(&mut self, component: ComponentType, types: &mut TypeAlloc) -> Result<()> {
2508
5.16k
        let id = types.push_ty(component);
2509
5.16k
        self.components.push(id);
2510
5.16k
        Ok(())
2511
5.16k
    }
2512
2513
5.16k
    pub fn add_instance(
2514
5.16k
        &mut self,
2515
5.16k
        instance: crate::ComponentInstance,
2516
5.16k
        types: &mut TypeAlloc,
2517
5.16k
        offset: usize,
2518
5.16k
    ) -> Result<()> {
2519
5.16k
        let instance = match instance {
2520
            crate::ComponentInstance::Instantiate {
2521
5.16k
                component_index,
2522
5.16k
                args,
2523
5.16k
            } => self.instantiate_component(component_index, args.into_vec(), types, offset)?,
2524
0
            crate::ComponentInstance::FromExports(exports) => {
2525
0
                self.instantiate_component_exports(exports.into_vec(), types, offset)?
2526
            }
2527
        };
2528
2529
5.16k
        self.instances.push(instance);
2530
2531
5.16k
        Ok(())
2532
5.16k
    }
2533
2534
66.6k
    pub fn add_alias(
2535
66.6k
        components: &mut [Self],
2536
66.6k
        alias: crate::ComponentAlias,
2537
66.6k
        types: &mut TypeAlloc,
2538
66.6k
        offset: usize,
2539
66.6k
    ) -> Result<()> {
2540
66.6k
        let component = components.last_mut().unwrap();
2541
2542
66.6k
        match component.kind {
2543
            // For a component itself all alias kind are allowed.
2544
48.7k
            ComponentKind::Component => {}
2545
2546
            // For instance/component types only aliases to `type` or `instance`
2547
            // items are allowed, and all other aliases are rejected.
2548
7.67k
            ComponentKind::InstanceType | ComponentKind::ComponentType => match &alias {
2549
                crate::ComponentAlias::InstanceExport {
2550
                    kind: ComponentExternalKind::Type | ComponentExternalKind::Instance,
2551
                    ..
2552
                }
2553
                | crate::ComponentAlias::Outer {
2554
                    kind: ComponentOuterAliasKind::Type | ComponentOuterAliasKind::CoreType,
2555
                    ..
2556
17.8k
                } => {}
2557
2558
0
                _ => bail!(
2559
0
                    offset,
2560
                    "aliases in a component or instance type may only refer to types or instances"
2561
                ),
2562
            },
2563
        }
2564
2565
66.6k
        match alias {
2566
            crate::ComponentAlias::InstanceExport {
2567
11.3k
                instance_index,
2568
11.3k
                kind,
2569
11.3k
                name,
2570
11.3k
            } => component.alias_instance_export(instance_index, kind, name, types, offset),
2571
            crate::ComponentAlias::CoreInstanceExport {
2572
45.1k
                instance_index,
2573
45.1k
                kind,
2574
45.1k
                name,
2575
45.1k
            } => component.alias_core_instance_export(instance_index, kind, name, types, offset),
2576
10.1k
            crate::ComponentAlias::Outer { kind, count, index } => match kind {
2577
                ComponentOuterAliasKind::CoreModule => {
2578
0
                    Self::alias_module(components, count, index, offset)
2579
                }
2580
                ComponentOuterAliasKind::CoreType => {
2581
0
                    Self::alias_core_type(components, count, index, offset)
2582
                }
2583
                ComponentOuterAliasKind::Type => {
2584
10.1k
                    Self::alias_type(components, count, index, types, offset)
2585
                }
2586
                ComponentOuterAliasKind::Component => {
2587
0
                    Self::alias_component(components, count, index, offset)
2588
                }
2589
            },
2590
        }
2591
66.6k
    }
2592
2593
0
    pub fn add_start(
2594
0
        &mut self,
2595
0
        func_index: u32,
2596
0
        args: &[u32],
2597
0
        results: u32,
2598
0
        types: &mut TypeList,
2599
0
        offset: usize,
2600
0
    ) -> Result<()> {
2601
0
        require_feature::cm_values(
2602
0
            self.features,
2603
            "support for component model `value`s is not enabled",
2604
0
            offset,
2605
0
        )?;
2606
0
        if self.has_start {
2607
0
            return Err(Error::new(
2608
0
                "component cannot have more than one start function",
2609
0
                offset,
2610
0
            ));
2611
0
        }
2612
2613
0
        let ft = &types[self.function_at(func_index, offset)?];
2614
2615
0
        if ft.params.len() != args.len() {
2616
0
            bail!(
2617
0
                offset,
2618
                "component start function requires {} arguments but was given {}",
2619
0
                ft.params.len(),
2620
0
                args.len()
2621
            );
2622
0
        }
2623
2624
0
        if u32::from(ft.result.is_some()) != results {
2625
0
            bail!(
2626
0
                offset,
2627
                "component start function has a result count of {results} \
2628
                 but the function type has a result count of {type_results}",
2629
0
                type_results = u32::from(ft.result.is_some()),
2630
            );
2631
0
        }
2632
2633
0
        let cx = SubtypeCx::new(types, types);
2634
0
        for (i, ((_, ty), arg)) in ft.params.iter().zip(args).enumerate() {
2635
            // Ensure the value's type is a subtype of the parameter type
2636
0
            cx.component_val_type(self.value_at(*arg, offset)?, ty, offset)
2637
0
                .with_context(|| {
2638
0
                    format!("value type mismatch for component start function argument {i}")
2639
0
                })?;
2640
        }
2641
2642
0
        if let Some(ty) = ft.result {
2643
0
            self.values.push((ty, false));
2644
0
        }
2645
2646
0
        self.has_start = true;
2647
2648
0
        Ok(())
2649
0
    }
2650
2651
17.1k
    fn check_options(
2652
17.1k
        &self,
2653
17.1k
        types: &TypeList,
2654
17.1k
        options: &[CanonicalOption],
2655
17.1k
        offset: usize,
2656
17.1k
    ) -> Result<CanonicalOptions> {
2657
0
        fn display(option: CanonicalOption) -> &'static str {
2658
0
            match option {
2659
0
                CanonicalOption::UTF8 => "utf8",
2660
0
                CanonicalOption::UTF16 => "utf16",
2661
0
                CanonicalOption::CompactUTF16 => "latin1-utf16",
2662
0
                CanonicalOption::Memory(_) => "memory",
2663
0
                CanonicalOption::Realloc(_) => "realloc",
2664
0
                CanonicalOption::PostReturn(_) => "post-return",
2665
0
                CanonicalOption::Async => "async",
2666
0
                CanonicalOption::Callback(_) => "callback",
2667
0
                CanonicalOption::CoreType(_) => "core-type",
2668
0
                CanonicalOption::Gc => "gc",
2669
            }
2670
0
        }
2671
2672
17.1k
        let mut encoding = None;
2673
17.1k
        let mut memory = None;
2674
17.1k
        let mut realloc = None;
2675
17.1k
        let mut post_return = None;
2676
17.1k
        let mut is_async = false;
2677
17.1k
        let mut callback = None;
2678
17.1k
        let mut core_type = None;
2679
17.1k
        let mut gc = false;
2680
2681
17.1k
        for option in options {
2682
16.3k
            match option {
2683
                CanonicalOption::UTF8 | CanonicalOption::UTF16 | CanonicalOption::CompactUTF16 => {
2684
972
                    match encoding {
2685
0
                        Some(existing) => {
2686
0
                            bail!(
2687
0
                                offset,
2688
                                "canonical encoding option `{existing}` conflicts with option `{}`",
2689
0
                                display(*option),
2690
                            )
2691
                        }
2692
                        None => {
2693
972
                            encoding = Some(match option {
2694
972
                                CanonicalOption::UTF8 => StringEncoding::Utf8,
2695
0
                                CanonicalOption::UTF16 => StringEncoding::Utf16,
2696
0
                                CanonicalOption::CompactUTF16 => StringEncoding::CompactUtf16,
2697
0
                                _ => unreachable!(),
2698
                            });
2699
                        }
2700
                    }
2701
                }
2702
2.25k
                CanonicalOption::Memory(idx) => {
2703
2.25k
                    memory = match memory {
2704
                        None => {
2705
2.25k
                            let ptr_size = self.cabi_memory_at(*idx, offset)?;
2706
2.25k
                            Some((*idx, ptr_size))
2707
                        }
2708
                        Some(_) => {
2709
0
                            return Err(Error::new(
2710
0
                                "canonical option `memory` is specified more than once",
2711
0
                                offset,
2712
0
                            ));
2713
                        }
2714
                    }
2715
                }
2716
975
                CanonicalOption::Realloc(idx) => {
2717
975
                    realloc = match realloc {
2718
                        None => {
2719
                            // Validation deferred because it may depend on the memory option.
2720
975
                            Some(*idx)
2721
                        }
2722
                        Some(_) => {
2723
0
                            return Err(Error::new(
2724
0
                                "canonical option `realloc` is specified more than once",
2725
0
                                offset,
2726
0
                            ));
2727
                        }
2728
                    }
2729
                }
2730
6.53k
                CanonicalOption::PostReturn(idx) => {
2731
6.53k
                    post_return = match post_return {
2732
6.53k
                        None => Some(*idx),
2733
                        Some(_) => {
2734
0
                            return Err(Error::new(
2735
0
                                "canonical option `post-return` is specified more than once",
2736
0
                                offset,
2737
0
                            ));
2738
                        }
2739
                    }
2740
                }
2741
                CanonicalOption::Async => {
2742
3.12k
                    if is_async {
2743
0
                        return Err(Error::new(
2744
0
                            "canonical option `async` is specified more than once",
2745
0
                            offset,
2746
0
                        ));
2747
                    } else {
2748
3.12k
                        require_feature::cm_async(
2749
3.12k
                            self.features,
2750
                            "canonical option `async` requires the component model async feature",
2751
3.12k
                            offset,
2752
0
                        )?;
2753
2754
3.12k
                        is_async = true;
2755
                    }
2756
                }
2757
2.53k
                CanonicalOption::Callback(idx) => {
2758
2.53k
                    callback = match callback {
2759
2.53k
                        None => Some(*idx),
2760
                        Some(_) => {
2761
0
                            return Err(Error::new(
2762
0
                                "canonical option `callback` is specified more than once",
2763
0
                                offset,
2764
0
                            ));
2765
                        }
2766
                    }
2767
                }
2768
0
                CanonicalOption::CoreType(idx) => {
2769
0
                    core_type = match core_type {
2770
                        None => {
2771
0
                            require_feature::cm_gc(
2772
0
                                self.features,
2773
                                "canonical option `core type` requires the component model gc feature",
2774
0
                                offset,
2775
0
                            )?;
2776
0
                            let ty = match self.core_type_at(*idx, offset)? {
2777
0
                                ComponentCoreTypeId::Sub(ty) => ty,
2778
                                ComponentCoreTypeId::Module(_) => {
2779
0
                                    return Err(Error::new(
2780
0
                                        "canonical option `core type` must reference a core function \
2781
0
                                     type",
2782
0
                                        offset,
2783
0
                                    ));
2784
                                }
2785
                            };
2786
0
                            match &types[ty].composite_type.inner {
2787
0
                                CompositeInnerType::Func(_) => {}
2788
                                CompositeInnerType::Array(_)
2789
                                | CompositeInnerType::Struct(_)
2790
                                | CompositeInnerType::Cont(_) => {
2791
0
                                    return Err(Error::new(
2792
0
                                        "canonical option `core type` must reference a core function \
2793
0
                                     type",
2794
0
                                        offset,
2795
0
                                    ));
2796
                                }
2797
                            }
2798
0
                            Some(ty)
2799
                        }
2800
                        Some(_) => {
2801
0
                            return Err(Error::new(
2802
0
                                "canonical option `core type` is specified more than once",
2803
0
                                offset,
2804
0
                            ));
2805
                        }
2806
                    };
2807
                }
2808
                CanonicalOption::Gc => {
2809
0
                    if gc {
2810
0
                        return Err(Error::new(
2811
0
                            "canonical option `gc` is specified more than once",
2812
0
                            offset,
2813
0
                        ));
2814
0
                    }
2815
0
                    require_feature::cm_gc(
2816
0
                        self.features,
2817
                        "canonical option `gc` requires the `cm-gc` feature",
2818
0
                        offset,
2819
0
                    )?;
2820
0
                    gc = true;
2821
                }
2822
            }
2823
        }
2824
2825
17.1k
        let string_encoding = encoding.unwrap_or_default();
2826
2827
17.1k
        let concurrency = match (is_async, callback, post_return.is_some()) {
2828
            (false, Some(_), _) => {
2829
0
                bail!(offset, "cannot specify callback without async")
2830
            }
2831
            (true, _, true) => {
2832
0
                bail!(offset, "cannot specify post-return function in async")
2833
            }
2834
14.0k
            (false, None, _) => Concurrency::Sync,
2835
3.12k
            (true, callback, false) => Concurrency::Async { callback },
2836
        };
2837
2838
17.1k
        if !gc && core_type.is_some() {
2839
0
            bail!(offset, "cannot specify `core-type` without `gc`")
2840
17.1k
        }
2841
2842
        // Validate `realloc`
2843
17.1k
        if let Some(realloc_idx) = realloc {
2844
975
            let addr_type = match memory {
2845
975
                Some((_, ptr_size)) => ptr_size.core_type(),
2846
                None => {
2847
0
                    return Err(Error::new(
2848
0
                        "canonical option `realloc` requires `memory` to also be specified",
2849
0
                        offset,
2850
0
                    ));
2851
                }
2852
            };
2853
975
            let ty_id = self.core_function_at(realloc_idx, offset)?;
2854
975
            let func_ty = types[ty_id].unwrap_func();
2855
975
            if func_ty.params() != [addr_type, addr_type, addr_type, addr_type]
2856
975
                || func_ty.results() != [addr_type]
2857
            {
2858
0
                return Err(Error::new(
2859
0
                    "canonical option `realloc` uses a core function with an incorrect signature",
2860
0
                    offset,
2861
0
                ));
2862
975
            }
2863
16.1k
        }
2864
2865
17.1k
        Ok(CanonicalOptions {
2866
17.1k
            string_encoding,
2867
17.1k
            memory,
2868
17.1k
            realloc,
2869
17.1k
            post_return,
2870
17.1k
            concurrency,
2871
17.1k
            core_type,
2872
17.1k
            gc,
2873
17.1k
        })
2874
17.1k
    }
2875
2876
215k
    fn check_type_ref(
2877
215k
        &mut self,
2878
215k
        ty: &ComponentTypeRef,
2879
215k
        types: &mut TypeAlloc,
2880
215k
        offset: usize,
2881
215k
    ) -> Result<ComponentEntityType> {
2882
98.2k
        Ok(match ty {
2883
0
            ComponentTypeRef::Module(index) => {
2884
0
                let id = self.core_type_at(*index, offset)?;
2885
0
                match id {
2886
                    ComponentCoreTypeId::Sub(_) => {
2887
0
                        bail!(offset, "core type index {index} is not a module type")
2888
                    }
2889
0
                    ComponentCoreTypeId::Module(id) => ComponentEntityType::Module(id),
2890
                }
2891
            }
2892
52.3k
            ComponentTypeRef::Func(index) => {
2893
52.3k
                let id = self.component_type_at(*index, offset)?;
2894
52.3k
                match id {
2895
52.3k
                    ComponentAnyTypeId::Func(id) => ComponentEntityType::Func(id),
2896
0
                    _ => bail!(offset, "type index {index} is not a function type"),
2897
                }
2898
            }
2899
0
            ComponentTypeRef::Value(ty) => {
2900
0
                self.check_value_support(offset)?;
2901
0
                let ty = match ty {
2902
0
                    crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty),
2903
0
                    crate::ComponentValType::Type(index) => {
2904
0
                        ComponentValType::Type(self.defined_type_at(*index, offset)?)
2905
                    }
2906
                };
2907
0
                ComponentEntityType::Value(ty)
2908
            }
2909
94.1k
            ComponentTypeRef::Type(TypeBounds::Eq(index)) => {
2910
94.1k
                let referenced = self.component_type_at(*index, offset)?;
2911
94.1k
                let created = types.with_unique(referenced);
2912
94.1k
                ComponentEntityType::Type {
2913
94.1k
                    referenced,
2914
94.1k
                    created,
2915
94.1k
                }
2916
            }
2917
            ComponentTypeRef::Type(TypeBounds::SubResource) => {
2918
4.12k
                let id = types.alloc_resource_id();
2919
4.12k
                ComponentEntityType::Type {
2920
4.12k
                    referenced: id.into(),
2921
4.12k
                    created: id.into(),
2922
4.12k
                }
2923
            }
2924
51.3k
            ComponentTypeRef::Instance(index) => {
2925
51.3k
                let id = self.component_type_at(*index, offset)?;
2926
51.3k
                match id {
2927
51.3k
                    ComponentAnyTypeId::Instance(id) => ComponentEntityType::Instance(id),
2928
0
                    _ => bail!(offset, "type index {index} is not an instance type"),
2929
                }
2930
            }
2931
13.6k
            ComponentTypeRef::Component(index) => {
2932
13.6k
                let id = self.component_type_at(*index, offset)?;
2933
13.6k
                match id {
2934
13.6k
                    ComponentAnyTypeId::Component(id) => ComponentEntityType::Component(id),
2935
0
                    _ => bail!(offset, "type index {index} is not a component type"),
2936
                }
2937
            }
2938
        })
2939
215k
    }
2940
2941
88.4k
    pub fn export_to_entity_type(
2942
88.4k
        &mut self,
2943
88.4k
        export: &crate::ComponentExport,
2944
88.4k
        types: &mut TypeAlloc,
2945
88.4k
        offset: usize,
2946
88.4k
    ) -> Result<ComponentEntityType> {
2947
88.4k
        let actual = match export.kind {
2948
            ComponentExternalKind::Module => {
2949
0
                ComponentEntityType::Module(self.module_at(export.index, offset)?)
2950
            }
2951
            ComponentExternalKind::Func => {
2952
9.12k
                ComponentEntityType::Func(self.function_at(export.index, offset)?)
2953
            }
2954
            ComponentExternalKind::Value => {
2955
0
                self.check_value_support(offset)?;
2956
0
                ComponentEntityType::Value(*self.value_at(export.index, offset)?)
2957
            }
2958
            ComponentExternalKind::Type => {
2959
74.1k
                let referenced = self.component_type_at(export.index, offset)?;
2960
74.1k
                let created = types.with_unique(referenced);
2961
74.1k
                ComponentEntityType::Type {
2962
74.1k
                    referenced,
2963
74.1k
                    created,
2964
74.1k
                }
2965
            }
2966
            ComponentExternalKind::Instance => {
2967
5.16k
                ComponentEntityType::Instance(self.instance_at(export.index, offset)?)
2968
            }
2969
            ComponentExternalKind::Component => {
2970
0
                ComponentEntityType::Component(self.component_at(export.index, offset)?)
2971
            }
2972
        };
2973
2974
88.4k
        let ascribed = match &export.ty {
2975
8.44k
            Some(ty) => self.check_type_ref(ty, types, offset)?,
2976
79.9k
            None => return Ok(actual),
2977
        };
2978
2979
8.44k
        SubtypeCx::new(types, types)
2980
8.44k
            .component_entity_type(&actual, &ascribed, offset)
2981
8.44k
            .with_context(|| "ascribed type of export is not compatible with item's type")?;
2982
2983
8.44k
        Ok(ascribed)
2984
88.4k
    }
2985
2986
0
    fn create_module_type(
2987
0
        components: &[Self],
2988
0
        decls: Vec<crate::ModuleTypeDeclaration>,
2989
0
        types: &mut TypeAlloc,
2990
0
        offset: usize,
2991
0
    ) -> Result<ModuleType> {
2992
0
        let mut state = Module::new(components[0].features);
2993
2994
0
        for decl in decls {
2995
0
            match decl {
2996
0
                crate::ModuleTypeDeclaration::Type(rec) => {
2997
0
                    state.add_types(rec, types, offset, true)?;
2998
                }
2999
0
                crate::ModuleTypeDeclaration::Export { name, mut ty } => {
3000
0
                    let ty = state.check_type_ref(&mut ty, types, offset)?;
3001
0
                    state.add_export(name, ty, offset, true, types)?;
3002
                }
3003
0
                crate::ModuleTypeDeclaration::OuterAlias { kind, count, index } => {
3004
0
                    match kind {
3005
                        crate::OuterAliasKind::Type => {
3006
0
                            let ty = if count == 0 {
3007
                                // Local alias, check the local module state
3008
0
                                ComponentCoreTypeId::Sub(state.type_id_at(index, offset)?)
3009
                            } else {
3010
                                // Otherwise, check the enclosing component state
3011
0
                                let component =
3012
0
                                    Self::check_alias_count(components, count - 1, offset)?;
3013
0
                                component.core_type_at(index, offset)?
3014
                            };
3015
3016
0
                            check_max(state.types.len(), 1, MAX_WASM_TYPES, "types", offset)?;
3017
3018
0
                            match ty {
3019
0
                                ComponentCoreTypeId::Sub(ty) => state.types.push(ty),
3020
                                // TODO https://github.com/WebAssembly/component-model/issues/265
3021
0
                                ComponentCoreTypeId::Module(_) => bail!(
3022
0
                                    offset,
3023
                                    "not implemented: aliasing core module types into a core \
3024
                                     module's types index space"
3025
                                ),
3026
                            }
3027
                        }
3028
                    }
3029
                }
3030
0
                crate::ModuleTypeDeclaration::Import(import) => {
3031
0
                    state.add_import(import, types, offset)?;
3032
                }
3033
            }
3034
        }
3035
3036
0
        let imports = state.imports_for_module_type(offset)?;
3037
3038
0
        Ok(ModuleType {
3039
0
            info: TypeInfo::core(state.type_size),
3040
0
            imports,
3041
0
            exports: state.exports,
3042
0
        })
3043
0
    }
3044
3045
63.1k
    fn create_component_type(
3046
63.1k
        components: &mut Vec<Self>,
3047
63.1k
        decls: Vec<crate::ComponentTypeDeclaration>,
3048
63.1k
        types: &mut TypeAlloc,
3049
63.1k
        offset: usize,
3050
63.1k
    ) -> Result<ComponentType> {
3051
63.1k
        let features = components[0].features;
3052
63.1k
        components.push(ComponentState::new(ComponentKind::ComponentType, features));
3053
3054
169k
        for decl in decls {
3055
169k
            match decl {
3056
0
                crate::ComponentTypeDeclaration::CoreType(ty) => {
3057
0
                    Self::add_core_type(components, ty, types, offset, true)?;
3058
                }
3059
86.7k
                crate::ComponentTypeDeclaration::Type(ty) => {
3060
86.7k
                    Self::add_type(components, ty, types, offset, true)?;
3061
                }
3062
57.6k
                crate::ComponentTypeDeclaration::Export { name, ty } => {
3063
57.6k
                    let current = components.last_mut().unwrap();
3064
57.6k
                    let ty = current.check_type_ref(&ty, types, offset)?;
3065
57.6k
                    current.add_export(name, ty, types, offset, true)?;
3066
                }
3067
16.9k
                crate::ComponentTypeDeclaration::Import(import) => {
3068
16.9k
                    components
3069
16.9k
                        .last_mut()
3070
16.9k
                        .unwrap()
3071
16.9k
                        .add_import(import, types, offset)?;
3072
                }
3073
7.67k
                crate::ComponentTypeDeclaration::Alias(alias) => {
3074
7.67k
                    Self::add_alias(components, alias, types, offset)?;
3075
                }
3076
            };
3077
        }
3078
3079
63.0k
        components.pop().unwrap().finish(types, offset)
3080
63.1k
    }
3081
3082
51.3k
    fn create_instance_type(
3083
51.3k
        components: &mut Vec<Self>,
3084
51.3k
        decls: Vec<crate::InstanceTypeDeclaration>,
3085
51.3k
        types: &mut TypeAlloc,
3086
51.3k
        offset: usize,
3087
51.3k
    ) -> Result<ComponentInstanceType> {
3088
51.3k
        let features = components[0].features;
3089
51.3k
        components.push(ComponentState::new(ComponentKind::InstanceType, features));
3090
3091
261k
        for decl in decls {
3092
261k
            match decl {
3093
0
                crate::InstanceTypeDeclaration::CoreType(ty) => {
3094
0
                    Self::add_core_type(components, ty, types, offset, true)?;
3095
                }
3096
135k
                crate::InstanceTypeDeclaration::Type(ty) => {
3097
135k
                    Self::add_type(components, ty, types, offset, true)?;
3098
                }
3099
115k
                crate::InstanceTypeDeclaration::Export { name, ty } => {
3100
115k
                    let current = components.last_mut().unwrap();
3101
115k
                    let ty = current.check_type_ref(&ty, types, offset)?;
3102
115k
                    current.add_export(name, ty, types, offset, true)?;
3103
                }
3104
10.1k
                crate::InstanceTypeDeclaration::Alias(alias) => {
3105
10.1k
                    Self::add_alias(components, alias, types, offset)?;
3106
                }
3107
            };
3108
        }
3109
3110
51.3k
        let mut state = components.pop().unwrap();
3111
3112
51.3k
        assert!(state.imported_resources.is_empty());
3113
3114
        Ok(ComponentInstanceType {
3115
51.3k
            info: state.type_info,
3116
3117
            // The defined resources for this instance type are those listed on
3118
            // the component state. The path to each defined resource is
3119
            // guaranteed to live within the `explicit_resources` map since,
3120
            // when in the type context, the introduction of any defined
3121
            // resource must have been done with `(export "x" (type (sub
3122
            // resource)))` which, in a sense, "fuses" the introduction of the
3123
            // variable with the export. This means that all defined resources,
3124
            // if any, should be guaranteed to have an `explicit_resources` path
3125
            // listed.
3126
51.3k
            defined_resources: mem::take(&mut state.defined_resources)
3127
51.3k
                .into_iter()
3128
51.3k
                .map(|(id, rep)| {
3129
2.68k
                    assert!(rep.is_none());
3130
2.68k
                    id
3131
2.68k
                })
3132
51.3k
                .collect(),
3133
3134
            // The map of what resources are explicitly exported and where
3135
            // they're exported is plumbed through as-is.
3136
51.3k
            explicit_resources: mem::take(&mut state.explicit_resources),
3137
3138
51.3k
            exports: mem::take(&mut state.exports),
3139
        })
3140
51.3k
    }
3141
3142
37.2k
    fn create_function_type(
3143
37.2k
        &self,
3144
37.2k
        ty: crate::ComponentFuncType,
3145
37.2k
        types: &TypeList,
3146
37.2k
        offset: usize,
3147
37.2k
    ) -> Result<ComponentFuncType> {
3148
37.2k
        let mut info = TypeInfo::new();
3149
3150
37.2k
        if ty.async_ {
3151
26.1k
            require_feature::cm_async(
3152
26.1k
                self.features,
3153
                "async component functions require the component model async feature",
3154
26.1k
                offset,
3155
0
            )?;
3156
11.0k
        }
3157
3158
37.2k
        let mut set = Set::default();
3159
37.2k
        set.reserve(core::cmp::max(
3160
37.2k
            ty.params.len(),
3161
37.2k
            usize::from(ty.result.is_some()),
3162
        ));
3163
3164
37.2k
        let params = ty
3165
37.2k
            .params
3166
37.2k
            .iter()
3167
92.1k
            .map(|(name, ty)| {
3168
92.1k
                let name = to_kebab_string(name, "function parameter", offset)?;
3169
92.1k
                if !set.insert(name.clone()) {
3170
0
                    bail!(
3171
0
                        offset,
3172
                        "function parameter name `{name}` conflicts with previous parameter name `{prev}`",
3173
0
                        prev = set.get(&name).unwrap(),
3174
                    );
3175
92.1k
                }
3176
3177
92.1k
                let ty = self.create_component_val_type(*ty, offset)?;
3178
92.1k
                info.combine(ty.info(types), offset)?;
3179
92.1k
                Ok((name, ty))
3180
92.1k
            })
3181
37.2k
            .collect::<Result<_>>()?;
3182
3183
37.2k
        set.clear();
3184
3185
37.2k
        let result = ty
3186
37.2k
            .result
3187
37.2k
            .map(|ty| {
3188
30.3k
                let ty = self.create_component_val_type(ty, offset)?;
3189
30.3k
                let ty_info = ty.info(types);
3190
30.3k
                if ty_info.contains_borrow() {
3191
0
                    bail!(offset, "function result cannot contain a `borrow` type");
3192
30.3k
                }
3193
30.3k
                info.combine(ty.info(types), offset)?;
3194
30.3k
                Ok(ty)
3195
30.3k
            })
3196
37.2k
            .transpose()?;
3197
3198
37.2k
        Ok(ComponentFuncType {
3199
37.2k
            async_: ty.async_,
3200
37.2k
            info,
3201
37.2k
            params,
3202
37.2k
            result,
3203
37.2k
        })
3204
37.2k
    }
3205
3206
21.7k
    fn instantiate_core_module(
3207
21.7k
        &self,
3208
21.7k
        module_index: u32,
3209
21.7k
        module_args: Vec<crate::InstantiationArg>,
3210
21.7k
        types: &mut TypeAlloc,
3211
21.7k
        offset: usize,
3212
21.7k
    ) -> Result<ComponentCoreInstanceTypeId> {
3213
16.7k
        fn insert_arg<'a>(
3214
16.7k
            name: &'a str,
3215
16.7k
            arg: &'a InstanceType,
3216
16.7k
            args: &mut IndexMap<&'a str, &'a InstanceType>,
3217
16.7k
            offset: usize,
3218
16.7k
        ) -> Result<()> {
3219
16.7k
            if args.insert(name, arg).is_some() {
3220
0
                bail!(
3221
0
                    offset,
3222
                    "duplicate module instantiation argument named `{name}`"
3223
                );
3224
16.7k
            }
3225
3226
16.7k
            Ok(())
3227
16.7k
        }
3228
3229
21.7k
        let module_type_id = self.module_at(module_index, offset)?;
3230
21.7k
        let mut args = IndexMap::default();
3231
3232
        // Populate the arguments
3233
21.7k
        for module_arg in module_args {
3234
16.7k
            match module_arg.kind {
3235
                InstantiationArgKind::Instance => {
3236
16.7k
                    let instance_type = &types[self.core_instance_at(module_arg.index, offset)?];
3237
16.7k
                    insert_arg(module_arg.name, instance_type, &mut args, offset)?;
3238
                }
3239
            }
3240
        }
3241
3242
        // Validate the arguments
3243
21.7k
        let module_type = &types[module_type_id];
3244
21.7k
        let cx = SubtypeCx::new(types, types);
3245
50.7k
        for ((module, name), expected) in module_type.imports.iter() {
3246
50.7k
            let instance = args.get(module.as_str()).ok_or_else(|| {
3247
0
                format_err!(
3248
0
                    offset,
3249
                    "missing module instantiation argument named `{module}`"
3250
                )
3251
0
            })?;
3252
3253
50.7k
            let arg = instance
3254
50.7k
                .internal_exports(types)
3255
50.7k
                .get(name.as_str())
3256
50.7k
                .ok_or_else(|| {
3257
0
                    format_err!(
3258
0
                        offset,
3259
                        "module instantiation argument `{module}` does not \
3260
                         export an item named `{name}`",
3261
                    )
3262
0
                })?;
3263
3264
50.7k
            cx.entity_type(arg, expected, offset).with_context(|| {
3265
0
                format!(
3266
                    "type mismatch for export `{name}` of module \
3267
                     instantiation argument `{module}`"
3268
                )
3269
0
            })?;
3270
        }
3271
3272
21.7k
        let mut info = TypeInfo::new();
3273
52.3k
        for (_, ty) in module_type.exports.iter() {
3274
52.3k
            info.combine(ty.info(types), offset)?;
3275
        }
3276
3277
21.7k
        Ok(types.push_ty(InstanceType {
3278
21.7k
            info,
3279
21.7k
            kind: CoreInstanceTypeKind::Instantiated(module_type_id),
3280
21.7k
        }))
3281
21.7k
    }
3282
3283
5.16k
    fn instantiate_component(
3284
5.16k
        &mut self,
3285
5.16k
        component_index: u32,
3286
5.16k
        component_args: Vec<crate::ComponentInstantiationArg>,
3287
5.16k
        types: &mut TypeAlloc,
3288
5.16k
        offset: usize,
3289
5.16k
    ) -> Result<ComponentInstanceTypeId> {
3290
5.16k
        let component_type_id = self.component_at(component_index, offset)?;
3291
5.16k
        let mut args = IndexMap::default();
3292
3293
        // Populate the arguments
3294
9.39k
        for component_arg in component_args {
3295
9.39k
            let ty = match component_arg.kind {
3296
                ComponentExternalKind::Module => {
3297
0
                    ComponentEntityType::Module(self.module_at(component_arg.index, offset)?)
3298
                }
3299
                ComponentExternalKind::Component => {
3300
0
                    ComponentEntityType::Component(self.component_at(component_arg.index, offset)?)
3301
                }
3302
                ComponentExternalKind::Instance => {
3303
0
                    ComponentEntityType::Instance(self.instance_at(component_arg.index, offset)?)
3304
                }
3305
                ComponentExternalKind::Func => {
3306
8.44k
                    ComponentEntityType::Func(self.function_at(component_arg.index, offset)?)
3307
                }
3308
                ComponentExternalKind::Value => {
3309
0
                    self.check_value_support(offset)?;
3310
0
                    ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?)
3311
                }
3312
                ComponentExternalKind::Type => {
3313
954
                    let ty = self.component_type_at(component_arg.index, offset)?;
3314
954
                    ComponentEntityType::Type {
3315
954
                        referenced: ty,
3316
954
                        created: ty,
3317
954
                    }
3318
                }
3319
            };
3320
9.39k
            match args.entry(component_arg.name.to_string()) {
3321
0
                Entry::Occupied(e) => {
3322
0
                    bail!(
3323
0
                        offset,
3324
                        "instantiation argument `{name}` conflicts with previous argument `{prev}`",
3325
0
                        prev = e.key(),
3326
                        name = component_arg.name
3327
                    );
3328
                }
3329
9.39k
                Entry::Vacant(e) => {
3330
9.39k
                    e.insert(ty);
3331
9.39k
                }
3332
            }
3333
        }
3334
3335
        // Here comes the fun part of the component model, we're instantiating
3336
        // the component with type `component_type_id` with the `args`
3337
        // specified. Easy enough!
3338
        //
3339
        // This operation, however, is one of the lynchpins of safety in the
3340
        // component model. Additionally what this ends up implementing ranges
3341
        // from "well just check the types are equal" to "let's have a
3342
        // full-blown ML-style module type system in the component model". There
3343
        // are primarily two major tricky pieces to the component model which
3344
        // make this operation, instantiating components, hard:
3345
        //
3346
        // 1. Components can import and exports other components. This means
3347
        //    that arguments to instantiation are along the lines of functions
3348
        //    being passed to functions or similar. Effectively this means that
3349
        //    the term "variance" comes into play with either contravariance
3350
        //    or covariance depending on where you are in typechecking. This is
3351
        //    one of the main rationales, however, that this check below is a
3352
        //    check for subtyping as opposed to exact type equivalence. For
3353
        //    example an instance that exports something is a subtype of an
3354
        //    instance that exports nothing. Components get a bit trick since
3355
        //    they both have imports and exports. My way of thinking about it
3356
        //    is "who's asking for what". If you're asking for imports then
3357
        //    I need to at least supply those imports, but I can possibly
3358
        //    supply more. If you're asking for a thing which you'll give a set
3359
        //    of imports, then I can give you something which takes less imports
3360
        //    because what you give still suffices. (things like that). The
3361
        //    real complication with components, however, comes with...
3362
        //
3363
        // 2. Resources. Resources in the component model are akin to "abstract
3364
        //    types". They're not abstract in the sense that they have no
3365
        //    representation, they're always backed by a 32-bit integer right
3366
        //    now. Instead they're abstract in the sense that some components
3367
        //    aren't allowed to understand the representation of a resource.
3368
        //    For example if you import a resource you can't get the underlying
3369
        //    internals of it. Furthermore the resource is strictly tracked
3370
        //    within the component with `own` and `borrow` runtime semantics.
3371
        //    The hardest part about resources, though, is handling them as
3372
        //    part of instantiation and subtyping.
3373
        //
3374
        //    For example one major aspect of resources is that if a component
3375
        //    exports a resource then each instantiation of the component
3376
        //    produces a fresh resource type. This means that the type recorded
3377
        //    for the instantiation here can't simply be "I instantiated
3378
        //    component X" since in such a situation the type of all
3379
        //    instantiations would be the same, which they aren't.
3380
        //
3381
        //    This sort of subtlety comes up quite frequently for resources.
3382
        //    This file contains references to `imported_resources` and
3383
        //    `defined_resources` for example which refer to the formal
3384
        //    nature of components and their abstract variables. Specifically
3385
        //    for instantiation though we're eventually faced with the problem
3386
        //    of subtype checks where resource subtyping is defined as "does
3387
        //    your id equal mine". Naively implemented that means anything with
3388
        //    resources isn't subtypes of anything else since resource ids are
3389
        //    unique between components. Instead what actually needs to happen
3390
        //    is types need to be substituted.
3391
        //
3392
        // Much of the complexity here is not actually apparent here in this
3393
        // literal one function. Instead it's spread out across validation
3394
        // in this file and type-checking in the `types.rs` module. Note that
3395
        // the "spread out" nature isn't because we're bad maintainers
3396
        // (hopefully), but rather it's quite infectious how many parts need
3397
        // to handle resources and account for defined/imported variables.
3398
        //
3399
        // For example only one subtyping method is called here where `args` is
3400
        // passed in. This method is quite recursive in its nature though and
3401
        // will internally touch all the fields that this file maintains to
3402
        // end up putting into various bits and pieces of type information.
3403
        //
3404
        // Unfortunately there's probably not really a succinct way to read
3405
        // this method and understand everything. If you've written ML module
3406
        // type systems this will probably look quite familiar, but otherwise
3407
        // the whole system is not really easily approachable at this time. It's
3408
        // hoped in the future that there's a formalism to refer to which will
3409
        // make things more clear as the code would be able to reference this
3410
        // hypothetical formalism. Until that's the case, though, these
3411
        // comments are hopefully enough when augmented with communication with
3412
        // the authors.
3413
3414
5.16k
        let component_type = &types[component_type_id];
3415
5.16k
        let mut exports = component_type.exports.clone();
3416
5.16k
        let mut info = TypeInfo::new();
3417
33.0k
        for (_, ty) in component_type.exports.iter() {
3418
33.0k
            info.combine(ty.ty.info(types), offset)?;
3419
        }
3420
3421
        // Perform the subtype check that `args` matches the imports of
3422
        // `component_type_id`. The result of this subtype check is the
3423
        // production of a mapping of resource types from the imports to the
3424
        // arguments provided. This is a substitution map which is then used
3425
        // below to perform a substitution into the exports of the instance
3426
        // since the types of the exports are now in terms of whatever was
3427
        // supplied as imports.
3428
5.16k
        let mut mapping = SubtypeCx::new(types, types).open_instance_type(
3429
5.16k
            &args,
3430
5.16k
            component_type_id,
3431
5.16k
            ExternKind::Import,
3432
5.16k
            offset,
3433
0
        )?;
3434
3435
        // Part of the instantiation of a component is that all of its
3436
        // defined resources become "fresh" on each instantiation. This
3437
        // means that each instantiation of a component gets brand new type
3438
        // variables representing its defined resources, modeling that each
3439
        // instantiation produces distinct types. The freshening is performed
3440
        // here by allocating new ids and inserting them into `mapping`.
3441
        //
3442
        // Note that technically the `mapping` from subtyping should be applied
3443
        // first and then the mapping for freshening should be applied
3444
        // afterwards. The keys of the map from subtyping are the imported
3445
        // resources from this component which are disjoint from its defined
3446
        // resources. That means it should be possible to place everything
3447
        // into one large map which maps from:
3448
        //
3449
        // * the component's imported resources go to whatever was explicitly
3450
        //   supplied in the import map
3451
        // * the component's defined resources go to fresh new resources
3452
        //
3453
        // These two remapping operations can then get folded into one by
3454
        // placing everything in the same `mapping` and using that for a remap
3455
        // only once.
3456
5.16k
        let fresh_defined_resources = (0..component_type.defined_resources.len())
3457
5.16k
            .map(|_| types.alloc_resource_id().resource())
3458
5.16k
            .collect::<IndexSet<_>>();
3459
5.16k
        let component_type = &types[component_type_id];
3460
5.16k
        for ((old, _path), new) in component_type
3461
5.16k
            .defined_resources
3462
5.16k
            .iter()
3463
5.16k
            .zip(&fresh_defined_resources)
3464
        {
3465
0
            let prev = mapping.resources.insert(*old, *new);
3466
0
            assert!(prev.is_none());
3467
        }
3468
3469
        // Perform the remapping operation over all the exports that will be
3470
        // listed for the final instance type. Note that this is performed
3471
        // both for all the export types in addition to the explicitly exported
3472
        // resources list.
3473
        //
3474
        // Note that this is a crucial step of the instantiation process which
3475
        // is intentionally transforming the type of a component based on the
3476
        // variables provided by imports and additionally ensuring that all
3477
        // references to the component's defined resources are rebound to the
3478
        // fresh ones introduced just above.
3479
33.0k
        for entity in exports.values_mut() {
3480
33.0k
            types.remap_component_entity(&mut entity.ty, &mut mapping);
3481
33.0k
        }
3482
5.16k
        let component_type = &types[component_type_id];
3483
5.16k
        let explicit_resources = component_type
3484
5.16k
            .explicit_resources
3485
5.16k
            .iter()
3486
5.16k
            .map(|(id, path)| {
3487
651
                (
3488
651
                    mapping.resources.get(id).copied().unwrap_or(*id),
3489
651
                    path.clone(),
3490
651
                )
3491
651
            })
3492
5.16k
            .collect::<IndexMap<_, _>>();
3493
3494
        // Technically in the last formalism that was consulted in writing this
3495
        // implementation there are two further steps that are part of the
3496
        // instantiation process:
3497
        //
3498
        // 1. The set of defined resources from the instance created, which are
3499
        //    added to the outer component, is the subset of the instance's
3500
        //    original defined resources and the free variables of the exports.
3501
        //
3502
        // 2. Each element of this subset is required to be "explicit in" the
3503
        //    instance, or otherwise explicitly exported somewhere within the
3504
        //    instance.
3505
        //
3506
        // With the syntactic structure of the component model, however, neither
3507
        // of these conditions should be necessary. The main reason for this is
3508
        // that this function is specifically dealing with instantiation of
3509
        // components which should already have these properties validated
3510
        // about them. Subsequently we shouldn't have to re-check them.
3511
        //
3512
        // In debug mode, however, do a sanity check.
3513
5.16k
        if cfg!(debug_assertions) {
3514
0
            let mut free = IndexSet::default();
3515
0
            for ty in exports.values() {
3516
0
                types.free_variables_component_entity(&ty.ty, &mut free);
3517
0
            }
3518
0
            assert!(fresh_defined_resources.is_subset(&free));
3519
0
            for resource in fresh_defined_resources.iter() {
3520
0
                assert!(explicit_resources.contains_key(resource));
3521
            }
3522
5.16k
        }
3523
3524
        // And as the final step of the instantiation process all of the
3525
        // new defined resources from this component instantiation are moved
3526
        // onto `self`. Note that concrete instances never have defined
3527
        // resources (see more comments in `instantiate_exports`) so the
3528
        // `defined_resources` listing in the final type is always empty. This
3529
        // represents how by having a concrete instance the definitions
3530
        // referred to in that instance are now problems for the outer
3531
        // component rather than the inner instance since the instance is bound
3532
        // to the component.
3533
        //
3534
        // All defined resources here have no known representation, so they're
3535
        // all listed with `None`. Also note that none of the resources were
3536
        // exported yet so `self.explicit_resources` is not updated yet. If
3537
        // this instance is exported, however, it'll consult the type's
3538
        // `explicit_resources` array and use that appropriately.
3539
5.16k
        for resource in fresh_defined_resources {
3540
0
            self.defined_resources.insert(resource, None);
3541
0
        }
3542
3543
5.16k
        Ok(types.push_ty(ComponentInstanceType {
3544
5.16k
            info,
3545
5.16k
            defined_resources: Default::default(),
3546
5.16k
            explicit_resources,
3547
5.16k
            exports,
3548
5.16k
        }))
3549
5.16k
    }
3550
3551
0
    fn instantiate_component_exports(
3552
0
        &mut self,
3553
0
        exports: Vec<crate::ComponentExport>,
3554
0
        types: &mut TypeAlloc,
3555
0
        offset: usize,
3556
0
    ) -> Result<ComponentInstanceTypeId> {
3557
0
        let mut info = TypeInfo::new();
3558
0
        let mut inst_exports = IndexMap::default();
3559
0
        let mut explicit_resources = IndexMap::default();
3560
0
        let mut export_names = IndexSet::default();
3561
3562
        // NB: It's intentional that this context is empty since no indices are
3563
        // introduced in the bag-of-exports construct which means there's no
3564
        // way syntactically to register something inside of this.
3565
0
        let names = ComponentNameContext::default();
3566
3567
0
        for export in exports {
3568
0
            assert!(export.ty.is_none());
3569
0
            let ty = match export.kind {
3570
                ComponentExternalKind::Module => {
3571
0
                    ComponentEntityType::Module(self.module_at(export.index, offset)?)
3572
                }
3573
                ComponentExternalKind::Component => {
3574
0
                    ComponentEntityType::Component(self.component_at(export.index, offset)?)
3575
                }
3576
                ComponentExternalKind::Instance => {
3577
0
                    let ty = self.instance_at(export.index, offset)?;
3578
3579
                    // When an instance is exported from an instance then
3580
                    // all explicitly exported resources on the sub-instance are
3581
                    // now also listed as exported resources on the outer
3582
                    // instance, just with one more element in their path.
3583
0
                    explicit_resources.extend(types[ty].explicit_resources.iter().map(
3584
0
                        |(id, path)| {
3585
0
                            let mut new_path = vec![inst_exports.len()];
3586
0
                            new_path.extend(path);
3587
0
                            (*id, new_path)
3588
0
                        },
3589
                    ));
3590
0
                    ComponentEntityType::Instance(ty)
3591
                }
3592
                ComponentExternalKind::Func => {
3593
0
                    ComponentEntityType::Func(self.function_at(export.index, offset)?)
3594
                }
3595
                ComponentExternalKind::Value => {
3596
0
                    self.check_value_support(offset)?;
3597
0
                    ComponentEntityType::Value(*self.value_at(export.index, offset)?)
3598
                }
3599
                ComponentExternalKind::Type => {
3600
0
                    let ty = self.component_type_at(export.index, offset)?;
3601
                    // If this is an export of a resource type be sure to
3602
                    // record that in the explicit list with the appropriate
3603
                    // path because if this instance ends up getting used
3604
                    // it'll count towards the "explicit in" check.
3605
0
                    if let ComponentAnyTypeId::Resource(id) = ty {
3606
0
                        explicit_resources.insert(id.resource(), vec![inst_exports.len()]);
3607
0
                    }
3608
0
                    ComponentEntityType::Type {
3609
0
                        referenced: ty,
3610
0
                        // The created type index here isn't used anywhere
3611
0
                        // in index spaces because a "bag of exports"
3612
0
                        // doesn't build up its own index spaces. Just fill
3613
0
                        // in the same index here in this case as what's
3614
0
                        // referenced.
3615
0
                        created: ty,
3616
0
                    }
3617
                }
3618
            };
3619
3620
0
            names.validate_extern(
3621
0
                &export.name,
3622
0
                ExternKind::Export,
3623
0
                &ty,
3624
0
                types,
3625
0
                offset,
3626
0
                &mut export_names,
3627
0
                &mut inst_exports,
3628
0
                &mut info,
3629
0
                &self.features,
3630
0
            )?;
3631
        }
3632
3633
0
        Ok(types.push_ty(ComponentInstanceType {
3634
0
            info,
3635
0
            explicit_resources,
3636
0
            exports: inst_exports,
3637
0
3638
0
            // NB: the list of defined resources for this instance itself
3639
0
            // is always empty. Even if this instance exports resources,
3640
0
            // it's empty.
3641
0
            //
3642
0
            // The reason for this is a bit subtle. The general idea, though, is
3643
0
            // that the defined resources list here is only used for instance
3644
0
            // types that are sort of "floating around" and haven't actually
3645
0
            // been attached to something yet. For example when an instance type
3646
0
            // is simply declared it can have defined resources introduced
3647
0
            // through `(export "name" (type (sub resource)))`. These
3648
0
            // definitions, however, are local to the instance itself and aren't
3649
0
            // defined elsewhere.
3650
0
            //
3651
0
            // Here, though, no new definitions were introduced. The instance
3652
0
            // created here is a "bag of exports" which could only refer to
3653
0
            // preexisting items. This means that inherently no new resources
3654
0
            // were created so there's nothing to put in this list. Any
3655
0
            // resources referenced by the instance must be bound by the outer
3656
0
            // component context or further above.
3657
0
            //
3658
0
            // Furthermore, however, actual instances of instances, which this
3659
0
            // is, aren't allowed to have defined resources. Instead the
3660
0
            // resources would have to be injected into the outer component
3661
0
            // enclosing the instance. That means that even if bag-of-exports
3662
0
            // could declare a new resource then the resource would be moved
3663
0
            // from here to `self.defined_resources`. This doesn't exist at this
3664
0
            // time, though, so this still remains empty and
3665
0
            // `self.defined_resources` remains unperturbed.
3666
0
            defined_resources: Default::default(),
3667
0
        }))
3668
0
    }
3669
3670
16.7k
    fn instantiate_core_exports(
3671
16.7k
        &mut self,
3672
16.7k
        exports: Vec<crate::Export>,
3673
16.7k
        types: &mut TypeAlloc,
3674
16.7k
        offset: usize,
3675
16.7k
    ) -> Result<ComponentCoreInstanceTypeId> {
3676
50.7k
        fn insert_export(
3677
50.7k
            types: &TypeList,
3678
50.7k
            name: &str,
3679
50.7k
            export: EntityType,
3680
50.7k
            exports: &mut IndexMap<String, EntityType>,
3681
50.7k
            info: &mut TypeInfo,
3682
50.7k
            offset: usize,
3683
50.7k
        ) -> Result<()> {
3684
50.7k
            info.combine(export.info(types), offset)?;
3685
3686
50.7k
            if exports.insert(name.to_string(), export).is_some() {
3687
0
                bail!(
3688
0
                    offset,
3689
                    "duplicate instantiation export name `{name}` already defined",
3690
                )
3691
50.7k
            }
3692
3693
50.7k
            Ok(())
3694
50.7k
        }
3695
3696
16.7k
        let mut info = TypeInfo::new();
3697
16.7k
        let mut inst_exports = IndexMap::default();
3698
50.7k
        for export in exports {
3699
50.7k
            match export.kind {
3700
                ExternalKind::Func | ExternalKind::FuncExact => {
3701
48.7k
                    insert_export(
3702
48.7k
                        types,
3703
48.7k
                        export.name,
3704
48.7k
                        EntityType::Func(self.core_function_at(export.index, offset)?),
3705
48.7k
                        &mut inst_exports,
3706
48.7k
                        &mut info,
3707
48.7k
                        offset,
3708
0
                    )?;
3709
                }
3710
2.03k
                ExternalKind::Table => insert_export(
3711
2.03k
                    types,
3712
2.03k
                    export.name,
3713
2.03k
                    EntityType::Table(*self.table_at(export.index, offset)?),
3714
2.03k
                    &mut inst_exports,
3715
2.03k
                    &mut info,
3716
2.03k
                    offset,
3717
0
                )?,
3718
0
                ExternalKind::Memory => insert_export(
3719
0
                    types,
3720
0
                    export.name,
3721
0
                    EntityType::Memory(*self.memory_at(export.index, offset)?),
3722
0
                    &mut inst_exports,
3723
0
                    &mut info,
3724
0
                    offset,
3725
0
                )?,
3726
                ExternalKind::Global => {
3727
0
                    insert_export(
3728
0
                        types,
3729
0
                        export.name,
3730
0
                        EntityType::Global(*self.global_at(export.index, offset)?),
3731
0
                        &mut inst_exports,
3732
0
                        &mut info,
3733
0
                        offset,
3734
0
                    )?;
3735
                }
3736
                ExternalKind::Tag => {
3737
0
                    require_feature::exceptions(
3738
0
                        self.features,
3739
                        "exceptions proposal not enabled",
3740
0
                        offset,
3741
0
                    )?;
3742
0
                    insert_export(
3743
0
                        types,
3744
0
                        export.name,
3745
0
                        EntityType::Tag(self.tag_at(export.index, offset)?),
3746
0
                        &mut inst_exports,
3747
0
                        &mut info,
3748
0
                        offset,
3749
0
                    )?
3750
                }
3751
            }
3752
        }
3753
3754
16.7k
        Ok(types.push_ty(InstanceType {
3755
16.7k
            info,
3756
16.7k
            kind: CoreInstanceTypeKind::Exports(inst_exports),
3757
16.7k
        }))
3758
16.7k
    }
3759
3760
45.1k
    fn alias_core_instance_export(
3761
45.1k
        &mut self,
3762
45.1k
        instance_index: u32,
3763
45.1k
        kind: ExternalKind,
3764
45.1k
        name: &str,
3765
45.1k
        types: &TypeList,
3766
45.1k
        offset: usize,
3767
45.1k
    ) -> Result<()> {
3768
        macro_rules! push_module_export {
3769
            ($expected:path, $collection:ident, $ty:literal) => {{
3770
                match self.core_instance_export(instance_index, name, types, offset)? {
3771
                    $expected(ty) => {
3772
                        self.$collection.push(*ty);
3773
                    }
3774
                    _ => {
3775
                        bail!(
3776
                            offset,
3777
                            "export `{name}` for core instance {instance_index} is not a {}",
3778
                            $ty
3779
                        )
3780
                    }
3781
                }
3782
            }};
3783
        }
3784
3785
45.1k
        match kind {
3786
            ExternalKind::Func | ExternalKind::FuncExact => {
3787
34.2k
                check_max(
3788
34.2k
                    self.function_count(),
3789
                    1,
3790
                    MAX_WASM_FUNCTIONS,
3791
34.2k
                    "functions",
3792
34.2k
                    offset,
3793
0
                )?;
3794
34.2k
                push_module_export!(EntityType::Func, core_funcs, "function");
3795
            }
3796
            ExternalKind::Table => {
3797
2.03k
                check_max(
3798
2.03k
                    self.core_tables.len(),
3799
                    1,
3800
                    MAX_CORE_INDEX_SPACE_ITEMS,
3801
2.03k
                    "tables",
3802
2.03k
                    offset,
3803
0
                )?;
3804
2.03k
                push_module_export!(EntityType::Table, core_tables, "table");
3805
            }
3806
            ExternalKind::Memory => {
3807
8.84k
                check_max(
3808
8.84k
                    self.core_memories.len(),
3809
                    1,
3810
                    MAX_CORE_INDEX_SPACE_ITEMS,
3811
8.84k
                    "memories",
3812
8.84k
                    offset,
3813
0
                )?;
3814
8.84k
                push_module_export!(EntityType::Memory, core_memories, "memory");
3815
            }
3816
            ExternalKind::Global => {
3817
0
                check_max(
3818
0
                    self.core_globals.len(),
3819
                    1,
3820
                    MAX_CORE_INDEX_SPACE_ITEMS,
3821
0
                    "globals",
3822
0
                    offset,
3823
0
                )?;
3824
0
                push_module_export!(EntityType::Global, core_globals, "global");
3825
            }
3826
            ExternalKind::Tag => {
3827
0
                require_feature::exceptions(
3828
0
                    self.features,
3829
                    "exceptions proposal not enabled",
3830
0
                    offset,
3831
0
                )?;
3832
0
                check_max(
3833
0
                    self.core_tags.len(),
3834
                    1,
3835
                    MAX_CORE_INDEX_SPACE_ITEMS,
3836
0
                    "tags",
3837
0
                    offset,
3838
0
                )?;
3839
0
                push_module_export!(EntityType::Tag, core_tags, "tag");
3840
            }
3841
        }
3842
3843
45.1k
        Ok(())
3844
45.1k
    }
3845
3846
11.3k
    fn alias_instance_export(
3847
11.3k
        &mut self,
3848
11.3k
        instance_index: u32,
3849
11.3k
        kind: ComponentExternalKind,
3850
11.3k
        name: &str,
3851
11.3k
        types: &mut TypeAlloc,
3852
11.3k
        offset: usize,
3853
11.3k
    ) -> Result<()> {
3854
11.3k
        if let ComponentExternalKind::Value = kind {
3855
0
            self.check_value_support(offset)?;
3856
11.3k
        }
3857
11.3k
        let mut ty = match types[self.instance_at(instance_index, offset)?]
3858
            .exports
3859
11.3k
            .get(name)
3860
        {
3861
11.3k
            Some(ty) => ty.ty,
3862
0
            None => bail!(
3863
0
                offset,
3864
                "instance {instance_index} has no export named `{name}`"
3865
            ),
3866
        };
3867
3868
11.3k
        let ok = match (ty, kind) {
3869
0
            (ComponentEntityType::Module(_), ComponentExternalKind::Module) => true,
3870
0
            (ComponentEntityType::Module(_), _) => false,
3871
0
            (ComponentEntityType::Component(_), ComponentExternalKind::Component) => true,
3872
0
            (ComponentEntityType::Component(_), _) => false,
3873
2.91k
            (ComponentEntityType::Func(_), ComponentExternalKind::Func) => true,
3874
0
            (ComponentEntityType::Func(_), _) => false,
3875
0
            (ComponentEntityType::Instance(_), ComponentExternalKind::Instance) => true,
3876
0
            (ComponentEntityType::Instance(_), _) => false,
3877
0
            (ComponentEntityType::Value(_), ComponentExternalKind::Value) => true,
3878
0
            (ComponentEntityType::Value(_), _) => false,
3879
8.41k
            (ComponentEntityType::Type { .. }, ComponentExternalKind::Type) => true,
3880
0
            (ComponentEntityType::Type { .. }, _) => false,
3881
        };
3882
11.3k
        if !ok {
3883
0
            bail!(
3884
0
                offset,
3885
                "export `{name}` for instance {instance_index} is not a {}",
3886
0
                kind.desc(),
3887
            );
3888
11.3k
        }
3889
3890
11.3k
        self.add_entity(&mut ty, None, types, offset)?;
3891
11.3k
        Ok(())
3892
11.3k
    }
3893
3894
0
    fn alias_module(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> {
3895
0
        let component = Self::check_alias_count(components, count, offset)?;
3896
0
        let ty = component.module_at(index, offset)?;
3897
3898
0
        let current = components.last_mut().unwrap();
3899
0
        check_max(
3900
0
            current.core_modules.len(),
3901
            1,
3902
            MAX_WASM_MODULES,
3903
0
            "modules",
3904
0
            offset,
3905
0
        )?;
3906
3907
0
        current.core_modules.push(ty);
3908
0
        Ok(())
3909
0
    }
3910
3911
0
    fn alias_component(
3912
0
        components: &mut [Self],
3913
0
        count: u32,
3914
0
        index: u32,
3915
0
        offset: usize,
3916
0
    ) -> Result<()> {
3917
0
        let component = Self::check_alias_count(components, count, offset)?;
3918
0
        let ty = component.component_at(index, offset)?;
3919
3920
0
        let current = components.last_mut().unwrap();
3921
0
        check_max(
3922
0
            current.components.len(),
3923
            1,
3924
            MAX_WASM_COMPONENTS,
3925
0
            "components",
3926
0
            offset,
3927
0
        )?;
3928
3929
0
        current.components.push(ty);
3930
0
        Ok(())
3931
0
    }
3932
3933
0
    fn alias_core_type(
3934
0
        components: &mut [Self],
3935
0
        count: u32,
3936
0
        index: u32,
3937
0
        offset: usize,
3938
0
    ) -> Result<()> {
3939
0
        let component = Self::check_alias_count(components, count, offset)?;
3940
0
        let ty = component.core_type_at(index, offset)?;
3941
3942
0
        let current = components.last_mut().unwrap();
3943
0
        check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
3944
3945
0
        current.core_types.push(ty);
3946
3947
0
        Ok(())
3948
0
    }
3949
3950
10.1k
    fn alias_type(
3951
10.1k
        components: &mut [Self],
3952
10.1k
        count: u32,
3953
10.1k
        index: u32,
3954
10.1k
        types: &mut TypeAlloc,
3955
10.1k
        offset: usize,
3956
10.1k
    ) -> Result<()> {
3957
10.1k
        let component = Self::check_alias_count(components, count, offset)?;
3958
10.1k
        let ty = component.component_type_at(index, offset)?;
3959
3960
        // If `count` "crossed a component boundary", meaning that it went from
3961
        // one component to another, then this must additionally verify that
3962
        // `ty` has no free variables with respect to resources. This is
3963
        // intended to preserve the property for components where each component
3964
        // is an isolated unit that can theoretically be extracted from other
3965
        // components. If resources from other components were allowed to leak
3966
        // in then it would prevent that.
3967
        //
3968
        // This check is done by calculating the `pos` within `components` that
3969
        // our target `component` above was selected at. Once this is acquired
3970
        // the component to the "right" is checked, and if that's a component
3971
        // then it's considered as crossing a component boundary meaning the
3972
        // free variables check runs.
3973
        //
3974
        // The reason this works is that in the list of `ComponentState` types
3975
        // it's guaranteed that any `is_type` components are contiguous at the
3976
        // end of the array. This means that if state one level deeper than the
3977
        // target of this alias is a `!is_type` component, then the target must
3978
        // be a component as well. If the one-level deeper state `is_type` then
3979
        // the target is either a type or a component, both of which are valid
3980
        // (as aliases can reach the enclosing component and have as many free
3981
        // variables as they want).
3982
10.1k
        let pos_after_component = components.len() - (count as usize);
3983
10.1k
        if let Some(component) = components.get(pos_after_component) {
3984
10.1k
            if component.kind == ComponentKind::Component {
3985
0
                let mut free = IndexSet::default();
3986
0
                types.free_variables_any_type_id(ty, &mut free);
3987
0
                if !free.is_empty() {
3988
0
                    bail!(
3989
0
                        offset,
3990
                        "cannot alias outer type which transitively refers \
3991
                         to resources not defined in the current component"
3992
                    );
3993
0
                }
3994
10.1k
            }
3995
0
        }
3996
3997
10.1k
        let current = components.last_mut().unwrap();
3998
10.1k
        check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?;
3999
4000
10.1k
        current.types.push(ty);
4001
4002
10.1k
        Ok(())
4003
10.1k
    }
4004
4005
10.1k
    fn check_alias_count(components: &[Self], count: u32, offset: usize) -> Result<&Self> {
4006
10.1k
        let count = count as usize;
4007
10.1k
        if count >= components.len() {
4008
0
            bail!(offset, "invalid outer alias count of {count}");
4009
10.1k
        }
4010
4011
10.1k
        Ok(&components[components.len() - count - 1])
4012
10.1k
    }
4013
4014
227k
    fn create_defined_type(
4015
227k
        &self,
4016
227k
        ty: crate::ComponentDefinedType,
4017
227k
        types: &TypeList,
4018
227k
        offset: usize,
4019
227k
    ) -> Result<ComponentDefinedType> {
4020
227k
        match ty {
4021
2.39k
            crate::ComponentDefinedType::Primitive(ty) => {
4022
2.39k
                self.check_primitive_type(ty, offset)?;
4023
2.39k
                Ok(ComponentDefinedType::Primitive(ty))
4024
            }
4025
7.04k
            crate::ComponentDefinedType::Record(fields) => {
4026
7.04k
                self.create_record_type(fields.as_ref(), types, offset)
4027
            }
4028
8.06k
            crate::ComponentDefinedType::Variant(cases) => {
4029
8.06k
                self.create_variant_type(cases.as_ref(), types, offset)
4030
            }
4031
6.81k
            crate::ComponentDefinedType::List(ty) => {
4032
6.81k
                let element = self.create_component_val_type(ty, offset)?;
4033
6.81k
                let mut info = TypeInfo::new();
4034
6.81k
                info.combine(element.info(types), offset)?;
4035
6.81k
                Ok(ComponentDefinedType::List { element, info })
4036
            }
4037
0
            crate::ComponentDefinedType::Map(key, value) => {
4038
0
                require_feature::cm_map(
4039
0
                    self.features,
4040
                    "Maps require the component model map feature",
4041
0
                    offset,
4042
0
                )?;
4043
0
                let key = self.create_component_val_type(key, offset)?;
4044
0
                let value = self.create_component_val_type(value, offset)?;
4045
0
                let mut info = TypeInfo::new();
4046
0
                info.combine(key.info(types), offset)?;
4047
0
                info.combine(value.info(types), offset)?;
4048
0
                Ok(ComponentDefinedType::Map { key, value, info })
4049
            }
4050
4.02k
            crate::ComponentDefinedType::FixedLengthList(ty, elements) => {
4051
4.02k
                require_feature::cm_fixed_length_lists(
4052
4.02k
                    self.features,
4053
                    "Fixed-length lists require the component model fixed-length lists feature",
4054
4.02k
                    offset,
4055
0
                )?;
4056
4.02k
                if elements < 1 {
4057
0
                    bail!(
4058
0
                        offset,
4059
                        "Fixed-length lists must have more than zero elements"
4060
                    )
4061
4.02k
                }
4062
4.02k
                check_max(
4063
                    0,
4064
4.02k
                    elements,
4065
                    MAX_WASM_FIXED_LENGTH_LIST_ELEMENTS,
4066
4.02k
                    "fixed-length list element",
4067
4.02k
                    offset,
4068
0
                )?;
4069
4.02k
                let element = self.create_component_val_type(ty, offset)?;
4070
4.02k
                let mut info = TypeInfo::new();
4071
4.02k
                info.combine(element.info(types), offset)?;
4072
4.02k
                Ok(ComponentDefinedType::FixedLengthList {
4073
4.02k
                    element,
4074
4.02k
                    length: elements,
4075
4.02k
                    info,
4076
4.02k
                })
4077
            }
4078
41.8k
            crate::ComponentDefinedType::Tuple(tys) => {
4079
41.8k
                self.create_tuple_type(tys.as_ref(), types, offset)
4080
            }
4081
1.27k
            crate::ComponentDefinedType::Flags(names) => {
4082
1.27k
                self.create_flags_type(names.as_ref(), offset)
4083
            }
4084
88.6k
            crate::ComponentDefinedType::Enum(cases) => {
4085
88.6k
                self.create_enum_type(cases.as_ref(), offset)
4086
            }
4087
19.4k
            crate::ComponentDefinedType::Option(ty) => {
4088
19.4k
                let ty = self.create_component_val_type(ty, offset)?;
4089
19.4k
                let mut info = TypeInfo::new();
4090
19.4k
                info.combine(ty.info(types), offset)?;
4091
19.4k
                Ok(ComponentDefinedType::Option { ty, info })
4092
            }
4093
32.8k
            crate::ComponentDefinedType::Result { ok, err } => {
4094
32.8k
                let ok = ok
4095
32.8k
                    .map(|ty| self.create_component_val_type(ty, offset))
4096
32.8k
                    .transpose()?;
4097
32.8k
                let err = err
4098
32.8k
                    .map(|ty| self.create_component_val_type(ty, offset))
4099
32.8k
                    .transpose()?;
4100
32.8k
                let mut info = TypeInfo::new();
4101
32.8k
                if let Some(ty) = &ok {
4102
30.5k
                    info.combine(ty.info(types), offset)?;
4103
2.28k
                }
4104
32.8k
                if let Some(ty) = &err {
4105
29.3k
                    info.combine(ty.info(types), offset)?;
4106
3.47k
                }
4107
32.8k
                Ok(ComponentDefinedType::Result { ok, err, info })
4108
            }
4109
1.39k
            crate::ComponentDefinedType::Own(idx) => Ok(ComponentDefinedType::Own(
4110
1.39k
                self.resource_at(idx, types, offset)?,
4111
            )),
4112
2.63k
            crate::ComponentDefinedType::Borrow(idx) => Ok(ComponentDefinedType::Borrow(
4113
2.63k
                self.resource_at(idx, types, offset)?,
4114
            )),
4115
6.84k
            crate::ComponentDefinedType::Future(ty) => {
4116
6.84k
                require_feature::cm_async(
4117
6.84k
                    self.features,
4118
                    "`future` requires the component model async feature",
4119
6.84k
                    offset,
4120
0
                )?;
4121
6.84k
                let ty = ty
4122
6.84k
                    .map(|ty| self.create_component_val_type(ty, offset))
4123
6.84k
                    .transpose()?;
4124
6.84k
                let mut info = TypeInfo::new();
4125
6.84k
                if let Some(ty) = &ty {
4126
6.26k
                    info.combine(ty.info(types), offset)?;
4127
583
                }
4128
6.84k
                Ok(ComponentDefinedType::Future { ty, info })
4129
            }
4130
4.15k
            crate::ComponentDefinedType::Stream(ty) => {
4131
4.15k
                require_feature::cm_async(
4132
4.15k
                    self.features,
4133
                    "`stream` requires the component model async feature",
4134
4.15k
                    offset,
4135
0
                )?;
4136
4.15k
                let ty = ty
4137
4.15k
                    .map(|ty| self.create_component_val_type(ty, offset))
4138
4.15k
                    .transpose()?;
4139
4.15k
                let prim = match ty {
4140
738
                    Some(ComponentValType::Primitive(p)) => Some(p),
4141
3.41k
                    Some(ComponentValType::Type(id)) => match types[id] {
4142
0
                        ComponentDefinedType::Primitive(p) => Some(p),
4143
3.41k
                        _ => None,
4144
                    },
4145
0
                    None => None,
4146
                };
4147
4.15k
                if prim == Some(crate::PrimitiveValType::Char) {
4148
22
                    bail!(
4149
22
                        offset,
4150
                        "`stream<char>` is not valid at this time, use `stream<u8>` \
4151
                         with a defined by encoding instead for now"
4152
                    )
4153
4.12k
                }
4154
4.12k
                let mut info = TypeInfo::new();
4155
4.12k
                if let Some(ty) = &ty {
4156
4.12k
                    info.combine(ty.info(types), offset)?;
4157
0
                }
4158
4.12k
                Ok(ComponentDefinedType::Stream { ty, info })
4159
            }
4160
        }
4161
227k
    }
4162
4163
7.04k
    fn create_record_type(
4164
7.04k
        &self,
4165
7.04k
        fields: &[(&str, crate::ComponentValType)],
4166
7.04k
        types: &TypeList,
4167
7.04k
        offset: usize,
4168
7.04k
    ) -> Result<ComponentDefinedType> {
4169
7.04k
        let mut info = TypeInfo::new();
4170
7.04k
        let mut field_map = IndexMap::default();
4171
7.04k
        field_map.reserve(fields.len());
4172
4173
7.04k
        if fields.is_empty() {
4174
0
            bail!(offset, "record type must have at least one field");
4175
7.04k
        }
4176
4177
25.6k
        for (name, ty) in fields {
4178
25.6k
            let kebab = to_kebab_string(name, "record field", offset)?;
4179
25.6k
            let ty = self.create_component_val_type(*ty, offset)?;
4180
4181
25.6k
            match field_map.entry(kebab) {
4182
0
                Entry::Occupied(e) => bail!(
4183
0
                    offset,
4184
                    "record field name `{name}` conflicts with previous field name `{prev}`",
4185
0
                    prev = e.key()
4186
                ),
4187
25.6k
                Entry::Vacant(e) => {
4188
25.6k
                    info.combine(ty.info(types), offset)?;
4189
25.6k
                    e.insert(ty);
4190
                }
4191
            }
4192
        }
4193
4194
7.04k
        Ok(ComponentDefinedType::Record(RecordType {
4195
7.04k
            info,
4196
7.04k
            fields: field_map,
4197
7.04k
        }))
4198
7.04k
    }
4199
4200
8.06k
    fn create_variant_type(
4201
8.06k
        &self,
4202
8.06k
        cases: &[crate::VariantCase],
4203
8.06k
        types: &TypeList,
4204
8.06k
        offset: usize,
4205
8.06k
    ) -> Result<ComponentDefinedType> {
4206
8.06k
        let mut info = TypeInfo::new();
4207
8.06k
        let mut case_map: IndexMap<KebabString, VariantCase> = IndexMap::default();
4208
8.06k
        case_map.reserve(cases.len());
4209
4210
8.06k
        if cases.is_empty() {
4211
0
            bail!(offset, "variant type must have at least one case");
4212
8.06k
        }
4213
4214
8.06k
        if cases.len() > u32::MAX as usize {
4215
0
            return Err(Error::new(
4216
0
                "variant type cannot be represented with a 32-bit discriminant value",
4217
0
                offset,
4218
0
            ));
4219
8.06k
        }
4220
4221
36.7k
        for case in cases {
4222
36.7k
            let name = to_kebab_string(case.name, "variant case", offset)?;
4223
4224
36.7k
            let ty = case
4225
36.7k
                .ty
4226
36.7k
                .map(|ty| self.create_component_val_type(ty, offset))
4227
36.7k
                .transpose()?;
4228
4229
36.7k
            match case_map.entry(name) {
4230
0
                Entry::Occupied(e) => bail!(
4231
0
                    offset,
4232
                    "variant case name `{name}` conflicts with previous case name `{prev}`",
4233
                    name = case.name,
4234
0
                    prev = e.key()
4235
                ),
4236
36.7k
                Entry::Vacant(e) => {
4237
36.7k
                    if let Some(ty) = ty {
4238
33.9k
                        info.combine(ty.info(types), offset)?;
4239
2.82k
                    }
4240
36.7k
                    e.insert(VariantCase { ty });
4241
                }
4242
            }
4243
        }
4244
4245
8.06k
        Ok(ComponentDefinedType::Variant(VariantType {
4246
8.06k
            info,
4247
8.06k
            cases: case_map,
4248
8.06k
        }))
4249
8.06k
    }
4250
4251
41.8k
    fn create_tuple_type(
4252
41.8k
        &self,
4253
41.8k
        tys: &[crate::ComponentValType],
4254
41.8k
        types: &TypeList,
4255
41.8k
        offset: usize,
4256
41.8k
    ) -> Result<ComponentDefinedType> {
4257
41.8k
        let mut info = TypeInfo::new();
4258
41.8k
        if tys.is_empty() {
4259
0
            bail!(offset, "tuple type must have at least one type");
4260
41.8k
        }
4261
41.8k
        let types = tys
4262
41.8k
            .iter()
4263
151k
            .map(|ty| {
4264
151k
                let ty = self.create_component_val_type(*ty, offset)?;
4265
151k
                info.combine(ty.info(types), offset)?;
4266
151k
                Ok(ty)
4267
151k
            })
4268
41.8k
            .collect::<Result<_>>()?;
4269
4270
41.8k
        Ok(ComponentDefinedType::Tuple(TupleType { info, types }))
4271
41.8k
    }
4272
4273
1.27k
    fn create_flags_type(&self, names: &[&str], offset: usize) -> Result<ComponentDefinedType> {
4274
1.27k
        let mut names_set = IndexSet::default();
4275
1.27k
        names_set.reserve(names.len());
4276
4277
1.27k
        if names.is_empty() {
4278
0
            bail!(offset, "flags must have at least one entry");
4279
1.27k
        }
4280
4281
1.27k
        if names.len() > 32 {
4282
0
            bail!(offset, "cannot have more than 32 flags");
4283
1.27k
        }
4284
4285
4.01k
        for name in names {
4286
4.01k
            let kebab = to_kebab_string(name, "flag", offset)?;
4287
4.01k
            if let Some(prev) = names_set.replace(kebab) {
4288
0
                bail!(
4289
0
                    offset,
4290
                    "flag name `{name}` conflicts with previous flag name `{prev}`",
4291
                );
4292
4.01k
            }
4293
        }
4294
4295
1.27k
        Ok(ComponentDefinedType::Flags(names_set))
4296
1.27k
    }
4297
4298
88.6k
    fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result<ComponentDefinedType> {
4299
88.6k
        if cases.len() > u32::MAX as usize {
4300
0
            return Err(Error::new(
4301
0
                "enumeration type cannot be represented with a 32-bit discriminant value",
4302
0
                offset,
4303
0
            ));
4304
88.6k
        }
4305
4306
88.6k
        if cases.is_empty() {
4307
0
            bail!(offset, "enum type must have at least one variant");
4308
88.6k
        }
4309
4310
88.6k
        let mut tags = IndexSet::default();
4311
88.6k
        tags.reserve(cases.len());
4312
4313
638k
        for tag in cases {
4314
638k
            let kebab = to_kebab_string(tag, "enum tag", offset)?;
4315
638k
            if let Some(prev) = tags.replace(kebab) {
4316
0
                bail!(
4317
0
                    offset,
4318
                    "enum tag name `{tag}` conflicts with previous tag name `{prev}`",
4319
                );
4320
638k
            }
4321
        }
4322
4323
88.6k
        Ok(ComponentDefinedType::Enum(tags))
4324
88.6k
    }
4325
4326
434k
    fn create_component_val_type(
4327
434k
        &self,
4328
434k
        ty: crate::ComponentValType,
4329
434k
        offset: usize,
4330
434k
    ) -> Result<ComponentValType> {
4331
434k
        Ok(match ty {
4332
296k
            crate::ComponentValType::Primitive(pt) => {
4333
296k
                self.check_primitive_type(pt, offset)?;
4334
296k
                ComponentValType::Primitive(pt)
4335
            }
4336
137k
            crate::ComponentValType::Type(idx) => {
4337
137k
                ComponentValType::Type(self.defined_type_at(idx, offset)?)
4338
            }
4339
        })
4340
434k
    }
4341
4342
0
    pub fn core_type_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreTypeId> {
4343
0
        self.core_types
4344
0
            .get(idx as usize)
4345
0
            .copied()
4346
0
            .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
4347
0
    }
4348
4349
453k
    pub fn component_type_at(&self, idx: u32, offset: usize) -> Result<ComponentAnyTypeId> {
4350
453k
        self.types
4351
453k
            .get(idx as usize)
4352
453k
            .copied()
4353
453k
            .ok_or_else(|| format_err!(offset, "unknown type {idx}: type index out of bounds"))
4354
453k
    }
4355
4356
9.12k
    fn function_type_at<'a>(
4357
9.12k
        &self,
4358
9.12k
        idx: u32,
4359
9.12k
        types: &'a TypeList,
4360
9.12k
        offset: usize,
4361
9.12k
    ) -> Result<&'a ComponentFuncType> {
4362
9.12k
        let id = self.component_type_at(idx, offset)?;
4363
9.12k
        match id {
4364
9.12k
            ComponentAnyTypeId::Func(id) => Ok(&types[id]),
4365
0
            _ => bail!(offset, "type index {idx} is not a function type"),
4366
        }
4367
9.12k
    }
4368
4369
22.5k
    fn function_at(&self, idx: u32, offset: usize) -> Result<ComponentFuncTypeId> {
4370
22.5k
        self.funcs.get(idx as usize).copied().ok_or_else(|| {
4371
0
            format_err!(
4372
0
                offset,
4373
                "unknown function {idx}: function index out of bounds"
4374
            )
4375
0
        })
4376
22.5k
    }
4377
4378
5.16k
    fn component_at(&self, idx: u32, offset: usize) -> Result<ComponentTypeId> {
4379
5.16k
        self.components.get(idx as usize).copied().ok_or_else(|| {
4380
0
            format_err!(
4381
0
                offset,
4382
                "unknown component {idx}: component index out of bounds"
4383
            )
4384
0
        })
4385
5.16k
    }
4386
4387
16.5k
    fn instance_at(&self, idx: u32, offset: usize) -> Result<ComponentInstanceTypeId> {
4388
16.5k
        self.instances.get(idx as usize).copied().ok_or_else(|| {
4389
0
            format_err!(
4390
0
                offset,
4391
                "unknown instance {idx}: instance index out of bounds"
4392
            )
4393
0
        })
4394
16.5k
    }
4395
4396
0
    fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> {
4397
0
        match self.values.get_mut(idx as usize) {
4398
0
            Some((ty, used)) if !*used => {
4399
0
                *used = true;
4400
0
                Ok(ty)
4401
            }
4402
0
            Some(_) => bail!(offset, "value {idx} cannot be used more than once"),
4403
0
            None => bail!(offset, "unknown value {idx}: value index out of bounds"),
4404
        }
4405
0
    }
4406
4407
141k
    fn defined_type_at(&self, idx: u32, offset: usize) -> Result<ComponentDefinedTypeId> {
4408
141k
        match self.component_type_at(idx, offset)? {
4409
141k
            ComponentAnyTypeId::Defined(id) => Ok(id),
4410
0
            _ => bail!(offset, "type index {idx} is not a defined type"),
4411
        }
4412
141k
    }
4413
4414
68.5k
    fn core_function_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
4415
68.5k
        match self.core_funcs.get(idx as usize) {
4416
68.5k
            Some(id) => Ok(*id),
4417
0
            None => bail!(
4418
0
                offset,
4419
                "unknown core function {idx}: function index out of bounds"
4420
            ),
4421
        }
4422
68.5k
    }
4423
4424
21.7k
    fn module_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreModuleTypeId> {
4425
21.7k
        match self.core_modules.get(idx as usize) {
4426
21.7k
            Some(id) => Ok(*id),
4427
0
            None => bail!(offset, "unknown module {idx}: module index out of bounds"),
4428
        }
4429
21.7k
    }
4430
4431
61.9k
    fn core_instance_at(&self, idx: u32, offset: usize) -> Result<ComponentCoreInstanceTypeId> {
4432
61.9k
        match self.core_instances.get(idx as usize) {
4433
61.9k
            Some(id) => Ok(*id),
4434
0
            None => bail!(
4435
0
                offset,
4436
                "unknown core instance {idx}: instance index out of bounds"
4437
            ),
4438
        }
4439
61.9k
    }
4440
4441
45.1k
    fn core_instance_export<'a>(
4442
45.1k
        &self,
4443
45.1k
        instance_index: u32,
4444
45.1k
        name: &str,
4445
45.1k
        types: &'a TypeList,
4446
45.1k
        offset: usize,
4447
45.1k
    ) -> Result<&'a EntityType> {
4448
45.1k
        match types[self.core_instance_at(instance_index, offset)?]
4449
45.1k
            .internal_exports(types)
4450
45.1k
            .get(name)
4451
        {
4452
45.1k
            Some(export) => Ok(export),
4453
0
            None => bail!(
4454
0
                offset,
4455
                "core instance {instance_index} has no export named `{name}`"
4456
            ),
4457
        }
4458
45.1k
    }
4459
4460
0
    fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> {
4461
0
        match self.core_globals.get(idx as usize) {
4462
0
            Some(t) => Ok(t),
4463
0
            None => bail!(offset, "unknown global {idx}: global index out of bounds"),
4464
        }
4465
0
    }
4466
4467
2.03k
    fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> {
4468
2.03k
        match self.core_tables.get(idx as usize) {
4469
2.03k
            Some(t) => Ok(t),
4470
0
            None => bail!(offset, "unknown table {idx}: table index out of bounds"),
4471
        }
4472
2.03k
    }
4473
4474
8.44k
    fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> {
4475
8.44k
        match self.core_memories.get(idx as usize) {
4476
8.44k
            Some(t) => Ok(t),
4477
0
            None => bail!(offset, "unknown memory {idx}: memory index out of bounds"),
4478
        }
4479
8.44k
    }
4480
4481
0
    fn tag_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
4482
0
        match self.core_tags.get(idx as usize) {
4483
0
            Some(t) => Ok(*t),
4484
0
            None => bail!(offset, "unknown tag {idx}: tag index out of bounds"),
4485
        }
4486
0
    }
4487
4488
    /// Validates that the linear memory at `idx` is valid to use as a canonical
4489
    /// ABI memory.
4490
    ///
4491
    /// At this time this requires that the memory is a plain 32-bit or 64-bit linear
4492
    /// memory. Notably this disallows shared memory.
4493
5.34k
    fn cabi_memory_at(&self, idx: u32, offset: usize) -> Result<PtrSize> {
4494
5.34k
        let ty = self.memory_at(idx, offset)?;
4495
5.34k
        let valid_memory_type = MemoryType {
4496
5.34k
            initial: 0,
4497
5.34k
            maximum: None,
4498
5.34k
            memory64: ty.memory64,
4499
5.34k
            shared: false,
4500
5.34k
            page_size_log2: ty.page_size_log2,
4501
5.34k
        };
4502
5.34k
        if ty.memory64 {
4503
0
            require_feature::cm64(
4504
0
                self.features,
4505
                "64-bit memories require the `cm64` feature to be enabled",
4506
0
                offset,
4507
0
            )?;
4508
5.34k
        }
4509
5.34k
        SubtypeCx::memory_type(ty, &valid_memory_type, offset)?;
4510
5.34k
        Ok(if ty.memory64 {
4511
0
            PtrSize::Ptr64
4512
        } else {
4513
5.34k
            PtrSize::Ptr32
4514
        })
4515
5.34k
    }
4516
4517
    /// Completes the translation of this component, performing final
4518
    /// validation of its structure.
4519
    ///
4520
    /// This method is required to be called for translating all components.
4521
    /// Internally this will convert local data structures into a
4522
    /// `ComponentType` which is suitable to use to describe the type of this
4523
    /// component.
4524
87.6k
    pub fn finish(&mut self, types: &TypeAlloc, offset: usize) -> Result<ComponentType> {
4525
87.6k
        let mut ty = ComponentType {
4526
87.6k
            // Inherit some fields based on translation of the component.
4527
87.6k
            info: self.type_info,
4528
87.6k
            imports: self.imports.clone(),
4529
87.6k
            exports: self.exports.clone(),
4530
87.6k
4531
87.6k
            // This is filled in as a subset of `self.defined_resources`
4532
87.6k
            // depending on what's actually used by the exports. See the
4533
87.6k
            // bottom of this function.
4534
87.6k
            defined_resources: Default::default(),
4535
87.6k
4536
87.6k
            // These are inherited directly from what was calculated for this
4537
87.6k
            // component.
4538
87.6k
            imported_resources: mem::take(&mut self.imported_resources)
4539
87.6k
                .into_iter()
4540
87.6k
                .collect(),
4541
87.6k
            explicit_resources: mem::take(&mut self.explicit_resources),
4542
87.6k
        };
4543
4544
        // Collect all "free variables", or resources, from the imports of this
4545
        // component. None of the resources defined within this component can
4546
        // be used as part of the exports. This set is then used to reject any
4547
        // of `self.defined_resources` which show up.
4548
87.6k
        let mut free = IndexSet::default();
4549
87.6k
        for ty in ty.imports.values() {
4550
33.8k
            types.free_variables_component_entity(&ty.ty, &mut free);
4551
33.8k
        }
4552
87.6k
        for (resource, _path) in self.defined_resources.iter() {
4553
            // FIXME: this error message is quite opaque and doesn't indicate
4554
            // more contextual information such as:
4555
            //
4556
            // * what was the exported resource found in the imports
4557
            // * which import was the resource found within
4558
            //
4559
            // These are possible to calculate here if necessary, however.
4560
2.25k
            if free.contains(resource) {
4561
0
                bail!(offset, "local resource type found in imports");
4562
2.25k
            }
4563
        }
4564
4565
        // The next step in validation a component, with respect to resources,
4566
        // is to minimize the set of defined resources to only those that
4567
        // are actually used by the exports. This weeds out resources that are
4568
        // defined, used within a component, and never exported, for example.
4569
        //
4570
        // The free variables of all exports are inserted into the `free` set
4571
        // (which is reused from the imports after clearing it). The defined
4572
        // resources calculated for this component are then inserted into this
4573
        // type's list of defined resources if it's contained somewhere in
4574
        // the free variables.
4575
        //
4576
        // Note that at the same time all defined resources must be exported,
4577
        // somehow, transitively from this component. The `explicit_resources`
4578
        // map is consulted for this purpose which lists all explicitly
4579
        // exported resources in the component, regardless from whence they
4580
        // came. If not present in this map then it's not exported and an error
4581
        // is returned.
4582
        //
4583
        // NB: the "types are exported" check is probably sufficient nowadays
4584
        // that the check of the `explicit_resources` map is probably not
4585
        // necessary, but it's left here for completeness and out of an
4586
        // abundance of caution.
4587
87.6k
        free.clear();
4588
145k
        for ty in ty.exports.values() {
4589
145k
            types.free_variables_component_entity(&ty.ty, &mut free);
4590
145k
        }
4591
87.6k
        for (id, _rep) in mem::take(&mut self.defined_resources) {
4592
2.25k
            if !free.contains(&id) {
4593
0
                continue;
4594
2.25k
            }
4595
4596
2.25k
            let path = match ty.explicit_resources.get(&id).cloned() {
4597
2.25k
                Some(path) => path,
4598
                // FIXME: this error message is quite opaque and doesn't
4599
                // indicate more contextual information such as:
4600
                //
4601
                // * which resource wasn't found in an export
4602
                // * which export has a reference to the resource
4603
                //
4604
                // These are possible to calculate here if necessary, however.
4605
0
                None => bail!(
4606
0
                    offset,
4607
                    "local resource type found in export but not exported itself"
4608
                ),
4609
            };
4610
4611
2.25k
            ty.defined_resources.push((id, path));
4612
        }
4613
4614
87.6k
        Ok(ty)
4615
87.6k
    }
4616
4617
0
    fn check_value_support(&self, offset: usize) -> Result<()> {
4618
0
        require_feature::cm_values(
4619
0
            self.features,
4620
            "support for component model `value`s is not enabled",
4621
0
            offset,
4622
0
        )?;
4623
0
        Ok(())
4624
0
    }
4625
4626
299k
    fn check_primitive_type(&self, ty: crate::PrimitiveValType, offset: usize) -> Result<()> {
4627
299k
        if ty == crate::PrimitiveValType::ErrorContext {
4628
40.8k
            require_feature::cm_error_context(
4629
40.8k
                self.features,
4630
                "`error-context` requires the component model error-context feature",
4631
40.8k
                offset,
4632
0
            )?;
4633
258k
        }
4634
299k
        Ok(())
4635
299k
    }
4636
}
4637
4638
impl InternRecGroup for ComponentState {
4639
0
    fn features(&self) -> &WasmFeatures {
4640
0
        &self.features
4641
0
    }
4642
4643
0
    fn add_type_id(&mut self, id: CoreTypeId) {
4644
0
        self.core_types.push(ComponentCoreTypeId::Sub(id));
4645
0
    }
4646
4647
0
    fn type_id_at(&self, idx: u32, offset: usize) -> Result<CoreTypeId> {
4648
0
        match self.core_type_at(idx, offset)? {
4649
0
            ComponentCoreTypeId::Sub(id) => Ok(id),
4650
            ComponentCoreTypeId::Module(_) => {
4651
0
                bail!(offset, "type index {idx} is a module type, not a sub type");
4652
            }
4653
        }
4654
0
    }
4655
4656
0
    fn types_len(&self) -> u32 {
4657
0
        u32::try_from(self.core_types.len()).unwrap()
4658
0
    }
4659
}
4660
4661
impl ComponentNameContext {
4662
    /// Registers that the resource `id` is named `name` within this context.
4663
5.54k
    fn register(&mut self, name: &str, id: AliasableResourceId) {
4664
5.54k
        let idx = self.all_resource_names.len();
4665
5.54k
        let prev = self.resource_name_map.insert(id, idx);
4666
5.54k
        assert!(
4667
5.54k
            prev.is_none(),
4668
            "for {id:?}, inserted {idx:?} but already had {prev:?}"
4669
        );
4670
5.54k
        self.all_resource_names.insert(name.to_string());
4671
5.54k
    }
4672
4673
295k
    fn validate_extern(
4674
295k
        &self,
4675
295k
        name: &ComponentExternName<'_>,
4676
295k
        kind: ExternKind,
4677
295k
        ty: &ComponentEntityType,
4678
295k
        types: &TypeAlloc,
4679
295k
        offset: usize,
4680
295k
        kind_names: &mut IndexSet<ComponentName>,
4681
295k
        items: &mut IndexMap<String, ComponentItem>,
4682
295k
        info: &mut TypeInfo,
4683
295k
        features: &WasmFeatures,
4684
295k
    ) -> Result<()> {
4685
        let ComponentExternName {
4686
295k
            name,
4687
295k
            implements,
4688
295k
            external_id,
4689
295k
            version_suffix,
4690
295k
        } = *name;
4691
        // First validate that `name` is even a valid kebab name, meaning it's
4692
        // in kebab-case, is an ID, etc.
4693
295k
        let kebab =
4694
295k
            ComponentName::new_with_features(name, offset, *features).with_context(|| {
4695
0
                format!("{} name `{name}` is not a valid extern name", kind.desc(),)
4696
0
            })?;
4697
4698
295k
        if let ExternKind::Export = kind {
4699
261k
            match kebab.kind() {
4700
                ComponentNameKind::Label(_)
4701
                | ComponentNameKind::Method(_)
4702
                | ComponentNameKind::Static(_)
4703
                | ComponentNameKind::Constructor(_)
4704
261k
                | ComponentNameKind::Interface(_) => {}
4705
4706
                ComponentNameKind::Hash(_)
4707
                | ComponentNameKind::Url(_)
4708
                | ComponentNameKind::Dependency(_) => {
4709
0
                    bail!(offset, "name `{name}` is not a valid export name")
4710
                }
4711
            }
4712
33.8k
        }
4713
4714
295k
        if let Some(implements) = implements {
4715
11.6k
            require_feature::cm_implements(
4716
11.6k
                *features,
4717
                "the `cm-implements` feature is not active",
4718
11.6k
                offset,
4719
0
            )?;
4720
11.6k
            match kebab.kind() {
4721
11.6k
                ComponentNameKind::Label(_) => {}
4722
0
                _ => bail!(offset, "name `{name}` is not valid with `implements`",),
4723
            }
4724
4725
11.6k
            match ty {
4726
11.6k
                ComponentEntityType::Instance(_) => {}
4727
0
                _ => bail!(offset, "only instances can have an `implements`"),
4728
            }
4729
4730
11.6k
            let implements = ComponentName::new_with_features(implements, offset, *features)
4731
11.6k
                .with_context(|| format!("`{implements}` is not a valid name"))?;
4732
11.6k
            match implements.kind() {
4733
11.6k
                ComponentNameKind::Interface(_) => {}
4734
0
                _ => bail!(offset, "name `{implements}` must be an interface"),
4735
            }
4736
283k
        }
4737
4738
295k
        if let Some(_) = version_suffix {
4739
0
            require_feature::cm_canon_names(
4740
0
                *features,
4741
                "the `cm-canon-names` feature is not active",
4742
0
                offset,
4743
0
            )?;
4744
0
            match ty {
4745
0
                ComponentEntityType::Instance(_) => {}
4746
0
                _ => bail!(offset, "only instances can have an `versionsuffix`"),
4747
            }
4748
295k
        }
4749
4750
295k
        if let Some(_) = external_id {
4751
156k
            require_feature::cm_implements(
4752
156k
                *features,
4753
                "the `cm-implements` feature is not active",
4754
156k
                offset,
4755
0
            )?;
4756
139k
        }
4757
4758
        // Validate that the kebab name, if it has structure such as
4759
        // `[method]a.b`, is indeed valid with respect to known resources.
4760
295k
        self.validate(&kebab, version_suffix, ty, types, offset)
4761
295k
            .with_context(|| format!("{} name `{kebab}` is not valid", kind.desc()))?;
4762
4763
        // Top-level kebab-names must all be unique, even between both imports
4764
        // and exports ot a component. For those names consult the `kebab_names`
4765
        // set.
4766
295k
        if let Some(prev) = kind_names.replace(kebab.clone()) {
4767
0
            bail!(
4768
0
                offset,
4769
                "{} name `{kebab}` conflicts with previous name `{prev}`",
4770
0
                kind.desc()
4771
            );
4772
295k
        }
4773
4774
        // Otherwise all strings must be unique, regardless of their name, so
4775
        // consult the `items` set to ensure that we're not for example
4776
        // importing the same interface ID twice.
4777
295k
        match items.entry(name.to_string()) {
4778
0
            Entry::Occupied(e) => {
4779
0
                bail!(
4780
0
                    offset,
4781
                    "{kind} name `{name}` conflicts with previous name `{prev}`",
4782
0
                    kind = kind.desc(),
4783
0
                    prev = e.key(),
4784
                );
4785
            }
4786
295k
            Entry::Vacant(e) => {
4787
295k
                e.insert(ComponentItem {
4788
295k
                    ty: *ty,
4789
295k
                    implements: implements.map(|s| s.to_string()),
4790
295k
                    version_suffix: version_suffix.map(|s| s.to_string()),
4791
295k
                    external_id: external_id.map(|s| s.to_string()),
4792
                });
4793
295k
                info.combine(ty.info(types), offset)?;
4794
            }
4795
        }
4796
295k
        Ok(())
4797
295k
    }
4798
4799
    /// Validates that the `name` provided is allowed to have the type `ty`.
4800
295k
    fn validate(
4801
295k
        &self,
4802
295k
        name: &ComponentName,
4803
295k
        version_suffix: Option<&str>,
4804
295k
        ty: &ComponentEntityType,
4805
295k
        types: &TypeAlloc,
4806
295k
        offset: usize,
4807
295k
    ) -> Result<()> {
4808
295k
        let func = || {
4809
10.8k
            let id = match ty {
4810
10.8k
                ComponentEntityType::Func(id) => *id,
4811
0
                _ => bail!(offset, "item is not a func"),
4812
            };
4813
10.8k
            Ok(&types[id])
4814
10.8k
        };
4815
4816
295k
        match name.kind() {
4817
            // No validation necessary for these styles of names
4818
            ComponentNameKind::Label(_)
4819
            | ComponentNameKind::Url(_)
4820
            | ComponentNameKind::Hash(_)
4821
228k
            | ComponentNameKind::Dependency(_) => {}
4822
4823
            // Validate the `version_suffix` field in the context of interface
4824
            // names.
4825
56.4k
            ComponentNameKind::Interface(name) => {
4826
56.4k
                if let Err(e) = name.version(version_suffix) {
4827
0
                    bail!(offset, "invalid interface version: {e}");
4828
56.4k
                }
4829
            }
4830
4831
            // Constructors must return `(own $resource)` or
4832
            // `(result (own $Tresource))` and the `$resource` must be named
4833
            // within this context to match `rname`.
4834
924
            ComponentNameKind::Constructor(rname) => {
4835
924
                let ty = func()?;
4836
924
                if ty.async_ {
4837
0
                    bail!(offset, "constructor function cannot be async");
4838
924
                }
4839
924
                let ty = match ty.result {
4840
924
                    Some(result) => result,
4841
0
                    None => bail!(offset, "function should return one value"),
4842
                };
4843
924
                let resource = match ty {
4844
0
                    ComponentValType::Primitive(_) => None,
4845
924
                    ComponentValType::Type(ty) => match &types[ty] {
4846
924
                        ComponentDefinedType::Own(id) => Some(id),
4847
                        ComponentDefinedType::Result {
4848
0
                            ok: Some(ComponentValType::Type(ok)),
4849
                            ..
4850
0
                        } => match &types[*ok] {
4851
0
                            ComponentDefinedType::Own(id) => Some(id),
4852
0
                            _ => None,
4853
                        },
4854
0
                        _ => None,
4855
                    },
4856
                };
4857
924
                let resource = match resource {
4858
924
                    Some(id) => id,
4859
0
                    None => bail!(
4860
0
                        offset,
4861
                        "function should return `(own $T)` or `(result (own $T))`"
4862
                    ),
4863
                };
4864
924
                self.validate_resource_name(*resource, rname, offset)?;
4865
            }
4866
4867
            // Methods must take `(param "self" (borrow $resource))` as the
4868
            // first argument where `$resources` matches the name `resource` as
4869
            // named in this context.
4870
3.87k
            ComponentNameKind::Method(name) => {
4871
3.87k
                let ty = func()?;
4872
3.87k
                if ty.params.len() == 0 {
4873
0
                    bail!(offset, "function should have at least one argument");
4874
3.87k
                }
4875
3.87k
                let (pname, pty) = &ty.params[0];
4876
3.87k
                if pname.as_str() != "self" {
4877
0
                    bail!(
4878
0
                        offset,
4879
                        "function should have a first argument called `self`",
4880
                    );
4881
3.87k
                }
4882
3.87k
                let id = match pty {
4883
0
                    ComponentValType::Primitive(_) => None,
4884
3.87k
                    ComponentValType::Type(ty) => match &types[*ty] {
4885
3.87k
                        ComponentDefinedType::Borrow(id) => Some(id),
4886
0
                        _ => None,
4887
                    },
4888
                };
4889
3.87k
                let id = match id {
4890
3.87k
                    Some(id) => id,
4891
0
                    None => bail!(
4892
0
                        offset,
4893
                        "function should take a first argument of `(borrow $T)`"
4894
                    ),
4895
                };
4896
3.87k
                self.validate_resource_name(*id, name.resource(), offset)?;
4897
            }
4898
4899
            // Static methods don't have much validation beyond that they must
4900
            // be a function and the resource name referred to must already be
4901
            // in this context.
4902
6.05k
            ComponentNameKind::Static(name) => {
4903
6.05k
                func()?;
4904
6.05k
                if !self.all_resource_names.contains(name.resource().as_str()) {
4905
0
                    bail!(offset, "static resource name is not known in this context");
4906
6.05k
                }
4907
            }
4908
        }
4909
4910
295k
        Ok(())
4911
295k
    }
4912
4913
4.79k
    fn validate_resource_name(
4914
4.79k
        &self,
4915
4.79k
        id: AliasableResourceId,
4916
4.79k
        name: KebabStr<'_>,
4917
4.79k
        offset: usize,
4918
4.79k
    ) -> Result<()> {
4919
4.79k
        let expected_name_idx = match self.resource_name_map.get(&id) {
4920
4.79k
            Some(idx) => *idx,
4921
            None => {
4922
0
                bail!(
4923
0
                    offset,
4924
                    "resource used in function does not have a name in this context"
4925
                )
4926
            }
4927
        };
4928
4.79k
        let expected_name = &self.all_resource_names[expected_name_idx];
4929
4.79k
        if name.as_str() != expected_name {
4930
0
            bail!(
4931
0
                offset,
4932
                "function does not match expected resource name `{expected_name}`"
4933
            );
4934
4.79k
        }
4935
4.79k
        Ok(())
4936
4.79k
    }
4937
}
4938
4939
use self::append_only::*;
4940
4941
mod append_only {
4942
    use crate::prelude::IndexMap;
4943
    use core::hash::Hash;
4944
    use core::ops::Deref;
4945
4946
    pub struct IndexMapAppendOnly<K, V>(IndexMap<K, V>);
4947
4948
    impl<K, V> IndexMapAppendOnly<K, V>
4949
    where
4950
        K: Hash + Eq + Ord + PartialEq + Clone,
4951
    {
4952
7.44k
        pub fn insert(&mut self, key: K, value: V) {
4953
7.44k
            let prev = self.0.insert(key, value);
4954
7.44k
            assert!(prev.is_none());
4955
7.44k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, alloc::vec::Vec<usize>>>::insert
Line
Count
Source
4952
2.49k
        pub fn insert(&mut self, key: K, value: V) {
4953
2.49k
            let prev = self.0.insert(key, value);
4954
2.49k
            assert!(prev.is_none());
4955
2.49k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, core::option::Option<wasmparser::readers::core::types::ValType>>>::insert
Line
Count
Source
4952
4.94k
        pub fn insert(&mut self, key: K, value: V) {
4953
4.94k
            let prev = self.0.insert(key, value);
4954
4.94k
            assert!(prev.is_none());
4955
4.94k
        }
4956
    }
4957
4958
    impl<K, V> Deref for IndexMapAppendOnly<K, V> {
4959
        type Target = IndexMap<K, V>;
4960
140k
        fn deref(&self) -> &IndexMap<K, V> {
4961
140k
            &self.0
4962
140k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, alloc::vec::Vec<usize>> as core::ops::deref::Deref>::deref
Line
Count
Source
4960
51.3k
        fn deref(&self) -> &IndexMap<K, V> {
4961
51.3k
            &self.0
4962
51.3k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, core::option::Option<wasmparser::readers::core::types::ValType>> as core::ops::deref::Deref>::deref
Line
Count
Source
4960
88.9k
        fn deref(&self) -> &IndexMap<K, V> {
4961
88.9k
            &self.0
4962
88.9k
        }
4963
    }
4964
4965
    impl<K, V> Default for IndexMapAppendOnly<K, V> {
4966
504k
        fn default() -> Self {
4967
504k
            Self(Default::default())
4968
504k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, alloc::vec::Vec<usize>> as core::default::Default>::default
Line
Count
Source
4966
226k
        fn default() -> Self {
4967
226k
            Self(Default::default())
4968
226k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, core::option::Option<wasmparser::readers::core::types::ValType>> as core::default::Default>::default
Line
Count
Source
4966
278k
        fn default() -> Self {
4967
278k
            Self(Default::default())
4968
278k
        }
4969
    }
4970
4971
    impl<K, V> IntoIterator for IndexMapAppendOnly<K, V> {
4972
        type IntoIter = <IndexMap<K, V> as IntoIterator>::IntoIter;
4973
        type Item = <IndexMap<K, V> as IntoIterator>::Item;
4974
226k
        fn into_iter(self) -> Self::IntoIter {
4975
226k
            self.0.into_iter()
4976
226k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, alloc::vec::Vec<usize>> as core::iter::traits::collect::IntoIterator>::into_iter
Line
Count
Source
4974
87.6k
        fn into_iter(self) -> Self::IntoIter {
4975
87.6k
            self.0.into_iter()
4976
87.6k
        }
<wasmparser::validator::component::append_only::IndexMapAppendOnly<wasmparser::validator::component_types::ResourceId, core::option::Option<wasmparser::readers::core::types::ValType>> as core::iter::traits::collect::IntoIterator>::into_iter
Line
Count
Source
4974
138k
        fn into_iter(self) -> Self::IntoIter {
4975
138k
            self.0.into_iter()
4976
138k
        }
4977
    }
4978
}