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