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