Coverage Report

Created: 2026-07-05 07:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wit-component/src/validation.rs
Line
Count
Source
1
use crate::encoding::{Instance, Item, LibraryInfo, MainOrAdapter, ModuleImportMap};
2
use crate::{ComponentEncoder, StringEncoding};
3
use anyhow::{Context, Result, anyhow, bail};
4
use indexmap::{IndexMap, IndexSet, map::Entry};
5
use std::fmt;
6
use std::hash::Hash;
7
use std::mem;
8
use wasm_encoder::ExportKind;
9
use wasmparser::names::{ComponentName, ComponentNameKind};
10
use wasmparser::{
11
    Encoding, ExternalKind, FuncType, Parser, Payload, TypeRef, ValType, ValidPayload, Validator,
12
    WasmFeatures, types::TypesRef,
13
};
14
use wit_parser::{
15
    Function, InterfaceId, PackageName, Resolve, Type, TypeDefKind, TypeId, World, WorldId,
16
    WorldItem, WorldKey,
17
    abi::{AbiVariant, WasmSignature, WasmType},
18
};
19
20
9.26k
fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType {
21
24.9k
    fn from_wasm_type(ty: &WasmType) -> ValType {
22
24.9k
        match ty {
23
20.3k
            WasmType::I32 => ValType::I32,
24
277
            WasmType::I64 => ValType::I64,
25
2.68k
            WasmType::F32 => ValType::F32,
26
273
            WasmType::F64 => ValType::F64,
27
1.07k
            WasmType::Pointer => ValType::I32,
28
2
            WasmType::PointerOrI64 => ValType::I64,
29
281
            WasmType::Length => ValType::I32,
30
        }
31
24.9k
    }
32
33
9.26k
    FuncType::new(
34
9.26k
        signature.params.iter().map(from_wasm_type),
35
9.26k
        signature.results.iter().map(from_wasm_type),
36
    )
37
9.26k
}
38
39
/// Metadata about a validated module and what was found internally.
40
///
41
/// This structure houses information about `imports` and `exports` to the
42
/// module. Each of these specialized types contains "connection" information
43
/// between a module's imports/exports and the WIT or component-level constructs
44
/// they correspond to.
45
46
#[derive(Default)]
47
pub struct ValidatedModule {
48
    /// Information about a module's imports.
49
    pub imports: ImportMap,
50
51
    /// Information about a module's exports.
52
    pub exports: ExportMap,
53
}
54
55
impl ValidatedModule {
56
3.26k
    fn new(
57
3.26k
        encoder: &ComponentEncoder,
58
3.26k
        bytes: &[u8],
59
3.26k
        exports: &IndexSet<WorldKey>,
60
3.26k
        import_map: Option<&ModuleImportMap>,
61
3.26k
        info: Option<&LibraryInfo>,
62
3.26k
    ) -> Result<ValidatedModule> {
63
3.26k
        let mut validator = Validator::new_with_features(WasmFeatures::all());
64
3.26k
        let mut ret = ValidatedModule::default();
65
66
41.7k
        for payload in Parser::new(0).parse_all(bytes) {
67
41.7k
            let payload = payload?;
68
41.7k
            if let ValidPayload::End(_) = validator.payload(&payload)? {
69
3.26k
                break;
70
38.4k
            }
71
72
38.4k
            let types = validator.types(0).unwrap();
73
74
3.26k
            match payload {
75
3.26k
                Payload::Version { encoding, .. } if encoding != Encoding::Module => {
76
0
                    bail!("data is not a WebAssembly module");
77
                }
78
1.17k
                Payload::ImportSection(s) => {
79
11.4k
                    for import in s.into_imports() {
80
11.4k
                        let import = import?;
81
11.4k
                        ret.imports.add(import, encoder, import_map, info, types)?;
82
                    }
83
                }
84
3.26k
                Payload::ExportSection(s) => {
85
17.7k
                    for export in s {
86
17.7k
                        let export = export?;
87
17.7k
                        ret.exports.add(export, encoder, &exports, types)?;
88
                    }
89
                }
90
34.0k
                _ => continue,
91
            }
92
        }
93
94
3.26k
        ret.exports.validate(encoder, exports)?;
95
96
3.26k
        Ok(ret)
97
3.26k
    }
98
}
99
100
/// Metadata information about a module's imports.
101
///
102
/// This structure maintains the connection between component model "things" and
103
/// core wasm "things" by ensuring that all imports to the core wasm module are
104
/// classified by the `Import` enumeration.
105
#[derive(Default)]
106
pub struct ImportMap {
107
    /// The first level of the map here is the module namespace of the import
108
    /// and the second level of the map is the field namespace. The item is then
109
    /// how the import is satisfied.
110
    names: IndexMap<String, ImportInstance>,
111
}
112
113
pub enum ImportInstance {
114
    /// This import is satisfied by an entire instance of another
115
    /// adapter/module.
116
    Whole(MainOrAdapter),
117
118
    /// This import is satisfied by filling out each name possibly differently.
119
    Names(IndexMap<String, Import>),
120
}
121
122
/// Represents metadata about a `stream<T>` or `future<T>` type for a specific
123
/// payload type `T`.
124
///
125
/// Currently, the name mangling scheme we use to represent `stream` and
126
/// `future` intrinsics as core module function imports refers to a specific
127
/// `stream` or `future` type by naming an imported or exported component
128
/// function which has that type as a parameter or return type (where the
129
/// specific type is referred to using an ordinal numbering scheme).  Not only
130
/// does this approach unambiguously indicate the type of interest, but it
131
/// allows us to reuse the `realloc`, string encoding, memory, etc. used by that
132
/// function when emitting intrinsic declarations.
133
///
134
/// TODO: Rather than reusing the same canon opts as the function in which the
135
/// type appears, consider encoding them in the name mangling stream on an
136
/// individual basis, similar to how we encode `error-context.*` built-in
137
/// imports.
138
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
139
pub struct PayloadInfo {
140
    /// The original, mangled import name used to import this built-in
141
    /// (currently used only for hashing and debugging).
142
    pub name: String,
143
    /// The resolved type id for the `stream` or `future` type of interest.
144
    ///
145
    /// If `Unit{Future,Stream}` this means that it's a "unit" payload or has no associated
146
    /// type being sent.
147
    pub ty: PayloadType,
148
    /// The world key representing the import or export context of `function`.
149
    pub key: WorldKey,
150
    /// The interface that `function` was imported from or exported in, if any.
151
    pub interface: Option<InterfaceId>,
152
    /// Whether `function` is being imported or exported.
153
    ///
154
    /// This may affect how we emit the declaration of the built-in, e.g. if the
155
    /// payload type is an exported resource.
156
    pub imported: bool,
157
}
158
159
/// The type of future/stream referenced by a `PayloadInfo`
160
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
161
pub enum PayloadType {
162
    /// This is a future or stream located in a `Resolve` where `id` points to
163
    /// either of `TypeDefKind::{Future, Stream}`.
164
    Type {
165
        id: TypeId,
166
        /// The component-level function import or export where the type
167
        /// appeared as a parameter or result type.
168
        function: String,
169
    },
170
    /// This is a `future` (no type)
171
    UnitFuture,
172
    /// This is a `stream` (no type)
173
    UnitStream,
174
}
175
176
impl PayloadInfo {
177
    /// Returns the payload type that this future/stream type is using.
178
180
    pub fn payload(&self, resolve: &Resolve) -> Option<Type> {
179
180
        let id = match self.ty {
180
180
            PayloadType::Type { id, .. } => id,
181
0
            PayloadType::UnitFuture | PayloadType::UnitStream => return None,
182
        };
183
180
        match resolve.types[id].kind {
184
180
            TypeDefKind::Future(payload) | TypeDefKind::Stream(payload) => payload,
185
0
            _ => unreachable!(),
186
        }
187
180
    }
188
}
189
190
/// The different kinds of items that a module or an adapter can import.
191
///
192
/// This is intended to be an exhaustive definition of what can be imported into
193
/// core modules within a component that wit-component supports. This doesn't
194
/// get down to the level of storing any idx numbers; at its most specific, it
195
/// gives a name.
196
#[derive(Debug, Clone)]
197
pub enum Import {
198
    /// A top-level world function, with the name provided here, is imported
199
    /// into the module.
200
    WorldFunc(WorldKey, String, AbiVariant),
201
202
    /// An interface's function is imported into the module.
203
    ///
204
    /// The `WorldKey` here is the name of the interface in the world in
205
    /// question. The `InterfaceId` is the interface that was imported from and
206
    /// `String` is the WIT name of the function.
207
    InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
208
209
    /// An imported resource's destructor is imported.
210
    ///
211
    /// The key provided indicates whether it's for the top-level types of the
212
    /// world (`None`) or an interface (`Some` with the name of the interface).
213
    /// The `TypeId` is what resource is being dropped.
214
    ImportedResourceDrop(WorldKey, Option<InterfaceId>, TypeId),
215
216
    /// A `canon resource.drop` intrinsic for an exported item is being
217
    /// imported.
218
    ///
219
    /// This lists the key of the interface that's exporting the resource plus
220
    /// the id within that interface.
221
    ExportedResourceDrop(WorldKey, TypeId),
222
223
    /// A `canon resource.new` intrinsic for an exported item is being
224
    /// imported.
225
    ///
226
    /// This lists the key of the interface that's exporting the resource plus
227
    /// the id within that interface.
228
    ExportedResourceNew(WorldKey, TypeId),
229
230
    /// A `canon resource.rep` intrinsic for an exported item is being
231
    /// imported.
232
    ///
233
    /// This lists the key of the interface that's exporting the resource plus
234
    /// the id within that interface.
235
    ExportedResourceRep(WorldKey, TypeId),
236
237
    /// An export of an adapter is being imported with the specified type.
238
    ///
239
    /// This is used for when the main module imports an adapter function. The
240
    /// adapter name and function name match the module's own import, and the
241
    /// type must match that listed here.
242
    AdapterExport {
243
        adapter: String,
244
        func: String,
245
        ty: FuncType,
246
    },
247
248
    /// An adapter is importing the memory of the main module.
249
    ///
250
    /// (should be combined with `MainModuleExport` below one day)
251
    MainModuleMemory,
252
253
    /// An adapter is importing an arbitrary item from the main module.
254
    MainModuleExport { name: String, kind: ExportKind },
255
256
    /// An arbitrary item from either the main module or an adapter is being
257
    /// imported.
258
    ///
259
    /// (should probably subsume `MainModule*` and maybe `AdapterExport` above
260
    /// one day.
261
    Item(Item),
262
263
    /// A `canon task.return` intrinsic for an exported function.
264
    ///
265
    /// This allows an exported function to return a value and then continue
266
    /// running.
267
    ///
268
    /// As of this writing, only async-lifted exports use `task.return`, but the
269
    /// plan is to also support it for sync-lifted exports in the future as
270
    /// well.
271
    ExportedTaskReturn(WorldKey, Option<InterfaceId>, Function),
272
273
    /// A `canon task.cancel` intrinsic for an exported function.
274
    ///
275
    /// This allows an exported function to acknowledge a `CANCELLED` event.
276
    ExportedTaskCancel,
277
278
    /// The `context.get` intrinsic for the nth slot of storage.
279
    ContextGet {
280
        /// The type of the slot (`i32` or `i64`).
281
        ty: ValType,
282
        /// The index of the storage slot.
283
        slot: u32,
284
    },
285
    /// The `context.set` intrinsic for the nth slot of storage.
286
    ContextSet {
287
        /// The type of the slot (`i32` or `i64`).
288
        ty: ValType,
289
        /// The index of the storage slot.
290
        slot: u32,
291
    },
292
293
    /// A `canon backpressure.inc` intrinsic.
294
    BackpressureInc,
295
296
    /// A `canon backpressure.dec` intrinsic.
297
    BackpressureDec,
298
299
    /// A `waitable-set.new` intrinsic.
300
    WaitableSetNew,
301
302
    /// A `canon waitable-set.wait` intrinsic.
303
    ///
304
    /// This allows the guest to wait for any pending calls to async-lowered
305
    /// imports and/or `stream` and `future` operations to complete without
306
    /// unwinding the current Wasm stack.
307
    WaitableSetWait { cancellable: bool },
308
309
    /// A `canon waitable.poll` intrinsic.
310
    ///
311
    /// This allows the guest to check whether any pending calls to
312
    /// async-lowered imports and/or `stream` and `future` operations have
313
    /// completed without unwinding the current Wasm stack and without blocking.
314
    WaitableSetPoll { cancellable: bool },
315
316
    /// A `waitable-set.drop` intrinsic.
317
    WaitableSetDrop,
318
319
    /// A `waitable.join` intrinsic.
320
    WaitableJoin,
321
322
    /// A `canon subtask.drop` intrinsic.
323
    ///
324
    /// This allows the guest to release its handle to a completed subtask.
325
    SubtaskDrop,
326
327
    /// A `canon subtask.cancel` intrinsic.
328
    ///
329
    /// This allows the guest to cancel an in-progress subtask.
330
    SubtaskCancel { async_: bool },
331
332
    /// A `canon stream.new` intrinsic.
333
    ///
334
    /// This allows the guest to create a new `stream` of the specified type.
335
    StreamNew(PayloadInfo),
336
337
    /// A `canon stream.read` intrinsic.
338
    ///
339
    /// This allows the guest to read the next values (if any) from the specified
340
    /// stream.
341
    StreamRead { async_: bool, info: PayloadInfo },
342
343
    /// A `canon stream.write` intrinsic.
344
    ///
345
    /// This allows the guest to write one or more values to the specified
346
    /// stream.
347
    StreamWrite { async_: bool, info: PayloadInfo },
348
349
    /// A `canon stream.cancel-read` intrinsic.
350
    ///
351
    /// This allows the guest to cancel a pending read it initiated earlier (but
352
    /// which may have already partially or entirely completed).
353
    StreamCancelRead { info: PayloadInfo, async_: bool },
354
355
    /// A `canon stream.cancel-write` intrinsic.
356
    ///
357
    /// This allows the guest to cancel a pending write it initiated earlier
358
    /// (but which may have already partially or entirely completed).
359
    StreamCancelWrite { info: PayloadInfo, async_: bool },
360
361
    /// A `canon stream.drop-readable` intrinsic.
362
    ///
363
    /// This allows the guest to drop the readable end of a `stream`.
364
    StreamDropReadable(PayloadInfo),
365
366
    /// A `canon stream.drop-writable` intrinsic.
367
    ///
368
    /// This allows the guest to drop the writable end of a `stream`.
369
    StreamDropWritable(PayloadInfo),
370
371
    /// A `canon future.new` intrinsic.
372
    ///
373
    /// This allows the guest to create a new `future` of the specified type.
374
    FutureNew(PayloadInfo),
375
376
    /// A `canon future.read` intrinsic.
377
    ///
378
    /// This allows the guest to read the value (if any) from the specified
379
    /// future.
380
    FutureRead { async_: bool, info: PayloadInfo },
381
382
    /// A `canon future.write` intrinsic.
383
    ///
384
    /// This allows the guest to write a value to the specified future.
385
    FutureWrite { async_: bool, info: PayloadInfo },
386
387
    /// A `canon future.cancel-read` intrinsic.
388
    ///
389
    /// This allows the guest to cancel a pending read it initiated earlier (but
390
    /// which may have already completed).
391
    FutureCancelRead { info: PayloadInfo, async_: bool },
392
393
    /// A `canon future.cancel-write` intrinsic.
394
    ///
395
    /// This allows the guest to cancel a pending write it initiated earlier
396
    /// (but which may have already completed).
397
    FutureCancelWrite { info: PayloadInfo, async_: bool },
398
399
    /// A `canon future.drop-readable` intrinsic.
400
    ///
401
    /// This allows the guest to drop the readable end of a `future`.
402
    FutureDropReadable(PayloadInfo),
403
404
    /// A `canon future.drop-writable` intrinsic.
405
    ///
406
    /// This allows the guest to drop the writable end of a `future`.
407
    FutureDropWritable(PayloadInfo),
408
409
    /// A `canon error-context.new` intrinsic.
410
    ///
411
    /// This allows the guest to create a new `error-context` instance with a
412
    /// specified debug message.
413
    ErrorContextNew { encoding: StringEncoding },
414
415
    /// A `canon error-context.debug-message` intrinsic.
416
    ///
417
    /// This allows the guest to retrieve the debug message from a
418
    /// `error-context` instance.  Note that the content of this message might
419
    /// not be identical to what was passed in to `error-context.new`.
420
    ErrorContextDebugMessage { encoding: StringEncoding },
421
422
    /// A `canon error-context.drop` intrinsic.
423
    ///
424
    /// This allows the guest to release its handle to the specified
425
    /// `error-context` instance.
426
    ErrorContextDrop,
427
428
    /// A `canon thread.index` intrinsic.
429
    ///
430
    /// This allows the guest to get the index of the current thread.
431
    ThreadIndex,
432
433
    /// A `canon thread.new-indirect` intrinsic.
434
    ///
435
    /// This allows the guest to create a new thread running a specified function.
436
    ThreadNewIndirect,
437
438
    /// A `canon thread.resume-later` intrinsic.
439
    ThreadResumeLater,
440
441
    /// A `canon thread.suspend` intrinsic.
442
    ThreadSuspend { cancellable: bool },
443
444
    /// A `canon thread.yield` intrinsic.
445
    ThreadYield { cancellable: bool },
446
447
    /// A `canon thread.suspend-then-resume` intrinsic.
448
    ThreadSuspendThenResume { cancellable: bool },
449
450
    /// A `canon thread.yield-then-resume` intrinsic.
451
    ThreadYieldThenResume { cancellable: bool },
452
453
    /// A `canon thread.suspend-then-promote` intrinsic.
454
    ThreadSuspendThenPromote { cancellable: bool },
455
456
    /// A `canon thread.yield-then-promote` intrinsic.
457
    ThreadYieldThenPromote { cancellable: bool },
458
}
459
460
impl ImportMap {
461
    /// Returns the list of items that the adapter named `name` must export.
462
0
    pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
463
0
        let names = match self.names.get(name) {
464
0
            Some(ImportInstance::Names(names)) => names,
465
0
            _ => return IndexMap::new(),
466
        };
467
0
        names
468
0
            .iter()
469
0
            .map(|(_, import)| match import {
470
0
                Import::AdapterExport { ty, func, adapter } => {
471
0
                    assert_eq!(adapter, name);
472
0
                    (func.clone(), ty.clone())
473
                }
474
0
                _ => unreachable!(),
475
0
            })
476
0
            .collect()
477
0
    }
478
479
    /// Returns an iterator over all individual imports registered in this map.
480
    ///
481
    /// Note that this doesn't iterate over the "whole instance" imports.
482
9.80k
    pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
483
9.80k
        self.names
484
9.80k
            .iter()
485
9.80k
            .filter_map(|(module, m)| match m {
486
6.50k
                ImportInstance::Names(names) => Some((module, names)),
487
0
                ImportInstance::Whole(_) => None,
488
6.50k
            })
489
9.80k
            .flat_map(|(module, m)| {
490
6.50k
                m.iter()
491
34.4k
                    .map(move |(field, import)| (module.as_str(), field.as_str(), import))
492
6.50k
            })
493
9.80k
    }
494
495
    /// Returns the map for how all imports must be satisfied.
496
3.26k
    pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
497
3.26k
        &self.names
498
3.26k
    }
499
500
    /// Classify an import and call `insert_import()` on it. Used during
501
    /// validation to build up this `ImportMap`.
502
11.4k
    fn add(
503
11.4k
        &mut self,
504
11.4k
        import: wasmparser::Import<'_>,
505
11.4k
        encoder: &ComponentEncoder,
506
11.4k
        import_map: Option<&ModuleImportMap>,
507
11.4k
        library_info: Option<&LibraryInfo>,
508
11.4k
        types: TypesRef<'_>,
509
11.4k
    ) -> Result<()> {
510
11.4k
        if self.classify_import_with_library(import, library_info)? {
511
0
            return Ok(());
512
11.4k
        }
513
11.4k
        let mut import_to_classify = import;
514
11.4k
        if let Some(map) = import_map {
515
57
            if let Some(original_name) = map.original_name(&import) {
516
14
                import_to_classify.name = original_name;
517
43
            }
518
11.4k
        }
519
11.4k
        let item = self
520
11.4k
            .classify(import_to_classify, encoder, types)
521
11.4k
            .with_context(|| {
522
0
                format!(
523
                    "failed to resolve import `{}::{}`",
524
                    import.module, import.name,
525
                )
526
0
            })?;
527
11.4k
        self.insert_import(import, item)
528
11.4k
    }
529
530
    /// Determines what kind of thing is being imported: maps it from the
531
    /// module/name/type triple in the raw wasm module to an enum.
532
    ///
533
    /// Handles a few special cases, then delegates to
534
    /// `classify_component_model_import()`.
535
11.4k
    fn classify(
536
11.4k
        &self,
537
11.4k
        import: wasmparser::Import<'_>,
538
11.4k
        encoder: &ComponentEncoder,
539
11.4k
        types: TypesRef<'_>,
540
11.4k
    ) -> Result<Import> {
541
        // Special-case the main module's memory imported into adapters which
542
        // currently with `wasm-ld` is not easily configurable.
543
11.4k
        if import.module == "env" && import.name == "memory" {
544
0
            return Ok(Import::MainModuleMemory);
545
11.4k
        }
546
547
        // Special-case imports from the main module into adapters.
548
11.4k
        if import.module == "__main_module__" {
549
            return Ok(Import::MainModuleExport {
550
0
                name: import.name.to_string(),
551
0
                kind: match import.ty {
552
0
                    TypeRef::Func(_) => ExportKind::Func,
553
0
                    TypeRef::Table(_) => ExportKind::Table,
554
0
                    TypeRef::Memory(_) => ExportKind::Memory,
555
0
                    TypeRef::Global(_) => ExportKind::Global,
556
0
                    TypeRef::Tag(_) => ExportKind::Tag,
557
0
                    TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
558
                },
559
            });
560
11.4k
        }
561
562
11.4k
        let ty_index = match import.ty {
563
11.4k
            TypeRef::Func(ty) => ty,
564
0
            _ => bail!("module is only allowed to import functions"),
565
        };
566
11.4k
        let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
567
568
        // Handle main module imports that match known adapters and set it up as
569
        // an import of an adapter export.
570
11.4k
        if encoder.adapters.contains_key(import.module) {
571
0
            return Ok(Import::AdapterExport {
572
0
                adapter: import.module.to_string(),
573
0
                func: import.name.to_string(),
574
0
                ty: ty.clone(),
575
0
            });
576
11.4k
        }
577
578
11.4k
        let (module, names) = match import.module.strip_prefix("cm32p2") {
579
311
            Some(suffix) => (suffix, STANDARD),
580
0
            None if encoder.reject_legacy_names => (import.module, STANDARD),
581
11.1k
            None => (import.module, LEGACY),
582
        };
583
11.4k
        self.classify_component_model_import(module, import.name, encoder, ty, names)
584
11.4k
    }
585
586
    /// Attempts to classify the import `{module}::{name}` with the rules
587
    /// specified in WebAssembly/component-model#378
588
11.4k
    fn classify_component_model_import(
589
11.4k
        &self,
590
11.4k
        module: &str,
591
11.4k
        name: &str,
592
11.4k
        encoder: &ComponentEncoder,
593
11.4k
        ty: &FuncType,
594
11.4k
        names: &dyn NameMangling,
595
11.4k
    ) -> Result<Import> {
596
11.4k
        let resolve = &encoder.metadata.resolve;
597
11.4k
        let world_id = encoder.metadata.world;
598
11.4k
        let world = &resolve.worlds[world_id];
599
600
11.4k
        if module == names.import_root() {
601
7.29k
            if names.error_context_drop(name) {
602
0
                let expected = FuncType::new([ValType::I32], []);
603
0
                validate_func_sig(name, &expected, ty)?;
604
0
                return Ok(Import::ErrorContextDrop);
605
7.29k
            }
606
607
7.29k
            if names.backpressure_inc(name) {
608
523
                let expected = FuncType::new([], []);
609
523
                validate_func_sig(name, &expected, ty)?;
610
523
                return Ok(Import::BackpressureInc);
611
6.76k
            }
612
613
6.76k
            if names.backpressure_dec(name) {
614
523
                let expected = FuncType::new([], []);
615
523
                validate_func_sig(name, &expected, ty)?;
616
523
                return Ok(Import::BackpressureDec);
617
6.24k
            }
618
619
6.24k
            if names.waitable_set_new(name) {
620
523
                let expected = FuncType::new([], [ValType::I32]);
621
523
                validate_func_sig(name, &expected, ty)?;
622
523
                return Ok(Import::WaitableSetNew);
623
5.72k
            }
624
625
5.72k
            if let Some((info, result_ty)) = names.waitable_set_wait(name) {
626
523
                let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
627
523
                validate_func_sig(name, &expected, ty)?;
628
523
                return Ok(Import::WaitableSetWait {
629
523
                    cancellable: info.cancellable,
630
523
                });
631
5.19k
            }
632
633
5.19k
            if let Some((info, result_ty)) = names.waitable_set_poll(name) {
634
523
                let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
635
523
                validate_func_sig(name, &expected, ty)?;
636
523
                return Ok(Import::WaitableSetPoll {
637
523
                    cancellable: info.cancellable,
638
523
                });
639
4.67k
            }
640
641
4.67k
            if names.waitable_set_drop(name) {
642
523
                let expected = FuncType::new([ValType::I32], []);
643
523
                validate_func_sig(name, &expected, ty)?;
644
523
                return Ok(Import::WaitableSetDrop);
645
4.15k
            }
646
647
4.15k
            if names.waitable_join(name) {
648
523
                let expected = FuncType::new([ValType::I32; 2], []);
649
523
                validate_func_sig(name, &expected, ty)?;
650
523
                return Ok(Import::WaitableJoin);
651
3.63k
            }
652
653
3.63k
            if names.subtask_drop(name) {
654
523
                let expected = FuncType::new([ValType::I32], []);
655
523
                validate_func_sig(name, &expected, ty)?;
656
523
                return Ok(Import::SubtaskDrop);
657
3.10k
            }
658
659
3.10k
            if let Some(info) = names.subtask_cancel(name) {
660
523
                let expected = FuncType::new([ValType::I32], [ValType::I32]);
661
523
                validate_func_sig(name, &expected, ty)?;
662
523
                return Ok(Import::SubtaskCancel {
663
523
                    async_: info.async_lowered,
664
523
                });
665
2.58k
            }
666
667
2.58k
            if let Some(encoding) = names.error_context_new(name) {
668
0
                let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
669
0
                validate_func_sig(name, &expected, ty)?;
670
0
                return Ok(Import::ErrorContextNew { encoding });
671
2.58k
            }
672
673
2.58k
            if let Some(encoding) = names.error_context_debug_message(name) {
674
0
                let expected = FuncType::new([ValType::I32; 2], []);
675
0
                validate_func_sig(name, &expected, ty)?;
676
0
                return Ok(Import::ErrorContextDebugMessage { encoding });
677
2.58k
            }
678
679
2.58k
            if let Some((slot_ty, slot)) = names.context_get(name) {
680
523
                let expected = FuncType::new([], [slot_ty]);
681
523
                validate_func_sig(name, &expected, ty)?;
682
523
                return Ok(Import::ContextGet { ty: slot_ty, slot });
683
2.06k
            }
684
2.06k
            if let Some((slot_ty, slot)) = names.context_set(name) {
685
523
                let expected = FuncType::new([slot_ty], []);
686
523
                validate_func_sig(name, &expected, ty)?;
687
523
                return Ok(Import::ContextSet { ty: slot_ty, slot });
688
1.53k
            }
689
1.53k
            if names.thread_index(name) {
690
0
                let expected = FuncType::new([], [ValType::I32]);
691
0
                validate_func_sig(name, &expected, ty)?;
692
0
                return Ok(Import::ThreadIndex);
693
1.53k
            }
694
1.53k
            if names.thread_new_indirect(name) {
695
0
                let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
696
0
                validate_func_sig(name, &expected, ty)?;
697
0
                return Ok(Import::ThreadNewIndirect);
698
1.53k
            }
699
1.53k
            if names.thread_resume_later(name) {
700
0
                let expected = FuncType::new([ValType::I32], []);
701
0
                validate_func_sig(name, &expected, ty)?;
702
0
                return Ok(Import::ThreadResumeLater);
703
1.53k
            }
704
1.53k
            if let Some(info) = names.thread_suspend(name) {
705
0
                let expected = FuncType::new([], [ValType::I32]);
706
0
                validate_func_sig(name, &expected, ty)?;
707
0
                return Ok(Import::ThreadSuspend {
708
0
                    cancellable: info.cancellable,
709
0
                });
710
1.53k
            }
711
1.53k
            if let Some(info) = names.thread_yield(name) {
712
523
                let expected = FuncType::new([], [ValType::I32]);
713
523
                validate_func_sig(name, &expected, ty)?;
714
523
                return Ok(Import::ThreadYield {
715
523
                    cancellable: info.cancellable,
716
523
                });
717
1.01k
            }
718
1.01k
            if let Some(info) = names.thread_suspend_then_resume(name) {
719
0
                let expected = FuncType::new([ValType::I32], [ValType::I32]);
720
0
                validate_func_sig(name, &expected, ty)?;
721
0
                return Ok(Import::ThreadSuspendThenResume {
722
0
                    cancellable: info.cancellable,
723
0
                });
724
1.01k
            }
725
1.01k
            if let Some(info) = names.thread_yield_then_resume(name) {
726
0
                let expected = FuncType::new([ValType::I32], [ValType::I32]);
727
0
                validate_func_sig(name, &expected, ty)?;
728
0
                return Ok(Import::ThreadYieldThenResume {
729
0
                    cancellable: info.cancellable,
730
0
                });
731
1.01k
            }
732
1.01k
            if let Some(info) = names.thread_suspend_then_promote(name) {
733
0
                let expected = FuncType::new([ValType::I32], [ValType::I32]);
734
0
                validate_func_sig(name, &expected, ty)?;
735
0
                return Ok(Import::ThreadSuspendThenPromote {
736
0
                    cancellable: info.cancellable,
737
0
                });
738
1.01k
            }
739
1.01k
            if let Some(info) = names.thread_yield_then_promote(name) {
740
0
                let expected = FuncType::new([ValType::I32], [ValType::I32]);
741
0
                validate_func_sig(name, &expected, ty)?;
742
0
                return Ok(Import::ThreadYieldThenPromote {
743
0
                    cancellable: info.cancellable,
744
0
                });
745
1.01k
            }
746
747
1.01k
            let (key_name, abi) = names.world_key_name_and_abi(name);
748
1.01k
            let key = WorldKey::Name(key_name.to_string());
749
1.01k
            if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
750
845
                validate_func(resolve, ty, func, abi)?;
751
845
                return Ok(Import::WorldFunc(key, func.name.clone(), abi));
752
170
            }
753
754
170
            if let Some(import) =
755
170
                self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
756
            {
757
170
                return Ok(import);
758
0
            }
759
760
0
            match world.imports.get(&key) {
761
0
                Some(_) => bail!("expected world top-level import `{name}` to be a function"),
762
0
                None => bail!("no top-level imported function `{name}` specified"),
763
            }
764
4.19k
        }
765
766
        // Check for `[export]$root::[task-return]foo` or similar
767
623
        if matches!(
768
4.19k
            module.strip_prefix(names.import_exported_intrinsic_prefix()),
769
2.52k
            Some(module) if module == names.import_root()
770
        ) {
771
623
            if let Some(import) =
772
623
                self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
773
            {
774
623
                return Ok(import);
775
0
            }
776
3.57k
        }
777
778
3.57k
        let interface = match module.strip_prefix(names.import_non_root_prefix()) {
779
3.57k
            Some(name) => name,
780
0
            None => bail!("unknown or invalid component model import syntax"),
781
        };
782
783
3.57k
        if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
784
1.91k
            let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
785
786
1.91k
            if let Some(import) =
787
1.91k
                self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
788
            {
789
1.91k
                return Ok(import);
790
0
            }
791
0
            bail!("unknown function `{name}`")
792
1.66k
        }
793
794
1.66k
        let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
795
1.66k
        let interface = &resolve.interfaces[id];
796
1.66k
        let (function_name, abi) = names.interface_function_name_and_abi(name);
797
1.66k
        if let Some(f) = interface.functions.get(function_name) {
798
1.43k
            validate_func(resolve, ty, f, abi).with_context(|| {
799
0
                let name = resolve.name_world_key(&key);
800
0
                format!("failed to validate import interface `{name}`")
801
0
            })?;
802
1.43k
            return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
803
229
        }
804
805
229
        if let Some(import) =
806
229
            self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
807
        {
808
229
            return Ok(import);
809
0
        }
810
0
        bail!(
811
            "import interface `{module}` is missing function \
812
             `{name}` that is required by the module",
813
        )
814
11.4k
    }
815
816
    /// Attempts to detect and classify `name` as a WIT intrinsic.
817
    ///
818
    /// This function is a bit of a sprawling sequence of matches used to
819
    /// detect whether `name` corresponds to a WIT intrinsic, so specifically
820
    /// not a WIT function itself. This is only used for functions imported
821
    /// into a module but the import could be for an imported item in a world
822
    /// or an exported item.
823
    ///
824
    /// ## Parameters
825
    ///
826
    /// * `name` - the core module name which is being pattern-matched. This
827
    ///   should be the "field" of the import. This may include the "[async-lower]"
828
    ///   or "[cancellable]" prefixes.
829
    /// * `key_and_id` - this is the inferred "container" for the function
830
    ///   being described which is inferred from the module portion of the core
831
    ///   wasm import field. This is `None` for root-level function/type
832
    ///   imports, such as when referring to `import x: func();`. This is `Some`
833
    ///   when an interface is used (either `import x: interface { .. }` or a
834
    ///   standalone `interface`) where the world key is specified for the
835
    ///   interface in addition to the interface that was identified.
836
    /// * `encoder` - this is the encoder state that contains
837
    ///   `Resolve`/metadata information.
838
    /// * `ty` - the core wasm type of this import.
839
    /// * `import` - whether or not this core wasm import is operating on a WIT
840
    ///   level import or export. An example of this being an export is when a
841
    ///   core module imports a destructor for an exported resource.
842
    /// * `names` - the name mangling scheme that's configured to be used.
843
2.93k
    fn maybe_classify_wit_intrinsic(
844
2.93k
        &self,
845
2.93k
        name: &str,
846
2.93k
        key_and_id: Option<(WorldKey, InterfaceId)>,
847
2.93k
        encoder: &ComponentEncoder,
848
2.93k
        ty: &FuncType,
849
2.93k
        import: bool,
850
2.93k
        names: &dyn NameMangling,
851
2.93k
    ) -> Result<Option<Import>> {
852
2.93k
        let resolve = &encoder.metadata.resolve;
853
2.93k
        let world_id = encoder.metadata.world;
854
2.93k
        let world = &resolve.worlds[world_id];
855
856
        // Separate out `Option<WorldKey>` and `Option<InterfaceId>`. If an
857
        // interface is NOT specified then the `WorldKey` which is attached to
858
        // imports is going to be calculated based on the name of the item
859
        // extracted, such as the resource or function referenced.
860
2.93k
        let (key, id) = match key_and_id {
861
2.13k
            Some((key, id)) => (Some(key), Some(id)),
862
793
            None => (None, None),
863
        };
864
865
        // Tests whether `name` is a resource within `id` (or `world_id`).
866
2.93k
        let resource_test = |name: &str| match id {
867
755
            Some(id) => resource_test_for_interface(resolve, id)(name),
868
142
            None => resource_test_for_world(resolve, world_id)(name),
869
897
        };
870
871
        // Test whether this is a `resource.drop` intrinsic.
872
2.93k
        if let Some(resource) = names.resource_drop_name(name) {
873
467
            if let Some(resource_id) = resource_test(resource) {
874
467
                let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
875
467
                let expected = FuncType::new([ValType::I32], []);
876
467
                validate_func_sig(name, &expected, ty)?;
877
467
                return Ok(Some(if import {
878
252
                    Import::ImportedResourceDrop(key, id, resource_id)
879
                } else {
880
215
                    Import::ExportedResourceDrop(key, resource_id)
881
                }));
882
0
            }
883
2.46k
        }
884
885
        // There are some intrinsics which are only applicable to exported
886
        // functions/resources, so check those use cases here.
887
2.46k
        if !import {
888
2.31k
            if let Some(name) = names.resource_new_name(name) {
889
215
                if let Some(id) = resource_test(name) {
890
215
                    let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
891
215
                    let expected = FuncType::new([ValType::I32], [ValType::I32]);
892
215
                    validate_func_sig(name, &expected, ty)?;
893
215
                    return Ok(Some(Import::ExportedResourceNew(key, id)));
894
0
                }
895
2.10k
            }
896
2.10k
            if let Some(name) = names.resource_rep_name(name) {
897
215
                if let Some(id) = resource_test(name) {
898
215
                    let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
899
215
                    let expected = FuncType::new([ValType::I32], [ValType::I32]);
900
215
                    validate_func_sig(name, &expected, ty)?;
901
215
                    return Ok(Some(Import::ExportedResourceRep(key, id)));
902
0
                }
903
1.88k
            }
904
1.88k
            if let Some(name) = names.task_return_name(name) {
905
882
                let func = get_function(resolve, world, name, id, import)?;
906
882
                let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
907
                // TODO: should call `validate_func_sig` but would require
908
                // calculating the expected signature based of `func.result`.
909
882
                return Ok(Some(Import::ExportedTaskReturn(key, id, func.clone())));
910
1.00k
            }
911
1.00k
            if names.task_cancel(name) {
912
523
                let expected = FuncType::new([], []);
913
523
                validate_func_sig(name, &expected, ty)?;
914
523
                return Ok(Some(Import::ExportedTaskCancel));
915
483
            }
916
147
        }
917
918
630
        let lookup_context = PayloadLookupContext {
919
630
            resolve,
920
630
            world,
921
630
            key,
922
630
            id,
923
630
            import,
924
630
        };
925
926
        // Test for a number of async-related intrinsics. All intrinsics are
927
        // prefixed with `[...-N]` where `...` is the name of the intrinsic and
928
        // the `N` is the indexed future/stream that is being referred to.
929
630
        let import = if let Some(info) = names.future_new(&lookup_context, name) {
930
80
            validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
931
80
            Import::FutureNew(info)
932
550
        } else if let Some(info) = names.future_write(&lookup_context, name) {
933
80
            validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
934
80
            Import::FutureWrite {
935
80
                async_: info.async_lowered,
936
80
                info: info.inner,
937
80
            }
938
470
        } else if let Some(info) = names.future_read(&lookup_context, name) {
939
80
            validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
940
80
            Import::FutureRead {
941
80
                async_: info.async_lowered,
942
80
                info: info.inner,
943
80
            }
944
390
        } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
945
80
            validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
946
80
            Import::FutureCancelWrite {
947
80
                async_: info.async_lowered,
948
80
                info: info.inner,
949
80
            }
950
310
        } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
951
80
            validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
952
80
            Import::FutureCancelRead {
953
80
                async_: info.async_lowered,
954
80
                info: info.inner,
955
80
            }
956
230
        } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
957
80
            validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
958
80
            Import::FutureDropWritable(info)
959
150
        } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
960
80
            validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
961
80
            Import::FutureDropReadable(info)
962
70
        } else if let Some(info) = names.stream_new(&lookup_context, name) {
963
10
            validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
964
10
            Import::StreamNew(info)
965
60
        } else if let Some(info) = names.stream_write(&lookup_context, name) {
966
10
            validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
967
10
            Import::StreamWrite {
968
10
                async_: info.async_lowered,
969
10
                info: info.inner,
970
10
            }
971
50
        } else if let Some(info) = names.stream_read(&lookup_context, name) {
972
10
            validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
973
10
            Import::StreamRead {
974
10
                async_: info.async_lowered,
975
10
                info: info.inner,
976
10
            }
977
40
        } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
978
10
            validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
979
10
            Import::StreamCancelWrite {
980
10
                async_: info.async_lowered,
981
10
                info: info.inner,
982
10
            }
983
30
        } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
984
10
            validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
985
10
            Import::StreamCancelRead {
986
10
                async_: info.async_lowered,
987
10
                info: info.inner,
988
10
            }
989
20
        } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
990
10
            validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
991
10
            Import::StreamDropWritable(info)
992
10
        } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
993
10
            validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
994
10
            Import::StreamDropReadable(info)
995
        } else {
996
0
            return Ok(None);
997
        };
998
630
        Ok(Some(import))
999
2.93k
    }
1000
1001
11.4k
    fn classify_import_with_library(
1002
11.4k
        &mut self,
1003
11.4k
        import: wasmparser::Import<'_>,
1004
11.4k
        library_info: Option<&LibraryInfo>,
1005
11.4k
    ) -> Result<bool> {
1006
11.4k
        let info = match library_info {
1007
0
            Some(info) => info,
1008
11.4k
            None => return Ok(false),
1009
        };
1010
0
        let Some((_, instance)) = info
1011
0
            .arguments
1012
0
            .iter()
1013
0
            .find(|(name, _items)| *name == import.module)
1014
        else {
1015
0
            return Ok(false);
1016
        };
1017
0
        match instance {
1018
0
            Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1019
0
                Some(ImportInstance::Whole(which)) => {
1020
0
                    if which != module {
1021
0
                        bail!("different whole modules imported under the same name");
1022
0
                    }
1023
                }
1024
                Some(ImportInstance::Names(_)) => {
1025
0
                    bail!("cannot mix individual imports and whole module imports")
1026
                }
1027
0
                None => {
1028
0
                    let instance = ImportInstance::Whole(module.clone());
1029
0
                    self.names.insert(import.module.to_string(), instance);
1030
0
                }
1031
            },
1032
0
            Instance::Items(items) => {
1033
0
                let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1034
0
                    return Ok(false);
1035
                };
1036
0
                self.insert_import(import, Import::Item(item.clone()))?;
1037
            }
1038
        }
1039
0
        Ok(true)
1040
11.4k
    }
1041
1042
    /// Map an imported item, by module and field name in `self.names`, to the
1043
    /// kind of `Import` it is: for example, a certain-typed function from an
1044
    /// adapter.
1045
11.4k
    fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1046
11.4k
        let entry = self
1047
11.4k
            .names
1048
11.4k
            .entry(import.module.to_string())
1049
11.4k
            .or_insert(ImportInstance::Names(IndexMap::default()));
1050
11.4k
        let names = match entry {
1051
11.4k
            ImportInstance::Names(names) => names,
1052
0
            _ => bail!("cannot mix individual imports with module imports"),
1053
        };
1054
11.4k
        let entry = match names.entry(import.name.to_string()) {
1055
            Entry::Occupied(_) => {
1056
0
                bail!(
1057
                    "module has duplicate import for `{}::{}`",
1058
                    import.module,
1059
                    import.name
1060
                );
1061
            }
1062
11.4k
            Entry::Vacant(v) => v,
1063
        };
1064
11.4k
        log::trace!(
1065
            "classifying import `{}::{} as {item:?}",
1066
            import.module,
1067
            import.name
1068
        );
1069
11.4k
        entry.insert(item);
1070
11.4k
        Ok(())
1071
11.4k
    }
1072
}
1073
1074
/// Dual of `ImportMap` except describes the exports of a module instead of the
1075
/// imports.
1076
#[derive(Default)]
1077
pub struct ExportMap {
1078
    names: IndexMap<String, Export>,
1079
    raw_exports: IndexMap<String, FuncType>,
1080
}
1081
1082
/// All possible (known) exports from a core wasm module that are recognized and
1083
/// handled during the componentization process.
1084
#[derive(Debug)]
1085
pub enum Export {
1086
    /// An export of a top-level function of a world, where the world function
1087
    /// is named here.
1088
    WorldFunc(WorldKey, String, AbiVariant),
1089
1090
    /// A post-return for a top-level function of a world.
1091
    WorldFuncPostReturn(WorldKey),
1092
1093
    /// An export of a function in an interface.
1094
    InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1095
1096
    /// A post-return for the above function.
1097
    InterfaceFuncPostReturn(WorldKey, String),
1098
1099
    /// A destructor for an exported resource.
1100
    ResourceDtor(TypeId),
1101
1102
    /// Memory, typically for an adapter.
1103
    Memory,
1104
1105
    /// `cabi_realloc`
1106
    GeneralPurposeRealloc,
1107
1108
    /// `cabi_export_realloc`
1109
    GeneralPurposeExportRealloc,
1110
1111
    /// `cabi_import_realloc`
1112
    GeneralPurposeImportRealloc,
1113
1114
    /// `_initialize`
1115
    Initialize,
1116
1117
    /// `cabi_realloc_adapter`
1118
    ReallocForAdapter,
1119
1120
    WorldFuncCallback(WorldKey),
1121
1122
    InterfaceFuncCallback(WorldKey, String),
1123
1124
    /// __indirect_function_table, used for `thread.new-indirect`
1125
    IndirectFunctionTable,
1126
1127
    /// __wasm_init_task, used for initializing export tasks
1128
    WasmInitTask,
1129
1130
    /// __wasm_init_async_task, used for initializing export tasks for async-lifted exports
1131
    WasmInitAsyncTask,
1132
}
1133
1134
impl ExportMap {
1135
17.7k
    fn add(
1136
17.7k
        &mut self,
1137
17.7k
        export: wasmparser::Export<'_>,
1138
17.7k
        encoder: &ComponentEncoder,
1139
17.7k
        exports: &IndexSet<WorldKey>,
1140
17.7k
        types: TypesRef<'_>,
1141
17.7k
    ) -> Result<()> {
1142
17.7k
        if let Some(item) = self.classify(export, encoder, exports, types)? {
1143
17.7k
            log::debug!("classifying export `{}` as {item:?}", export.name);
1144
17.7k
            let prev = self.names.insert(export.name.to_string(), item);
1145
17.7k
            assert!(prev.is_none());
1146
0
        }
1147
17.7k
        Ok(())
1148
17.7k
    }
1149
1150
17.7k
    fn classify(
1151
17.7k
        &mut self,
1152
17.7k
        export: wasmparser::Export<'_>,
1153
17.7k
        encoder: &ComponentEncoder,
1154
17.7k
        exports: &IndexSet<WorldKey>,
1155
17.7k
        types: TypesRef<'_>,
1156
17.7k
    ) -> Result<Option<Export>> {
1157
17.7k
        match export.kind {
1158
14.4k
            ExternalKind::Func => {
1159
14.4k
                let ty = types[types.core_function_at(export.index)].unwrap_func();
1160
14.4k
                self.raw_exports.insert(export.name.to_string(), ty.clone());
1161
14.4k
            }
1162
3.26k
            _ => {}
1163
        }
1164
1165
        // Handle a few special-cased names first.
1166
17.7k
        if export.name == "canonical_abi_realloc" {
1167
0
            return Ok(Some(Export::GeneralPurposeRealloc));
1168
17.7k
        } else if export.name == "cabi_import_realloc" {
1169
0
            return Ok(Some(Export::GeneralPurposeImportRealloc));
1170
17.7k
        } else if export.name == "cabi_export_realloc" {
1171
0
            return Ok(Some(Export::GeneralPurposeExportRealloc));
1172
17.7k
        } else if export.name == "cabi_realloc_adapter" {
1173
0
            return Ok(Some(Export::ReallocForAdapter));
1174
17.7k
        }
1175
1176
17.7k
        let (name, names) = match export.name.strip_prefix("cm32p2") {
1177
2.08k
            Some(name) => (name, STANDARD),
1178
0
            None if encoder.reject_legacy_names => return Ok(None),
1179
15.6k
            None => (export.name, LEGACY),
1180
        };
1181
1182
17.7k
        if let Some(export) = self
1183
17.7k
            .classify_component_export(names, name, &export, encoder, exports, types)
1184
17.7k
            .with_context(|| format!("failed to classify export `{}`", export.name))?
1185
        {
1186
17.7k
            return Ok(Some(export));
1187
0
        }
1188
0
        log::debug!("unknown export `{}`", export.name);
1189
0
        Ok(None)
1190
17.7k
    }
1191
1192
17.7k
    fn classify_component_export(
1193
17.7k
        &mut self,
1194
17.7k
        names: &dyn NameMangling,
1195
17.7k
        name: &str,
1196
17.7k
        export: &wasmparser::Export<'_>,
1197
17.7k
        encoder: &ComponentEncoder,
1198
17.7k
        exports: &IndexSet<WorldKey>,
1199
17.7k
        types: TypesRef<'_>,
1200
17.7k
    ) -> Result<Option<Export>> {
1201
17.7k
        let resolve = &encoder.metadata.resolve;
1202
17.7k
        let world = encoder.metadata.world;
1203
17.7k
        match export.kind {
1204
14.4k
            ExternalKind::Func => {}
1205
            ExternalKind::Memory => {
1206
3.26k
                if name == names.export_memory() {
1207
3.26k
                    return Ok(Some(Export::Memory));
1208
0
                }
1209
0
                return Ok(None);
1210
            }
1211
            ExternalKind::Table => {
1212
0
                if Some(name) == names.export_indirect_function_table() {
1213
0
                    return Ok(Some(Export::IndirectFunctionTable));
1214
0
                }
1215
0
                return Ok(None);
1216
            }
1217
0
            _ => return Ok(None),
1218
        }
1219
14.4k
        let ty = types[types.core_function_at(export.index)].unwrap_func();
1220
1221
        // Handle a few special-cased names first.
1222
14.4k
        if name == names.export_realloc() {
1223
3.26k
            let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1224
3.26k
            validate_func_sig(name, &expected, ty)?;
1225
3.26k
            return Ok(Some(Export::GeneralPurposeRealloc));
1226
11.1k
        } else if name == names.export_initialize() {
1227
3.26k
            let expected = FuncType::new([], []);
1228
3.26k
            validate_func_sig(name, &expected, ty)?;
1229
3.26k
            return Ok(Some(Export::Initialize));
1230
7.90k
        } else if Some(name) == names.export_wasm_init_task() {
1231
0
            let expected = FuncType::new([], []);
1232
0
            validate_func_sig(name, &expected, ty)?;
1233
0
            return Ok(Some(Export::WasmInitTask));
1234
7.90k
        } else if Some(name) == names.export_wasm_init_async_task() {
1235
0
            let expected = FuncType::new([], []);
1236
0
            validate_func_sig(name, &expected, ty)?;
1237
0
            return Ok(Some(Export::WasmInitAsyncTask));
1238
7.90k
        }
1239
1240
7.90k
        let full_name = name;
1241
7.90k
        let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1242
708
            (AbiVariant::GuestExportAsync, name)
1243
7.19k
        } else if let Some(name) = names.async_lift_stackful_name(name) {
1244
88
            (AbiVariant::GuestExportAsyncStackful, name)
1245
        } else {
1246
7.10k
            (AbiVariant::GuestExport, name)
1247
        };
1248
1249
        // Try to match this to a known WIT export that `exports` allows.
1250
7.90k
        if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1251
3.88k
            validate_func(resolve, ty, f, abi).with_context(|| {
1252
0
                let key = resolve.name_world_key(key);
1253
0
                format!("failed to validate export for `{key}`")
1254
0
            })?;
1255
3.88k
            match id {
1256
3.58k
                Some(id) => {
1257
3.58k
                    return Ok(Some(Export::InterfaceFunc(
1258
3.58k
                        key.clone(),
1259
3.58k
                        id,
1260
3.58k
                        f.name.clone(),
1261
3.58k
                        abi,
1262
3.58k
                    )));
1263
                }
1264
                None => {
1265
302
                    return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1266
                }
1267
            }
1268
4.01k
        }
1269
1270
        // See if this is a post-return for any known WIT export.
1271
4.01k
        if let Some(remaining) = names.strip_post_return(name) {
1272
3.09k
            if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1273
3.09k
                validate_post_return(resolve, ty, f).with_context(|| {
1274
0
                    let key = resolve.name_world_key(key);
1275
0
                    format!("failed to validate export for `{key}`")
1276
0
                })?;
1277
3.09k
                match id {
1278
2.82k
                    Some(_id) => {
1279
2.82k
                        return Ok(Some(Export::InterfaceFuncPostReturn(
1280
2.82k
                            key.clone(),
1281
2.82k
                            f.name.clone(),
1282
2.82k
                        )));
1283
                    }
1284
                    None => {
1285
275
                        return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1286
                    }
1287
                }
1288
0
            }
1289
920
        }
1290
1291
920
        if let Some(suffix) = names.async_lift_callback_name(full_name) {
1292
705
            if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1293
705
                validate_func_sig(
1294
705
                    full_name,
1295
705
                    &FuncType::new([ValType::I32; 3], [ValType::I32]),
1296
705
                    ty,
1297
0
                )?;
1298
705
                return Ok(Some(if id.is_some() {
1299
692
                    Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1300
                } else {
1301
13
                    Export::WorldFuncCallback(key.clone())
1302
                }));
1303
0
            }
1304
215
        }
1305
1306
        // And, finally, see if it matches a known destructor.
1307
215
        if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1308
215
            let expected = FuncType::new([ValType::I32], []);
1309
215
            validate_func_sig(full_name, &expected, ty)?;
1310
215
            return Ok(Some(Export::ResourceDtor(dtor)));
1311
0
        }
1312
1313
0
        Ok(None)
1314
17.7k
    }
1315
1316
    /// Returns the name of the post-return export, if any, for the `key` and
1317
    /// `func` combo.
1318
3.88k
    pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1319
153k
        self.find(|m| match m {
1320
1.04k
            Export::WorldFuncPostReturn(k) => k == key,
1321
54.6k
            Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1322
98.1k
            _ => false,
1323
153k
        })
1324
3.88k
    }
1325
1326
    /// Returns the name of the async callback export, if any, for the `key` and
1327
    /// `func` combo.
1328
3.88k
    pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1329
253k
        self.find(|m| match m {
1330
26
            Export::WorldFuncCallback(k) => k == key,
1331
8.77k
            Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1332
244k
            _ => false,
1333
253k
        })
1334
3.88k
    }
1335
1336
3.88k
    pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1337
3.88k
        self.names.values().find_map(|m| match m {
1338
1.15k
            Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1339
65.4k
            Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1340
125k
            _ => None,
1341
129k
        })
1342
3.88k
    }
1343
1344
    /// Returns the realloc that the exported function `interface` and `func`
1345
    /// are using.
1346
4.02k
    pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1347
        // TODO: This realloc detection should probably be improved with
1348
        // some sort of scheme to have per-function reallocs like
1349
        // `cabi_realloc_{name}` or something like that.
1350
4.02k
        let _ = (key, func);
1351
1352
283k
        if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1353
0
            return Some(name);
1354
4.02k
        }
1355
4.02k
        self.general_purpose_realloc()
1356
4.02k
    }
1357
1358
    /// Returns the realloc that the imported function `interface` and `func`
1359
    /// are using.
1360
450
    pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1361
        // TODO: This realloc detection should probably be improved with
1362
        // some sort of scheme to have per-function reallocs like
1363
        // `cabi_realloc_{name}` or something like that.
1364
450
        let _ = (interface, func);
1365
1366
450
        self.import_realloc_fallback()
1367
450
    }
1368
1369
    /// Returns the general-purpose realloc function to use for imports.
1370
    ///
1371
    /// Note that `import_realloc_for` should be used instead where possible.
1372
450
    pub fn import_realloc_fallback(&self) -> Option<&str> {
1373
3.78k
        if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1374
0
            return Some(name);
1375
450
        }
1376
450
        self.general_purpose_realloc()
1377
450
    }
1378
1379
    /// Returns the realloc that the main module is exporting into the adapter.
1380
0
    pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1381
0
        if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1382
0
            return Some(name);
1383
0
        }
1384
0
        self.general_purpose_realloc()
1385
0
    }
1386
1387
4.47k
    fn general_purpose_realloc(&self) -> Option<&str> {
1388
282k
        self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1389
4.47k
    }
1390
1391
    /// Returns the memory, if exported, for this module.
1392
3.26k
    pub fn memory(&self) -> Option<&str> {
1393
11.1k
        self.find(|m| matches!(m, Export::Memory))
1394
3.26k
    }
1395
1396
    /// Returns the indirect function table, if exported, for this module.
1397
0
    pub fn indirect_function_table(&self) -> Option<&str> {
1398
0
        self.find(|t| matches!(t, Export::IndirectFunctionTable))
1399
0
    }
1400
1401
    /// Returns the `__wasm_init_task` function, if exported, for this module.
1402
3.26k
    pub fn wasm_init_task(&self) -> Option<&str> {
1403
17.7k
        self.find(|t| matches!(t, Export::WasmInitTask))
1404
3.26k
    }
1405
1406
    /// Returns the `__wasm_init_async_task` function, if exported, for this module.
1407
3.26k
    pub fn wasm_init_async_task(&self) -> Option<&str> {
1408
17.7k
        self.find(|t| matches!(t, Export::WasmInitAsyncTask))
1409
3.26k
    }
1410
1411
    /// Returns the `_initialize` intrinsic, if exported, for this module.
1412
3.26k
    pub fn initialize(&self) -> Option<&str> {
1413
17.7k
        self.find(|m| matches!(m, Export::Initialize))
1414
3.26k
    }
1415
1416
    /// Returns destructor for the exported resource `ty`, if it was listed.
1417
215
    pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1418
7.12k
        self.find(|m| match m {
1419
873
            Export::ResourceDtor(t) => *t == ty,
1420
6.25k
            _ => false,
1421
7.12k
        })
1422
215
    }
1423
1424
    /// NB: this is a linear search and if that's ever a problem this should
1425
    /// build up an inverse map during construction to accelerate it.
1426
33.8k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
1.17M
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::validate::{closure#2}::{closure#0}>::{closure#0}
Line
Count
Source
1427
443
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::validate::{closure#1}::{closure#0}>::{closure#0}
Line
Count
Source
1427
128k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::initialize::{closure#0}>::{closure#0}
Line
Count
Source
1427
17.7k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::post_return::{closure#0}>::{closure#0}
Line
Count
Source
1427
153k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::resource_dtor::{closure#0}>::{closure#0}
Line
Count
Source
1427
7.12k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::wasm_init_task::{closure#0}>::{closure#0}
Line
Count
Source
1427
17.7k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::export_realloc_for::{closure#0}>::{closure#0}
Line
Count
Source
1427
283k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::wasm_init_async_task::{closure#0}>::{closure#0}
Line
Count
Source
1427
17.7k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::general_purpose_realloc::{closure#0}>::{closure#0}
Line
Count
Source
1427
282k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::import_realloc_fallback::{closure#0}>::{closure#0}
Line
Count
Source
1427
3.78k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
Unexecuted instantiation: <wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::indirect_function_table::{closure#0}>::{closure#0}
Unexecuted instantiation: <wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::realloc_to_import_into_adapter::{closure#0}>::{closure#0}
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::memory::{closure#0}>::{closure#0}
Line
Count
Source
1427
11.1k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::callback::{closure#0}>::{closure#0}
Line
Count
Source
1427
253k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
18.9k
        Some(name)
1429
33.8k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::validate::{closure#2}::{closure#0}>
Line
Count
Source
1426
302
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
302
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
302
        Some(name)
1429
302
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::validate::{closure#1}::{closure#0}>
Line
Count
Source
1426
3.58k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
3.58k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
3.58k
        Some(name)
1429
3.58k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::initialize::{closure#0}>
Line
Count
Source
1426
3.26k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
3.26k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
3.26k
        Some(name)
1429
3.26k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::post_return::{closure#0}>
Line
Count
Source
1426
3.88k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
3.88k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
3.09k
        Some(name)
1429
3.88k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::resource_dtor::{closure#0}>
Line
Count
Source
1426
215
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
215
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
215
        Some(name)
1429
215
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::wasm_init_task::{closure#0}>
Line
Count
Source
1426
3.26k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
3.26k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
0
        Some(name)
1429
3.26k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::export_realloc_for::{closure#0}>
Line
Count
Source
1426
4.02k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
4.02k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
0
        Some(name)
1429
4.02k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::wasm_init_async_task::{closure#0}>
Line
Count
Source
1426
3.26k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
3.26k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
0
        Some(name)
1429
3.26k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::general_purpose_realloc::{closure#0}>
Line
Count
Source
1426
4.47k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
4.47k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
4.47k
        Some(name)
1429
4.47k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::import_realloc_fallback::{closure#0}>
Line
Count
Source
1426
450
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
450
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
0
        Some(name)
1429
450
    }
Unexecuted instantiation: <wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::indirect_function_table::{closure#0}>
Unexecuted instantiation: <wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::realloc_to_import_into_adapter::{closure#0}>
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::memory::{closure#0}>
Line
Count
Source
1426
3.26k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
3.26k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
3.26k
        Some(name)
1429
3.26k
    }
<wit_component::validation::ExportMap>::find::<<wit_component::validation::ExportMap>::callback::{closure#0}>
Line
Count
Source
1426
3.88k
    fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427
3.88k
        let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428
705
        Some(name)
1429
3.88k
    }
1430
1431
    /// Iterates over all exports of this module.
1432
4.02k
    pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1433
27.8k
        self.names.iter().map(|(n, e)| (n.as_str(), e))
1434
4.02k
    }
1435
1436
3.26k
    fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1437
3.26k
        let resolve = &encoder.metadata.resolve;
1438
3.26k
        let world = encoder.metadata.world;
1439
        // Multi-memory isn't supported because otherwise we don't know what
1440
        // memory to put things in.
1441
3.26k
        if self
1442
3.26k
            .names
1443
3.26k
            .values()
1444
17.7k
            .filter(|m| matches!(m, Export::Memory))
1445
3.26k
            .count()
1446
            > 1
1447
        {
1448
0
            bail!("cannot componentize module that exports multiple memories")
1449
3.26k
        }
1450
1451
        // Every async-with-callback-lifted export must have a callback.
1452
17.7k
        for (name, export) in &self.names {
1453
302
            match export {
1454
                Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1455
0
                    if !matches!(
1456
13
                        self.names.get(&format!("[callback]{name}")),
1457
                        Some(Export::WorldFuncCallback(_))
1458
                    ) {
1459
0
                        bail!("missing callback for `{name}`");
1460
13
                    }
1461
                }
1462
                Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1463
0
                    if !matches!(
1464
692
                        self.names.get(&format!("[callback]{name}")),
1465
                        Some(Export::InterfaceFuncCallback(_, _))
1466
                    ) {
1467
0
                        bail!("missing callback for `{name}`");
1468
692
                    }
1469
                }
1470
17.0k
                _ => {}
1471
            }
1472
        }
1473
1474
        // All of `exports` must be exported and found within this module.
1475
3.26k
        for export in exports {
1476
3.58k
            let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1477
128k
                let result = self.find(|e| match e {
1478
65.4k
                    Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1479
63.4k
                    _ => false,
1480
128k
                });
1481
3.58k
                if result.is_some() {
1482
3.58k
                    Ok(())
1483
                } else {
1484
0
                    let export = resolve.name_world_key(export);
1485
0
                    bail!("failed to find export of interface `{export}` function `{name}`")
1486
                }
1487
3.58k
            };
1488
2.06k
            let require_world_func = |name: &str| -> Result<()> {
1489
443
                let result = self.find(|e| match e {
1490
374
                    Export::WorldFunc(_, s, _) => name == s,
1491
69
                    _ => false,
1492
443
                });
1493
302
                if result.is_some() {
1494
302
                    Ok(())
1495
                } else {
1496
0
                    bail!("failed to find export of function `{name}`")
1497
                }
1498
302
            };
1499
2.06k
            match &resolve.worlds[world].exports[export] {
1500
1.76k
                WorldItem::Interface { id, .. } => {
1501
3.58k
                    for (name, _) in resolve.interfaces[*id].functions.iter() {
1502
3.58k
                        require_interface_func(*id, name)?;
1503
                    }
1504
                }
1505
302
                WorldItem::Function(f) => {
1506
302
                    require_world_func(&f.name)?;
1507
                }
1508
0
                WorldItem::Type { .. } => unreachable!(),
1509
            }
1510
        }
1511
1512
3.26k
        Ok(())
1513
3.26k
    }
1514
}
1515
1516
/// A builtin that may be declared as cancellable.
1517
struct MaybeCancellable<T> {
1518
    #[allow(unused)]
1519
    inner: T,
1520
    cancellable: bool,
1521
}
1522
1523
/// A builtin that may be declared as async-lowered.
1524
struct MaybeAsyncLowered<T> {
1525
    inner: T,
1526
    async_lowered: bool,
1527
}
1528
1529
/// Context passed to `NameMangling` implementations of stream and future functions
1530
/// to help with looking up payload information.
1531
struct PayloadLookupContext<'a> {
1532
    resolve: &'a Resolve,
1533
    world: &'a World,
1534
    id: Option<InterfaceId>,
1535
    import: bool,
1536
    key: Option<WorldKey>,
1537
}
1538
1539
/// Trait dispatch and definition for parsing and interpreting "mangled names"
1540
/// which show up in imports and exports of the component model.
1541
///
1542
/// This trait is used to implement classification of imports and exports in the
1543
/// component model. The methods on `ImportMap` and `ExportMap` will use this to
1544
/// determine what an import is and how it's lifted/lowered in the world being
1545
/// bound.
1546
///
1547
/// This trait has a bit of history behind it as well. Before
1548
/// WebAssembly/component-model#378 there was no standard naming scheme for core
1549
/// wasm imports or exports when componenitizing. This meant that
1550
/// `wit-component` implemented a particular scheme which mostly worked but was
1551
/// mostly along the lines of "this at least works" rather than "someone sat
1552
/// down and designed this". Since then, however, an standard naming scheme has
1553
/// now been specified which was indeed designed.
1554
///
1555
/// This trait serves as the bridge between these two. The historical naming
1556
/// scheme is still supported for now through the `Legacy` implementation below
1557
/// and will be for some time. The transition plan at this time is to support
1558
/// the new scheme, eventually get it supported in bindings generators, and once
1559
/// that's all propagated remove support for the legacy scheme.
1560
trait NameMangling {
1561
    fn import_root(&self) -> &str;
1562
    fn import_non_root_prefix(&self) -> &str;
1563
    fn import_exported_intrinsic_prefix(&self) -> &str;
1564
    fn export_memory(&self) -> &str;
1565
    fn export_initialize(&self) -> &str;
1566
    fn export_realloc(&self) -> &str;
1567
    fn export_indirect_function_table(&self) -> Option<&str>;
1568
    fn export_wasm_init_task(&self) -> Option<&str>;
1569
    fn export_wasm_init_async_task(&self) -> Option<&str>;
1570
    fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1571
    fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1572
    fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1573
    fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1574
    fn task_cancel(&self, name: &str) -> bool;
1575
    fn backpressure_inc(&self, name: &str) -> bool;
1576
    fn backpressure_dec(&self, name: &str) -> bool;
1577
    fn waitable_set_new(&self, name: &str) -> bool;
1578
    fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1579
    fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1580
    fn waitable_set_drop(&self, name: &str) -> bool;
1581
    fn waitable_join(&self, name: &str) -> bool;
1582
    fn subtask_drop(&self, name: &str) -> bool;
1583
    fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1584
    fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1585
    fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1586
    fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1587
    fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1588
    fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1589
    fn error_context_drop(&self, name: &str) -> bool;
1590
    fn context_get(&self, name: &str) -> Option<(ValType, u32)>;
1591
    fn context_set(&self, name: &str) -> Option<(ValType, u32)>;
1592
    fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1593
    fn future_write(
1594
        &self,
1595
        lookup_context: &PayloadLookupContext,
1596
        name: &str,
1597
    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1598
    fn future_read(
1599
        &self,
1600
        lookup_context: &PayloadLookupContext,
1601
        name: &str,
1602
    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1603
    fn future_cancel_write(
1604
        &self,
1605
        lookup_context: &PayloadLookupContext,
1606
        name: &str,
1607
    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1608
    fn future_cancel_read(
1609
        &self,
1610
        lookup_context: &PayloadLookupContext,
1611
        name: &str,
1612
    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1613
    fn future_drop_writable(
1614
        &self,
1615
        lookup_context: &PayloadLookupContext,
1616
        name: &str,
1617
    ) -> Option<PayloadInfo>;
1618
    fn future_drop_readable(
1619
        &self,
1620
        lookup_context: &PayloadLookupContext,
1621
        name: &str,
1622
    ) -> Option<PayloadInfo>;
1623
    fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1624
    fn stream_write(
1625
        &self,
1626
        lookup_context: &PayloadLookupContext,
1627
        name: &str,
1628
    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1629
    fn stream_read(
1630
        &self,
1631
        lookup_context: &PayloadLookupContext,
1632
        name: &str,
1633
    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1634
    fn stream_cancel_write(
1635
        &self,
1636
        lookup_context: &PayloadLookupContext,
1637
        name: &str,
1638
    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1639
    fn stream_cancel_read(
1640
        &self,
1641
        lookup_context: &PayloadLookupContext,
1642
        name: &str,
1643
    ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1644
    fn stream_drop_writable(
1645
        &self,
1646
        lookup_context: &PayloadLookupContext,
1647
        name: &str,
1648
    ) -> Option<PayloadInfo>;
1649
    fn stream_drop_readable(
1650
        &self,
1651
        lookup_context: &PayloadLookupContext,
1652
        name: &str,
1653
    ) -> Option<PayloadInfo>;
1654
    fn thread_index(&self, name: &str) -> bool;
1655
    fn thread_new_indirect(&self, name: &str) -> bool;
1656
    fn thread_resume_later(&self, name: &str) -> bool;
1657
    fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1658
    fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1659
    fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1660
    fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1661
    fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1662
    fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1663
    fn module_to_interface(
1664
        &self,
1665
        module: &str,
1666
        resolve: &Resolve,
1667
        items: &IndexMap<WorldKey, WorldItem>,
1668
    ) -> Result<(WorldKey, InterfaceId)>;
1669
    fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1670
    fn match_wit_export<'a>(
1671
        &self,
1672
        export_name: &str,
1673
        resolve: &'a Resolve,
1674
        world: WorldId,
1675
        exports: &'a IndexSet<WorldKey>,
1676
    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1677
    fn match_wit_resource_dtor<'a>(
1678
        &self,
1679
        export_name: &str,
1680
        resolve: &'a Resolve,
1681
        world: WorldId,
1682
        exports: &'a IndexSet<WorldKey>,
1683
    ) -> Option<TypeId>;
1684
    fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1685
    fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1686
}
1687
1688
/// Definition of the "standard" naming scheme which currently starts with
1689
/// "cm32p2". Note that wasm64 is not supported at this time.
1690
struct Standard;
1691
1692
const STANDARD: &'static dyn NameMangling = &Standard;
1693
1694
impl NameMangling for Standard {
1695
311
    fn import_root(&self) -> &str {
1696
311
        ""
1697
311
    }
1698
252
    fn import_non_root_prefix(&self) -> &str {
1699
252
        "|"
1700
252
    }
1701
504
    fn import_exported_intrinsic_prefix(&self) -> &str {
1702
504
        "_ex_"
1703
504
    }
1704
169
    fn export_memory(&self) -> &str {
1705
169
        "_memory"
1706
169
    }
1707
1.75k
    fn export_initialize(&self) -> &str {
1708
1.75k
        "_initialize"
1709
1.75k
    }
1710
1.91k
    fn export_realloc(&self) -> &str {
1711
1.91k
        "_realloc"
1712
1.91k
    }
1713
0
    fn export_indirect_function_table(&self) -> Option<&str> {
1714
0
        None
1715
0
    }
1716
1.58k
    fn export_wasm_init_task(&self) -> Option<&str> {
1717
1.58k
        None
1718
1.58k
    }
1719
1.58k
    fn export_wasm_init_async_task(&self) -> Option<&str> {
1720
1.58k
        None
1721
1.58k
    }
1722
25
    fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1723
25
        name.strip_suffix("_drop")
1724
25
    }
1725
6
    fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1726
6
        name.strip_suffix("_new")
1727
6
    }
1728
3
    fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1729
3
        name.strip_suffix("_rep")
1730
3
    }
1731
0
    fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1732
0
        None
1733
0
    }
1734
0
    fn task_cancel(&self, _name: &str) -> bool {
1735
0
        false
1736
0
    }
1737
59
    fn backpressure_inc(&self, _name: &str) -> bool {
1738
59
        false
1739
59
    }
1740
59
    fn backpressure_dec(&self, _name: &str) -> bool {
1741
59
        false
1742
59
    }
1743
59
    fn waitable_set_new(&self, _name: &str) -> bool {
1744
59
        false
1745
59
    }
1746
59
    fn waitable_set_wait(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1747
59
        None
1748
59
    }
1749
59
    fn waitable_set_poll(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1750
59
        None
1751
59
    }
1752
59
    fn waitable_set_drop(&self, _name: &str) -> bool {
1753
59
        false
1754
59
    }
1755
59
    fn waitable_join(&self, _name: &str) -> bool {
1756
59
        false
1757
59
    }
1758
59
    fn subtask_drop(&self, _name: &str) -> bool {
1759
59
        false
1760
59
    }
1761
59
    fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1762
59
        None
1763
59
    }
1764
3
    fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1765
3
        None
1766
3
    }
1767
1.58k
    fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1768
1.58k
        None
1769
1.58k
    }
1770
1.58k
    fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1771
1.58k
        None
1772
1.58k
    }
1773
59
    fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1774
59
        None
1775
59
    }
1776
59
    fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1777
59
        None
1778
59
    }
1779
59
    fn error_context_drop(&self, _name: &str) -> bool {
1780
59
        false
1781
59
    }
1782
59
    fn context_get(&self, _name: &str) -> Option<(ValType, u32)> {
1783
59
        None
1784
59
    }
1785
59
    fn context_set(&self, _name: &str) -> Option<(ValType, u32)> {
1786
59
        None
1787
59
    }
1788
59
    fn thread_index(&self, _name: &str) -> bool {
1789
59
        false
1790
59
    }
1791
59
    fn thread_new_indirect(&self, _name: &str) -> bool {
1792
59
        false
1793
59
    }
1794
59
    fn thread_resume_later(&self, _name: &str) -> bool {
1795
59
        false
1796
59
    }
1797
59
    fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1798
59
        None
1799
59
    }
1800
59
    fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1801
59
        None
1802
59
    }
1803
59
    fn thread_suspend_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1804
59
        None
1805
59
    }
1806
59
    fn thread_yield_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1807
59
        None
1808
59
    }
1809
59
    fn thread_suspend_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1810
59
        None
1811
59
    }
1812
59
    fn thread_yield_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1813
59
        None
1814
59
    }
1815
0
    fn future_new(
1816
0
        &self,
1817
0
        _lookup_context: &PayloadLookupContext,
1818
0
        _name: &str,
1819
0
    ) -> Option<PayloadInfo> {
1820
0
        None
1821
0
    }
1822
0
    fn future_write(
1823
0
        &self,
1824
0
        _lookup_context: &PayloadLookupContext,
1825
0
        _name: &str,
1826
0
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1827
0
        None
1828
0
    }
1829
0
    fn future_read(
1830
0
        &self,
1831
0
        _lookup_context: &PayloadLookupContext,
1832
0
        _name: &str,
1833
0
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1834
0
        None
1835
0
    }
1836
0
    fn future_cancel_write(
1837
0
        &self,
1838
0
        _lookup_context: &PayloadLookupContext,
1839
0
        _name: &str,
1840
0
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1841
0
        None
1842
0
    }
1843
0
    fn future_cancel_read(
1844
0
        &self,
1845
0
        _lookup_context: &PayloadLookupContext,
1846
0
        _name: &str,
1847
0
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1848
0
        None
1849
0
    }
1850
0
    fn future_drop_writable(
1851
0
        &self,
1852
0
        _lookup_context: &PayloadLookupContext,
1853
0
        _name: &str,
1854
0
    ) -> Option<PayloadInfo> {
1855
0
        None
1856
0
    }
1857
0
    fn future_drop_readable(
1858
0
        &self,
1859
0
        _lookup_context: &PayloadLookupContext,
1860
0
        _name: &str,
1861
0
    ) -> Option<PayloadInfo> {
1862
0
        None
1863
0
    }
1864
0
    fn stream_new(
1865
0
        &self,
1866
0
        _lookup_context: &PayloadLookupContext,
1867
0
        _name: &str,
1868
0
    ) -> Option<PayloadInfo> {
1869
0
        None
1870
0
    }
1871
0
    fn stream_write(
1872
0
        &self,
1873
0
        _lookup_context: &PayloadLookupContext,
1874
0
        _name: &str,
1875
0
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1876
0
        None
1877
0
    }
1878
0
    fn stream_read(
1879
0
        &self,
1880
0
        _lookup_context: &PayloadLookupContext,
1881
0
        _name: &str,
1882
0
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1883
0
        None
1884
0
    }
1885
0
    fn stream_cancel_write(
1886
0
        &self,
1887
0
        _lookup_context: &PayloadLookupContext,
1888
0
        _name: &str,
1889
0
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1890
0
        None
1891
0
    }
1892
0
    fn stream_cancel_read(
1893
0
        &self,
1894
0
        _lookup_context: &PayloadLookupContext,
1895
0
        _name: &str,
1896
0
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1897
0
        None
1898
0
    }
1899
0
    fn stream_drop_writable(
1900
0
        &self,
1901
0
        _lookup_context: &PayloadLookupContext,
1902
0
        _name: &str,
1903
0
    ) -> Option<PayloadInfo> {
1904
0
        None
1905
0
    }
1906
0
    fn stream_drop_readable(
1907
0
        &self,
1908
0
        _lookup_context: &PayloadLookupContext,
1909
0
        _name: &str,
1910
0
    ) -> Option<PayloadInfo> {
1911
0
        None
1912
0
    }
1913
252
    fn module_to_interface(
1914
252
        &self,
1915
252
        interface: &str,
1916
252
        resolve: &Resolve,
1917
252
        items: &IndexMap<WorldKey, WorldItem>,
1918
252
    ) -> Result<(WorldKey, InterfaceId)> {
1919
284
        for (key, item) in items.iter() {
1920
284
            let id = match key {
1921
                // Bare keys are matched exactly against `interface`
1922
81
                WorldKey::Name(name) => match item {
1923
78
                    WorldItem::Interface { id, .. } if name == interface => *id,
1924
20
                    _ => continue,
1925
                },
1926
                // ID-identified keys are matched with their "canonical name"
1927
203
                WorldKey::Interface(id) => {
1928
203
                    if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1929
12
                        continue;
1930
191
                    }
1931
191
                    *id
1932
                }
1933
            };
1934
252
            return Ok((key.clone(), id));
1935
        }
1936
0
        bail!("failed to find world item corresponding to interface `{interface}`")
1937
252
    }
1938
792
    fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1939
792
        name.strip_suffix("_post")
1940
792
    }
1941
2.37k
    fn match_wit_export<'a>(
1942
2.37k
        &self,
1943
2.37k
        export_name: &str,
1944
2.37k
        resolve: &'a Resolve,
1945
2.37k
        world: WorldId,
1946
2.37k
        exports: &'a IndexSet<WorldKey>,
1947
2.37k
    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1948
2.37k
        if let Some(world_export_name) = export_name.strip_prefix("||") {
1949
66
            let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1950
44
            match &resolve.worlds[world].exports[key] {
1951
44
                WorldItem::Function(f) => return Some((key, None, f)),
1952
0
                _ => return None,
1953
            }
1954
2.30k
        }
1955
1956
2.30k
        let (key, id, func_name) =
1957
2.30k
            self.match_wit_interface(export_name, resolve, world, exports)?;
1958
2.30k
        let func = resolve.interfaces[id].functions.get(func_name)?;
1959
1.53k
        Some((key, Some(id), func))
1960
2.37k
    }
1961
1962
3
    fn match_wit_resource_dtor<'a>(
1963
3
        &self,
1964
3
        export_name: &str,
1965
3
        resolve: &'a Resolve,
1966
3
        world: WorldId,
1967
3
        exports: &'a IndexSet<WorldKey>,
1968
3
    ) -> Option<TypeId> {
1969
3
        let (_key, id, name) =
1970
3
            self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1971
3
        let ty = *resolve.interfaces[id].types.get(name)?;
1972
3
        match resolve.types[ty].kind {
1973
3
            TypeDefKind::Resource => Some(ty),
1974
0
            _ => None,
1975
        }
1976
3
    }
1977
1978
59
    fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1979
59
        (name, AbiVariant::GuestImport)
1980
59
    }
1981
243
    fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1982
243
        (name, AbiVariant::GuestImport)
1983
243
    }
1984
}
1985
1986
impl Standard {
1987
2.30k
    fn match_wit_interface<'a, 'b>(
1988
2.30k
        &self,
1989
2.30k
        export_name: &'b str,
1990
2.30k
        resolve: &'a Resolve,
1991
2.30k
        world: WorldId,
1992
2.30k
        exports: &'a IndexSet<WorldKey>,
1993
2.30k
    ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
1994
2.30k
        let world = &resolve.worlds[world];
1995
2.30k
        let export_name = export_name.strip_prefix("|")?;
1996
1997
10.2k
        for export in exports {
1998
10.2k
            let id = match &world.exports[export] {
1999
9.00k
                WorldItem::Interface { id, .. } => *id,
2000
1.27k
                WorldItem::Function(_) => continue,
2001
0
                WorldItem::Type { .. } => unreachable!(),
2002
            };
2003
9.00k
            let remaining = match export {
2004
8.94k
                WorldKey::Name(name) => export_name.strip_prefix(name),
2005
                WorldKey::Interface(_) => {
2006
56
                    let prefix = resolve.canonicalized_id_of(id).unwrap();
2007
56
                    export_name.strip_prefix(&prefix)
2008
                }
2009
            };
2010
9.00k
            let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
2011
2.30k
                Some(name) => name,
2012
6.69k
                None => continue,
2013
            };
2014
2.30k
            return Some((export, id, item_name));
2015
        }
2016
2017
0
        None
2018
2.30k
    }
2019
}
2020
2021
/// Definition of wit-component's "legacy" naming scheme which predates
2022
/// WebAssembly/component-model#378.
2023
struct Legacy;
2024
2025
const LEGACY: &'static dyn NameMangling = &Legacy;
2026
2027
impl Legacy {
2028
    // Looks for `[$prefix-N]foo` within `name`. If found then `foo` is
2029
    // used to find a function within `id` and `world` above. Once found
2030
    // then `N` is used to index within that function to extract a
2031
    // future/stream type. If that's all found then a `PayloadInfo` is
2032
    // returned to get attached to an intrinsic.
2033
3.01k
    fn prefixed_payload(
2034
3.01k
        &self,
2035
3.01k
        lookup_context: &PayloadLookupContext,
2036
3.01k
        name: &str,
2037
3.01k
        prefix: &str,
2038
3.01k
    ) -> Option<PayloadInfo> {
2039
        // parse the `prefix` into `func_name` and `type_index`, bailing out
2040
        // with `None` if anything doesn't match.
2041
3.01k
        let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2042
630
        let ty = match index_or_unit {
2043
630
            "unit" => {
2044
0
                if name.starts_with("[future") {
2045
0
                    PayloadType::UnitFuture
2046
0
                } else if name.starts_with("[stream") {
2047
0
                    PayloadType::UnitStream
2048
                } else {
2049
0
                    unreachable!()
2050
                }
2051
            }
2052
630
            other => {
2053
                // Note that this is parsed as a `u32` to ensure that the
2054
                // integer parsing is the same across platforms regardless of
2055
                // the the width of `usize`.
2056
630
                let type_index = other.parse::<u32>().ok()? as usize;
2057
2058
                // Double-check that `func_name` is indeed a function name within
2059
                // this interface/world. Then additionally double-check that
2060
                // `type_index` is indeed a valid index for this function's type
2061
                // signature.
2062
630
                let function = get_function(
2063
630
                    lookup_context.resolve,
2064
630
                    lookup_context.world,
2065
630
                    func_name,
2066
630
                    lookup_context.id,
2067
630
                    lookup_context.import,
2068
                )
2069
630
                .ok()?;
2070
                PayloadType::Type {
2071
630
                    id: *function
2072
630
                        .find_futures_and_streams(lookup_context.resolve)
2073
630
                        .get(type_index)?,
2074
630
                    function: function.name.clone(),
2075
                }
2076
            }
2077
        };
2078
2079
        // And if all that passes wrap up everything in a `PayloadInfo`.
2080
        Some(PayloadInfo {
2081
630
            name: name.to_string(),
2082
630
            ty,
2083
630
            key: lookup_context
2084
630
                .key
2085
630
                .clone()
2086
630
                .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2087
630
            interface: lookup_context.id,
2088
630
            imported: lookup_context.import,
2089
        })
2090
3.01k
    }
2091
2092
1.90k
    fn maybe_async_lowered_payload(
2093
1.90k
        &self,
2094
1.90k
        lookup_context: &PayloadLookupContext,
2095
1.90k
        name: &str,
2096
1.90k
        prefix: &str,
2097
1.90k
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2098
1.90k
        let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2099
1.90k
        let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2100
360
        Some(MaybeAsyncLowered {
2101
360
            inner: payload,
2102
360
            async_lowered,
2103
360
        })
2104
1.90k
    }
2105
2106
7.32k
    fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2107
7.32k
        name.strip_prefix("[async-lower]")
2108
7.32k
            .map_or((false, name), |s| (true, s))
2109
7.32k
    }
2110
3.04k
    fn match_with_async_lowered_prefix(
2111
3.04k
        &self,
2112
3.04k
        name: &str,
2113
3.04k
        expected: &str,
2114
3.04k
    ) -> Option<MaybeAsyncLowered<()>> {
2115
3.04k
        let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2116
3.04k
        if clean_name == expected {
2117
523
            Some(MaybeAsyncLowered {
2118
523
                inner: (),
2119
523
                async_lowered,
2120
523
            })
2121
        } else {
2122
2.52k
            None
2123
        }
2124
3.04k
    }
2125
17.5k
    fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2126
17.5k
        name.strip_prefix("[cancellable]")
2127
17.5k
            .map_or((false, name), |s| (true, s))
2128
17.5k
    }
2129
6.78k
    fn match_with_cancellable_prefix(
2130
6.78k
        &self,
2131
6.78k
        name: &str,
2132
6.78k
        expected: &str,
2133
6.78k
    ) -> Option<MaybeCancellable<()>> {
2134
6.78k
        let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2135
6.78k
        if clean_name == expected {
2136
523
            Some(MaybeCancellable {
2137
523
                inner: (),
2138
523
                cancellable,
2139
523
            })
2140
        } else {
2141
6.25k
            None
2142
        }
2143
6.78k
    }
2144
2145
    /// Matches a name with the given prefix and either no suffix (for backwards compat) or
2146
    /// "-i32" or "-i64".
2147
    /// Returns a `ValType` based on the suffix and defaults to `I32`.
2148
10.8k
    fn match_with_optional_type_suffix(name: &str, match_prefix: &str) -> Option<ValType> {
2149
10.8k
        let tail = name.strip_prefix(match_prefix)?.strip_suffix(']')?;
2150
1.04k
        if tail.is_empty() {
2151
1.04k
            Some(ValType::I32)
2152
        } else {
2153
0
            match tail.strip_prefix('-')? {
2154
0
                "i32" => Some(ValType::I32),
2155
0
                "i64" => Some(ValType::I64),
2156
                // Other suffixes
2157
0
                _ => None,
2158
            }
2159
        }
2160
10.8k
    }
2161
}
2162
2163
impl NameMangling for Legacy {
2164
13.7k
    fn import_root(&self) -> &str {
2165
13.7k
        "$root"
2166
13.7k
    }
2167
3.32k
    fn import_non_root_prefix(&self) -> &str {
2168
3.32k
        ""
2169
3.32k
    }
2170
7.26k
    fn import_exported_intrinsic_prefix(&self) -> &str {
2171
7.26k
        "[export]"
2172
7.26k
    }
2173
3.09k
    fn export_memory(&self) -> &str {
2174
3.09k
        "memory"
2175
3.09k
    }
2176
9.42k
    fn export_initialize(&self) -> &str {
2177
9.42k
        "_initialize"
2178
9.42k
    }
2179
12.5k
    fn export_realloc(&self) -> &str {
2180
12.5k
        "cabi_realloc"
2181
12.5k
    }
2182
0
    fn export_indirect_function_table(&self) -> Option<&str> {
2183
0
        Some("__indirect_function_table")
2184
0
    }
2185
6.32k
    fn export_wasm_init_task(&self) -> Option<&str> {
2186
6.32k
        Some("__wasm_init_task")
2187
6.32k
    }
2188
6.32k
    fn export_wasm_init_async_task(&self) -> Option<&str> {
2189
6.32k
        Some("__wasm_init_async_task")
2190
6.32k
    }
2191
2.90k
    fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2192
2.90k
        name.strip_prefix("[resource-drop]")
2193
2.90k
    }
2194
2.31k
    fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2195
2.31k
        name.strip_prefix("[resource-new]")
2196
2.31k
    }
2197
2.10k
    fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2198
2.10k
        name.strip_prefix("[resource-rep]")
2199
2.10k
    }
2200
1.88k
    fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2201
1.88k
        name.strip_prefix("[task-return]")
2202
1.88k
    }
2203
1.00k
    fn task_cancel(&self, name: &str) -> bool {
2204
1.00k
        name == "[task-cancel]"
2205
1.00k
    }
2206
7.23k
    fn backpressure_inc(&self, name: &str) -> bool {
2207
7.23k
        name == "[backpressure-inc]"
2208
7.23k
    }
2209
6.70k
    fn backpressure_dec(&self, name: &str) -> bool {
2210
6.70k
        name == "[backpressure-dec]"
2211
6.70k
    }
2212
6.18k
    fn waitable_set_new(&self, name: &str) -> bool {
2213
6.18k
        name == "[waitable-set-new]"
2214
6.18k
    }
2215
5.66k
    fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2216
5.66k
        let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2217
5.66k
        let mb_cancellable = MaybeCancellable {
2218
5.66k
            inner: (),
2219
5.66k
            cancellable,
2220
5.66k
        };
2221
5.66k
        let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-wait")?;
2222
523
        Some((mb_cancellable, result_ty))
2223
5.66k
    }
2224
5.14k
    fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2225
5.14k
        let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2226
5.14k
        let mb_cancellable = MaybeCancellable {
2227
5.14k
            inner: (),
2228
5.14k
            cancellable,
2229
5.14k
        };
2230
5.14k
        let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-poll")?;
2231
523
        Some((mb_cancellable, result_ty))
2232
5.14k
    }
2233
4.61k
    fn waitable_set_drop(&self, name: &str) -> bool {
2234
4.61k
        name == "[waitable-set-drop]"
2235
4.61k
    }
2236
4.09k
    fn waitable_join(&self, name: &str) -> bool {
2237
4.09k
        name == "[waitable-join]"
2238
4.09k
    }
2239
3.57k
    fn subtask_drop(&self, name: &str) -> bool {
2240
3.57k
        name == "[subtask-drop]"
2241
3.57k
    }
2242
3.04k
    fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2243
3.04k
        self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2244
3.04k
    }
2245
917
    fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2246
917
        name.strip_prefix("[callback][async-lift]")
2247
917
    }
2248
6.32k
    fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2249
6.32k
        name.strip_prefix("[async-lift]")
2250
6.32k
    }
2251
5.61k
    fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2252
5.61k
        name.strip_prefix("[async-lift-stackful]")
2253
5.61k
    }
2254
2.52k
    fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2255
2.52k
        match name {
2256
2.52k
            "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2257
2.52k
            "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2258
2.52k
            "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2259
2.52k
            _ => None,
2260
        }
2261
2.52k
    }
2262
2.52k
    fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2263
2.52k
        match name {
2264
2.52k
            "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2265
2.52k
            "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2266
2.52k
            "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2267
2.52k
            _ => None,
2268
        }
2269
2.52k
    }
2270
7.23k
    fn error_context_drop(&self, name: &str) -> bool {
2271
7.23k
        name == "[error-context-drop]"
2272
7.23k
    }
2273
2.52k
    fn context_get(&self, name: &str) -> Option<(ValType, u32)> {
2274
2.52k
        parse_context_name(name, "[context-get-")
2275
2.52k
    }
2276
2.00k
    fn context_set(&self, name: &str) -> Option<(ValType, u32)> {
2277
2.00k
        parse_context_name(name, "[context-set-")
2278
2.00k
    }
2279
1.47k
    fn thread_index(&self, name: &str) -> bool {
2280
1.47k
        name == "[thread-index]"
2281
1.47k
    }
2282
1.47k
    fn thread_new_indirect(&self, name: &str) -> bool {
2283
        // For now, we'll fix the type of the start function and the table to extract it from
2284
1.47k
        name == "[thread-new-indirect-v0]"
2285
1.47k
    }
2286
1.47k
    fn thread_resume_later(&self, name: &str) -> bool {
2287
1.47k
        name == "[thread-resume-later]"
2288
1.47k
    }
2289
1.47k
    fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2290
1.47k
        self.match_with_cancellable_prefix(name, "[thread-suspend]")
2291
1.47k
    }
2292
1.47k
    fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2293
1.47k
        self.match_with_cancellable_prefix(name, "[thread-yield]")
2294
1.47k
    }
2295
956
    fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2296
956
        self.match_with_cancellable_prefix(name, "[thread-suspend-then-resume]")
2297
956
    }
2298
956
    fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2299
956
        self.match_with_cancellable_prefix(name, "[thread-yield-then-resume]")
2300
956
    }
2301
956
    fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2302
956
        self.match_with_cancellable_prefix(name, "[thread-suspend-then-promote]")
2303
956
    }
2304
956
    fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2305
956
        self.match_with_cancellable_prefix(name, "[thread-yield-then-promote]")
2306
956
    }
2307
630
    fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2308
630
        self.prefixed_payload(lookup_context, name, "[future-new-")
2309
630
    }
2310
550
    fn future_write(
2311
550
        &self,
2312
550
        lookup_context: &PayloadLookupContext,
2313
550
        name: &str,
2314
550
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2315
550
        self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2316
550
    }
2317
470
    fn future_read(
2318
470
        &self,
2319
470
        lookup_context: &PayloadLookupContext,
2320
470
        name: &str,
2321
470
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2322
470
        self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2323
470
    }
2324
390
    fn future_cancel_write(
2325
390
        &self,
2326
390
        lookup_context: &PayloadLookupContext,
2327
390
        name: &str,
2328
390
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2329
390
        self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2330
390
    }
2331
310
    fn future_cancel_read(
2332
310
        &self,
2333
310
        lookup_context: &PayloadLookupContext,
2334
310
        name: &str,
2335
310
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2336
310
        self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2337
310
    }
2338
230
    fn future_drop_writable(
2339
230
        &self,
2340
230
        lookup_context: &PayloadLookupContext,
2341
230
        name: &str,
2342
230
    ) -> Option<PayloadInfo> {
2343
230
        self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2344
230
    }
2345
150
    fn future_drop_readable(
2346
150
        &self,
2347
150
        lookup_context: &PayloadLookupContext,
2348
150
        name: &str,
2349
150
    ) -> Option<PayloadInfo> {
2350
150
        self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2351
150
    }
2352
70
    fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2353
70
        self.prefixed_payload(lookup_context, name, "[stream-new-")
2354
70
    }
2355
60
    fn stream_write(
2356
60
        &self,
2357
60
        lookup_context: &PayloadLookupContext,
2358
60
        name: &str,
2359
60
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2360
60
        self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2361
60
    }
2362
50
    fn stream_read(
2363
50
        &self,
2364
50
        lookup_context: &PayloadLookupContext,
2365
50
        name: &str,
2366
50
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2367
50
        self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2368
50
    }
2369
40
    fn stream_cancel_write(
2370
40
        &self,
2371
40
        lookup_context: &PayloadLookupContext,
2372
40
        name: &str,
2373
40
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2374
40
        self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2375
40
    }
2376
30
    fn stream_cancel_read(
2377
30
        &self,
2378
30
        lookup_context: &PayloadLookupContext,
2379
30
        name: &str,
2380
30
    ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2381
30
        self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2382
30
    }
2383
20
    fn stream_drop_writable(
2384
20
        &self,
2385
20
        lookup_context: &PayloadLookupContext,
2386
20
        name: &str,
2387
20
    ) -> Option<PayloadInfo> {
2388
20
        self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2389
20
    }
2390
10
    fn stream_drop_readable(
2391
10
        &self,
2392
10
        lookup_context: &PayloadLookupContext,
2393
10
        name: &str,
2394
10
    ) -> Option<PayloadInfo> {
2395
10
        self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2396
10
    }
2397
3.32k
    fn module_to_interface(
2398
3.32k
        &self,
2399
3.32k
        module: &str,
2400
3.32k
        resolve: &Resolve,
2401
3.32k
        items: &IndexMap<WorldKey, WorldItem>,
2402
3.32k
    ) -> Result<(WorldKey, InterfaceId)> {
2403
        // First see if this is a bare name
2404
3.32k
        let bare_name = WorldKey::Name(module.to_string());
2405
3.32k
        if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2406
2.31k
            return Ok((bare_name, *id));
2407
1.01k
        }
2408
2409
        // ... and if this isn't a bare name then it's time to do some parsing
2410
        // related to interfaces, versions, and such. First up the `module` name
2411
        // is parsed as a normal component name from `wasmparser` to see if it's
2412
        // of the "interface kind". If it's not then that means the above match
2413
        // should have been a hit but it wasn't, so an error is returned.
2414
1.01k
        let kebab_name = ComponentName::new(module, 0);
2415
1.01k
        let name = match kebab_name.as_ref().map(|k| k.kind()) {
2416
1.01k
            Ok(ComponentNameKind::Interface(name)) => name,
2417
0
            _ => bail!("module requires an import interface named `{module}`"),
2418
        };
2419
2420
        // FIXME: this prevents core wasm from importing from `@1` or
2421
        // `@0.1`, for example. More refactoring will be necessary to enable
2422
        // that.
2423
1.01k
        let version = name.version(None)?;
2424
2425
        // Prioritize an exact match based on versions, so try that first.
2426
1.01k
        let pkgname = PackageName {
2427
1.01k
            namespace: name.namespace().to_string(),
2428
1.01k
            name: name.package().to_string(),
2429
1.01k
            version: version.clone(),
2430
1.01k
        };
2431
1.01k
        if let Some(pkg) = resolve.package_names.get(&pkgname) {
2432
1.01k
            if let Some(id) = resolve.packages[*pkg]
2433
1.01k
                .interfaces
2434
1.01k
                .get(name.interface().as_str())
2435
            {
2436
                // If the interface from the package is directly in `items` then
2437
                // return that.
2438
1.01k
                let key = WorldKey::Interface(*id);
2439
1.01k
                if items.contains_key(&key) {
2440
999
                    return Ok((key, *id));
2441
13
                }
2442
2443
                // .. otherwise see if any interface in `items` is a clone of
2444
                // the package's interface. This means it's created by
2445
                // `generate_nominal_type_ids` and is used to match up exports
2446
                // to their nominal clone since the original is no longer
2447
                // exported.
2448
15
                for k in items.keys() {
2449
15
                    let i = match *k {
2450
13
                        WorldKey::Interface(id) => id,
2451
2
                        WorldKey::Name(_) => continue,
2452
                    };
2453
13
                    if resolve.interfaces[i].clone_of == Some(*id) {
2454
13
                        return Ok((WorldKey::Interface(i), i));
2455
0
                    }
2456
                }
2457
0
            }
2458
0
        }
2459
2460
        // If an exact match wasn't found then instead search for the first
2461
        // match based on versions. This means that a core wasm import for
2462
        // "1.2.3" might end up matching an interface at "1.2.4", for example.
2463
        // (or "1.2.2", depending on what's available).
2464
0
        for (key, _) in items {
2465
0
            let id = match key {
2466
0
                WorldKey::Interface(id) => *id,
2467
0
                WorldKey::Name(_) => continue,
2468
            };
2469
            // Make sure the interface names match
2470
0
            let interface = &resolve.interfaces[id];
2471
0
            if interface.name.as_ref().unwrap() != name.interface().as_str() {
2472
0
                continue;
2473
0
            }
2474
2475
            // Make sure the package name (without version) matches
2476
0
            let pkg = &resolve.packages[interface.package.unwrap()];
2477
0
            if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2478
0
                continue;
2479
0
            }
2480
2481
0
            let module_version = match &version {
2482
0
                Some(version) => version,
2483
0
                None => continue,
2484
            };
2485
0
            let pkg_version = match &pkg.name.version {
2486
0
                Some(version) => version,
2487
0
                None => continue,
2488
            };
2489
2490
            // Test if the two semver versions are compatible
2491
0
            let module_compat = PackageName::version_compat_track(&module_version);
2492
0
            let pkg_compat = PackageName::version_compat_track(pkg_version);
2493
0
            if module_compat == pkg_compat {
2494
0
                return Ok((key.clone(), id));
2495
0
            }
2496
        }
2497
2498
0
        bail!("module requires an import interface named `{module}`")
2499
3.32k
    }
2500
3.22k
    fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2501
3.22k
        name.strip_prefix("cabi_post_")
2502
3.22k
    }
2503
9.33k
    fn match_wit_export<'a>(
2504
9.33k
        &self,
2505
9.33k
        export_name: &str,
2506
9.33k
        resolve: &'a Resolve,
2507
9.33k
        world: WorldId,
2508
9.33k
        exports: &'a IndexSet<WorldKey>,
2509
9.33k
    ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2510
9.33k
        let world = &resolve.worlds[world];
2511
33.6k
        for name in exports {
2512
33.6k
            match &world.exports[name] {
2513
2.05k
                WorldItem::Function(f) => {
2514
2.05k
                    if f.legacy_core_export_name(None) == export_name {
2515
546
                        return Some((name, None, f));
2516
1.51k
                    }
2517
                }
2518
31.5k
                WorldItem::Interface { id, .. } => {
2519
31.5k
                    let string = resolve.name_world_key(name);
2520
175k
                    for (_, func) in resolve.interfaces[*id].functions.iter() {
2521
175k
                        if func.legacy_core_export_name(Some(&string)) == export_name {
2522
5.56k
                            return Some((name, Some(*id), func));
2523
169k
                        }
2524
                    }
2525
                }
2526
2527
0
                WorldItem::Type { .. } => unreachable!(),
2528
            }
2529
        }
2530
2531
3.22k
        None
2532
9.33k
    }
2533
2534
212
    fn match_wit_resource_dtor<'a>(
2535
212
        &self,
2536
212
        export_name: &str,
2537
212
        resolve: &'a Resolve,
2538
212
        world: WorldId,
2539
212
        exports: &'a IndexSet<WorldKey>,
2540
212
    ) -> Option<TypeId> {
2541
212
        let world = &resolve.worlds[world];
2542
739
        for name in exports {
2543
739
            let id = match &world.exports[name] {
2544
715
                WorldItem::Interface { id, .. } => *id,
2545
24
                WorldItem::Function(_) => continue,
2546
0
                WorldItem::Type { .. } => unreachable!(),
2547
            };
2548
715
            let name = resolve.name_world_key(name);
2549
715
            let resource = match export_name
2550
715
                .strip_prefix(&name)
2551
715
                .and_then(|s| s.strip_prefix("#[dtor]"))
2552
715
                .and_then(|r| resolve.interfaces[id].types.get(r))
2553
            {
2554
212
                Some(id) => *id,
2555
503
                None => continue,
2556
            };
2557
2558
212
            match resolve.types[resource].kind {
2559
212
                TypeDefKind::Resource => {}
2560
0
                _ => continue,
2561
            }
2562
2563
212
            return Some(resource);
2564
        }
2565
2566
0
        None
2567
212
    }
2568
2569
956
    fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2570
956
        let (async_abi, name) = self.strip_async_lowered_prefix(name);
2571
        (
2572
956
            name,
2573
956
            if async_abi {
2574
62
                AbiVariant::GuestImportAsync
2575
            } else {
2576
894
                AbiVariant::GuestImport
2577
            },
2578
        )
2579
956
    }
2580
1.42k
    fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2581
1.42k
        let (async_abi, name) = self.strip_async_lowered_prefix(name);
2582
        (
2583
1.42k
            name,
2584
1.42k
            if async_abi {
2585
151
                AbiVariant::GuestImportAsync
2586
            } else {
2587
1.27k
                AbiVariant::GuestImport
2588
            },
2589
        )
2590
1.42k
    }
2591
}
2592
2593
/// This function validates the following:
2594
///
2595
/// * The `bytes` represent a valid core WebAssembly module.
2596
/// * The module's imports are all satisfied by the given `imports` interfaces
2597
///   or the `adapters` set.
2598
/// * The given default and exported interfaces are satisfied by the module's
2599
///   exports.
2600
///
2601
/// The `ValidatedModule` return value contains the metadata which describes the
2602
/// input module on success. This is then further used to generate a component
2603
/// for this module.
2604
3.26k
pub fn validate_module(
2605
3.26k
    encoder: &ComponentEncoder,
2606
3.26k
    bytes: &[u8],
2607
3.26k
    import_map: Option<&ModuleImportMap>,
2608
3.26k
) -> Result<ValidatedModule> {
2609
3.26k
    ValidatedModule::new(
2610
3.26k
        encoder,
2611
3.26k
        bytes,
2612
3.26k
        &encoder.main_module_exports,
2613
3.26k
        import_map,
2614
3.26k
        None,
2615
    )
2616
3.26k
}
2617
2618
/// This function will validate the `bytes` provided as a wasm adapter module.
2619
/// Notably this will validate the wasm module itself in addition to ensuring
2620
/// that it has the "shape" of an adapter module. Current constraints are:
2621
///
2622
/// * The adapter module can import only one memory
2623
/// * The adapter module can only import from the name of `interface` specified,
2624
///   and all function imports must match the `required` types which correspond
2625
///   to the lowered types of the functions in `interface`.
2626
///
2627
/// The wasm module passed into this function is the output of the GC pass of an
2628
/// adapter module's original source. This means that the adapter module is
2629
/// already minimized and this is a double-check that the minimization pass
2630
/// didn't accidentally break the wasm module.
2631
///
2632
/// If `is_library` is true, we waive some of the constraints described above,
2633
/// allowing the module to import tables and globals, as well as import
2634
/// functions at the world level, not just at the interface level.
2635
0
pub fn validate_adapter_module(
2636
0
    encoder: &ComponentEncoder,
2637
0
    bytes: &[u8],
2638
0
    required_by_import: &IndexMap<String, FuncType>,
2639
0
    exports: &IndexSet<WorldKey>,
2640
0
    library_info: Option<&LibraryInfo>,
2641
0
) -> Result<ValidatedModule> {
2642
0
    let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2643
2644
0
    for (name, required_ty) in required_by_import {
2645
0
        let actual = match ret.exports.raw_exports.get(name) {
2646
0
            Some(ty) => ty,
2647
0
            None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2648
        };
2649
0
        validate_func_sig(name, required_ty, &actual)?;
2650
    }
2651
2652
0
    Ok(ret)
2653
0
}
2654
2655
/// An error that can be returned from adapting a core Wasm module into a
2656
/// component using an adapter module.
2657
///
2658
/// If the core Wasm module contained an import that it requires to be
2659
/// satisfied by the adapter, and the adapter does not contain an export
2660
/// with the same name, an instance of this error is returned.
2661
#[derive(Debug, Clone)]
2662
pub struct AdapterModuleDidNotExport(String);
2663
2664
impl fmt::Display for AdapterModuleDidNotExport {
2665
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2666
0
        write!(f, "adapter module did not export `{}`", self.0)
2667
0
    }
2668
}
2669
2670
impl std::error::Error for AdapterModuleDidNotExport {}
2671
2672
755
fn resource_test_for_interface<'a>(
2673
755
    resolve: &'a Resolve,
2674
755
    id: InterfaceId,
2675
755
) -> impl Fn(&str) -> Option<TypeId> + 'a {
2676
755
    let interface = &resolve.interfaces[id];
2677
755
    move |name: &str| {
2678
755
        let ty = match interface.types.get(name) {
2679
755
            Some(ty) => *ty,
2680
0
            None => return None,
2681
        };
2682
755
        if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2683
755
            Some(ty)
2684
        } else {
2685
0
            None
2686
        }
2687
755
    }
2688
755
}
2689
2690
142
fn resource_test_for_world<'a>(
2691
142
    resolve: &'a Resolve,
2692
142
    id: WorldId,
2693
142
) -> impl Fn(&str) -> Option<TypeId> + 'a {
2694
142
    let world = &resolve.worlds[id];
2695
142
    move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2696
142
        WorldItem::Type { id, .. } => {
2697
142
            if matches!(resolve.types[*id].kind, TypeDefKind::Resource) {
2698
142
                Some(*id)
2699
            } else {
2700
0
                None
2701
            }
2702
        }
2703
0
        _ => None,
2704
142
    }
2705
142
}
2706
2707
6.16k
fn validate_func(
2708
6.16k
    resolve: &Resolve,
2709
6.16k
    ty: &wasmparser::FuncType,
2710
6.16k
    func: &Function,
2711
6.16k
    abi: AbiVariant,
2712
6.16k
) -> Result<()> {
2713
6.16k
    validate_func_sig(
2714
6.16k
        &func.name,
2715
6.16k
        &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2716
6.16k
        ty,
2717
    )
2718
6.16k
}
2719
2720
3.09k
fn validate_post_return(
2721
3.09k
    resolve: &Resolve,
2722
3.09k
    ty: &wasmparser::FuncType,
2723
3.09k
    func: &Function,
2724
3.09k
) -> Result<()> {
2725
    // The expected signature of a post-return function is to take all the
2726
    // parameters that are returned by the guest function and then return no
2727
    // results. Model this by calculating the signature of `func` and then
2728
    // moving its results into the parameters list while emptying out the
2729
    // results.
2730
3.09k
    let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2731
3.09k
    sig.params = mem::take(&mut sig.results);
2732
3.09k
    validate_func_sig(
2733
3.09k
        &format!("{} post-return", func.name),
2734
3.09k
        &wasm_sig_to_func_type(sig),
2735
3.09k
        ty,
2736
    )
2737
3.09k
}
2738
2739
25.0k
fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2740
25.0k
    if ty != expected {
2741
0
        bail!(
2742
            "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2743
            name,
2744
0
            expected.params(),
2745
0
            expected.results(),
2746
0
            ty.params(),
2747
0
            ty.results()
2748
        );
2749
25.0k
    }
2750
2751
25.0k
    Ok(())
2752
25.0k
}
2753
2754
/// Matches `name` as `[${prefix}S]...`, and if found returns `("S", "...")`
2755
7.53k
fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2756
7.53k
    assert!(prefix.starts_with("["));
2757
7.53k
    assert!(prefix.ends_with("-"));
2758
7.53k
    let suffix = name.strip_prefix(prefix)?;
2759
1.67k
    let index = suffix.find(']')?;
2760
1.67k
    let rest = &suffix[index + 1..];
2761
1.67k
    Some((&suffix[..index], rest))
2762
7.53k
}
2763
2764
/// Parses a `[context-get-<N>]` / `[context-set-<N>]` style name, optionally
2765
/// carrying a type width infix: `[context-get-i64-<N>]`.
2766
///
2767
/// Returns the value type together with the numeric slot. Additional type
2768
/// widths can be added here by extending the match below.
2769
4.52k
fn parse_context_name(name: &str, prefix: &str) -> Option<(ValType, u32)> {
2770
4.52k
    let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2771
1.04k
    if !rest.is_empty() {
2772
0
        return None;
2773
1.04k
    }
2774
1.04k
    let (ty, slot) = match suffix.split_once('-') {
2775
0
        Some(("i64", slot)) => (ValType::I64, slot),
2776
0
        Some(("i32", slot)) => (ValType::I32, slot),
2777
1.04k
        _ => (ValType::I32, suffix),
2778
    };
2779
1.04k
    let slot = slot.parse().ok()?;
2780
1.04k
    Some((ty, slot))
2781
4.52k
}
2782
2783
1.51k
fn get_function<'a>(
2784
1.51k
    resolve: &'a Resolve,
2785
1.51k
    world: &'a World,
2786
1.51k
    name: &str,
2787
1.51k
    interface: Option<InterfaceId>,
2788
1.51k
    imported: bool,
2789
1.51k
) -> Result<&'a Function> {
2790
1.51k
    let function = if let Some(id) = interface {
2791
1.38k
        return resolve.interfaces[id]
2792
1.38k
            .functions
2793
1.38k
            .get(name)
2794
1.38k
            .ok_or_else(|| anyhow!("no export `{name}` found"));
2795
128
    } else if imported {
2796
28
        world.imports.get(&WorldKey::Name(name.to_string()))
2797
    } else {
2798
100
        world.exports.get(&WorldKey::Name(name.to_string()))
2799
    };
2800
128
    let Some(WorldItem::Function(function)) = function else {
2801
0
        bail!("no export `{name}` found");
2802
    };
2803
128
    Ok(function)
2804
1.51k
}