wasmtime_environ/component/translate.rs
1use crate::Abi;
2use crate::component::dfg::AbstractInstantiations;
3use crate::component::*;
4use crate::prelude::*;
5use crate::{
6 DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, EngineOrModuleTypeIndex,
7 EntityIndex, FactInlineIntrinsic, FuncKey, KnownEntity, KnownGlobal, ModuleEnvironment,
8 ModuleInternedTypeIndex, ModuleTranslation, ModuleTypesBuilder, PrimaryMap, ScopeVec, TagIndex,
9 Tunables, TypeConvert, WasmHeapType, WasmResult, WasmValType,
10};
11use core::str::FromStr;
12use cranelift_entity::{EntityRef, SecondaryMap};
13use indexmap::IndexMap;
14use std::collections::{HashMap, HashSet};
15use std::mem;
16use wasmparser::component_types::{
17 AliasableResourceId, ComponentCoreModuleTypeId, ComponentDefinedTypeId, ComponentEntityType,
18 ComponentFuncTypeId, ComponentInstanceTypeId, ComponentValType,
19};
20use wasmparser::types::Types;
21use wasmparser::{Chunk, ComponentExternName, Encoding, Parser, Payload, Validator};
22
23mod adapt;
24pub use self::adapt::*;
25mod inline;
26
27/// Structure used to translate a component and parse it.
28pub struct Translator<'a, 'data> {
29 /// The current component being translated.
30 ///
31 /// This will get swapped out as translation traverses the body of a
32 /// component and a sub-component is entered or left.
33 result: Translation<'data>,
34
35 /// Current state of parsing a binary component. Note that like `result`
36 /// this will change as the component is traversed.
37 parser: Parser,
38
39 /// Stack of lexical scopes that are in-progress but not finished yet.
40 ///
41 /// This is pushed to whenever a component is entered and popped from
42 /// whenever a component is left. Each lexical scope also contains
43 /// information about the variables that it is currently required to close
44 /// over which is threaded into the current in-progress translation of
45 /// the sub-component which pushed a scope here.
46 lexical_scopes: Vec<LexicalScope<'data>>,
47
48 /// The validator in use to verify that the raw input binary is a valid
49 /// component.
50 validator: &'a mut Validator,
51
52 /// Type information shared for the entire component.
53 ///
54 /// This builder is also used for all core wasm modules found to intern
55 /// signatures across all modules.
56 types: PreInliningComponentTypes<'a>,
57
58 /// The compiler configuration provided by the embedder.
59 tunables: &'a Tunables,
60
61 /// Auxiliary location to push generated adapter modules onto.
62 scope_vec: &'data ScopeVec<u8>,
63
64 /// Completely translated core wasm modules that have been found so far.
65 ///
66 /// Note that this translation only involves learning about type
67 /// information and functions are not actually compiled here.
68 static_modules: PrimaryMap<StaticModuleIndex, ModuleTranslation<'data>>,
69
70 /// Completely translated components that have been found so far.
71 ///
72 /// As frames are popped from `lexical_scopes` their completed component
73 /// will be pushed onto this list.
74 static_components: PrimaryMap<StaticComponentIndex, Translation<'data>>,
75
76 /// The top-level import name for Wasmtime's unsafe intrinsics, if any.
77 unsafe_intrinsics_import: Option<&'a str>,
78}
79
80/// Representation of the syntactic scope of a component meaning where it is
81/// and what its state is at in the binary format.
82///
83/// These scopes are pushed and popped when a sub-component starts being
84/// parsed and finishes being parsed. The main purpose of this frame is to
85/// have a `ClosedOverVars` field which encapsulates data that is inherited
86/// from the scope specified into the component being translated just beneath
87/// it.
88///
89/// This structure exists to implement outer aliases to components and modules.
90/// When a component or module is closed over then that means it needs to be
91/// inherited in a sense to the component which actually had the alias. This is
92/// achieved with a deceptively simple scheme where each parent of the
93/// component with the alias will inherit the component from the desired
94/// location.
95///
96/// For example with a component structure that looks like:
97///
98/// ```wasm
99/// (component $A
100/// (core module $M)
101/// (component $B
102/// (component $C
103/// (alias outer $A $M (core module))
104/// )
105/// )
106/// )
107/// ```
108///
109/// here the `C` component is closing over `M` located in the root component
110/// `A`. When `C` is being translated the `lexical_scopes` field will look like
111/// `[A, B]`. When the alias is encountered (for module index 0) this will
112/// place a `ClosedOverModule::Local(0)` entry into the `closure_args` field of
113/// `A`'s frame. This will in turn give a `ModuleUpvarIndex` which is then
114/// inserted into `closure_args` in `B`'s frame. This produces yet another
115/// `ModuleUpvarIndex` which is finally inserted into `C`'s module index space
116/// via `LocalInitializer::AliasModuleUpvar` with the last index.
117///
118/// All of these upvar indices and such are interpreted in the "inline" phase
119/// of compilation and not at runtime. This means that when `A` is being
120/// instantiated one of its initializers will be
121/// `LocalInitializer::ComponentStatic`. This starts to create `B` and the
122/// variables captured for `B` are listed as local module 0, or `M`. This list
123/// is then preserved in the definition of the component `B` and later reused
124/// by `C` again to finally get access to the closed over component.
125///
126/// Effectively the scopes are managed hierarchically where a reference to an
127/// outer variable automatically injects references into all parents up to
128/// where the reference is. This variable scopes are the processed during
129/// inlining where a component definition is a reference to the static
130/// component information (`Translation`) plus closed over variables
131/// (`ComponentClosure` during inlining).
132struct LexicalScope<'data> {
133 /// Current state of translating the `translation` below.
134 parser: Parser,
135 /// Current state of the component's translation as found so far.
136 translation: Translation<'data>,
137 /// List of captures that `translation` will need to process to create the
138 /// sub-component which is directly beneath this lexical scope.
139 closure_args: ClosedOverVars,
140}
141
142/// A "local" translation of a component.
143///
144/// This structure is used as a sort of in-progress translation of a component.
145/// This is not `Component` which is the final form as consumed by Wasmtime
146/// at runtime. Instead this is a fairly simple representation of a component
147/// where almost everything is ordered as a list of initializers. The binary
148/// format is translated to a list of initializers here which is later processed
149/// during "inlining" to produce a final component with the final set of
150/// initializers.
151#[derive(Default)]
152struct Translation<'data> {
153 /// Instructions which form this component.
154 ///
155 /// There is one initializer for all members of each index space, and all
156 /// index spaces are incrementally built here as the initializer list is
157 /// processed.
158 initializers: Vec<LocalInitializer<'data>>,
159
160 /// The list of exports from this component, as pairs of names and an
161 /// index into an index space of what's being exported.
162 exports: IndexMap<&'data str, (ComponentItem, wasmparser::ComponentExternName<'data>)>,
163
164 /// Type information produced by `wasmparser` for this component.
165 ///
166 /// This type information is available after the translation of the entire
167 /// component has finished, e.g. for the `inline` pass, but beforehand this
168 /// is set to `None`.
169 types: Option<Types>,
170}
171
172// NB: the type information contained in `LocalInitializer` should always point
173// to `wasmparser`'s type information, not Wasmtime's. Component types cannot be
174// fully determined due to resources until instantiations are known which is
175// tracked during the inlining phase. This means that all type information below
176// is straight from `wasmparser`'s passes.
177enum LocalInitializer<'data> {
178 // imports
179 Import(ComponentExternName<'data>, ComponentEntityType),
180
181 // An import of an intrinsic for compile-time builtins.
182 IntrinsicsImport,
183
184 // canonical function sections
185 Lower {
186 func: ComponentFuncIndex,
187 lower_ty: ComponentFuncTypeId,
188 options: LocalCanonicalOptions,
189 },
190 Lift(ComponentFuncTypeId, FuncIndex, LocalCanonicalOptions),
191
192 // resources
193 Resource(AliasableResourceId, WasmValType, Option<FuncIndex>),
194 ResourceNew(AliasableResourceId, ModuleInternedTypeIndex),
195 ResourceRep(AliasableResourceId, ModuleInternedTypeIndex),
196 ResourceDrop(AliasableResourceId, ModuleInternedTypeIndex),
197
198 BackpressureInc {
199 func: ModuleInternedTypeIndex,
200 },
201 BackpressureDec {
202 func: ModuleInternedTypeIndex,
203 },
204 TaskReturn {
205 result: Option<ComponentValType>,
206 options: LocalCanonicalOptions,
207 },
208 TaskCancel {
209 func: ModuleInternedTypeIndex,
210 },
211 WaitableSetNew {
212 func: ModuleInternedTypeIndex,
213 },
214 WaitableSetWait {
215 options: LocalCanonicalOptions,
216 },
217 WaitableSetPoll {
218 options: LocalCanonicalOptions,
219 },
220 WaitableSetDrop {
221 func: ModuleInternedTypeIndex,
222 },
223 WaitableJoin {
224 func: ModuleInternedTypeIndex,
225 },
226 SubtaskDrop {
227 func: ModuleInternedTypeIndex,
228 },
229 SubtaskCancel {
230 func: ModuleInternedTypeIndex,
231 async_: bool,
232 },
233 StreamNew {
234 ty: ComponentDefinedTypeId,
235 func: ModuleInternedTypeIndex,
236 },
237 StreamRead {
238 ty: ComponentDefinedTypeId,
239 options: LocalCanonicalOptions,
240 },
241 StreamWrite {
242 ty: ComponentDefinedTypeId,
243 options: LocalCanonicalOptions,
244 },
245 StreamCancelRead {
246 ty: ComponentDefinedTypeId,
247 func: ModuleInternedTypeIndex,
248 async_: bool,
249 },
250 StreamCancelWrite {
251 ty: ComponentDefinedTypeId,
252 func: ModuleInternedTypeIndex,
253 async_: bool,
254 },
255 StreamDropReadable {
256 ty: ComponentDefinedTypeId,
257 func: ModuleInternedTypeIndex,
258 },
259 StreamDropWritable {
260 ty: ComponentDefinedTypeId,
261 func: ModuleInternedTypeIndex,
262 },
263 FutureNew {
264 ty: ComponentDefinedTypeId,
265 func: ModuleInternedTypeIndex,
266 },
267 FutureRead {
268 ty: ComponentDefinedTypeId,
269 options: LocalCanonicalOptions,
270 },
271 FutureWrite {
272 ty: ComponentDefinedTypeId,
273 options: LocalCanonicalOptions,
274 },
275 FutureCancelRead {
276 ty: ComponentDefinedTypeId,
277 func: ModuleInternedTypeIndex,
278 async_: bool,
279 },
280 FutureCancelWrite {
281 ty: ComponentDefinedTypeId,
282 func: ModuleInternedTypeIndex,
283 async_: bool,
284 },
285 FutureDropReadable {
286 ty: ComponentDefinedTypeId,
287 func: ModuleInternedTypeIndex,
288 },
289 FutureDropWritable {
290 ty: ComponentDefinedTypeId,
291 func: ModuleInternedTypeIndex,
292 },
293 ErrorContextNew {
294 options: LocalCanonicalOptions,
295 },
296 ErrorContextDebugMessage {
297 options: LocalCanonicalOptions,
298 },
299 ErrorContextDrop {
300 func: ModuleInternedTypeIndex,
301 },
302 ContextGet {
303 func: ModuleInternedTypeIndex,
304 i: u32,
305 },
306 ContextSet {
307 func: ModuleInternedTypeIndex,
308 i: u32,
309 },
310 ThreadIndex {
311 func: ModuleInternedTypeIndex,
312 },
313 ThreadNewIndirect {
314 func: ModuleInternedTypeIndex,
315 start_func_ty: ComponentTypeIndex,
316 start_func_table_index: TableIndex,
317 },
318 ThreadResumeLater {
319 func: ModuleInternedTypeIndex,
320 },
321 ThreadSuspend {
322 func: ModuleInternedTypeIndex,
323 cancellable: bool,
324 },
325 ThreadYield {
326 func: ModuleInternedTypeIndex,
327 cancellable: bool,
328 },
329 ThreadSuspendThenResume {
330 func: ModuleInternedTypeIndex,
331 cancellable: bool,
332 },
333 ThreadYieldThenResume {
334 func: ModuleInternedTypeIndex,
335 cancellable: bool,
336 },
337 ThreadSuspendThenPromote {
338 func: ModuleInternedTypeIndex,
339 cancellable: bool,
340 },
341 ThreadYieldThenPromote {
342 func: ModuleInternedTypeIndex,
343 cancellable: bool,
344 },
345
346 // core wasm modules
347 ModuleStatic(StaticModuleIndex, ComponentCoreModuleTypeId),
348
349 // core wasm module instances
350 ModuleInstantiate(ModuleIndex, HashMap<&'data str, ModuleInstanceIndex>),
351 ModuleSynthetic(HashMap<&'data str, EntityIndex>),
352
353 // components
354 ComponentStatic(StaticComponentIndex, ClosedOverVars),
355
356 // component instances
357 ComponentInstantiate(
358 ComponentIndex,
359 HashMap<&'data str, ComponentItem>,
360 ComponentInstanceTypeId,
361 ),
362 ComponentSynthetic(
363 HashMap<&'data str, (ComponentItem, wasmparser::ComponentExternName<'data>)>,
364 ComponentInstanceTypeId,
365 ),
366
367 // alias section
368 AliasExportFunc(ModuleInstanceIndex, &'data str),
369 AliasExportTable(ModuleInstanceIndex, &'data str),
370 AliasExportGlobal(ModuleInstanceIndex, &'data str),
371 AliasExportMemory(ModuleInstanceIndex, &'data str),
372 AliasExportTag(ModuleInstanceIndex, &'data str),
373 AliasComponentExport(ComponentInstanceIndex, &'data str),
374 AliasModule(ClosedOverModule),
375 AliasComponent(ClosedOverComponent),
376
377 // export section
378 Export(ComponentItem),
379}
380
381/// The "closure environment" of components themselves.
382///
383/// For more information see `LexicalScope`.
384#[derive(Default)]
385struct ClosedOverVars {
386 components: PrimaryMap<ComponentUpvarIndex, ClosedOverComponent>,
387 modules: PrimaryMap<ModuleUpvarIndex, ClosedOverModule>,
388}
389
390/// Description how a component is closed over when the closure variables for
391/// a component are being created.
392///
393/// For more information see `LexicalScope`.
394enum ClosedOverComponent {
395 /// A closed over component is coming from the local component's index
396 /// space, meaning a previously defined component is being captured.
397 Local(ComponentIndex),
398 /// A closed over component is coming from our own component's list of
399 /// upvars. This list was passed to us by our enclosing component, which
400 /// will eventually have bottomed out in closing over a `Local` component
401 /// index for some parent component.
402 Upvar(ComponentUpvarIndex),
403}
404
405/// Same as `ClosedOverComponent`, but for modules.
406enum ClosedOverModule {
407 Local(ModuleIndex),
408 Upvar(ModuleUpvarIndex),
409}
410
411/// The data model for objects that are not unboxed in locals.
412#[derive(Debug, Clone, Hash, Eq, PartialEq)]
413pub enum LocalDataModel {
414 /// Data is stored in GC objects.
415 Gc {},
416
417 /// Data is stored in a linear memory.
418 LinearMemory {
419 /// An optional memory definition supplied.
420 memory: Option<MemoryIndex>,
421 /// An optional definition of `realloc` to used.
422 realloc: Option<FuncIndex>,
423 },
424}
425
426/// Representation of canonical ABI options.
427struct LocalCanonicalOptions {
428 string_encoding: StringEncoding,
429 post_return: Option<FuncIndex>,
430 async_: bool,
431 cancellable: bool,
432 callback: Option<FuncIndex>,
433 /// The type index of the core GC types signature.
434 core_type: ModuleInternedTypeIndex,
435 data_model: LocalDataModel,
436}
437
438enum Action {
439 KeepGoing,
440 Skip(usize),
441 Done,
442}
443
444impl<'a, 'data> Translator<'a, 'data> {
445 /// Creates a new translation state ready to translate a component.
446 pub fn new(
447 tunables: &'a Tunables,
448 validator: &'a mut Validator,
449 types: &'a mut ComponentTypesBuilder,
450 scope_vec: &'data ScopeVec<u8>,
451 ) -> Self {
452 let mut parser = Parser::new(0);
453 parser.set_features(*validator.features());
454 Self {
455 result: Translation::default(),
456 tunables,
457 validator,
458 types: PreInliningComponentTypes::new(types),
459 parser,
460 lexical_scopes: Vec::new(),
461 static_components: Default::default(),
462 static_modules: Default::default(),
463 scope_vec,
464 unsafe_intrinsics_import: None,
465 }
466 }
467
468 /// Expose Wasmtime's unsafe intrinsics under the given top-level import
469 /// name.
470 pub fn expose_unsafe_intrinsics(&mut self, name: &'a str) -> &mut Self {
471 assert!(self.unsafe_intrinsics_import.is_none());
472 self.unsafe_intrinsics_import = Some(name);
473 self
474 }
475
476 /// Translates the binary `component`.
477 ///
478 /// This is the workhorse of compilation which will parse all of
479 /// `component` and create type information for Wasmtime and such. The
480 /// `component` does not have to be valid and it will be validated during
481 /// compilation.
482 ///
483 /// The result of this function is a tuple of the final component's
484 /// description plus a list of core wasm modules found within the
485 /// component. The component's description actually erases internal
486 /// components, instances, etc, as much as it can. Instead `Component`
487 /// retains a flat list of initializers (no nesting) which was created
488 /// as part of compilation from the nested structure of the original
489 /// component.
490 ///
491 /// The list of core wasm modules found is provided to allow compiling
492 /// modules externally in parallel. Additionally initializers in
493 /// `Component` may refer to the modules in the map returned by index.
494 ///
495 /// # Errors
496 ///
497 /// This function will return an error if the `component` provided is
498 /// invalid.
499 pub fn translate(
500 mut self,
501 component: &'data [u8],
502 ) -> Result<(
503 ComponentTranslation,
504 PrimaryMap<StaticModuleIndex, ModuleTranslation<'data>>,
505 )> {
506 // First up wasmparser is used to actually perform the translation and
507 // validation of this component. This will produce a list of core wasm
508 // modules in addition to components which are found during the
509 // translation process. When doing this only a `Translation` is created
510 // which is a simple representation of a component.
511 let mut remaining = component;
512 loop {
513 let payload = match self.parser.parse(remaining, true)? {
514 Chunk::Parsed { payload, consumed } => {
515 remaining = &remaining[consumed..];
516 payload
517 }
518 Chunk::NeedMoreData(_) => unreachable!(),
519 };
520
521 match self.translate_payload(payload, component)? {
522 Action::KeepGoing => {}
523 Action::Skip(n) => remaining = &remaining[n..],
524 Action::Done => break,
525 }
526 }
527 assert!(remaining.is_empty());
528 assert!(self.lexical_scopes.is_empty());
529
530 // ... after translation initially finishes the next pass is performed
531 // which we're calling "inlining". This will "instantiate" the root
532 // component, following nested component instantiations, creating a
533 // global list of initializers along the way. This phase uses the simple
534 // initializers in each component to track dataflow of host imports and
535 // internal references to items throughout a component at compile-time.
536 // The produce initializers in the final `Component` are intended to be
537 // much simpler than the original component and more efficient for
538 // Wasmtime to process at runtime as well (e.g. no string lookups as
539 // most everything is done through indices instead).
540 let mut component = inline::run(
541 self.types.types_mut_for_inlining(),
542 &self.result,
543 &self.static_modules,
544 &self.static_components,
545 )?;
546
547 self.partition_adapter_modules(&mut component);
548
549 let translation =
550 component.finish(self.types.types_mut_for_inlining(), self.result.types_ref())?;
551
552 self.analyze_imports(&translation);
553
554 Ok((translation, self.static_modules))
555 }
556
557 /// Record everything we statically know about each module's imports.
558 ///
559 /// See `ModuleTranslation::known_imported_functions` and
560 /// `ModuleTranslation::known_imported_globals` for how we can optimize
561 /// lowering based on this information.
562 fn analyze_imports(&mut self, translation: &ComponentTranslation) {
563 // First, abstract interpret the initializers to create a map from each
564 // static module to its abstract set of instantiations.
565 let mut instantiations = SecondaryMap::<StaticModuleIndex, AbstractInstantiations>::new();
566 let mut instances = StaticInstances::new();
567 for init in &translation.component.initializers {
568 match init {
569 GlobalInitializer::InstantiateModule(instantiation, _) => match instantiation {
570 InstantiateModule::Static(module, args) => {
571 instantiations[*module].join(AbstractInstantiations::One(&*args));
572 instances.push(Some((*module, &args[..])));
573 }
574 _ => {
575 instances.push(None);
576 }
577 },
578 _ => continue,
579 }
580 }
581
582 // Second, make sure to mark exported modules as instantiated many
583 // times, since they could be linked with who-knows-what at runtime.
584 for item in translation.component.export_items.values() {
585 if let Export::ModuleStatic { index, .. } = item {
586 instantiations[*index].join(AbstractInstantiations::Many)
587 }
588 }
589
590 // Third, find the globals, memories, and tables whose identity is not
591 // statically known to everything that can access them. Note that this
592 // is a property of the whole component and not of a single module's
593 // instantiations; see `ModuleTranslation::known_imported_globals` for
594 // details.
595 let ambiguous = ambiguous_entities(
596 &self.static_modules,
597 translation,
598 &instantiations,
599 &instances,
600 );
601
602 // Fourth, record which of each module's own defined entities all of
603 // their importers agree on, which lets those modules use a precise alias
604 // region for them even when they are exported.
605 for (module, translation) in self.static_modules.iter_mut() {
606 for i in 0..translation.module.num_defined_globals() {
607 let index = DefinedGlobalIndex::new(i);
608 let global = translation.module.global_index(index);
609 if !ambiguous
610 .entities
611 .contains(&(module, EntityIndex::Global(global)))
612 {
613 translation.globals_known_to_importers.insert(index);
614 }
615 }
616 for i in 0..translation.module.num_defined_memories() {
617 let index = DefinedMemoryIndex::new(i);
618 let memory = translation.module.memory_index(index);
619 if !ambiguous
620 .entities
621 .contains(&(module, EntityIndex::Memory(memory)))
622 {
623 translation.memories_known_to_importers.insert(index);
624 }
625 }
626 for i in 0..translation.module.num_defined_tables() {
627 let index = DefinedTableIndex::new(i);
628 let table = translation.module.table_index(index);
629 if !ambiguous
630 .entities
631 .contains(&(module, EntityIndex::Table(table)))
632 {
633 translation.tables_known_to_importers.insert(index);
634 }
635 }
636 }
637
638 // Finally, iterate over our instantiations and record statically-known
639 // imports: function imports so that they can get translated into direct
640 // calls (and eventually get inlined) rather than indirect calls through
641 // the imports table; and global, memory, and table imports so that they
642 // can get precise alias regions instead of the conservative regions
643 // shared by everything that crosses a module boundary.
644 for (module, instantiations) in instantiations.iter() {
645 let args = match instantiations {
646 dfg::AbstractInstantiations::Many | dfg::AbstractInstantiations::None => continue,
647 dfg::AbstractInstantiations::One(args) => args,
648 };
649
650 for (i, arg) in args.iter().enumerate() {
651 // Record that this global, memory, or table import is always the
652 // same defined entity, when we know that and when everything
653 // else that imports that entity knows it too.
654 macro_rules! record_known_entity {
655 ($variant:ident, $imported:expr, $defined_index:ident, $known:ident, $wrap:expr) => {{
656 let Some((arg_module, EntityIndex::$variant(arg_entity))) =
657 unambiguous_entity(
658 &self.static_modules,
659 &instances,
660 &ambiguous.entities,
661 arg,
662 )
663 else {
664 continue;
665 };
666 let index = self.static_modules[arg_module]
667 .module
668 .$defined_index(arg_entity)
669 .expect(
670 "`resolve_core_export` only returns entities that their module \
671 defines",
672 );
673 assert!(self.static_modules[module].$known[$imported].is_none());
674 self.static_modules[module].$known[$imported] = Some($wrap(KnownEntity {
675 module: arg_module,
676 index,
677 }));
678 }};
679 }
680
681 match self.static_modules[module].module.import_index(i).unwrap() {
682 EntityIndex::Function(imported_func) => {
683 debug_assert!(
684 self.static_modules[module]
685 .module
686 .defined_func_index(imported_func)
687 .is_none()
688 );
689
690 let known_func = match arg {
691 CoreDef::InstanceFlags(_) => {
692 unreachable!("instance flags are not a function")
693 }
694
695 // We could in theory inline these trampolines, so it
696 // could potentially make sense to record that we
697 // know this imported function is this particular
698 // trampoline. However, everything else is based
699 // around (module, defined-function) pairs and these
700 // trampolines don't fit that paradigm. Also,
701 // inlining trampolines gets really tricky when we
702 // consider the stack pointer, frame pointer, and
703 // return address note-taking that they do for the
704 // purposes of stack walking. We could, with enough
705 // effort, turn them into direct calls even though we
706 // probably wouldn't ever inline them, but it just
707 // doesn't seem worth the effort.
708 //
709 // That said, a couple of adapter trampolines are
710 // lowered inline during translation. We record these
711 // here so `FuncEnvironment` recognizes them. All
712 // other trampolines remain indirect calls.
713 CoreDef::Trampoline(index) => match translation.trampolines[*index] {
714 Trampoline::EnterSyncCall => {
715 FactInlineIntrinsic::EnterSyncCall.into()
716 }
717 Trampoline::ExitSyncCall => {
718 FactInlineIntrinsic::ExitSyncCall.into()
719 }
720 Trampoline::Trap(trap) => FactInlineIntrinsic::Trap(trap).into(),
721 _ => continue,
722 },
723
724 // This import is a compile-time builtin intrinsic,
725 // we should inline its implementation during
726 // function translation.
727 CoreDef::UnsafeIntrinsic(i) => {
728 FuncKey::UnsafeIntrinsic(Abi::Wasm, *i).into()
729 }
730
731 // This imported function is an export from another
732 // instance, a perfect candidate for becoming an
733 // inlinable direct call!
734 CoreDef::Export(export) => {
735 let Some((arg_module, arg_entity)) =
736 resolve_core_export(&self.static_modules, &instances, export)
737 else {
738 // Either an instance of a dynamic module that
739 // is not part of this component, or a
740 // re-export chain that bottoms out in
741 // something that isn't a defined function
742 // (for example a re-export of a trampoline;
743 // note that we only match trampolines and
744 // intrinsics as *direct* arguments above).
745 // Either way we have to do an indirect call.
746 continue;
747 };
748
749 let EntityIndex::Function(arg_func) = arg_entity else {
750 unreachable!("function imports must be functions")
751 };
752
753 let arg_module_def_func = self.static_modules[arg_module]
754 .module
755 .defined_func_index(arg_func)
756 .expect(
757 "`resolve_core_export` only returns entities that their \
758 module defines",
759 );
760
761 FuncKey::DefinedWasmFunction(arg_module, arg_module_def_func).into()
762 }
763 };
764
765 assert!(
766 self.static_modules[module].known_imported_functions[imported_func]
767 .is_none()
768 );
769 self.static_modules[module].known_imported_functions[imported_func] =
770 Some(known_func);
771 }
772
773 // Note that a global import is not necessarily satisfied by a
774 // wasm global: it can also be one of the component-model
775 // flags that live in the `VMComponentContext`, and those get
776 // their own alias regions rather than a defined-global one.
777 EntityIndex::Global(imported_global) => match component_flags(arg) {
778 Some(flags) => {
779 if ambiguous.flags.contains(&flags) {
780 continue;
781 }
782 assert!(
783 self.static_modules[module].known_imported_globals[imported_global]
784 .is_none()
785 );
786 self.static_modules[module].known_imported_globals[imported_global] =
787 Some(flags);
788 }
789 None => record_known_entity!(
790 Global,
791 imported_global,
792 defined_global_index,
793 known_imported_globals,
794 KnownGlobal::Defined
795 ),
796 },
797
798 EntityIndex::Memory(imported_memory) => record_known_entity!(
799 Memory,
800 imported_memory,
801 defined_memory_index,
802 known_imported_memories,
803 core::convert::identity
804 ),
805
806 EntityIndex::Table(imported_table) => record_known_entity!(
807 Table,
808 imported_table,
809 defined_table_index,
810 known_imported_tables,
811 core::convert::identity
812 ),
813
814 // Tags don't have alias regions of their own.
815 EntityIndex::Tag(_) => {}
816 }
817 }
818 }
819 }
820
821 fn translate_payload(
822 &mut self,
823 payload: Payload<'data>,
824 component: &'data [u8],
825 ) -> Result<Action> {
826 match payload {
827 Payload::Version {
828 num,
829 encoding,
830 range,
831 } => {
832 self.validator.version(num, encoding, &range)?;
833
834 match encoding {
835 Encoding::Component => {}
836 Encoding::Module => {
837 bail!("attempted to parse a wasm module with a component parser");
838 }
839 }
840 }
841
842 Payload::End(offset) => {
843 assert!(self.result.types.is_none());
844 self.result.types = Some(self.validator.end(offset)?);
845
846 // Exit the current lexical scope. If there is no parent (no
847 // frame currently on the stack) then translation is finished.
848 // Otherwise that means that a nested component has been
849 // completed and is recorded as such.
850 let LexicalScope {
851 parser,
852 translation,
853 closure_args,
854 } = match self.lexical_scopes.pop() {
855 Some(frame) => frame,
856 None => return Ok(Action::Done),
857 };
858 self.parser = parser;
859 let component = mem::replace(&mut self.result, translation);
860 let static_idx = self.static_components.push(component);
861 self.result
862 .initializers
863 .push(LocalInitializer::ComponentStatic(static_idx, closure_args));
864 }
865
866 // When we see a type section the types are validated and then
867 // translated into Wasmtime's representation. Each active type
868 // definition is recorded in the `ComponentTypesBuilder` tables, or
869 // this component's active scope.
870 //
871 // Note that the push/pop of the component types scope happens above
872 // in `Version` and `End` since multiple type sections can appear
873 // within a component.
874 Payload::ComponentTypeSection(s) => {
875 let mut component_type_index =
876 self.validator.types(0).unwrap().component_type_count();
877 self.validator.component_type_section(&s)?;
878
879 // Look for resource types and if a local resource is defined
880 // then an initializer is added to define that resource type and
881 // reference its destructor.
882 let types = self.validator.types(0).unwrap();
883 for ty in s {
884 match ty? {
885 wasmparser::ComponentType::Resource { rep, dtor } => {
886 let rep = self.types.convert_valtype(rep)?;
887 let id = types
888 .component_any_type_at(component_type_index)
889 .unwrap_resource();
890 let dtor = dtor.map(FuncIndex::from_u32);
891 self.result
892 .initializers
893 .push(LocalInitializer::Resource(id, rep, dtor));
894 }
895
896 // no extra processing needed
897 wasmparser::ComponentType::Defined(_)
898 | wasmparser::ComponentType::Func(_)
899 | wasmparser::ComponentType::Instance(_)
900 | wasmparser::ComponentType::Component(_) => {}
901 }
902
903 component_type_index += 1;
904 }
905 }
906 Payload::CoreTypeSection(s) => {
907 self.validator.core_type_section(&s)?;
908 }
909
910 // Processing the import section at this point is relatively simple
911 // which is to simply record the name of the import and the type
912 // information associated with it.
913 Payload::ComponentImportSection(s) => {
914 self.validator.component_import_section(&s)?;
915 for import in s {
916 let import = import?;
917 let types = self.validator.types(0).unwrap();
918 let ty = types
919 .component_item_for_import(import.name.name)
920 .unwrap()
921 .ty;
922
923 if self.is_unsafe_intrinsics_import(import.name.name) {
924 self.check_unsafe_intrinsics_import(import.name.name, ty)?;
925 self.result
926 .initializers
927 .push(LocalInitializer::IntrinsicsImport);
928 } else {
929 self.result
930 .initializers
931 .push(LocalInitializer::Import(import.name, ty));
932 }
933 }
934 }
935
936 // Entries in the canonical section will get initializers recorded
937 // with the listed options for lifting/lowering.
938 Payload::ComponentCanonicalSection(s) => {
939 let types = self.validator.types(0).unwrap();
940 let mut core_func_index = types.function_count();
941 self.validator.component_canonical_section(&s)?;
942 for func in s {
943 let init = match func? {
944 wasmparser::CanonicalFunction::Lift {
945 type_index,
946 core_func_index,
947 options,
948 } => {
949 let ty = self
950 .validator
951 .types(0)
952 .unwrap()
953 .component_any_type_at(type_index)
954 .unwrap_func();
955
956 let func = FuncIndex::from_u32(core_func_index);
957 let options = self.canonical_options(&options, core_func_index)?;
958 LocalInitializer::Lift(ty, func, options)
959 }
960 wasmparser::CanonicalFunction::Lower {
961 func_index,
962 options,
963 } => {
964 let lower_ty = self
965 .validator
966 .types(0)
967 .unwrap()
968 .component_function_at(func_index);
969 let func = ComponentFuncIndex::from_u32(func_index);
970 let options = self.canonical_options(&options, core_func_index)?;
971 core_func_index += 1;
972 LocalInitializer::Lower {
973 func,
974 options,
975 lower_ty,
976 }
977 }
978 wasmparser::CanonicalFunction::ResourceNew { resource } => {
979 let resource = self
980 .validator
981 .types(0)
982 .unwrap()
983 .component_any_type_at(resource)
984 .unwrap_resource();
985 let ty = self.core_func_signature(core_func_index)?;
986 core_func_index += 1;
987 LocalInitializer::ResourceNew(resource, ty)
988 }
989 wasmparser::CanonicalFunction::ResourceDrop { resource } => {
990 let resource = self
991 .validator
992 .types(0)
993 .unwrap()
994 .component_any_type_at(resource)
995 .unwrap_resource();
996 let ty = self.core_func_signature(core_func_index)?;
997 core_func_index += 1;
998 LocalInitializer::ResourceDrop(resource, ty)
999 }
1000 wasmparser::CanonicalFunction::ResourceRep { resource } => {
1001 let resource = self
1002 .validator
1003 .types(0)
1004 .unwrap()
1005 .component_any_type_at(resource)
1006 .unwrap_resource();
1007 let ty = self.core_func_signature(core_func_index)?;
1008 core_func_index += 1;
1009 LocalInitializer::ResourceRep(resource, ty)
1010 }
1011 wasmparser::CanonicalFunction::ThreadSpawnRef { .. }
1012 | wasmparser::CanonicalFunction::ThreadSpawnIndirect { .. }
1013 | wasmparser::CanonicalFunction::ThreadAvailableParallelism => {
1014 bail!("unsupported intrinsic")
1015 }
1016 wasmparser::CanonicalFunction::BackpressureInc => {
1017 let core_type = self.core_func_signature(core_func_index)?;
1018 core_func_index += 1;
1019 LocalInitializer::BackpressureInc { func: core_type }
1020 }
1021 wasmparser::CanonicalFunction::BackpressureDec => {
1022 let core_type = self.core_func_signature(core_func_index)?;
1023 core_func_index += 1;
1024 LocalInitializer::BackpressureDec { func: core_type }
1025 }
1026
1027 wasmparser::CanonicalFunction::TaskReturn { result, options } => {
1028 let result = result.map(|ty| match ty {
1029 wasmparser::ComponentValType::Primitive(ty) => {
1030 ComponentValType::Primitive(ty)
1031 }
1032 wasmparser::ComponentValType::Type(ty) => ComponentValType::Type(
1033 self.validator
1034 .types(0)
1035 .unwrap()
1036 .component_defined_type_at(ty),
1037 ),
1038 });
1039 let options = self.canonical_options(&options, core_func_index)?;
1040 core_func_index += 1;
1041 LocalInitializer::TaskReturn { result, options }
1042 }
1043 wasmparser::CanonicalFunction::TaskCancel => {
1044 let func = self.core_func_signature(core_func_index)?;
1045 core_func_index += 1;
1046 LocalInitializer::TaskCancel { func }
1047 }
1048 wasmparser::CanonicalFunction::WaitableSetNew => {
1049 let func = self.core_func_signature(core_func_index)?;
1050 core_func_index += 1;
1051 LocalInitializer::WaitableSetNew { func }
1052 }
1053 wasmparser::CanonicalFunction::WaitableSetWait {
1054 cancellable,
1055 memory,
1056 } => {
1057 let core_type = self.core_func_signature(core_func_index)?;
1058 core_func_index += 1;
1059 LocalInitializer::WaitableSetWait {
1060 options: LocalCanonicalOptions {
1061 core_type,
1062 cancellable,
1063 async_: false,
1064 data_model: LocalDataModel::LinearMemory {
1065 memory: Some(MemoryIndex::from_u32(memory)),
1066 realloc: None,
1067 },
1068 post_return: None,
1069 callback: None,
1070 string_encoding: StringEncoding::Utf8,
1071 },
1072 }
1073 }
1074 wasmparser::CanonicalFunction::WaitableSetPoll {
1075 cancellable,
1076 memory,
1077 } => {
1078 let core_type = self.core_func_signature(core_func_index)?;
1079 core_func_index += 1;
1080 LocalInitializer::WaitableSetPoll {
1081 options: LocalCanonicalOptions {
1082 core_type,
1083 async_: false,
1084 cancellable,
1085 data_model: LocalDataModel::LinearMemory {
1086 memory: Some(MemoryIndex::from_u32(memory)),
1087 realloc: None,
1088 },
1089 post_return: None,
1090 callback: None,
1091 string_encoding: StringEncoding::Utf8,
1092 },
1093 }
1094 }
1095 wasmparser::CanonicalFunction::WaitableSetDrop => {
1096 let func = self.core_func_signature(core_func_index)?;
1097 core_func_index += 1;
1098 LocalInitializer::WaitableSetDrop { func }
1099 }
1100 wasmparser::CanonicalFunction::WaitableJoin => {
1101 let func = self.core_func_signature(core_func_index)?;
1102 core_func_index += 1;
1103 LocalInitializer::WaitableJoin { func }
1104 }
1105 wasmparser::CanonicalFunction::SubtaskDrop => {
1106 let func = self.core_func_signature(core_func_index)?;
1107 core_func_index += 1;
1108 LocalInitializer::SubtaskDrop { func }
1109 }
1110 wasmparser::CanonicalFunction::SubtaskCancel { async_ } => {
1111 let func = self.core_func_signature(core_func_index)?;
1112 core_func_index += 1;
1113 LocalInitializer::SubtaskCancel { func, async_ }
1114 }
1115 wasmparser::CanonicalFunction::StreamNew { ty } => {
1116 let ty = self
1117 .validator
1118 .types(0)
1119 .unwrap()
1120 .component_defined_type_at(ty);
1121 let func = self.core_func_signature(core_func_index)?;
1122 core_func_index += 1;
1123 LocalInitializer::StreamNew { ty, func }
1124 }
1125 wasmparser::CanonicalFunction::StreamRead { ty, options } => {
1126 let ty = self
1127 .validator
1128 .types(0)
1129 .unwrap()
1130 .component_defined_type_at(ty);
1131 let options = self.canonical_options(&options, core_func_index)?;
1132 core_func_index += 1;
1133 LocalInitializer::StreamRead { ty, options }
1134 }
1135 wasmparser::CanonicalFunction::StreamWrite { ty, options } => {
1136 let ty = self
1137 .validator
1138 .types(0)
1139 .unwrap()
1140 .component_defined_type_at(ty);
1141 let options = self.canonical_options(&options, core_func_index)?;
1142 core_func_index += 1;
1143 LocalInitializer::StreamWrite { ty, options }
1144 }
1145 wasmparser::CanonicalFunction::StreamCancelRead { ty, async_ } => {
1146 let ty = self
1147 .validator
1148 .types(0)
1149 .unwrap()
1150 .component_defined_type_at(ty);
1151 let func = self.core_func_signature(core_func_index)?;
1152 core_func_index += 1;
1153 LocalInitializer::StreamCancelRead { ty, func, async_ }
1154 }
1155 wasmparser::CanonicalFunction::StreamCancelWrite { ty, async_ } => {
1156 let ty = self
1157 .validator
1158 .types(0)
1159 .unwrap()
1160 .component_defined_type_at(ty);
1161 let func = self.core_func_signature(core_func_index)?;
1162 core_func_index += 1;
1163 LocalInitializer::StreamCancelWrite { ty, func, async_ }
1164 }
1165 wasmparser::CanonicalFunction::StreamDropReadable { ty } => {
1166 let ty = self
1167 .validator
1168 .types(0)
1169 .unwrap()
1170 .component_defined_type_at(ty);
1171 let func = self.core_func_signature(core_func_index)?;
1172 core_func_index += 1;
1173 LocalInitializer::StreamDropReadable { ty, func }
1174 }
1175 wasmparser::CanonicalFunction::StreamDropWritable { ty } => {
1176 let ty = self
1177 .validator
1178 .types(0)
1179 .unwrap()
1180 .component_defined_type_at(ty);
1181 let func = self.core_func_signature(core_func_index)?;
1182 core_func_index += 1;
1183 LocalInitializer::StreamDropWritable { ty, func }
1184 }
1185 wasmparser::CanonicalFunction::FutureNew { ty } => {
1186 let ty = self
1187 .validator
1188 .types(0)
1189 .unwrap()
1190 .component_defined_type_at(ty);
1191 let func = self.core_func_signature(core_func_index)?;
1192 core_func_index += 1;
1193 LocalInitializer::FutureNew { ty, func }
1194 }
1195 wasmparser::CanonicalFunction::FutureRead { ty, options } => {
1196 let ty = self
1197 .validator
1198 .types(0)
1199 .unwrap()
1200 .component_defined_type_at(ty);
1201 let options = self.canonical_options(&options, core_func_index)?;
1202 core_func_index += 1;
1203 LocalInitializer::FutureRead { ty, options }
1204 }
1205 wasmparser::CanonicalFunction::FutureWrite { ty, options } => {
1206 let ty = self
1207 .validator
1208 .types(0)
1209 .unwrap()
1210 .component_defined_type_at(ty);
1211 let options = self.canonical_options(&options, core_func_index)?;
1212 core_func_index += 1;
1213 LocalInitializer::FutureWrite { ty, options }
1214 }
1215 wasmparser::CanonicalFunction::FutureCancelRead { ty, async_ } => {
1216 let ty = self
1217 .validator
1218 .types(0)
1219 .unwrap()
1220 .component_defined_type_at(ty);
1221 let func = self.core_func_signature(core_func_index)?;
1222 core_func_index += 1;
1223 LocalInitializer::FutureCancelRead { ty, func, async_ }
1224 }
1225 wasmparser::CanonicalFunction::FutureCancelWrite { ty, async_ } => {
1226 let ty = self
1227 .validator
1228 .types(0)
1229 .unwrap()
1230 .component_defined_type_at(ty);
1231 let func = self.core_func_signature(core_func_index)?;
1232 core_func_index += 1;
1233 LocalInitializer::FutureCancelWrite { ty, func, async_ }
1234 }
1235 wasmparser::CanonicalFunction::FutureDropReadable { ty } => {
1236 let ty = self
1237 .validator
1238 .types(0)
1239 .unwrap()
1240 .component_defined_type_at(ty);
1241 let func = self.core_func_signature(core_func_index)?;
1242 core_func_index += 1;
1243 LocalInitializer::FutureDropReadable { ty, func }
1244 }
1245 wasmparser::CanonicalFunction::FutureDropWritable { ty } => {
1246 let ty = self
1247 .validator
1248 .types(0)
1249 .unwrap()
1250 .component_defined_type_at(ty);
1251 let func = self.core_func_signature(core_func_index)?;
1252 core_func_index += 1;
1253 LocalInitializer::FutureDropWritable { ty, func }
1254 }
1255 wasmparser::CanonicalFunction::ErrorContextNew { options } => {
1256 let options = self.canonical_options(&options, core_func_index)?;
1257 core_func_index += 1;
1258 LocalInitializer::ErrorContextNew { options }
1259 }
1260 wasmparser::CanonicalFunction::ErrorContextDebugMessage { options } => {
1261 let options = self.canonical_options(&options, core_func_index)?;
1262 core_func_index += 1;
1263 LocalInitializer::ErrorContextDebugMessage { options }
1264 }
1265 wasmparser::CanonicalFunction::ErrorContextDrop => {
1266 let func = self.core_func_signature(core_func_index)?;
1267 core_func_index += 1;
1268 LocalInitializer::ErrorContextDrop { func }
1269 }
1270 wasmparser::CanonicalFunction::ContextGet { slot, ty } => {
1271 if ty != wasmparser::ValType::I32 {
1272 bail!("unsupported context.get type: {ty:?}");
1273 }
1274 let func = self.core_func_signature(core_func_index)?;
1275 core_func_index += 1;
1276 LocalInitializer::ContextGet { i: slot, func }
1277 }
1278 wasmparser::CanonicalFunction::ContextSet { slot, ty } => {
1279 if ty != wasmparser::ValType::I32 {
1280 bail!("unsupported context.set type: {ty:?}");
1281 }
1282 let func = self.core_func_signature(core_func_index)?;
1283 core_func_index += 1;
1284 LocalInitializer::ContextSet { i: slot, func }
1285 }
1286 wasmparser::CanonicalFunction::ThreadIndex => {
1287 let func = self.core_func_signature(core_func_index)?;
1288 core_func_index += 1;
1289 LocalInitializer::ThreadIndex { func }
1290 }
1291 wasmparser::CanonicalFunction::ThreadNewIndirect {
1292 func_ty_index,
1293 table_index,
1294 } => {
1295 let func = self.core_func_signature(core_func_index)?;
1296 core_func_index += 1;
1297 LocalInitializer::ThreadNewIndirect {
1298 func,
1299 start_func_ty: ComponentTypeIndex::from_u32(func_ty_index),
1300 start_func_table_index: TableIndex::from_u32(table_index),
1301 }
1302 }
1303 wasmparser::CanonicalFunction::ThreadResumeLater => {
1304 let func = self.core_func_signature(core_func_index)?;
1305 core_func_index += 1;
1306 LocalInitializer::ThreadResumeLater { func }
1307 }
1308 wasmparser::CanonicalFunction::ThreadSuspend { cancellable } => {
1309 let func = self.core_func_signature(core_func_index)?;
1310 core_func_index += 1;
1311 LocalInitializer::ThreadSuspend { func, cancellable }
1312 }
1313 wasmparser::CanonicalFunction::ThreadYield { cancellable } => {
1314 let func = self.core_func_signature(core_func_index)?;
1315 core_func_index += 1;
1316 LocalInitializer::ThreadYield { func, cancellable }
1317 }
1318 wasmparser::CanonicalFunction::ThreadSuspendThenResume { cancellable } => {
1319 let func = self.core_func_signature(core_func_index)?;
1320 core_func_index += 1;
1321 LocalInitializer::ThreadSuspendThenResume { func, cancellable }
1322 }
1323 wasmparser::CanonicalFunction::ThreadYieldThenResume { cancellable } => {
1324 let func = self.core_func_signature(core_func_index)?;
1325 core_func_index += 1;
1326 LocalInitializer::ThreadYieldThenResume { func, cancellable }
1327 }
1328 wasmparser::CanonicalFunction::ThreadSuspendThenPromote { cancellable } => {
1329 let func = self.core_func_signature(core_func_index)?;
1330 core_func_index += 1;
1331 LocalInitializer::ThreadSuspendThenPromote { func, cancellable }
1332 }
1333 wasmparser::CanonicalFunction::ThreadYieldThenPromote { cancellable } => {
1334 let func = self.core_func_signature(core_func_index)?;
1335 core_func_index += 1;
1336 LocalInitializer::ThreadYieldThenPromote { func, cancellable }
1337 }
1338 };
1339 self.result.initializers.push(init);
1340 }
1341 }
1342
1343 // Core wasm modules are translated inline directly here with the
1344 // `ModuleEnvironment` from core wasm compilation. This will return
1345 // to the caller the size of the module so it knows how many bytes
1346 // of the input are skipped.
1347 //
1348 // Note that this is just initial type translation of the core wasm
1349 // module and actual function compilation is deferred until this
1350 // entire process has completed.
1351 Payload::ModuleSection {
1352 parser,
1353 unchecked_range,
1354 } => {
1355 let index = self.validator.types(0).unwrap().module_count();
1356 self.validator.module_section(&unchecked_range)?;
1357 let static_module_index = self.static_modules.next_key();
1358 let mut translation = ModuleEnvironment::new(
1359 self.tunables,
1360 self.validator,
1361 self.types.module_types_builder(),
1362 static_module_index,
1363 )
1364 .translate(
1365 parser,
1366 component
1367 .get(unchecked_range.start as usize..unchecked_range.end as usize)
1368 .ok_or_else(|| {
1369 format_err!(
1370 "section range {}..{} is out of bounds (bound = {})",
1371 unchecked_range.start,
1372 unchecked_range.end,
1373 component.len()
1374 )
1375 .context("wasm component contains an invalid module section")
1376 })?,
1377 )?;
1378
1379 translation.wasm_module_offset = unchecked_range.start;
1380 let static_module_index2 = self.static_modules.push(translation);
1381 assert_eq!(static_module_index, static_module_index2);
1382 let types = self.validator.types(0).unwrap();
1383 let ty = types.module_at(index);
1384 self.result
1385 .initializers
1386 .push(LocalInitializer::ModuleStatic(static_module_index, ty));
1387 return Ok(Action::Skip(
1388 (unchecked_range.end - unchecked_range.start) as usize,
1389 ));
1390 }
1391
1392 // When a sub-component is found then the current translation state
1393 // is pushed onto the `lexical_scopes` stack. This will subsequently
1394 // get popped as part of `Payload::End` processing above.
1395 //
1396 // Note that the set of closure args for this new lexical scope
1397 // starts empty since it will only get populated if translation of
1398 // the nested component ends up aliasing some outer module or
1399 // component.
1400 Payload::ComponentSection {
1401 parser,
1402 unchecked_range,
1403 } => {
1404 self.validator.component_section(&unchecked_range)?;
1405 self.lexical_scopes.push(LexicalScope {
1406 parser: mem::replace(&mut self.parser, parser),
1407 translation: mem::take(&mut self.result),
1408 closure_args: ClosedOverVars::default(),
1409 });
1410 }
1411
1412 // Both core wasm instances and component instances record
1413 // initializers of what form of instantiation is performed which
1414 // largely just records the arguments given from wasmparser into a
1415 // `HashMap` for processing later during inlining.
1416 Payload::InstanceSection(s) => {
1417 self.validator.instance_section(&s)?;
1418 for instance in s {
1419 let init = match instance? {
1420 wasmparser::Instance::Instantiate { module_index, args } => {
1421 let index = ModuleIndex::from_u32(module_index);
1422 self.instantiate_module(index, &args)
1423 }
1424 wasmparser::Instance::FromExports(exports) => {
1425 self.instantiate_module_from_exports(&exports)
1426 }
1427 };
1428 self.result.initializers.push(init);
1429 }
1430 }
1431 Payload::ComponentInstanceSection(s) => {
1432 let mut index = self.validator.types(0).unwrap().component_instance_count();
1433 self.validator.component_instance_section(&s)?;
1434 for instance in s {
1435 let types = self.validator.types(0).unwrap();
1436 let ty = types.component_instance_at(index);
1437 let init = match instance? {
1438 wasmparser::ComponentInstance::Instantiate {
1439 component_index,
1440 args,
1441 } => {
1442 let index = ComponentIndex::from_u32(component_index);
1443 self.instantiate_component(index, &args, ty)?
1444 }
1445 wasmparser::ComponentInstance::FromExports(exports) => {
1446 self.instantiate_component_from_exports(&exports, ty)?
1447 }
1448 };
1449 self.result.initializers.push(init);
1450 index += 1;
1451 }
1452 }
1453
1454 // Exports don't actually fill out the `initializers` array but
1455 // instead fill out the one other field in a `Translation`, the
1456 // `exports` field (as one might imagine). This for now simply
1457 // records the index of what's exported and that's tracked further
1458 // later during inlining.
1459 Payload::ComponentExportSection(s) => {
1460 self.validator.component_export_section(&s)?;
1461 for export in s {
1462 let export = export?;
1463 let item = self.kind_to_item(export.kind, export.index)?;
1464 let prev = self
1465 .result
1466 .exports
1467 .insert(export.name.name, (item, export.name));
1468 assert!(prev.is_none());
1469 self.result
1470 .initializers
1471 .push(LocalInitializer::Export(item));
1472 }
1473 }
1474
1475 Payload::ComponentStartSection { start, range } => {
1476 self.validator.component_start_section(&start, &range)?;
1477 unimplemented!("component start section");
1478 }
1479
1480 // Aliases of instance exports (either core or component) will be
1481 // recorded as an initializer of the appropriate type with outer
1482 // aliases handled specially via upvars and type processing.
1483 Payload::ComponentAliasSection(s) => {
1484 self.validator.component_alias_section(&s)?;
1485 for alias in s {
1486 let init = match alias? {
1487 wasmparser::ComponentAlias::InstanceExport {
1488 kind: _,
1489 instance_index,
1490 name,
1491 } => {
1492 let instance = ComponentInstanceIndex::from_u32(instance_index);
1493 LocalInitializer::AliasComponentExport(instance, name)
1494 }
1495 wasmparser::ComponentAlias::Outer { kind, count, index } => {
1496 self.alias_component_outer(kind, count, index);
1497 continue;
1498 }
1499 wasmparser::ComponentAlias::CoreInstanceExport {
1500 kind,
1501 instance_index,
1502 name,
1503 } => {
1504 let instance = ModuleInstanceIndex::from_u32(instance_index);
1505 self.alias_module_instance_export(kind, instance, name)
1506 }
1507 };
1508 self.result.initializers.push(init);
1509 }
1510 }
1511
1512 // All custom sections are ignored by Wasmtime at this time.
1513 //
1514 // FIXME(WebAssembly/component-model#14): probably want to specify
1515 // and parse a `name` section here.
1516 Payload::CustomSection { .. } => {}
1517
1518 // Anything else is either not reachable since we never enable the
1519 // feature in Wasmtime or we do enable it and it's a bug we don't
1520 // implement it, so let validation take care of most errors here and
1521 // if it gets past validation provide a helpful error message to
1522 // debug.
1523 other => {
1524 self.validator.payload(&other)?;
1525 panic!("unimplemented section {other:?}");
1526 }
1527 }
1528
1529 Ok(Action::KeepGoing)
1530 }
1531
1532 fn instantiate_module(
1533 &mut self,
1534 module: ModuleIndex,
1535 raw_args: &[wasmparser::InstantiationArg<'data>],
1536 ) -> LocalInitializer<'data> {
1537 let mut args = HashMap::with_capacity(raw_args.len());
1538 for arg in raw_args {
1539 match arg.kind {
1540 wasmparser::InstantiationArgKind::Instance => {
1541 let idx = ModuleInstanceIndex::from_u32(arg.index);
1542 args.insert(arg.name, idx);
1543 }
1544 }
1545 }
1546 LocalInitializer::ModuleInstantiate(module, args)
1547 }
1548
1549 /// Creates a synthetic module from the list of items currently in the
1550 /// module and their given names.
1551 fn instantiate_module_from_exports(
1552 &mut self,
1553 exports: &[wasmparser::Export<'data>],
1554 ) -> LocalInitializer<'data> {
1555 let mut map = HashMap::with_capacity(exports.len());
1556 for export in exports {
1557 let idx = match export.kind {
1558 wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => {
1559 let index = FuncIndex::from_u32(export.index);
1560 EntityIndex::Function(index)
1561 }
1562 wasmparser::ExternalKind::Table => {
1563 let index = TableIndex::from_u32(export.index);
1564 EntityIndex::Table(index)
1565 }
1566 wasmparser::ExternalKind::Memory => {
1567 let index = MemoryIndex::from_u32(export.index);
1568 EntityIndex::Memory(index)
1569 }
1570 wasmparser::ExternalKind::Global => {
1571 let index = GlobalIndex::from_u32(export.index);
1572 EntityIndex::Global(index)
1573 }
1574 wasmparser::ExternalKind::Tag => {
1575 let index = TagIndex::from_u32(export.index);
1576 EntityIndex::Tag(index)
1577 }
1578 };
1579 map.insert(export.name, idx);
1580 }
1581 LocalInitializer::ModuleSynthetic(map)
1582 }
1583
1584 fn instantiate_component(
1585 &mut self,
1586 component: ComponentIndex,
1587 raw_args: &[wasmparser::ComponentInstantiationArg<'data>],
1588 ty: ComponentInstanceTypeId,
1589 ) -> Result<LocalInitializer<'data>> {
1590 let mut args = HashMap::with_capacity(raw_args.len());
1591 for arg in raw_args {
1592 let idx = self.kind_to_item(arg.kind, arg.index)?;
1593 args.insert(arg.name, idx);
1594 }
1595
1596 Ok(LocalInitializer::ComponentInstantiate(component, args, ty))
1597 }
1598
1599 /// Creates a synthetic module from the list of items currently in the
1600 /// module and their given names.
1601 fn instantiate_component_from_exports(
1602 &mut self,
1603 exports: &[wasmparser::ComponentExport<'data>],
1604 ty: ComponentInstanceTypeId,
1605 ) -> Result<LocalInitializer<'data>> {
1606 let mut map = HashMap::with_capacity(exports.len());
1607 for export in exports {
1608 let idx = self.kind_to_item(export.kind, export.index)?;
1609 map.insert(export.name.name, (idx, export.name));
1610 }
1611
1612 Ok(LocalInitializer::ComponentSynthetic(map, ty))
1613 }
1614
1615 fn kind_to_item(
1616 &mut self,
1617 kind: wasmparser::ComponentExternalKind,
1618 index: u32,
1619 ) -> Result<ComponentItem> {
1620 Ok(match kind {
1621 wasmparser::ComponentExternalKind::Func => {
1622 let index = ComponentFuncIndex::from_u32(index);
1623 ComponentItem::Func(index)
1624 }
1625 wasmparser::ComponentExternalKind::Module => {
1626 let index = ModuleIndex::from_u32(index);
1627 ComponentItem::Module(index)
1628 }
1629 wasmparser::ComponentExternalKind::Instance => {
1630 let index = ComponentInstanceIndex::from_u32(index);
1631 ComponentItem::ComponentInstance(index)
1632 }
1633 wasmparser::ComponentExternalKind::Component => {
1634 let index = ComponentIndex::from_u32(index);
1635 ComponentItem::Component(index)
1636 }
1637 wasmparser::ComponentExternalKind::Value => {
1638 unimplemented!("component values");
1639 }
1640 wasmparser::ComponentExternalKind::Type => {
1641 let types = self.validator.types(0).unwrap();
1642 let ty = types.component_any_type_at(index);
1643 ComponentItem::Type(ty)
1644 }
1645 })
1646 }
1647
1648 fn alias_module_instance_export(
1649 &mut self,
1650 kind: wasmparser::ExternalKind,
1651 instance: ModuleInstanceIndex,
1652 name: &'data str,
1653 ) -> LocalInitializer<'data> {
1654 match kind {
1655 wasmparser::ExternalKind::Func | wasmparser::ExternalKind::FuncExact => {
1656 LocalInitializer::AliasExportFunc(instance, name)
1657 }
1658 wasmparser::ExternalKind::Memory => LocalInitializer::AliasExportMemory(instance, name),
1659 wasmparser::ExternalKind::Table => LocalInitializer::AliasExportTable(instance, name),
1660 wasmparser::ExternalKind::Global => LocalInitializer::AliasExportGlobal(instance, name),
1661 wasmparser::ExternalKind::Tag => LocalInitializer::AliasExportTag(instance, name),
1662 }
1663 }
1664
1665 fn alias_component_outer(
1666 &mut self,
1667 kind: wasmparser::ComponentOuterAliasKind,
1668 count: u32,
1669 index: u32,
1670 ) {
1671 match kind {
1672 wasmparser::ComponentOuterAliasKind::CoreType
1673 | wasmparser::ComponentOuterAliasKind::Type => {}
1674
1675 // For more information about the implementation of outer aliases
1676 // see the documentation of `LexicalScope`. Otherwise though the
1677 // main idea here is that the data to close over starts as `Local`
1678 // and then transitions to `Upvar` as its inserted into the parents
1679 // in order from target we're aliasing back to the current
1680 // component.
1681 wasmparser::ComponentOuterAliasKind::CoreModule => {
1682 let index = ModuleIndex::from_u32(index);
1683 let mut module = ClosedOverModule::Local(index);
1684 let depth = self.lexical_scopes.len() - (count as usize);
1685 for frame in self.lexical_scopes[depth..].iter_mut() {
1686 module = ClosedOverModule::Upvar(frame.closure_args.modules.push(module));
1687 }
1688
1689 // If the `module` is still `Local` then the `depth` was 0 and
1690 // it's an alias into our own space. Otherwise it's switched to
1691 // an upvar and will index into the upvar space. Either way
1692 // it's just plumbed directly into the initializer.
1693 self.result
1694 .initializers
1695 .push(LocalInitializer::AliasModule(module));
1696 }
1697 wasmparser::ComponentOuterAliasKind::Component => {
1698 let index = ComponentIndex::from_u32(index);
1699 let mut component = ClosedOverComponent::Local(index);
1700 let depth = self.lexical_scopes.len() - (count as usize);
1701 for frame in self.lexical_scopes[depth..].iter_mut() {
1702 component =
1703 ClosedOverComponent::Upvar(frame.closure_args.components.push(component));
1704 }
1705
1706 self.result
1707 .initializers
1708 .push(LocalInitializer::AliasComponent(component));
1709 }
1710 }
1711 }
1712
1713 fn canonical_options(
1714 &mut self,
1715 opts: &[wasmparser::CanonicalOption],
1716 core_func_index: u32,
1717 ) -> WasmResult<LocalCanonicalOptions> {
1718 let core_type = self.core_func_signature(core_func_index)?;
1719
1720 let mut string_encoding = StringEncoding::Utf8;
1721 let mut post_return = None;
1722 let mut async_ = false;
1723 let mut callback = None;
1724 let mut memory = None;
1725 let mut realloc = None;
1726 let mut gc = false;
1727
1728 for opt in opts {
1729 match opt {
1730 wasmparser::CanonicalOption::UTF8 => {
1731 string_encoding = StringEncoding::Utf8;
1732 }
1733 wasmparser::CanonicalOption::UTF16 => {
1734 string_encoding = StringEncoding::Utf16;
1735 }
1736 wasmparser::CanonicalOption::CompactUTF16 => {
1737 string_encoding = StringEncoding::CompactUtf16;
1738 }
1739 wasmparser::CanonicalOption::Memory(idx) => {
1740 let idx = MemoryIndex::from_u32(*idx);
1741 memory = Some(idx);
1742 }
1743 wasmparser::CanonicalOption::Realloc(idx) => {
1744 let idx = FuncIndex::from_u32(*idx);
1745 realloc = Some(idx);
1746 }
1747 wasmparser::CanonicalOption::PostReturn(idx) => {
1748 let idx = FuncIndex::from_u32(*idx);
1749 post_return = Some(idx);
1750 }
1751 wasmparser::CanonicalOption::Async => async_ = true,
1752 wasmparser::CanonicalOption::Callback(idx) => {
1753 let idx = FuncIndex::from_u32(*idx);
1754 callback = Some(idx);
1755 }
1756 wasmparser::CanonicalOption::CoreType(idx) => {
1757 if cfg!(debug_assertions) {
1758 let types = self.validator.types(0).unwrap();
1759 let core_ty_id = types.core_type_at_in_component(*idx).unwrap_sub();
1760 let interned = self
1761 .types
1762 .module_types_builder()
1763 .intern_type(types, core_ty_id)?;
1764 debug_assert_eq!(interned, core_type);
1765 }
1766 }
1767 wasmparser::CanonicalOption::Gc => {
1768 gc = true;
1769 }
1770 }
1771 }
1772
1773 Ok(LocalCanonicalOptions {
1774 string_encoding,
1775 post_return,
1776 cancellable: false,
1777 async_,
1778 callback,
1779 core_type,
1780 data_model: if gc {
1781 LocalDataModel::Gc {}
1782 } else {
1783 LocalDataModel::LinearMemory { memory, realloc }
1784 },
1785 })
1786 }
1787
1788 /// Get the interned type index for the `index`th core function.
1789 fn core_func_signature(&mut self, index: u32) -> WasmResult<ModuleInternedTypeIndex> {
1790 let types = self.validator.types(0).unwrap();
1791 let id = types.core_function_at(index);
1792 self.types.module_types_builder().intern_type(types, id)
1793 }
1794
1795 fn is_unsafe_intrinsics_import(&self, import: &str) -> bool {
1796 self.lexical_scopes.is_empty()
1797 && self
1798 .unsafe_intrinsics_import
1799 .is_some_and(|name| import == name)
1800 }
1801
1802 fn check_unsafe_intrinsics_import(&self, import: &str, ty: ComponentEntityType) -> Result<()> {
1803 let types = &self.validator.types(0).unwrap();
1804
1805 let ComponentEntityType::Instance(instance_ty) = ty else {
1806 bail!("bad unsafe intrinsics import: import `{import}` must be an instance import")
1807 };
1808 let instance_ty = &types[instance_ty];
1809
1810 ensure!(
1811 instance_ty.defined_resources.is_empty(),
1812 "bad unsafe intrinsics import: import `{import}` cannot define any resources"
1813 );
1814 ensure!(
1815 instance_ty.explicit_resources.is_empty(),
1816 "bad unsafe intrinsics import: import `{import}` cannot export any resources"
1817 );
1818
1819 for (name, ty) in &instance_ty.exports {
1820 let ComponentEntityType::Func(func_ty) = ty.ty else {
1821 bail!(
1822 "bad unsafe intrinsics import: imported instance `{import}` must \
1823 only export functions"
1824 )
1825 };
1826 let func_ty = &types[func_ty];
1827
1828 fn ty_eq(a: &InterfaceType, b: &wasmparser::component_types::ComponentValType) -> bool {
1829 use wasmparser::{PrimitiveValType as P, component_types::ComponentValType as C};
1830 match (a, b) {
1831 (InterfaceType::U8, C::Primitive(P::U8)) => true,
1832 (InterfaceType::U8, _) => false,
1833
1834 (InterfaceType::U16, C::Primitive(P::U16)) => true,
1835 (InterfaceType::U16, _) => false,
1836
1837 (InterfaceType::U32, C::Primitive(P::U32)) => true,
1838 (InterfaceType::U32, _) => false,
1839
1840 (InterfaceType::U64, C::Primitive(P::U64)) => true,
1841 (InterfaceType::U64, _) => false,
1842
1843 (ty, _) => unreachable!("no unsafe intrinsics use {ty:?}"),
1844 }
1845 }
1846
1847 fn check_types<'a>(
1848 expected: impl ExactSizeIterator<Item = &'a InterfaceType>,
1849 actual: impl ExactSizeIterator<Item = &'a wasmparser::component_types::ComponentValType>,
1850 kind: &str,
1851 import: &str,
1852 name: &str,
1853 ) -> Result<()> {
1854 let expected_len = expected.len();
1855 let actual_len = actual.len();
1856 ensure!(
1857 expected_len == actual_len,
1858 "bad unsafe intrinsics import at `{import}`: function `{name}` must have \
1859 {expected_len} {kind}, found {actual_len}"
1860 );
1861
1862 for (i, (actual_ty, expected_ty)) in actual.zip(expected).enumerate() {
1863 ensure!(
1864 ty_eq(expected_ty, actual_ty),
1865 "bad unsafe intrinsics import at `{import}`: {kind}[{i}] for function \
1866 `{name}` must be `{expected_ty:?}`, found `{actual_ty:?}`"
1867 );
1868 }
1869 Ok(())
1870 }
1871
1872 let intrinsic = UnsafeIntrinsic::from_str(name)
1873 .with_context(|| format!("bad unsafe intrinsics import at `{import}`"))?;
1874
1875 check_types(
1876 intrinsic.component_params().iter(),
1877 func_ty.params.iter().map(|(_name, ty)| ty),
1878 "parameters",
1879 &import,
1880 &name,
1881 )?;
1882 check_types(
1883 intrinsic.component_results().iter(),
1884 func_ty.result.iter(),
1885 "results",
1886 &import,
1887 &name,
1888 )?;
1889 }
1890
1891 Ok(())
1892 }
1893}
1894
1895impl Translation<'_> {
1896 fn types_ref(&self) -> wasmparser::types::TypesRef<'_> {
1897 self.types.as_ref().unwrap().as_ref()
1898 }
1899}
1900
1901/// A small helper module which wraps a `ComponentTypesBuilder` and attempts
1902/// to disallow access to mutable access to the builder before the inlining
1903/// pass.
1904///
1905/// Type information in this translation pass must be preserved at the
1906/// wasmparser layer of abstraction rather than being lowered into Wasmtime's
1907/// own type system. Only during inlining are types fully assigned because
1908/// that's when resource types become available as it's known which instance
1909/// defines which resource, or more concretely the same component instantiated
1910/// twice will produce two unique resource types unlike one as seen by
1911/// wasmparser within the component.
1912mod pre_inlining {
1913 use super::*;
1914
1915 pub struct PreInliningComponentTypes<'a> {
1916 types: &'a mut ComponentTypesBuilder,
1917 }
1918
1919 impl<'a> PreInliningComponentTypes<'a> {
1920 pub fn new(types: &'a mut ComponentTypesBuilder) -> Self {
1921 Self { types }
1922 }
1923
1924 pub fn module_types_builder(&mut self) -> &mut ModuleTypesBuilder {
1925 self.types.module_types_builder_mut()
1926 }
1927
1928 pub fn types(&self) -> &ComponentTypesBuilder {
1929 self.types
1930 }
1931
1932 // NB: this should in theory only be used for the `inline` phase of
1933 // translation.
1934 pub fn types_mut_for_inlining(&mut self) -> &mut ComponentTypesBuilder {
1935 self.types
1936 }
1937 }
1938
1939 impl TypeConvert for PreInliningComponentTypes<'_> {
1940 fn lookup_heap_type(&self, index: wasmparser::UnpackedIndex) -> WasmHeapType {
1941 self.types.lookup_heap_type(index)
1942 }
1943
1944 fn lookup_type_index(&self, index: wasmparser::UnpackedIndex) -> EngineOrModuleTypeIndex {
1945 self.types.lookup_type_index(index)
1946 }
1947 }
1948}
1949use pre_inlining::PreInliningComponentTypes;
1950
1951/// A map from each runtime instance to the static module it is an instance of
1952/// and the arguments it was instantiated with, when we statically know them.
1953///
1954/// `None` for instances of modules that are not part of this component, and
1955/// whose shape we therefore cannot see into.
1956type StaticInstances<'a> =
1957 PrimaryMap<RuntimeInstanceIndex, Option<(StaticModuleIndex, &'a [CoreDef])>>;
1958
1959/// Every entity whose identity is not statically known to everything that can
1960/// access it.
1961#[derive(Default)]
1962struct Ambiguous {
1963 /// Globals, memories, and tables defined by a static module in this
1964 /// component.
1965 entities: HashSet<(StaticModuleIndex, EntityIndex)>,
1966
1967 /// Component-model flags living in the `VMComponentContext`. Only ever
1968 /// contains the non-`KnownGlobal::Defined` variants.
1969 flags: HashSet<KnownGlobal>,
1970}
1971
1972/// Get the component-model flag that a `CoreDef` names, if it names one.
1973fn component_flags(def: &CoreDef) -> Option<KnownGlobal> {
1974 match def {
1975 CoreDef::InstanceFlags(instance) => Some(KnownGlobal::ComponentInstanceFlags(*instance)),
1976 CoreDef::Export(_) | CoreDef::Trampoline(_) | CoreDef::UnsafeIntrinsic(_) => None,
1977 }
1978}
1979
1980/// Resolve a `CoreExport` to the static module that *defines* it and the entity
1981/// index it refers to within that module, when we can see through it statically.
1982///
1983/// A module may import an entity and then re-export it, in which case the
1984/// export names an index in the re-exporting module's *imported* index space.
1985/// We follow those chains all the way back to the module that actually defines
1986/// the entity, so that the returned pair is a canonical identity for it: every
1987/// reference to the same entity resolves to the same `(module, entity)` pair, no
1988/// matter how many modules it was laundered through along the way. That is
1989/// load-bearing for alias regions, where naming the same bytes with two
1990/// different keys is a miscompile.
1991///
1992/// Therefore a returned `Some((module, entity))` always satisfies
1993/// `!static_modules[module].module.is_imported(entity)`.
1994fn resolve_core_export(
1995 static_modules: &PrimaryMap<StaticModuleIndex, ModuleTranslation<'_>>,
1996 instances: &StaticInstances<'_>,
1997 export: &CoreExport<EntityIndex>,
1998) -> Option<(StaticModuleIndex, EntityIndex)> {
1999 let mut instance = export.instance;
2000 let mut item = &export.item;
2001
2002 loop {
2003 // This can be an instance of a dynamic module that is not part of this
2004 // component, rather than a statically-known module inside of it.
2005 let (module, args) = instances[instance]?;
2006
2007 let index = match item {
2008 ExportItem::Index(index) => *index,
2009 // Names are only used for instances of modules whose shape we don't
2010 // statically know, which we already filtered out.
2011 ExportItem::Name(_) => return None,
2012 };
2013
2014 // The common case: this instance's module defines the entity itself, so
2015 // we've bottomed out at its canonical identity.
2016 if !static_modules[module].module.is_imported(index) {
2017 return Some((module, index));
2018 }
2019
2020 // Otherwise this is a re-export of one of the module's imports, so keep
2021 // walking through whichever argument satisfied that import.
2022 let position = static_modules[module]
2023 .module
2024 .import_position(index)
2025 .expect("imported entities always have an associated import initializer");
2026 match &args[position] {
2027 CoreDef::Export(next) => {
2028 // An instantiation's arguments are always exports of instances
2029 // created before the instance being instantiated: `LinearizeDfg`
2030 // builds the argument `CoreDef`s before assigning the new
2031 // instance's `RuntimeInstanceIndex`, and would panic building an
2032 // export of an instance it had not linearized yet. So this walk
2033 // strictly decreases and must terminate.
2034 assert!(next.instance < instance);
2035 instance = next.instance;
2036 item = &next.item;
2037 }
2038
2039 // The chain bottoms out in something that is not an export of
2040 // another instance in this component, so there is no defining module
2041 // for us to name.
2042 CoreDef::InstanceFlags(_) | CoreDef::Trampoline(_) | CoreDef::UnsafeIntrinsic(_) => {
2043 return None;
2044 }
2045 }
2046 }
2047}
2048
2049/// Same as `resolve_core_export`, but for a `CoreDef` that must additionally be
2050/// unambiguous.
2051fn unambiguous_entity(
2052 static_modules: &PrimaryMap<StaticModuleIndex, ModuleTranslation<'_>>,
2053 instances: &StaticInstances<'_>,
2054 ambiguous: &HashSet<(StaticModuleIndex, EntityIndex)>,
2055 def: &CoreDef,
2056) -> Option<(StaticModuleIndex, EntityIndex)> {
2057 let CoreDef::Export(export) = def else {
2058 return None;
2059 };
2060 let entity = resolve_core_export(static_modules, instances, export)?;
2061 if ambiguous.contains(&entity) {
2062 return None;
2063 }
2064 Some(entity)
2065}
2066
2067/// Find every core wasm entity in this component whose identity is *not*
2068/// statically known to every module that may import it.
2069///
2070/// An entity is unambiguous when every argument it flows into belongs to a
2071/// module that we only ever instantiate with that same entity:
2072///
2073/// * An argument to a module that we may instantiate differently elsewhere is
2074/// ambiguous because that module cannot statically know which one of these
2075/// entities it was given at runtime.
2076///
2077/// * An argument to an imported module is ambiguous because that module is
2078/// compiled separately from this component, and it may re-export the entity
2079/// back to us under a name we cannot see through, which we may then hand to a
2080/// module whose imports we do otherwise know.
2081///
2082/// Note that ambiguity is never partial: if a module importing an entity has to
2083/// conservatively tag its accesses with that entity's public alias region, then
2084/// the module defining the entity must do the same, or else inlining one of
2085/// them into the other would access the same bytes through two different alias
2086/// regions, which is invalid.
2087///
2088/// Entities in the returned set are identified by the module that *defines*
2089/// them, as resolved by `resolve_core_export`. That is what makes the previous
2090/// paragraph work through re-exports: marking a module's re-export of an import
2091/// as ambiguous poisons the definition it ultimately refers to, and therefore
2092/// every other module that can reach that definition, and not just the
2093/// re-exporter.
2094fn ambiguous_entities(
2095 static_modules: &PrimaryMap<StaticModuleIndex, ModuleTranslation<'_>>,
2096 translation: &ComponentTranslation,
2097 instantiations: &SecondaryMap<StaticModuleIndex, dfg::AbstractInstantiations<'_>>,
2098 instances: &StaticInstances<'_>,
2099) -> Ambiguous {
2100 let mut ambiguous = Ambiguous::default();
2101
2102 let mut mark = |def: &CoreDef| match def {
2103 CoreDef::Export(export) => {
2104 if let Some(entity) = resolve_core_export(static_modules, instances, export) {
2105 ambiguous.entities.insert(entity);
2106 }
2107 }
2108
2109 CoreDef::InstanceFlags(_) => {
2110 ambiguous.flags.insert(component_flags(def).unwrap());
2111 }
2112
2113 // Neither of these is an entity that gets an alias region keyed by a
2114 // defining module and index.
2115 CoreDef::Trampoline(_) | CoreDef::UnsafeIntrinsic(_) => {}
2116 };
2117
2118 for init in &translation.component.initializers {
2119 match init {
2120 GlobalInitializer::InstantiateModule(instantiation, _) => match instantiation {
2121 InstantiateModule::Static(module, args) => {
2122 // Arguments to modules that we only instantiate one way are
2123 // exactly the references that keep an entity unambiguous, so
2124 // they are the one case we do not mark here. Everything else
2125 // gets whichever of a number of different entities it was
2126 // handed at runtime, and so has to be conservative.
2127 if !matches!(instantiations[*module], dfg::AbstractInstantiations::One(_)) {
2128 for arg in args.iter() {
2129 mark(arg);
2130 }
2131 }
2132 }
2133
2134 // We cannot see through an imported module's exports, so an
2135 // entity we pass into one and that comes back out to a module
2136 // whose imports we do know would be accessed via two different
2137 // alias regions.
2138 InstantiateModule::Import(_, args) => {
2139 for arg in args.values().flat_map(|args| args.values()) {
2140 mark(arg);
2141 }
2142 }
2143 },
2144
2145 // The remaining initializers do not involve the global/table/memory
2146 // alias regions.
2147 GlobalInitializer::ExtractMemory(_)
2148 | GlobalInitializer::ExtractTable(_)
2149 | GlobalInitializer::ExtractRealloc(_)
2150 | GlobalInitializer::ExtractCallback(_)
2151 | GlobalInitializer::ExtractPostReturn(_)
2152 | GlobalInitializer::Resource(_)
2153 | GlobalInitializer::LowerImport { .. } => {}
2154 }
2155 }
2156
2157 ambiguous
2158}