1//! Support for encoding a core wasm module into a component.
2//!
3//! This module, at a high level, is tasked with transforming a core wasm
4//! module into a component. This will process the imports/exports of the core
5//! wasm module and translate between the `wit-parser` AST and the component
6//! model binary format, producing a final component which will import
7//! `*.wit` defined interfaces and export `*.wit` defined interfaces as well
8//! with everything wired up internally according to the canonical ABI and such.
9//!
10//! This doc block here is not currently 100% complete and doesn't cover the
11//! full functionality of this module.
12//!
13//! # Adapter Modules
14//!
15//! One feature of this encoding process which is non-obvious is the support for
16//! "adapter modules". The general idea here is that historical host API
17//! definitions have been around for quite some time, such as
18//! `wasi_snapshot_preview1`, but these host API definitions are not compatible
19//! with the canonical ABI or component model exactly. These APIs, however, can
20//! in most situations be roughly adapted to component-model equivalents. This
21//! is where adapter modules come into play, they're converting from some
22//! arbitrary API/ABI into a component-model using API.
23//!
24//! An adapter module is a separately compiled `*.wasm` blob which will export
25//! functions matching the desired ABI (e.g. exporting functions matching the
26//! `wasi_snapshot_preview1` ABI). The `*.wasm` blob will then import functions
27//! in the canonical ABI and internally adapt the exported functions to the
28//! imported functions. The encoding support in this module is what wires
29//! everything up and makes sure that everything is imported and exported to the
30//! right place. Adapter modules currently always use "indirect lowerings"
31//! meaning that a shim module is created and provided as the imports to the
32//! main core wasm module, and the shim module is "filled in" at a later time
33//! during the instantiation process.
34//!
35//! Adapter modules are not intended to be general purpose and are currently
36//! very restrictive, namely:
37//!
38//! * They must import a linear memory and not define their own linear memory
39//! otherwise. In other words they import memory and cannot use multi-memory.
40//! * They cannot define any `elem` or `data` segments since otherwise there's
41//! no knowledge ahead-of-time of where their data or element segments could
42//! go. This means things like no panics, no indirect calls, etc.
43//! * If the adapter uses a shadow stack, the global that points to it must be a
44//! mutable `i32` named `__stack_pointer`. This stack is automatically
45//! allocated with an injected `allocate_stack` function that will either use
46//! the main module's `cabi_realloc` export (if present) or `memory.grow`. It
47//! allocates only 64KB of stack space, and there is no protection if that
48//! overflows.
49//! * If the adapter has a global, mutable `i32` named `allocation_state`, it
50//! will be used to keep track of stack allocation status and avoid infinite
51//! recursion if the main module's `cabi_realloc` function calls back into the
52//! adapter. `allocate_stack` will check this global on entry; if it is zero,
53//! it will set it to one, then allocate the stack, and finally set it to two.
54//! If it is non-zero, `allocate_stack` will do nothing and return immediately
55//! (because either the stack has already been allocated or is in the process
56//! of being allocated). If the adapter does not have an `allocation_state`,
57//! `allocate_stack` will use `memory.grow` to allocate the stack; it will
58//! _not_ use the main module's `cabi_realloc` even if it's available.
59//! * If the adapter imports a `cabi_realloc` function, and the main module
60//! exports one, they'll be linked together via an alias. If the adapter
61//! imports such a function but the main module does _not_ export one, we'll
62//! synthesize one based on `memory.grow` (which will trap for any size other
63//! than 64KB). Note that the main module's `cabi_realloc` function may call
64//! back into the adapter before the shadow stack has been allocated. In this
65//! case (when `allocation_state` is zero or one), the adapter should return
66//! whatever dummy value(s) it can immediately without touching the stack.
67//!
68//! This means that adapter modules are not meant to be written by everyone.
69//! It's assumed that these will be relatively few and far between yet still a
70//! crucial part of the transition process from to the component model since
71//! otherwise there's no way to run a `wasi_snapshot_preview1` module within the
72//! component model.
73
74use crate::metadata::{self, Bindgen, ModuleMetadata};
75use crate::validation::{Export, ExportMap, Import, ImportInstance, ImportMap, PayloadInfo};
76use crate::StringEncoding;
77use anyhow::{anyhow, bail, Context, Result};
78use indexmap::{IndexMap, IndexSet};
79use std::borrow::Cow;
80use std::collections::HashMap;
81use std::hash::Hash;
82use std::mem;
83use wasm_encoder::*;
84use wasmparser::Validator;
85use wit_parser::{
86 abi::{AbiVariant, WasmSignature, WasmType},
87 Docs, Function, FunctionKind, InterfaceId, LiveTypes, Resolve, Results, Stability, Type,
88 TypeDefKind, TypeId, TypeOwner, WorldItem, WorldKey,
89};
90
91const INDIRECT_TABLE_NAME: &str = "$imports";
92
93mod wit;
94pub use wit::{encode, encode_world};
95
96mod types;
97use types::{InstanceTypeEncoder, RootTypeEncoder, ValtypeEncoder};
98mod world;
99use world::{ComponentWorld, ImportedInterface, Lowering};
100
101fn to_val_type(ty: &WasmType) -> ValType {
102 match ty {
103 WasmType::I32 => ValType::I32,
104 WasmType::I64 => ValType::I64,
105 WasmType::F32 => ValType::F32,
106 WasmType::F64 => ValType::F64,
107 WasmType::Pointer => ValType::I32,
108 WasmType::PointerOrI64 => ValType::I64,
109 WasmType::Length => ValType::I32,
110 }
111}
112
113bitflags::bitflags! {
114 /// Options in the `canon lower` or `canon lift` required for a particular
115 /// function.
116 #[derive(Copy, Clone, Debug)]
117 pub struct RequiredOptions: u8 {
118 /// A memory must be specified, typically the "main module"'s memory
119 /// export.
120 const MEMORY = 1 << 0;
121 /// A `realloc` function must be specified, typically named
122 /// `cabi_realloc`.
123 const REALLOC = 1 << 1;
124 /// A string encoding must be specified, which is always utf-8 for now
125 /// today.
126 const STRING_ENCODING = 1 << 2;
127 const ASYNC = 1 << 3;
128 }
129}
130
131impl RequiredOptions {
132 fn for_import(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
133 let sig = resolve.wasm_signature(abi, func);
134 let mut ret = RequiredOptions::empty();
135 // Lift the params and lower the results for imports
136 ret.add_lift(TypeContents::for_types(
137 resolve,
138 func.params.iter().map(|(_, t)| t),
139 ));
140 ret.add_lower(TypeContents::for_types(resolve, func.results.iter_types()));
141
142 // If anything is indirect then `memory` will be required to read the
143 // indirect values.
144 if sig.retptr || sig.indirect_params {
145 ret |= RequiredOptions::MEMORY;
146 }
147 if abi == AbiVariant::GuestImportAsync {
148 ret |= RequiredOptions::ASYNC;
149 }
150 ret
151 }
152
153 fn for_export(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
154 let sig = resolve.wasm_signature(abi, func);
155 let mut ret = RequiredOptions::empty();
156 // Lower the params and lift the results for exports
157 ret.add_lower(TypeContents::for_types(
158 resolve,
159 func.params.iter().map(|(_, t)| t),
160 ));
161 ret.add_lift(TypeContents::for_types(resolve, func.results.iter_types()));
162
163 // If anything is indirect then `memory` will be required to read the
164 // indirect values, but if the arguments are indirect then `realloc` is
165 // additionally required to allocate space for the parameters.
166 if sig.retptr || sig.indirect_params {
167 ret |= RequiredOptions::MEMORY;
168 if sig.indirect_params {
169 ret |= RequiredOptions::REALLOC;
170 }
171 }
172 if let AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful = abi {
173 ret |= RequiredOptions::ASYNC;
174 }
175 ret
176 }
177
178 fn add_lower(&mut self, types: TypeContents) {
179 // If lists/strings are lowered into wasm then memory is required as
180 // usual but `realloc` is also required to allow the external caller to
181 // allocate space in the destination for the list/string.
182 if types.contains(TypeContents::LIST) {
183 *self |= RequiredOptions::MEMORY | RequiredOptions::REALLOC;
184 }
185 if types.contains(TypeContents::STRING) {
186 *self |= RequiredOptions::MEMORY
187 | RequiredOptions::STRING_ENCODING
188 | RequiredOptions::REALLOC;
189 }
190 }
191
192 fn add_lift(&mut self, types: TypeContents) {
193 // Unlike for `lower` when lifting a string/list all that's needed is
194 // memory, since the string/list already resides in memory `realloc`
195 // isn't needed.
196 if types.contains(TypeContents::LIST) {
197 *self |= RequiredOptions::MEMORY;
198 }
199 if types.contains(TypeContents::STRING) {
200 *self |= RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING;
201 }
202 }
203
204 fn into_iter(
205 self,
206 encoding: StringEncoding,
207 memory_index: Option<u32>,
208 realloc_index: Option<u32>,
209 ) -> Result<impl ExactSizeIterator<Item = CanonicalOption>> {
210 #[derive(Default)]
211 struct Iter {
212 options: [Option<CanonicalOption>; 5],
213 current: usize,
214 count: usize,
215 }
216
217 impl Iter {
218 fn push(&mut self, option: CanonicalOption) {
219 assert!(self.count < self.options.len());
220 self.options[self.count] = Some(option);
221 self.count += 1;
222 }
223 }
224
225 impl Iterator for Iter {
226 type Item = CanonicalOption;
227
228 fn next(&mut self) -> Option<Self::Item> {
229 if self.current == self.count {
230 return None;
231 }
232 let option = self.options[self.current];
233 self.current += 1;
234 option
235 }
236
237 fn size_hint(&self) -> (usize, Option<usize>) {
238 (self.count - self.current, Some(self.count - self.current))
239 }
240 }
241
242 impl ExactSizeIterator for Iter {}
243
244 let mut iter = Iter::default();
245
246 if self.contains(RequiredOptions::MEMORY) {
247 iter.push(CanonicalOption::Memory(memory_index.ok_or_else(|| {
248 anyhow!("module does not export a memory named `memory`")
249 })?));
250 }
251
252 if self.contains(RequiredOptions::REALLOC) {
253 iter.push(CanonicalOption::Realloc(realloc_index.ok_or_else(
254 || anyhow!("module does not export a function named `cabi_realloc`"),
255 )?));
256 }
257
258 if self.contains(RequiredOptions::STRING_ENCODING) {
259 iter.push(encoding.into());
260 }
261
262 if self.contains(RequiredOptions::ASYNC) {
263 iter.push(CanonicalOption::Async);
264 }
265
266 Ok(iter)
267 }
268}
269
270bitflags::bitflags! {
271 /// Flags about what kinds of types are present within the recursive
272 /// structure of a type.
273 struct TypeContents: u8 {
274 const STRING = 1 << 0;
275 const LIST = 1 << 1;
276 }
277}
278
279impl TypeContents {
280 fn for_types<'a>(resolve: &Resolve, types: impl Iterator<Item = &'a Type>) -> Self {
281 let mut cur = TypeContents::empty();
282 for ty in types {
283 cur |= Self::for_type(resolve, ty);
284 }
285 cur
286 }
287
288 fn for_optional_types<'a>(
289 resolve: &Resolve,
290 types: impl Iterator<Item = Option<&'a Type>>,
291 ) -> Self {
292 Self::for_types(resolve, types.flatten())
293 }
294
295 fn for_optional_type(resolve: &Resolve, ty: Option<&Type>) -> Self {
296 match ty {
297 Some(ty) => Self::for_type(resolve, ty),
298 None => Self::empty(),
299 }
300 }
301
302 fn for_type(resolve: &Resolve, ty: &Type) -> Self {
303 match ty {
304 Type::Id(id) => match &resolve.types[*id].kind {
305 TypeDefKind::Handle(h) => match h {
306 wit_parser::Handle::Own(_) => Self::empty(),
307 wit_parser::Handle::Borrow(_) => Self::empty(),
308 },
309 TypeDefKind::Resource => Self::empty(),
310 TypeDefKind::Record(r) => Self::for_types(resolve, r.fields.iter().map(|f| &f.ty)),
311 TypeDefKind::Tuple(t) => Self::for_types(resolve, t.types.iter()),
312 TypeDefKind::Flags(_) => Self::empty(),
313 TypeDefKind::Option(t) => Self::for_type(resolve, t),
314 TypeDefKind::Result(r) => {
315 Self::for_optional_type(resolve, r.ok.as_ref())
316 | Self::for_optional_type(resolve, r.err.as_ref())
317 }
318 TypeDefKind::Variant(v) => {
319 Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref()))
320 }
321 TypeDefKind::Enum(_) => Self::empty(),
322 TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST,
323 TypeDefKind::Type(t) => Self::for_type(resolve, t),
324 TypeDefKind::Future(_) => Self::empty(),
325 TypeDefKind::Stream(_) => Self::empty(),
326 TypeDefKind::ErrorContext => Self::empty(),
327 TypeDefKind::Unknown => unreachable!(),
328 },
329 Type::String => Self::STRING,
330 _ => Self::empty(),
331 }
332 }
333}
334
335/// State relating to encoding a component.
336pub struct EncodingState<'a> {
337 /// The component being encoded.
338 component: ComponentBuilder,
339 /// The index into the core module index space for the inner core module.
340 ///
341 /// If `None`, the core module has not been encoded.
342 module_index: Option<u32>,
343 /// The index into the core instance index space for the inner core module.
344 ///
345 /// If `None`, the core module has not been instantiated.
346 instance_index: Option<u32>,
347 /// The index in the core memory index space for the exported memory.
348 ///
349 /// If `None`, then the memory has not yet been aliased.
350 memory_index: Option<u32>,
351 /// The index of the shim instance used for lowering imports into the core instance.
352 ///
353 /// If `None`, then the shim instance how not yet been encoded.
354 shim_instance_index: Option<u32>,
355 /// The index of the fixups module to instantiate to fill in the lowered imports.
356 ///
357 /// If `None`, then a fixup module has not yet been encoded.
358 fixups_module_index: Option<u32>,
359
360 /// A map of named adapter modules and the index that the module was defined
361 /// at.
362 adapter_modules: IndexMap<&'a str, u32>,
363 /// A map of adapter module instances and the index of their instance.
364 adapter_instances: IndexMap<&'a str, u32>,
365
366 /// Imported instances and what index they were imported as.
367 imported_instances: IndexMap<InterfaceId, u32>,
368 imported_funcs: IndexMap<String, u32>,
369 exported_instances: IndexMap<InterfaceId, u32>,
370
371 /// Maps used when translating types to the component model binary format.
372 /// Note that imports and exports are stored in separate maps since they
373 /// need fresh hierarchies of types in case the same interface is both
374 /// imported and exported.
375 import_type_map: HashMap<TypeId, u32>,
376 import_func_type_map: HashMap<types::FunctionKey<'a>, u32>,
377 export_type_map: HashMap<TypeId, u32>,
378 export_func_type_map: HashMap<types::FunctionKey<'a>, u32>,
379
380 /// Cache of items that have been aliased from core instances.
381 ///
382 /// This is a helper to reduce the number of aliases created by ensuring
383 /// that repeated requests for the same item return the same index of an
384 /// original `core alias` item.
385 aliased_core_items: HashMap<(u32, String), u32>,
386
387 /// Metadata about the world inferred from the input to `ComponentEncoder`.
388 info: &'a ComponentWorld<'a>,
389}
390
391impl<'a> EncodingState<'a> {
392 fn encode_core_modules(&mut self) {
393 assert!(self.module_index.is_none());
394 let idx = self.component.core_module_raw(&self.info.encoder.module);
395 self.module_index = Some(idx);
396
397 for (name, adapter) in self.info.adapters.iter() {
398 let add_meta = wasm_metadata::AddMetadata {
399 name: Some(if adapter.library_info.is_some() {
400 name.to_string()
401 } else {
402 format!("wit-component:adapter:{name}")
403 }),
404 ..Default::default()
405 };
406 let wasm = add_meta
407 .to_wasm(&adapter.wasm)
408 .expect("core wasm can get name added");
409 let idx = self.component.core_module_raw(&wasm);
410 let prev = self.adapter_modules.insert(name, idx);
411 assert!(prev.is_none());
412 }
413 }
414
415 fn root_import_type_encoder(
416 &mut self,
417 interface: Option<InterfaceId>,
418 ) -> RootTypeEncoder<'_, 'a> {
419 RootTypeEncoder {
420 state: self,
421 interface,
422 import_types: true,
423 }
424 }
425
426 fn root_export_type_encoder(
427 &mut self,
428 interface: Option<InterfaceId>,
429 ) -> RootTypeEncoder<'_, 'a> {
430 RootTypeEncoder {
431 state: self,
432 interface,
433 import_types: false,
434 }
435 }
436
437 fn instance_type_encoder(&mut self, interface: InterfaceId) -> InstanceTypeEncoder<'_, 'a> {
438 InstanceTypeEncoder {
439 state: self,
440 interface,
441 type_map: Default::default(),
442 func_type_map: Default::default(),
443 ty: Default::default(),
444 }
445 }
446
447 fn encode_imports(&mut self, name_map: &HashMap<String, String>) -> Result<()> {
448 let mut has_funcs = false;
449 for (name, info) in self.info.import_map.iter() {
450 match name {
451 Some(name) => {
452 self.encode_interface_import(name_map.get(name).unwrap_or(name), info)?
453 }
454 None => has_funcs = true,
455 }
456 }
457
458 let resolve = &self.info.encoder.metadata.resolve;
459 let world = &resolve.worlds[self.info.encoder.metadata.world];
460 for (_name, item) in world.imports.iter() {
461 if let WorldItem::Type(ty) = item {
462 self.root_import_type_encoder(None)
463 .encode_valtype(resolve, &Type::Id(*ty))?;
464 }
465 }
466
467 if has_funcs {
468 let info = &self.info.import_map[&None];
469 self.encode_root_import_funcs(info)?;
470 }
471 Ok(())
472 }
473
474 fn encode_interface_import(&mut self, name: &str, info: &ImportedInterface) -> Result<()> {
475 let resolve = &self.info.encoder.metadata.resolve;
476 let interface_id = info.interface.as_ref().unwrap();
477 let interface_id = *interface_id;
478 let interface = &resolve.interfaces[interface_id];
479 log::trace!("encoding imports for `{name}` as {:?}", interface_id);
480 let mut encoder = self.instance_type_encoder(interface_id);
481
482 // First encode all type information
483 if let Some(live) = encoder.state.info.live_type_imports.get(&interface_id) {
484 for ty in live {
485 log::trace!(
486 "encoding extra type {ty:?} name={:?}",
487 resolve.types[*ty].name
488 );
489 encoder.encode_valtype(resolve, &Type::Id(*ty))?;
490 }
491 }
492
493 // Next encode all required functions from this imported interface
494 // into the instance type.
495 for (_, func) in interface.functions.iter() {
496 if !(info
497 .lowerings
498 .contains_key(&(func.name.clone(), AbiVariant::GuestImport))
499 || info
500 .lowerings
501 .contains_key(&(func.name.clone(), AbiVariant::GuestImportAsync)))
502 {
503 continue;
504 }
505 log::trace!("encoding function type for `{}`", func.name);
506 let idx = encoder.encode_func_type(resolve, func)?;
507
508 encoder.ty.export(&func.name, ComponentTypeRef::Func(idx));
509 }
510
511 let ty = encoder.ty;
512 // Don't encode empty instance types since they're not
513 // meaningful to the runtime of the component anyway.
514 if ty.is_empty() {
515 return Ok(());
516 }
517 let instance_type_idx = self.component.type_instance(&ty);
518 let instance_idx = self
519 .component
520 .import(name, ComponentTypeRef::Instance(instance_type_idx));
521 let prev = self.imported_instances.insert(interface_id, instance_idx);
522 assert!(prev.is_none());
523 Ok(())
524 }
525
526 fn encode_root_import_funcs(&mut self, info: &ImportedInterface) -> Result<()> {
527 let resolve = &self.info.encoder.metadata.resolve;
528 let world = self.info.encoder.metadata.world;
529 for (name, item) in resolve.worlds[world].imports.iter() {
530 let func = match item {
531 WorldItem::Function(f) => f,
532 WorldItem::Interface { .. } | WorldItem::Type(_) => continue,
533 };
534 let name = resolve.name_world_key(name);
535 if !(info
536 .lowerings
537 .contains_key(&(name.clone(), AbiVariant::GuestImport))
538 || info
539 .lowerings
540 .contains_key(&(name.clone(), AbiVariant::GuestImportAsync)))
541 {
542 continue;
543 }
544 log::trace!("encoding function type for `{}`", func.name);
545 let idx = self
546 .root_import_type_encoder(None)
547 .encode_func_type(resolve, func)?;
548 let func_idx = self.component.import(&name, ComponentTypeRef::Func(idx));
549 let prev = self.imported_funcs.insert(name, func_idx);
550 assert!(prev.is_none());
551 }
552 Ok(())
553 }
554
555 fn alias_imported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
556 let ty = &self.info.encoder.metadata.resolve.types[id];
557 let name = ty.name.as_ref().expect("type must have a name");
558 let instance = self.imported_instances[&interface];
559 self.component
560 .alias_export(instance, name, ComponentExportKind::Type)
561 }
562
563 fn alias_exported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
564 let ty = &self.info.encoder.metadata.resolve.types[id];
565 let name = ty.name.as_ref().expect("type must have a name");
566 let instance = self.exported_instances[&interface];
567 self.component
568 .alias_export(instance, name, ComponentExportKind::Type)
569 }
570
571 fn encode_core_instantiation(&mut self) -> Result<()> {
572 // Encode a shim instantiation if needed
573 let shims = self.encode_shim_instantiation()?;
574
575 // Next declare all exported resource types. This populates
576 // `export_type_map` and will additionally be used for imports to
577 // modules instantiated below.
578 self.declare_exported_resources(&shims);
579
580 // Next instantiate the main module. This provides the linear memory to
581 // use for all future adapters and enables creating indirect lowerings
582 // at the end.
583 self.instantiate_main_module(&shims)?;
584
585 // Separate the adapters according which should be instantiated before
586 // and after indirect lowerings are encoded.
587 let (before, after) = self
588 .info
589 .adapters
590 .iter()
591 .partition::<Vec<_>, _>(|(_, adapter)| {
592 !matches!(
593 adapter.library_info,
594 Some(LibraryInfo {
595 instantiate_after_shims: true,
596 ..
597 })
598 )
599 });
600
601 for (name, _adapter) in before {
602 self.instantiate_adapter_module(&shims, name)?;
603 }
604
605 // With all the relevant core wasm instances in play now the original shim
606 // module, if present, can be filled in with lowerings/adapters/etc.
607 self.encode_indirect_lowerings(&shims)?;
608
609 for (name, _adapter) in after {
610 self.instantiate_adapter_module(&shims, name)?;
611 }
612
613 self.encode_initialize_with_start()?;
614
615 Ok(())
616 }
617
618 fn lookup_resource_index(&mut self, id: TypeId) -> u32 {
619 let resolve = &self.info.encoder.metadata.resolve;
620 let ty = &resolve.types[id];
621 match ty.owner {
622 // If this resource is owned by a world then it's a top-level
623 // resource which means it must have already been translated so
624 // it's available for lookup in `import_type_map`.
625 TypeOwner::World(_) => self.import_type_map[&id],
626 TypeOwner::Interface(i) => {
627 let instance = self.imported_instances[&i];
628 let name = ty.name.as_ref().expect("resources must be named");
629 self.component
630 .alias_export(instance, name, ComponentExportKind::Type)
631 }
632 TypeOwner::None => panic!("resources must have an owner"),
633 }
634 }
635
636 fn encode_exports(&mut self, module: CustomModule) -> Result<()> {
637 let resolve = &self.info.encoder.metadata.resolve;
638 let exports = match module {
639 CustomModule::Main => &self.info.encoder.main_module_exports,
640 CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports,
641 };
642
643 if exports.is_empty() {
644 return Ok(());
645 }
646
647 let mut interface_func_core_names = IndexMap::new();
648 let mut world_func_core_names = IndexMap::new();
649 for (core_name, export) in self.info.exports_for(module).iter() {
650 match export {
651 Export::WorldFunc(_, name, _) => {
652 let prev = world_func_core_names.insert(name, core_name);
653 assert!(prev.is_none());
654 }
655 Export::InterfaceFunc(_, id, name, _) => {
656 let prev = interface_func_core_names
657 .entry(id)
658 .or_insert(IndexMap::new())
659 .insert(name.as_str(), core_name);
660 assert!(prev.is_none());
661 }
662 Export::WorldFuncCallback(..)
663 | Export::InterfaceFuncCallback(..)
664 | Export::WorldFuncPostReturn(..)
665 | Export::InterfaceFuncPostReturn(..)
666 | Export::ResourceDtor(..)
667 | Export::Memory
668 | Export::GeneralPurposeRealloc
669 | Export::GeneralPurposeExportRealloc
670 | Export::GeneralPurposeImportRealloc
671 | Export::Initialize
672 | Export::ReallocForAdapter => continue,
673 }
674 }
675
676 let world = &resolve.worlds[self.info.encoder.metadata.world];
677
678 for export_name in exports {
679 let export_string = resolve.name_world_key(export_name);
680 match &world.exports[export_name] {
681 WorldItem::Function(func) => {
682 let ty = self
683 .root_import_type_encoder(None)
684 .encode_func_type(resolve, func)?;
685 let core_name = world_func_core_names[&func.name];
686 let idx = self.encode_lift(module, &core_name, export_name, func, ty)?;
687 self.component
688 .export(&export_string, ComponentExportKind::Func, idx, None);
689 }
690 WorldItem::Interface { id, .. } => {
691 let core_names = interface_func_core_names.get(id);
692 self.encode_interface_export(
693 &export_string,
694 module,
695 export_name,
696 *id,
697 core_names,
698 )?;
699 }
700 WorldItem::Type(_) => unreachable!(),
701 }
702 }
703
704 Ok(())
705 }
706
707 fn encode_interface_export(
708 &mut self,
709 export_name: &str,
710 module: CustomModule<'_>,
711 key: &WorldKey,
712 export: InterfaceId,
713 interface_func_core_names: Option<&IndexMap<&str, &str>>,
714 ) -> Result<()> {
715 log::trace!("encode interface export `{export_name}`");
716 let resolve = &self.info.encoder.metadata.resolve;
717
718 // First execute a `canon lift` for all the functions in this interface
719 // from the core wasm export. This requires type information but notably
720 // not exported type information since we don't want to export this
721 // interface's types from the root of the component. Each lifted
722 // function is saved off into an `imports` array to get imported into
723 // the nested component synthesized below.
724 let mut imports = Vec::new();
725 let mut root = self.root_export_type_encoder(Some(export));
726 for (_, func) in &resolve.interfaces[export].functions {
727 let core_name = interface_func_core_names.unwrap()[func.name.as_str()];
728 let ty = root.encode_func_type(resolve, func)?;
729 let func_index = root.state.encode_lift(module, &core_name, key, func, ty)?;
730 imports.push((
731 import_func_name(func),
732 ComponentExportKind::Func,
733 func_index,
734 ));
735 }
736
737 // Next a nested component is created which will import the functions
738 // above and then reexport them. The purpose of them is to "re-type" the
739 // functions through type ascription on each `func` item.
740 let mut nested = NestedComponentTypeEncoder {
741 component: ComponentBuilder::default(),
742 type_map: Default::default(),
743 func_type_map: Default::default(),
744 export_types: false,
745 interface: export,
746 state: self,
747 imports: IndexMap::new(),
748 };
749
750 // Import all transitively-referenced types from other interfaces into
751 // this component. This temporarily switches the `interface` listed to
752 // the interface of the referred-to-type to generate the import. After
753 // this loop `interface` is rewritten to `export`.
754 //
755 // Each component is a standalone "island" so the necessary type
756 // information needs to be rebuilt within this component. This ensures
757 // that we're able to build a valid component and additionally connect
758 // all the type information to the outer context.
759 let mut types_to_import = LiveTypes::default();
760 types_to_import.add_interface(resolve, export);
761 let exports_used = &nested.state.info.exports_used[&export];
762 for ty in types_to_import.iter() {
763 if let TypeOwner::Interface(owner) = resolve.types[ty].owner {
764 if owner == export {
765 // Here this deals with the current exported interface which
766 // is handled below.
767 continue;
768 }
769
770 // Ensure that `self` has encoded this type before. If so this
771 // is a noop but otherwise it generates the type here.
772 let mut encoder = if exports_used.contains(&owner) {
773 nested.state.root_export_type_encoder(Some(export))
774 } else {
775 nested.state.root_import_type_encoder(Some(export))
776 };
777 encoder.encode_valtype(resolve, &Type::Id(ty))?;
778
779 // Next generate the same type but this time within the
780 // component itself. The type generated above (or prior) will be
781 // used to satisfy this type import.
782 nested.interface = owner;
783 nested.encode_valtype(resolve, &Type::Id(ty))?;
784 }
785 }
786 nested.interface = export;
787
788 // Record the map of types imported to their index at where they were
789 // imported. This is used after imports are encoded as exported types
790 // will refer to these.
791 let imported_types = nested.type_map.clone();
792
793 // Handle resource types for this instance specially, namely importing
794 // them into the nested component. This models how the resource is
795 // imported from its definition in the outer component to get reexported
796 // internally. This chiefly avoids creating a second resource which is
797 // not desired in this situation.
798 let mut resources = HashMap::new();
799 for (_name, ty) in resolve.interfaces[export].types.iter() {
800 if !matches!(resolve.types[*ty].kind, TypeDefKind::Resource) {
801 continue;
802 }
803 let idx = match nested.encode_valtype(resolve, &Type::Id(*ty))? {
804 ComponentValType::Type(idx) => idx,
805 _ => unreachable!(),
806 };
807 resources.insert(*ty, idx);
808 }
809
810 // Next import each function of this interface. This will end up
811 // defining local types as necessary or using the types as imported
812 // above.
813 for (_, func) in resolve.interfaces[export].functions.iter() {
814 let ty = nested.encode_func_type(resolve, func)?;
815 nested
816 .component
817 .import(&import_func_name(func), ComponentTypeRef::Func(ty));
818 }
819
820 // Swap the `nested.type_map` which was previously from `TypeId` to
821 // `u32` to instead being from `u32` to `TypeId`. This reverse map is
822 // then used in conjunction with `self.type_map` to satisfy all type
823 // imports of the nested component generated. The type import's index in
824 // the inner component is translated to a `TypeId` via `reverse_map`
825 // which is then translated back to our own index space via `type_map`.
826 let reverse_map = nested
827 .type_map
828 .drain()
829 .map(|p| (p.1, p.0))
830 .collect::<HashMap<_, _>>();
831 for (name, idx) in nested.imports.drain(..) {
832 let id = reverse_map[&idx];
833 let owner = match resolve.types[id].owner {
834 TypeOwner::Interface(id) => id,
835 _ => unreachable!(),
836 };
837 let idx = if owner == export || exports_used.contains(&owner) {
838 log::trace!("consulting exports for {id:?}");
839 nested.state.export_type_map[&id]
840 } else {
841 log::trace!("consulting imports for {id:?}");
842 nested.state.import_type_map[&id]
843 };
844 imports.push((name, ComponentExportKind::Type, idx))
845 }
846
847 // Before encoding exports reset the type map to what all was imported
848 // from foreign interfaces. This will enable any encoded types below to
849 // refer to imports which, after type substitution, will point to the
850 // correct type in the outer component context.
851 nested.type_map = imported_types;
852
853 // Next the component reexports all of its imports, but notably uses the
854 // type ascription feature to change the type of the function. Note that
855 // no structural change is happening to the types here but instead types
856 // are getting proper names and such now that this nested component is a
857 // new type index space. Hence the `export_types = true` flag here which
858 // flows through the type encoding and when types are emitted.
859 nested.export_types = true;
860 nested.func_type_map.clear();
861
862 // To start off all type information is encoded. This will be used by
863 // functions below but notably this also has special handling for
864 // resources. Resources reexport their imported resource type under
865 // the final name which achieves the desired goal of threading through
866 // the original resource without creating a new one.
867 for (_, id) in resolve.interfaces[export].types.iter() {
868 let ty = &resolve.types[*id];
869 match ty.kind {
870 TypeDefKind::Resource => {
871 let idx = nested.component.export(
872 ty.name.as_ref().expect("resources must be named"),
873 ComponentExportKind::Type,
874 resources[id],
875 None,
876 );
877 nested.type_map.insert(*id, idx);
878 }
879 _ => {
880 nested.encode_valtype(resolve, &Type::Id(*id))?;
881 }
882 }
883 }
884
885 for (i, (_, func)) in resolve.interfaces[export].functions.iter().enumerate() {
886 let ty = nested.encode_func_type(resolve, func)?;
887 nested.component.export(
888 &func.name,
889 ComponentExportKind::Func,
890 i as u32,
891 Some(ComponentTypeRef::Func(ty)),
892 );
893 }
894
895 // Embed the component within our component and then instantiate it with
896 // the lifted functions. That final instance is then exported under the
897 // appropriate name as the final typed export of this component.
898 let component = nested.component;
899 let component_index = self.component.component(component);
900 let instance_index = self.component.instantiate(component_index, imports);
901 let idx = self.component.export(
902 export_name,
903 ComponentExportKind::Instance,
904 instance_index,
905 None,
906 );
907 let prev = self.exported_instances.insert(export, idx);
908 assert!(prev.is_none());
909
910 // After everything is all said and done remove all the type information
911 // about type exports of this interface. Any entries in the map
912 // currently were used to create the instance above but aren't the
913 // actual copy of the exported type since that comes from the exported
914 // instance itself. Entries will be re-inserted into this map as
915 // necessary via aliases from the exported instance which is the new
916 // source of truth for all these types.
917 for (_name, id) in resolve.interfaces[export].types.iter() {
918 self.export_type_map.remove(id);
919 }
920
921 return Ok(());
922
923 struct NestedComponentTypeEncoder<'state, 'a> {
924 component: ComponentBuilder,
925 type_map: HashMap<TypeId, u32>,
926 func_type_map: HashMap<types::FunctionKey<'a>, u32>,
927 export_types: bool,
928 interface: InterfaceId,
929 state: &'state mut EncodingState<'a>,
930 imports: IndexMap<String, u32>,
931 }
932
933 impl<'a> ValtypeEncoder<'a> for NestedComponentTypeEncoder<'_, 'a> {
934 fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
935 self.component.type_defined()
936 }
937 fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
938 self.component.type_function()
939 }
940 fn export_type(&mut self, idx: u32, name: &'a str) -> Option<u32> {
941 if self.export_types {
942 Some(
943 self.component
944 .export(name, ComponentExportKind::Type, idx, None),
945 )
946 } else {
947 let name = self.unique_import_name(name);
948 let ret = self
949 .component
950 .import(&name, ComponentTypeRef::Type(TypeBounds::Eq(idx)));
951 self.imports.insert(name, ret);
952 Some(ret)
953 }
954 }
955 fn export_resource(&mut self, name: &'a str) -> u32 {
956 if self.export_types {
957 panic!("resources should already be exported")
958 } else {
959 let name = self.unique_import_name(name);
960 let ret = self
961 .component
962 .import(&name, ComponentTypeRef::Type(TypeBounds::SubResource));
963 self.imports.insert(name, ret);
964 ret
965 }
966 }
967 fn import_type(&mut self, _: InterfaceId, _id: TypeId) -> u32 {
968 unreachable!()
969 }
970 fn type_map(&mut self) -> &mut HashMap<TypeId, u32> {
971 &mut self.type_map
972 }
973 fn func_type_map(&mut self) -> &mut HashMap<types::FunctionKey<'a>, u32> {
974 &mut self.func_type_map
975 }
976 fn interface(&self) -> Option<InterfaceId> {
977 Some(self.interface)
978 }
979 }
980
981 impl NestedComponentTypeEncoder<'_, '_> {
982 fn unique_import_name(&mut self, name: &str) -> String {
983 let mut name = format!("import-type-{name}");
984 let mut n = 0;
985 while self.imports.contains_key(&name) {
986 name = format!("{name}{n}");
987 n += 1;
988 }
989 name
990 }
991 }
992
993 fn import_func_name(f: &Function) -> String {
994 match f.kind {
995 FunctionKind::Freestanding => {
996 format!("import-func-{}", f.name)
997 }
998
999 // transform `[method]foo.bar` into `import-method-foo-bar` to
1000 // have it be a valid kebab-name which can't conflict with
1001 // anything else.
1002 //
1003 // There's probably a better and more "formal" way to do this
1004 // but quick-and-dirty string manipulation should work well
1005 // enough for now hopefully.
1006 FunctionKind::Method(_)
1007 | FunctionKind::Static(_)
1008 | FunctionKind::Constructor(_) => {
1009 format!(
1010 "import-{}",
1011 f.name.replace('[', "").replace([']', '.'], "-")
1012 )
1013 }
1014 }
1015 }
1016 }
1017
1018 fn encode_lift(
1019 &mut self,
1020 module: CustomModule<'_>,
1021 core_name: &str,
1022 key: &WorldKey,
1023 func: &Function,
1024 ty: u32,
1025 ) -> Result<u32> {
1026 let resolve = &self.info.encoder.metadata.resolve;
1027 let metadata = self.info.module_metadata_for(module);
1028 let instance_index = self.instance_for(module);
1029 let core_func_index = self.core_alias_export(instance_index, core_name, ExportKind::Func);
1030 let exports = self.info.exports_for(module);
1031
1032 let options = RequiredOptions::for_export(
1033 resolve,
1034 func,
1035 exports
1036 .abi(key, func)
1037 .ok_or_else(|| anyhow!("no ABI found for {}", func.name))?,
1038 );
1039
1040 let encoding = metadata
1041 .export_encodings
1042 .get(resolve, key, &func.name)
1043 .unwrap();
1044 let exports = self.info.exports_for(module);
1045 let realloc_index = exports
1046 .export_realloc_for(key, func)
1047 .map(|name| self.core_alias_export(instance_index, name, ExportKind::Func));
1048 let mut options = options
1049 .into_iter(encoding, self.memory_index, realloc_index)?
1050 .collect::<Vec<_>>();
1051
1052 if let Some(post_return) = exports.post_return(key, func) {
1053 let post_return = self.core_alias_export(instance_index, post_return, ExportKind::Func);
1054 options.push(CanonicalOption::PostReturn(post_return));
1055 }
1056 if let Some(callback) = exports.callback(key, func) {
1057 let callback = self.core_alias_export(instance_index, callback, ExportKind::Func);
1058 options.push(CanonicalOption::Callback(callback));
1059 }
1060 let func_index = self.component.lift_func(core_func_index, ty, options);
1061 Ok(func_index)
1062 }
1063
1064 fn encode_shim_instantiation(&mut self) -> Result<Shims<'a>> {
1065 let mut ret = Shims::default();
1066
1067 ret.append_indirect(self.info, CustomModule::Main)
1068 .context("failed to register indirect shims for main module")?;
1069
1070 // For all required adapter modules a shim is created for each required
1071 // function and additionally a set of shims are created for the
1072 // interface imported into the shim module itself.
1073 for (adapter_name, _adapter) in self.info.adapters.iter() {
1074 ret.append_indirect(self.info, CustomModule::Adapter(adapter_name))
1075 .with_context(|| {
1076 format!("failed to register indirect shims for adapter {adapter_name}")
1077 })?;
1078 }
1079
1080 if ret.shims.is_empty() {
1081 return Ok(ret);
1082 }
1083
1084 assert!(self.shim_instance_index.is_none());
1085 assert!(self.fixups_module_index.is_none());
1086
1087 // This function encodes two modules:
1088 // - A shim module that defines a table and exports functions
1089 // that indirectly call through the table.
1090 // - A fixup module that imports that table and a set of functions
1091 // and populates the imported table via active element segments. The
1092 // fixup module is used to populate the shim's table once the
1093 // imported functions have been lowered.
1094
1095 let mut types = TypeSection::new();
1096 let mut tables = TableSection::new();
1097 let mut functions = FunctionSection::new();
1098 let mut exports = ExportSection::new();
1099 let mut code = CodeSection::new();
1100 let mut sigs = IndexMap::new();
1101 let mut imports_section = ImportSection::new();
1102 let mut elements = ElementSection::new();
1103 let mut func_indexes = Vec::new();
1104 let mut func_names = NameMap::new();
1105
1106 for (i, shim) in ret.shims.values().enumerate() {
1107 let i = i as u32;
1108 let type_index = *sigs.entry(&shim.sig).or_insert_with(|| {
1109 let index = types.len();
1110 types.ty().function(
1111 shim.sig.params.iter().map(to_val_type),
1112 shim.sig.results.iter().map(to_val_type),
1113 );
1114 index
1115 });
1116
1117 functions.function(type_index);
1118 Self::encode_shim_function(type_index, i, &mut code, shim.sig.params.len() as u32);
1119 exports.export(&shim.name, ExportKind::Func, i);
1120
1121 imports_section.import("", &shim.name, EntityType::Function(type_index));
1122 func_indexes.push(i);
1123 func_names.append(i, &shim.debug_name);
1124 }
1125 let mut names = NameSection::new();
1126 names.module("wit-component:shim");
1127 names.functions(&func_names);
1128
1129 let table_type = TableType {
1130 element_type: RefType::FUNCREF,
1131 minimum: ret.shims.len() as u64,
1132 maximum: Some(ret.shims.len() as u64),
1133 table64: false,
1134 shared: false,
1135 };
1136
1137 tables.table(table_type);
1138
1139 exports.export(INDIRECT_TABLE_NAME, ExportKind::Table, 0);
1140 imports_section.import("", INDIRECT_TABLE_NAME, table_type);
1141
1142 elements.active(
1143 None,
1144 &ConstExpr::i32_const(0),
1145 Elements::Functions(func_indexes.into()),
1146 );
1147
1148 let mut shim = Module::new();
1149 shim.section(&types);
1150 shim.section(&functions);
1151 shim.section(&tables);
1152 shim.section(&exports);
1153 shim.section(&code);
1154 shim.section(&RawCustomSection(
1155 &crate::base_producers().raw_custom_section(),
1156 ));
1157 shim.section(&names);
1158
1159 let mut fixups = Module::default();
1160 fixups.section(&types);
1161 fixups.section(&imports_section);
1162 fixups.section(&elements);
1163 fixups.section(&RawCustomSection(
1164 &crate::base_producers().raw_custom_section(),
1165 ));
1166
1167 let mut names = NameSection::new();
1168 names.module("wit-component:fixups");
1169 fixups.section(&names);
1170
1171 let shim_module_index = self.component.core_module(&shim);
1172 self.fixups_module_index = Some(self.component.core_module(&fixups));
1173 self.shim_instance_index = Some(self.component.core_instantiate(shim_module_index, []));
1174
1175 return Ok(ret);
1176 }
1177
1178 fn encode_shim_function(
1179 type_index: u32,
1180 func_index: u32,
1181 code: &mut CodeSection,
1182 param_count: u32,
1183 ) {
1184 let mut func = wasm_encoder::Function::new(std::iter::empty());
1185 for i in 0..param_count {
1186 func.instruction(&Instruction::LocalGet(i));
1187 }
1188 func.instruction(&Instruction::I32Const(func_index as i32));
1189 func.instruction(&Instruction::CallIndirect {
1190 type_index,
1191 table_index: 0,
1192 });
1193 func.instruction(&Instruction::End);
1194 code.function(&func);
1195 }
1196
1197 fn encode_indirect_lowerings(&mut self, shims: &Shims<'_>) -> Result<()> {
1198 if shims.shims.is_empty() {
1199 return Ok(());
1200 }
1201
1202 let shim_instance_index = self
1203 .shim_instance_index
1204 .expect("must have an instantiated shim");
1205
1206 let table_index =
1207 self.core_alias_export(shim_instance_index, INDIRECT_TABLE_NAME, ExportKind::Table);
1208
1209 let resolve = &self.info.encoder.metadata.resolve;
1210
1211 let mut exports = Vec::new();
1212 exports.push((INDIRECT_TABLE_NAME, ExportKind::Table, table_index));
1213
1214 for shim in shims.shims.values() {
1215 let core_func_index = match &shim.kind {
1216 // Indirect lowerings are a `canon lower`'d function with
1217 // options specified from a previously instantiated instance.
1218 // This previous instance could either be the main module or an
1219 // adapter module, which affects the `realloc` option here.
1220 // Currently only one linear memory is supported so the linear
1221 // memory always comes from the main module.
1222 ShimKind::IndirectLowering {
1223 interface,
1224 index,
1225 realloc,
1226 encoding,
1227 } => {
1228 let interface = &self.info.import_map[interface];
1229 let ((name, _), _) = interface.lowerings.get_index(*index).unwrap();
1230 let func_index = match &interface.interface {
1231 Some(interface_id) => {
1232 let instance_index = self.imported_instances[interface_id];
1233 self.component.alias_export(
1234 instance_index,
1235 name,
1236 ComponentExportKind::Func,
1237 )
1238 }
1239 None => self.imported_funcs[name],
1240 };
1241
1242 let realloc = self
1243 .info
1244 .exports_for(*realloc)
1245 .import_realloc_for(interface.interface, name)
1246 .map(|name| {
1247 let instance = self.instance_for(*realloc);
1248 self.core_alias_export(instance, name, ExportKind::Func)
1249 });
1250
1251 self.component.lower_func(
1252 func_index,
1253 shim.options
1254 .into_iter(*encoding, self.memory_index, realloc)?,
1255 )
1256 }
1257
1258 // Adapter shims are defined by an export from an adapter
1259 // instance, so use the specified name here and the previously
1260 // created instances to get the core item that represents the
1261 // shim.
1262 ShimKind::Adapter { adapter, func } => {
1263 self.core_alias_export(self.adapter_instances[adapter], func, ExportKind::Func)
1264 }
1265
1266 // Resources are required for a module to be instantiated
1267 // meaning that any destructor for the resource must be called
1268 // indirectly due to the otherwise circular dependency between
1269 // the module and the resource itself.
1270 ShimKind::ResourceDtor { module, export } => {
1271 self.core_alias_export(self.instance_for(*module), export, ExportKind::Func)
1272 }
1273
1274 ShimKind::PayloadFunc {
1275 for_module,
1276 async_,
1277 info,
1278 kind,
1279 } => {
1280 let metadata = self.info.module_metadata_for(*for_module);
1281 let exports = self.info.exports_for(*for_module);
1282 let instance_index = self.instance_for(*for_module);
1283 let (encoding, realloc) = if info.imported {
1284 (
1285 metadata
1286 .import_encodings
1287 .get(resolve, &info.key, &info.function.name),
1288 exports.import_realloc_for(info.interface, &info.function.name),
1289 )
1290 } else {
1291 (
1292 metadata
1293 .export_encodings
1294 .get(resolve, &info.key, &info.function.name),
1295 exports.export_realloc_for(&info.key, &info.function),
1296 )
1297 };
1298 let encoding = encoding.unwrap_or(StringEncoding::UTF8);
1299 let realloc_index = realloc
1300 .map(|name| self.core_alias_export(instance_index, name, ExportKind::Func));
1301 let options = |me: &mut Self, params: Vec<Type>, results: Vec<Type>| {
1302 Ok::<_, anyhow::Error>(
1303 (RequiredOptions::for_import(
1304 resolve,
1305 &Function {
1306 name: String::new(),
1307 kind: FunctionKind::Freestanding,
1308 params: params
1309 .into_iter()
1310 .enumerate()
1311 .map(|(i, v)| (format!("a{i}"), v))
1312 .collect(),
1313 results: match &results[..] {
1314 [] => Results::Named(Vec::new()),
1315 [ty] => Results::Anon(*ty),
1316 _ => unreachable!(),
1317 },
1318 docs: Default::default(),
1319 stability: Stability::Unknown,
1320 },
1321 if *async_ {
1322 AbiVariant::GuestImportAsync
1323 } else {
1324 AbiVariant::GuestImport
1325 },
1326 ) | RequiredOptions::MEMORY)
1327 .into_iter(encoding, me.memory_index, realloc_index)?
1328 .collect::<Vec<_>>(),
1329 )
1330 };
1331 let type_index = self.payload_type_index(info.ty, info.imported)?;
1332
1333 match kind {
1334 PayloadFuncKind::FutureWrite => {
1335 let TypeDefKind::Future(payload_type) = &resolve.types[info.ty].kind
1336 else {
1337 unreachable!()
1338 };
1339 let options = options(
1340 self,
1341 if let Some(payload_type) = payload_type {
1342 vec![*payload_type]
1343 } else {
1344 vec![]
1345 },
1346 vec![],
1347 )?;
1348 self.component.future_write(type_index, options)
1349 }
1350 PayloadFuncKind::FutureRead => {
1351 let TypeDefKind::Future(payload_type) = &resolve.types[info.ty].kind
1352 else {
1353 unreachable!()
1354 };
1355 let options = options(
1356 self,
1357 vec![],
1358 if let Some(payload_type) = payload_type {
1359 vec![*payload_type]
1360 } else {
1361 vec![]
1362 },
1363 )?;
1364 self.component.future_read(type_index, options)
1365 }
1366 PayloadFuncKind::StreamWrite => {
1367 let TypeDefKind::Stream(payload_type) = &resolve.types[info.ty].kind
1368 else {
1369 unreachable!()
1370 };
1371 let options = options(self, vec![*payload_type], vec![])?;
1372 self.component.stream_write(type_index, options)
1373 }
1374 PayloadFuncKind::StreamRead => {
1375 let TypeDefKind::Stream(payload_type) = &resolve.types[info.ty].kind
1376 else {
1377 unreachable!()
1378 };
1379 let options = options(self, vec![], vec![*payload_type])?;
1380 self.component.stream_read(type_index, options)
1381 }
1382 }
1383 }
1384
1385 ShimKind::TaskWait { async_ } => self
1386 .component
1387 .task_wait(*async_, self.memory_index.unwrap()),
1388 ShimKind::TaskPoll { async_ } => self
1389 .component
1390 .task_poll(*async_, self.memory_index.unwrap()),
1391 ShimKind::ErrorContextNew { encoding }
1392 | ShimKind::ErrorContextDebugMessage { encoding, .. } => match &shim.kind {
1393 ShimKind::ErrorContextNew { .. } => self.component.error_context_new(
1394 (RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING)
1395 .into_iter(*encoding, self.memory_index, None)?
1396 .collect::<Vec<_>>(),
1397 ),
1398 ShimKind::ErrorContextDebugMessage {
1399 for_module,
1400 realloc,
1401 ..
1402 } => {
1403 let instance_index = self.instance_for(*for_module);
1404 let realloc_index =
1405 Some(self.core_alias_export(instance_index, realloc, ExportKind::Func));
1406
1407 self.component.error_context_debug_message(
1408 (RequiredOptions::MEMORY
1409 | RequiredOptions::STRING_ENCODING
1410 | RequiredOptions::REALLOC)
1411 .into_iter(*encoding, self.memory_index, realloc_index)?
1412 .collect::<Vec<_>>(),
1413 )
1414 }
1415 _ => unreachable!(),
1416 },
1417 };
1418
1419 exports.push((shim.name.as_str(), ExportKind::Func, core_func_index));
1420 }
1421
1422 let instance_index = self.component.core_instantiate_exports(exports);
1423 self.component.core_instantiate(
1424 self.fixups_module_index.expect("must have fixup module"),
1425 [("", ModuleArg::Instance(instance_index))],
1426 );
1427 Ok(())
1428 }
1429
1430 /// Encode the specified `stream` or `future` type in the component using
1431 /// either the `root_import_type_encoder` or the `root_export_type_encoder`
1432 /// depending on the value of `imported`.
1433 ///
1434 /// Note that the payload type `T` of `stream<T>` or `future<T>` may be an
1435 /// imported or exported type, and that determines the appropriate type
1436 /// encoder to use.
1437 fn payload_type_index(&mut self, ty: TypeId, imported: bool) -> Result<u32> {
1438 // `stream` and `future` types don't have owners, but their payload
1439 // types (or the payload type of the payload type, etc. in the case of
1440 // nesting) might have an owner, in which case we need to find that in
1441 // order to make the types match up e.g. when we're exporting a resource
1442 // that's used as a payload type.
1443 fn owner(resolve: &Resolve, ty: TypeId) -> Option<InterfaceId> {
1444 let def = &resolve.types[ty];
1445 match &def.kind {
1446 TypeDefKind::Future(Some(Type::Id(ty))) => owner(resolve, *ty),
1447 TypeDefKind::Stream(Type::Id(ty)) => owner(resolve, *ty),
1448 _ => match &def.owner {
1449 TypeOwner::World(_) | TypeOwner::None => None,
1450 TypeOwner::Interface(id) => Some(*id),
1451 },
1452 }
1453 }
1454
1455 let resolve = &self.info.encoder.metadata.resolve;
1456 let ComponentValType::Type(type_index) = if imported {
1457 self.root_import_type_encoder(None)
1458 } else {
1459 let owner = owner(resolve, ty);
1460 self.root_export_type_encoder(owner)
1461 }
1462 .encode_valtype(resolve, &Type::Id(ty))?
1463 else {
1464 unreachable!()
1465 };
1466 Ok(type_index)
1467 }
1468
1469 /// This is a helper function that will declare, in the component itself,
1470 /// all exported resources.
1471 ///
1472 /// These resources later on get packaged up into instances and such. The
1473 /// main thing that this handles is that it registers the right destructor
1474 /// from `shims`, if needed, for each resource.
1475 fn declare_exported_resources(&mut self, shims: &Shims<'_>) {
1476 let resolve = &self.info.encoder.metadata.resolve;
1477 let world = &resolve.worlds[self.info.encoder.metadata.world];
1478
1479 // Iterate over the main module's exports and the exports of all
1480 // adapters. Look for exported interfaces that themselves have
1481 // resources.
1482 let main_module_keys = self.info.encoder.main_module_exports.iter();
1483 let main_module_keys = main_module_keys.map(|key| (CustomModule::Main, key));
1484 let adapter_keys = self.info.encoder.adapters.iter().flat_map(|(name, info)| {
1485 info.required_exports
1486 .iter()
1487 .map(move |key| (CustomModule::Adapter(name), key))
1488 });
1489 for (for_module, key) in main_module_keys.chain(adapter_keys) {
1490 let id = match &world.exports[key] {
1491 WorldItem::Interface { id, .. } => *id,
1492 WorldItem::Type { .. } => unreachable!(),
1493 WorldItem::Function(_) => continue,
1494 };
1495
1496 for ty in resolve.interfaces[id].types.values() {
1497 match resolve.types[*ty].kind {
1498 TypeDefKind::Resource => {}
1499 _ => continue,
1500 }
1501
1502 // Load the destructor, previously detected in module
1503 // validation, if one is present.
1504 let exports = self.info.exports_for(for_module);
1505 let dtor = exports.resource_dtor(*ty).map(|name| {
1506 let name = &shims.shims[&ShimKind::ResourceDtor {
1507 module: for_module,
1508 export: name,
1509 }]
1510 .name;
1511 let shim = self.shim_instance_index.unwrap();
1512 self.core_alias_export(shim, name, ExportKind::Func)
1513 });
1514
1515 // Declare the resource with this destructor and register it in
1516 // our internal map. This should be the first and only time this
1517 // type is inserted into this map.
1518 let resource_idx = self.component.type_resource(ValType::I32, dtor);
1519 let prev = self.export_type_map.insert(*ty, resource_idx);
1520 assert!(prev.is_none());
1521 }
1522 }
1523 }
1524
1525 /// Helper to instantiate the main module and record various results of its
1526 /// instantiation within `self`.
1527 fn instantiate_main_module(&mut self, shims: &Shims<'_>) -> Result<()> {
1528 assert!(self.instance_index.is_none());
1529
1530 let instance_index = self.instantiate_core_module(shims, CustomModule::Main)?;
1531
1532 if let Some(memory) = self.info.info.exports.memory() {
1533 self.memory_index =
1534 Some(self.core_alias_export(instance_index, memory, ExportKind::Memory));
1535 }
1536
1537 self.instance_index = Some(instance_index);
1538 Ok(())
1539 }
1540
1541 /// This function will instantiate the specified adapter module, which may
1542 /// depend on previously-instantiated modules.
1543 fn instantiate_adapter_module(&mut self, shims: &Shims<'_>, name: &'a str) -> Result<()> {
1544 let instance = self.instantiate_core_module(shims, CustomModule::Adapter(name))?;
1545 self.adapter_instances.insert(name, instance);
1546 Ok(())
1547 }
1548
1549 /// Generic helper to instantiate a module.
1550 ///
1551 /// The `for_module` provided will have all of its imports satisfied from
1552 /// either previous instantiations or the `shims` module present. This
1553 /// iterates over the metadata produced during validation to determine what
1554 /// hooks up to what import.
1555 fn instantiate_core_module(
1556 &mut self,
1557 shims: &Shims,
1558 for_module: CustomModule<'_>,
1559 ) -> Result<u32> {
1560 let module = self.module_for(for_module);
1561
1562 let mut args = Vec::new();
1563 for (core_wasm_name, instance) in self.info.imports_for(for_module).modules() {
1564 match instance {
1565 // For import modules that are a "bag of names" iterate over
1566 // each name and materialize it into this component with the
1567 // `materialize_import` helper. This is then all bottled up into
1568 // a bag-of-exports instances which is then used for
1569 // instantiation.
1570 ImportInstance::Names(names) => {
1571 let mut exports = Vec::new();
1572 for (name, import) in names {
1573 let (kind, index) = self
1574 .materialize_import(&shims, for_module, core_wasm_name, name, import)
1575 .with_context(|| {
1576 format!("failed to satisfy import `{core_wasm_name}::{name}`")
1577 })?;
1578 exports.push((name.as_str(), kind, index));
1579 }
1580 let index = self.component.core_instantiate_exports(exports);
1581 args.push((core_wasm_name.as_str(), ModuleArg::Instance(index)));
1582 }
1583
1584 // Some imports are entire instances, so use the instance for
1585 // the module identifier as the import.
1586 ImportInstance::Whole(which) => {
1587 let instance = self.instance_for(which.to_custom_module());
1588 args.push((core_wasm_name.as_str(), ModuleArg::Instance(instance)));
1589 }
1590 }
1591 }
1592
1593 // And with all arguments prepared now, instantiate the module.
1594 Ok(self.component.core_instantiate(module, args))
1595 }
1596
1597 /// Helper function to materialize an import into a core module within the
1598 /// component being built.
1599 ///
1600 /// This function is called for individual imports and uses the results of
1601 /// validation, notably the `Import` type, to determine what WIT-level or
1602 /// component-level construct is being hooked up.
1603 fn materialize_import(
1604 &mut self,
1605 shims: &Shims<'_>,
1606 for_module: CustomModule<'_>,
1607 module: &str,
1608 field: &str,
1609 import: &'a Import,
1610 ) -> Result<(ExportKind, u32)> {
1611 log::trace!("attempting to materialize import of `{module}::{field}` for {for_module:?}");
1612 let resolve = &self.info.encoder.metadata.resolve;
1613 let payload_indirect = |me: &mut Self, async_, info, kind| {
1614 me.component.core_alias_export(
1615 me.shim_instance_index.expect("shim should be instantiated"),
1616 &shims.shims[&ShimKind::PayloadFunc {
1617 for_module,
1618 async_,
1619 info,
1620 kind,
1621 }]
1622 .name,
1623 ExportKind::Func,
1624 )
1625 };
1626 let name_tmp;
1627 let (key, name, interface_key, abi) = match import {
1628 // Main module dependencies on an adapter in use are done with an
1629 // indirection here, so load the shim function and use that.
1630 Import::AdapterExport(_) => {
1631 assert!(self.info.encoder.adapters.contains_key(module));
1632 let shim_instance = self
1633 .shim_instance_index
1634 .expect("shim should be instantiated");
1635 let index = self.core_alias_export(
1636 shim_instance,
1637 &shims.shims[&ShimKind::Adapter {
1638 adapter: module,
1639 func: field,
1640 }]
1641 .name,
1642 ExportKind::Func,
1643 );
1644 return Ok((ExportKind::Func, index));
1645 }
1646
1647 // Adapters might uset he main module's memory, in which case it
1648 // should have been previously instantiated.
1649 Import::MainModuleMemory => {
1650 let index = self
1651 .memory_index
1652 .ok_or_else(|| anyhow!("main module cannot import memory"))?;
1653 return Ok((ExportKind::Memory, index));
1654 }
1655
1656 // Grab-bag of "this adapter wants this thing from the main module".
1657 Import::MainModuleExport { name, kind } => {
1658 let instance = self.instance_index.unwrap();
1659 let index = self.core_alias_export(instance, name, *kind);
1660 return Ok((*kind, index));
1661 }
1662
1663 // A similar grab-bag to above but with a slightly different
1664 // structure. Should probably refactor to make these two the same in
1665 // the future.
1666 Import::Item(item) => {
1667 let instance = self.instance_for(item.which.to_custom_module());
1668 let index = self.core_alias_export(instance, &item.name, item.kind);
1669 return Ok((item.kind, index));
1670 }
1671
1672 // Resource intrinsics related to exported resources. Despite being
1673 // an exported resource the component still provides necessary
1674 // intrinsics for manipulating resource state. These are all
1675 // handled here using the resource types created during
1676 // `declare_exported_resources` above.
1677 Import::ExportedResourceDrop(_key, id) => {
1678 let index = self.component.resource_drop(self.export_type_map[id]);
1679 return Ok((ExportKind::Func, index));
1680 }
1681 Import::ExportedResourceRep(_key, id) => {
1682 let index = self.component.resource_rep(self.export_type_map[id]);
1683 return Ok((ExportKind::Func, index));
1684 }
1685 Import::ExportedResourceNew(_key, id) => {
1686 let index = self.component.resource_new(self.export_type_map[id]);
1687 return Ok((ExportKind::Func, index));
1688 }
1689
1690 // And finally here at the end these cases are going to all fall
1691 // through to the code below. This is where these are connected to a
1692 // WIT `ImportedInterface` one way or another with the name that was
1693 // detected during validation.
1694 Import::ImportedResourceDrop(key, iface, id) => {
1695 let ty = &resolve.types[*id];
1696 let name = ty.name.as_ref().unwrap();
1697 name_tmp = format!("{name}_drop");
1698 (
1699 key,
1700 &name_tmp,
1701 iface.map(|_| resolve.name_world_key(key)),
1702 AbiVariant::GuestImport,
1703 )
1704 }
1705 Import::ExportedTaskReturn(function) => {
1706 let signature = resolve.wasm_signature(
1707 AbiVariant::GuestImport,
1708 &Function {
1709 name: String::new(),
1710 kind: FunctionKind::Freestanding,
1711 params: match &function.results {
1712 Results::Named(params) => params.clone(),
1713 Results::Anon(ty) => vec![("v".to_string(), *ty)],
1714 },
1715 results: Results::Named(Vec::new()),
1716 docs: Docs::default(),
1717 stability: Stability::Unknown,
1718 },
1719 );
1720 let (type_index, encoder) = self.component.core_type();
1721 encoder.core().function(
1722 signature.params.into_iter().map(into_val_type),
1723 signature.results.into_iter().map(into_val_type),
1724 );
1725
1726 let index = self.component.task_return(type_index);
1727 return Ok((ExportKind::Func, index));
1728
1729 fn into_val_type(ty: WasmType) -> ValType {
1730 match ty {
1731 WasmType::I32 | WasmType::Pointer | WasmType::Length => ValType::I32,
1732 WasmType::I64 | WasmType::PointerOrI64 => ValType::I64,
1733 WasmType::F32 => ValType::F32,
1734 WasmType::F64 => ValType::F64,
1735 }
1736 }
1737 }
1738 Import::TaskBackpressure => {
1739 let index = self.component.task_backpressure();
1740 return Ok((ExportKind::Func, index));
1741 }
1742 Import::TaskWait { async_ } => {
1743 let index = self.component.core_alias_export(
1744 self.shim_instance_index
1745 .expect("shim should be instantiated"),
1746 &shims.shims[&ShimKind::TaskWait { async_: *async_ }].name,
1747 ExportKind::Func,
1748 );
1749 return Ok((ExportKind::Func, index));
1750 }
1751 Import::TaskPoll { async_ } => {
1752 let index = self.component.core_alias_export(
1753 self.shim_instance_index
1754 .expect("shim should be instantiated"),
1755 &shims.shims[&ShimKind::TaskPoll { async_: *async_ }].name,
1756 ExportKind::Func,
1757 );
1758 return Ok((ExportKind::Func, index));
1759 }
1760 Import::TaskYield { async_ } => {
1761 let index = self.component.task_yield(*async_);
1762 return Ok((ExportKind::Func, index));
1763 }
1764 Import::SubtaskDrop => {
1765 let index = self.component.subtask_drop();
1766 return Ok((ExportKind::Func, index));
1767 }
1768 Import::StreamNew(info) => {
1769 let ty = self.payload_type_index(info.ty, info.imported)?;
1770 let index = self.component.stream_new(ty);
1771 return Ok((ExportKind::Func, index));
1772 }
1773 Import::StreamRead { async_, info } => {
1774 return Ok((
1775 ExportKind::Func,
1776 payload_indirect(self, *async_, info, PayloadFuncKind::StreamRead),
1777 ));
1778 }
1779 Import::StreamWrite { async_, info } => {
1780 return Ok((
1781 ExportKind::Func,
1782 payload_indirect(self, *async_, info, PayloadFuncKind::StreamWrite),
1783 ));
1784 }
1785 Import::StreamCancelRead {
1786 ty,
1787 imported,
1788 async_,
1789 } => {
1790 let ty = self.payload_type_index(*ty, *imported)?;
1791 let index = self.component.stream_cancel_read(ty, *async_);
1792 return Ok((ExportKind::Func, index));
1793 }
1794 Import::StreamCancelWrite {
1795 ty,
1796 imported,
1797 async_,
1798 } => {
1799 let ty = self.payload_type_index(*ty, *imported)?;
1800 let index = self.component.stream_cancel_write(ty, *async_);
1801 return Ok((ExportKind::Func, index));
1802 }
1803 Import::StreamCloseReadable { ty, imported } => {
1804 let type_index = self.payload_type_index(*ty, *imported)?;
1805 let index = self.component.stream_close_readable(type_index);
1806 return Ok((ExportKind::Func, index));
1807 }
1808 Import::StreamCloseWritable { ty, imported } => {
1809 let type_index = self.payload_type_index(*ty, *imported)?;
1810 let index = self.component.stream_close_writable(type_index);
1811 return Ok((ExportKind::Func, index));
1812 }
1813 Import::FutureNew(info) => {
1814 let ty = self.payload_type_index(info.ty, info.imported)?;
1815 let index = self.component.future_new(ty);
1816 return Ok((ExportKind::Func, index));
1817 }
1818 Import::FutureRead { async_, info } => {
1819 return Ok((
1820 ExportKind::Func,
1821 payload_indirect(self, *async_, info, PayloadFuncKind::FutureRead),
1822 ));
1823 }
1824 Import::FutureWrite { async_, info } => {
1825 return Ok((
1826 ExportKind::Func,
1827 payload_indirect(self, *async_, info, PayloadFuncKind::FutureWrite),
1828 ));
1829 }
1830 Import::FutureCancelRead {
1831 ty,
1832 imported,
1833 async_,
1834 } => {
1835 let ty = self.payload_type_index(*ty, *imported)?;
1836 let index = self.component.future_cancel_read(ty, *async_);
1837 return Ok((ExportKind::Func, index));
1838 }
1839 Import::FutureCancelWrite {
1840 ty,
1841 imported,
1842 async_,
1843 } => {
1844 let ty = self.payload_type_index(*ty, *imported)?;
1845 let index = self.component.future_cancel_write(ty, *async_);
1846 return Ok((ExportKind::Func, index));
1847 }
1848 Import::FutureCloseReadable { ty, imported } => {
1849 let type_index = self.payload_type_index(*ty, *imported)?;
1850 let index = self.component.future_close_readable(type_index);
1851 return Ok((ExportKind::Func, index));
1852 }
1853 Import::FutureCloseWritable { ty, imported } => {
1854 let type_index = self.payload_type_index(*ty, *imported)?;
1855 let index = self.component.future_close_writable(type_index);
1856 return Ok((ExportKind::Func, index));
1857 }
1858 Import::ErrorContextNew { encoding } => {
1859 let index = self.component.core_alias_export(
1860 self.shim_instance_index
1861 .expect("shim should be instantiated"),
1862 &shims.shims[&ShimKind::ErrorContextNew {
1863 encoding: *encoding,
1864 }]
1865 .name,
1866 ExportKind::Func,
1867 );
1868 return Ok((ExportKind::Func, index));
1869 }
1870 Import::ErrorContextDebugMessage { encoding, realloc } => {
1871 let index = self.component.core_alias_export(
1872 self.shim_instance_index
1873 .expect("shim should be instantiated"),
1874 &shims.shims[&ShimKind::ErrorContextDebugMessage {
1875 for_module,
1876 encoding: *encoding,
1877 realloc,
1878 }]
1879 .name,
1880 ExportKind::Func,
1881 );
1882 return Ok((ExportKind::Func, index));
1883 }
1884 Import::ErrorContextDrop => {
1885 let index = self.component.error_context_drop();
1886 return Ok((ExportKind::Func, index));
1887 }
1888 Import::WorldFunc(key, name, abi) => (key, name, None, *abi),
1889 Import::InterfaceFunc(key, _, name, abi) => {
1890 (key, name, Some(resolve.name_world_key(key)), *abi)
1891 }
1892 };
1893
1894 let import = &self.info.import_map[&interface_key];
1895 let (index, _, lowering) = import.lowerings.get_full(&(name.clone(), abi)).unwrap();
1896 let metadata = self.info.module_metadata_for(for_module);
1897
1898 let index = match lowering {
1899 // All direct lowerings can be `canon lower`'d here immediately
1900 // and passed as arguments.
1901 Lowering::Direct => {
1902 let func_index = match &import.interface {
1903 Some(interface) => {
1904 let instance_index = self.imported_instances[interface];
1905 self.component
1906 .alias_export(instance_index, name, ComponentExportKind::Func)
1907 }
1908 None => self.imported_funcs[name],
1909 };
1910 self.component.lower_func(
1911 func_index,
1912 if let AbiVariant::GuestImportAsync = abi {
1913 vec![CanonicalOption::Async]
1914 } else {
1915 Vec::new()
1916 },
1917 )
1918 }
1919
1920 // Indirect lowerings come from the shim that was previously
1921 // created, so the specific export is loaded here and used as an
1922 // import.
1923 Lowering::Indirect { .. } => {
1924 let encoding = metadata.import_encodings.get(resolve, key, name).unwrap();
1925 self.core_alias_export(
1926 self.shim_instance_index
1927 .expect("shim should be instantiated"),
1928 &shims.shims[&ShimKind::IndirectLowering {
1929 interface: interface_key,
1930 index,
1931 realloc: for_module,
1932 encoding,
1933 }]
1934 .name,
1935 ExportKind::Func,
1936 )
1937 }
1938
1939 // A "resource drop" intrinsic only needs to find the index of the
1940 // resource type itself and then the intrinsic is declared.
1941 Lowering::ResourceDrop(id) => {
1942 let resource_idx = self.lookup_resource_index(*id);
1943 self.component.resource_drop(resource_idx)
1944 }
1945 };
1946 Ok((ExportKind::Func, index))
1947 }
1948
1949 /// Generates component bits that are responsible for executing
1950 /// `_initialize`, if found, in the original component.
1951 ///
1952 /// The `_initialize` function was a part of WASIp1 where it generally is
1953 /// intended to run after imports and memory and such are all "hooked up"
1954 /// and performs other various initialization tasks. This is additionally
1955 /// specified in https://github.com/WebAssembly/component-model/pull/378
1956 /// to be part of the component model lowerings as well.
1957 ///
1958 /// This implements this functionality by encoding a core module that
1959 /// imports a function and then registers a `start` section with that
1960 /// imported function. This is all encoded after the
1961 /// imports/lowerings/tables/etc are all filled in above meaning that this
1962 /// is the last piece to run. That means that when this is running
1963 /// everything should be hooked up for all imported functions to work.
1964 ///
1965 /// Note that at this time `_initialize` is only detected in the "main
1966 /// module", not adapters/libraries.
1967 fn encode_initialize_with_start(&mut self) -> Result<()> {
1968 let initialize = match self.info.info.exports.initialize() {
1969 Some(name) => name,
1970 // If this core module didn't have `_initialize` or similar, then
1971 // there's nothing to do here.
1972 None => return Ok(()),
1973 };
1974 let initialize_index =
1975 self.core_alias_export(self.instance_index.unwrap(), initialize, ExportKind::Func);
1976 let mut shim = Module::default();
1977 let mut section = TypeSection::new();
1978 section.ty().function([], []);
1979 shim.section(&section);
1980 let mut section = ImportSection::new();
1981 section.import("", "", EntityType::Function(0));
1982 shim.section(&section);
1983 shim.section(&StartSection { function_index: 0 });
1984
1985 // Declare the core module within the component, create a dummy core
1986 // instance with one export of our `_initialize` function, and then use
1987 // that to instantiate the module we emit to run the `start` function in
1988 // core wasm to run `_initialize`.
1989 let shim_module_index = self.component.core_module(&shim);
1990 let shim_args_instance_index =
1991 self.component
1992 .core_instantiate_exports([("", ExportKind::Func, initialize_index)]);
1993 self.component.core_instantiate(
1994 shim_module_index,
1995 [("", ModuleArg::Instance(shim_args_instance_index))],
1996 );
1997 Ok(())
1998 }
1999
2000 /// Convenience function to go from `CustomModule` to the instance index
2001 /// corresponding to what that points to.
2002 fn instance_for(&self, module: CustomModule) -> u32 {
2003 match module {
2004 CustomModule::Main => self.instance_index.expect("instantiated by now"),
2005 CustomModule::Adapter(name) => self.adapter_instances[name],
2006 }
2007 }
2008
2009 /// Convenience function to go from `CustomModule` to the module index
2010 /// corresponding to what that points to.
2011 fn module_for(&self, module: CustomModule) -> u32 {
2012 match module {
2013 CustomModule::Main => self.module_index.unwrap(),
2014 CustomModule::Adapter(name) => self.adapter_modules[name],
2015 }
2016 }
2017
2018 /// Convenience function which caches aliases created so repeated calls to
2019 /// this function will all return the same index.
2020 fn core_alias_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 {
2021 *self
2022 .aliased_core_items
2023 .entry((instance, name.to_string()))
2024 .or_insert_with(|| self.component.core_alias_export(instance, name, kind))
2025 }
2026}
2027
2028/// A list of "shims" which start out during the component instantiation process
2029/// as functions which immediately trap due to a `call_indirect`-to-`null` but
2030/// will get filled in by the time the component instantiation process
2031/// completes.
2032///
2033/// Shims currently include:
2034///
2035/// * "Indirect functions" lowered from imported instances where the lowering
2036/// requires an item exported from the main module. These are indirect due to
2037/// the circular dependency between the module needing an import and the
2038/// import needing the module.
2039///
2040/// * Adapter modules which convert from a historical ABI to the component
2041/// model's ABI (e.g. wasi preview1 to preview2) get a shim since the adapters
2042/// are currently indicated as always requiring the memory of the main module.
2043///
2044/// This structure is created by `encode_shim_instantiation`.
2045#[derive(Default)]
2046struct Shims<'a> {
2047 /// The list of all shims that a module will require.
2048 shims: IndexMap<ShimKind<'a>, Shim<'a>>,
2049}
2050
2051struct Shim<'a> {
2052 /// Canonical ABI options required by this shim, used during `canon lower`
2053 /// operations.
2054 options: RequiredOptions,
2055
2056 /// The name, in the shim instance, of this shim.
2057 ///
2058 /// Currently this is `"0"`, `"1"`, ...
2059 name: String,
2060
2061 /// A human-readable debugging name for this shim, used in a core wasm
2062 /// `name` section.
2063 debug_name: String,
2064
2065 /// Precise information about what this shim is a lowering of.
2066 kind: ShimKind<'a>,
2067
2068 /// Wasm type of this shim.
2069 sig: WasmSignature,
2070}
2071
2072/// Which variation of `{stream|future}.{read|write}` we're emitting for a
2073/// `ShimKind::PayloadFunc`.
2074#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2075enum PayloadFuncKind {
2076 FutureWrite,
2077 FutureRead,
2078 StreamWrite,
2079 StreamRead,
2080}
2081
2082#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2083enum ShimKind<'a> {
2084 /// This shim is a late indirect lowering of an imported function in a
2085 /// component which is only possible after prior core wasm modules are
2086 /// instantiated so their memories and functions are available.
2087 IndirectLowering {
2088 /// The name of the interface that's being lowered.
2089 interface: Option<String>,
2090 /// The index within the `lowerings` array of the function being lowered.
2091 index: usize,
2092 /// Which instance to pull the `realloc` function from, if necessary.
2093 realloc: CustomModule<'a>,
2094 /// The string encoding that this lowering is going to use.
2095 encoding: StringEncoding,
2096 },
2097 /// This shim is a core wasm function defined in an adapter module but isn't
2098 /// available until the adapter module is itself instantiated.
2099 Adapter {
2100 /// The name of the adapter module this shim comes from.
2101 adapter: &'a str,
2102 /// The name of the export in the adapter module this shim points to.
2103 func: &'a str,
2104 },
2105 /// A shim used as the destructor for a resource which allows defining the
2106 /// resource before the core module being instantiated.
2107 ResourceDtor {
2108 /// Which instance to pull the destructor function from.
2109 module: CustomModule<'a>,
2110 /// The exported function name of this destructor in the core module.
2111 export: &'a str,
2112 },
2113 /// A shim used for a `{stream|future}.{read|write}` built-in function,
2114 /// which must refer to the core module instance's memory from/to which
2115 /// payload values must be lifted/lowered.
2116 PayloadFunc {
2117 /// Which instance to pull the `realloc` function and string encoding
2118 /// from, if necessary.
2119 for_module: CustomModule<'a>,
2120 /// Whether this read/write call is using the `async` option.
2121 async_: bool,
2122 /// Additional information regarding the function where this `stream` or
2123 /// `future` type appeared, which we use in combination with
2124 /// `for_module` to determine which `realloc` and string encoding to
2125 /// use, as well as which type to specify when emitting the built-in.
2126 info: &'a PayloadInfo,
2127 /// Which variation of `{stream|future}.{read|write}` we're emitting.
2128 kind: PayloadFuncKind,
2129 },
2130 /// A shim used for the `task.wait` built-in function, which must refer to
2131 /// the core module instance's memory to which results will be written.
2132 TaskWait { async_: bool },
2133 /// A shim used for the `task.poll` built-in function, which must refer to
2134 /// the core module instance's memory to which results will be written.
2135 TaskPoll { async_: bool },
2136 /// A shim used for the `error-context.new` built-in function, which must
2137 /// refer to the core module instance's memory from which the debug message
2138 /// will be read.
2139 ErrorContextNew {
2140 /// String encoding to use when lifting the debug message.
2141 encoding: StringEncoding,
2142 },
2143 /// A shim used for the `error-context.debug-message` built-in function,
2144 /// which must refer to the core module instance's memory to which results
2145 /// will be written.
2146 ErrorContextDebugMessage {
2147 /// Which instance to pull the `realloc` function from, if necessary.
2148 for_module: CustomModule<'a>,
2149 /// The string encoding to use when lowering the debug message.
2150 encoding: StringEncoding,
2151 /// The realloc function to use when allocating linear memory for the
2152 /// debug message.
2153 realloc: &'a str,
2154 },
2155}
2156
2157/// Indicator for which module is being used for a lowering or where options
2158/// like `realloc` are drawn from.
2159///
2160/// This is necessary for situations such as an imported function being lowered
2161/// into the main module and additionally into an adapter module. For example an
2162/// adapter might adapt from preview1 to preview2 for the standard library of a
2163/// programming language but the main module's custom application code may also
2164/// explicitly import from preview2. These two different lowerings of a preview2
2165/// function are parameterized by this enumeration.
2166#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
2167enum CustomModule<'a> {
2168 /// This points to the "main module" which is generally the "output of LLVM"
2169 /// or what a user wrote.
2170 Main,
2171 /// This is selecting an adapter module, identified by name here, where
2172 /// something is being lowered into.
2173 Adapter(&'a str),
2174}
2175
2176impl<'a> Shims<'a> {
2177 /// Adds all shims necessary for the instantiation of `for_module`.
2178 ///
2179 /// This function will iterate over all the imports required by this module
2180 /// and for those that require a shim they're registered here.
2181 fn append_indirect(
2182 &mut self,
2183 world: &'a ComponentWorld<'a>,
2184 for_module: CustomModule<'a>,
2185 ) -> Result<()> {
2186 let module_imports = world.imports_for(for_module);
2187 let module_exports = world.exports_for(for_module);
2188 let metadata = world.module_metadata_for(for_module);
2189 let resolve = &world.encoder.metadata.resolve;
2190
2191 let payload_push =
2192 |me: &mut Self, module, async_, info: &'a PayloadInfo, kind, params, results| {
2193 let debug_name = format!("{module}-{}", info.name);
2194 let name = me.shims.len().to_string();
2195 me.push(Shim {
2196 name,
2197 debug_name,
2198 options: RequiredOptions::empty(),
2199 kind: ShimKind::PayloadFunc {
2200 for_module,
2201 async_,
2202 info,
2203 kind,
2204 },
2205 sig: WasmSignature {
2206 params,
2207 results,
2208 indirect_params: false,
2209 retptr: false,
2210 },
2211 });
2212 };
2213
2214 for (module, field, import) in module_imports.imports() {
2215 let (key, name, interface_key, abi) = match import {
2216 // These imports don't require shims, they can be satisfied
2217 // as-needed when required.
2218 Import::ImportedResourceDrop(..)
2219 | Import::MainModuleMemory
2220 | Import::MainModuleExport { .. }
2221 | Import::Item(_)
2222 | Import::ExportedResourceDrop(..)
2223 | Import::ExportedResourceRep(..)
2224 | Import::ExportedResourceNew(..)
2225 | Import::ErrorContextDrop
2226 | Import::TaskBackpressure
2227 | Import::TaskYield { .. }
2228 | Import::SubtaskDrop
2229 | Import::ExportedTaskReturn(..)
2230 | Import::FutureNew(..)
2231 | Import::StreamNew(..)
2232 | Import::FutureCancelRead { .. }
2233 | Import::FutureCancelWrite { .. }
2234 | Import::FutureCloseWritable { .. }
2235 | Import::FutureCloseReadable { .. }
2236 | Import::StreamCancelRead { .. }
2237 | Import::StreamCancelWrite { .. }
2238 | Import::StreamCloseWritable { .. }
2239 | Import::StreamCloseReadable { .. } => continue,
2240
2241 Import::FutureWrite { async_, info } => {
2242 payload_push(
2243 self,
2244 module,
2245 *async_,
2246 info,
2247 PayloadFuncKind::FutureWrite,
2248 vec![WasmType::I32; 2],
2249 vec![WasmType::I32],
2250 );
2251 continue;
2252 }
2253 Import::FutureRead { async_, info } => {
2254 payload_push(
2255 self,
2256 module,
2257 *async_,
2258 info,
2259 PayloadFuncKind::FutureRead,
2260 vec![WasmType::I32; 2],
2261 vec![WasmType::I32],
2262 );
2263 continue;
2264 }
2265 Import::StreamWrite { async_, info } => {
2266 payload_push(
2267 self,
2268 module,
2269 *async_,
2270 info,
2271 PayloadFuncKind::StreamWrite,
2272 vec![WasmType::I32; 3],
2273 vec![WasmType::I32],
2274 );
2275 continue;
2276 }
2277 Import::StreamRead { async_, info } => {
2278 payload_push(
2279 self,
2280 module,
2281 *async_,
2282 info,
2283 PayloadFuncKind::StreamRead,
2284 vec![WasmType::I32; 3],
2285 vec![WasmType::I32],
2286 );
2287 continue;
2288 }
2289
2290 Import::TaskWait { async_ } => {
2291 let name = self.shims.len().to_string();
2292 self.push(Shim {
2293 name,
2294 debug_name: "task-wait".to_string(),
2295 options: RequiredOptions::empty(),
2296 kind: ShimKind::TaskWait { async_: *async_ },
2297 sig: WasmSignature {
2298 params: vec![WasmType::I32],
2299 results: vec![WasmType::I32],
2300 indirect_params: false,
2301 retptr: false,
2302 },
2303 });
2304 continue;
2305 }
2306
2307 Import::TaskPoll { async_ } => {
2308 let name = self.shims.len().to_string();
2309 self.push(Shim {
2310 name,
2311 debug_name: "task-poll".to_string(),
2312 options: RequiredOptions::empty(),
2313 kind: ShimKind::TaskPoll { async_: *async_ },
2314 sig: WasmSignature {
2315 params: vec![WasmType::I32],
2316 results: vec![WasmType::I32],
2317 indirect_params: false,
2318 retptr: false,
2319 },
2320 });
2321 continue;
2322 }
2323
2324 Import::ErrorContextNew { encoding } => {
2325 let name = self.shims.len().to_string();
2326 self.push(Shim {
2327 name,
2328 debug_name: "error-new".to_string(),
2329 options: RequiredOptions::empty(),
2330 kind: ShimKind::ErrorContextNew {
2331 encoding: *encoding,
2332 },
2333 sig: WasmSignature {
2334 params: vec![WasmType::I32; 2],
2335 results: vec![WasmType::I32],
2336 indirect_params: false,
2337 retptr: false,
2338 },
2339 });
2340 continue;
2341 }
2342
2343 Import::ErrorContextDebugMessage { encoding, realloc } => {
2344 let name = self.shims.len().to_string();
2345 self.push(Shim {
2346 name,
2347 debug_name: "error-debug-message".to_string(),
2348 options: RequiredOptions::empty(),
2349 kind: ShimKind::ErrorContextDebugMessage {
2350 for_module,
2351 encoding: *encoding,
2352 realloc,
2353 },
2354 sig: WasmSignature {
2355 params: vec![WasmType::I32; 2],
2356 results: vec![],
2357 indirect_params: false,
2358 retptr: false,
2359 },
2360 });
2361 continue;
2362 }
2363
2364 // Adapter imports into the main module must got through an
2365 // indirection, so that's registered here.
2366 Import::AdapterExport(ty) => {
2367 let name = self.shims.len().to_string();
2368 log::debug!("shim {name} is adapter `{module}::{field}`");
2369 self.push(Shim {
2370 name,
2371 debug_name: format!("adapt-{module}-{field}"),
2372 // Pessimistically assume that all adapters require
2373 // memory in one form or another. While this isn't
2374 // technically true it's true enough for WASI.
2375 options: RequiredOptions::MEMORY,
2376 kind: ShimKind::Adapter {
2377 adapter: module,
2378 func: field,
2379 },
2380 sig: WasmSignature {
2381 params: ty.params().iter().map(to_wasm_type).collect(),
2382 results: ty.results().iter().map(to_wasm_type).collect(),
2383 indirect_params: false,
2384 retptr: false,
2385 },
2386 });
2387 continue;
2388
2389 fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType {
2390 match ty {
2391 wasmparser::ValType::I32 => WasmType::I32,
2392 wasmparser::ValType::I64 => WasmType::I64,
2393 wasmparser::ValType::F32 => WasmType::F32,
2394 wasmparser::ValType::F64 => WasmType::F64,
2395 _ => unreachable!(),
2396 }
2397 }
2398 }
2399
2400 // WIT-level functions may require an indirection, so yield some
2401 // metadata out of this `match` to the loop below to figure that
2402 // out.
2403 Import::InterfaceFunc(key, _, name, abi) => {
2404 (key, name, Some(resolve.name_world_key(key)), *abi)
2405 }
2406 Import::WorldFunc(key, name, abi) => (key, name, None, *abi),
2407 };
2408 let interface = &world.import_map[&interface_key];
2409 let (index, _, lowering) = interface.lowerings.get_full(&(name.clone(), abi)).unwrap();
2410 let shim_name = self.shims.len().to_string();
2411 match lowering {
2412 Lowering::Direct | Lowering::ResourceDrop(_) => {}
2413
2414 Lowering::Indirect { sig, options } => {
2415 log::debug!(
2416 "shim {shim_name} is import `{module}::{field}` lowering {index} `{name}`",
2417 );
2418 let encoding = metadata
2419 .import_encodings
2420 .get(resolve, key, name)
2421 .ok_or_else(|| {
2422 anyhow::anyhow!(
2423 "missing component metadata for import of \
2424 `{module}::{field}`"
2425 )
2426 })?;
2427 self.push(Shim {
2428 name: shim_name,
2429 debug_name: format!("indirect-{module}-{field}"),
2430 options: *options,
2431 kind: ShimKind::IndirectLowering {
2432 interface: interface_key,
2433 index,
2434 realloc: for_module,
2435 encoding,
2436 },
2437 sig: sig.clone(),
2438 });
2439 }
2440 }
2441 }
2442
2443 // In addition to all the shims added for imports above this module also
2444 // requires shims for resource destructors that it exports. Resource
2445 // types are declared before the module is instantiated so the actual
2446 // destructor is registered as a shim (defined here) and it's then
2447 // filled in with the module's exports later.
2448 for (export_name, export) in module_exports.iter() {
2449 let id = match export {
2450 Export::ResourceDtor(id) => id,
2451 _ => continue,
2452 };
2453 let resource = resolve.types[*id].name.as_ref().unwrap();
2454 let name = self.shims.len().to_string();
2455 self.push(Shim {
2456 name,
2457 debug_name: format!("dtor-{resource}"),
2458 options: RequiredOptions::empty(),
2459 kind: ShimKind::ResourceDtor {
2460 module: for_module,
2461 export: export_name,
2462 },
2463 sig: WasmSignature {
2464 params: vec![WasmType::I32],
2465 results: Vec::new(),
2466 indirect_params: false,
2467 retptr: false,
2468 },
2469 });
2470 }
2471
2472 Ok(())
2473 }
2474
2475 fn push(&mut self, shim: Shim<'a>) {
2476 // Only one shim per `ShimKind` is retained, so if it's already present
2477 // don't overwrite it. If it's not present though go ahead and insert
2478 // it.
2479 if !self.shims.contains_key(&shim.kind) {
2480 self.shims.insert(shim.kind.clone(), shim);
2481 }
2482 }
2483}
2484
2485/// Alias argument to an instantiation
2486#[derive(Clone, Debug)]
2487pub struct Item {
2488 pub alias: String,
2489 pub kind: ExportKind,
2490 pub which: MainOrAdapter,
2491 pub name: String,
2492}
2493
2494/// Module argument to an instantiation
2495#[derive(Debug, PartialEq, Clone)]
2496pub enum MainOrAdapter {
2497 Main,
2498 Adapter(String),
2499}
2500
2501impl MainOrAdapter {
2502 fn to_custom_module(&self) -> CustomModule<'_> {
2503 match self {
2504 MainOrAdapter::Main => CustomModule::Main,
2505 MainOrAdapter::Adapter(s: &String) => CustomModule::Adapter(s),
2506 }
2507 }
2508}
2509
2510/// Module instantiation argument
2511#[derive(Clone)]
2512pub enum Instance {
2513 /// Module argument
2514 MainOrAdapter(MainOrAdapter),
2515
2516 /// Alias argument
2517 Items(Vec<Item>),
2518}
2519
2520/// Provides fine-grained control of how a library module is instantiated
2521/// relative to other module instances
2522#[derive(Clone)]
2523pub struct LibraryInfo {
2524 /// If true, instantiate any shims prior to this module
2525 pub instantiate_after_shims: bool,
2526
2527 /// Instantiation arguments
2528 pub arguments: Vec<(String, Instance)>,
2529}
2530
2531/// Represents an adapter or library to be instantiated as part of the component
2532pub(super) struct Adapter {
2533 /// The wasm of the module itself, with `component-type` sections stripped
2534 wasm: Vec<u8>,
2535
2536 /// The metadata for the adapter
2537 metadata: ModuleMetadata,
2538
2539 /// The set of exports from the final world which are defined by this
2540 /// adapter or library
2541 required_exports: IndexSet<WorldKey>,
2542
2543 /// If present, treat this module as a library rather than a "minimal" adapter
2544 ///
2545 /// TODO: We should refactor how various flavors of module are represented
2546 /// and differentiated to avoid mistaking one for another.
2547 library_info: Option<LibraryInfo>,
2548}
2549
2550/// An encoder of components based on `wit` interface definitions.
2551#[derive(Default)]
2552pub struct ComponentEncoder {
2553 module: Vec<u8>,
2554 pub(super) metadata: Bindgen,
2555 validate: bool,
2556 pub(super) main_module_exports: IndexSet<WorldKey>,
2557 pub(super) adapters: IndexMap<String, Adapter>,
2558 import_name_map: HashMap<String, String>,
2559 realloc_via_memory_grow: bool,
2560 merge_imports_based_on_semver: Option<bool>,
2561 pub(super) reject_legacy_names: bool,
2562}
2563
2564impl ComponentEncoder {
2565 /// Set the core module to encode as a component.
2566 /// This method will also parse any component type information stored in custom sections
2567 /// inside the module, and add them as the interface, imports, and exports.
2568 /// It will also add any producers information inside the component type information to the
2569 /// core module.
2570 pub fn module(mut self, module: &[u8]) -> Result<Self> {
2571 let (wasm, metadata) = self.decode(module)?;
2572 let exports = self
2573 .merge_metadata(metadata)
2574 .context("failed merge WIT metadata for module with previous metadata")?;
2575 self.main_module_exports.extend(exports);
2576 self.module = if let Some(producers) = &self.metadata.producers {
2577 producers.add_to_wasm(&wasm)?
2578 } else {
2579 wasm.to_vec()
2580 };
2581 Ok(self)
2582 }
2583
2584 fn decode<'a>(&self, wasm: &'a [u8]) -> Result<(Cow<'a, [u8]>, Bindgen)> {
2585 let (bytes, metadata) = metadata::decode(wasm)?;
2586 match bytes {
2587 Some(wasm) => Ok((Cow::Owned(wasm), metadata)),
2588 None => Ok((Cow::Borrowed(wasm), metadata)),
2589 }
2590 }
2591
2592 fn merge_metadata(&mut self, metadata: Bindgen) -> Result<IndexSet<WorldKey>> {
2593 self.metadata.merge(metadata)
2594 }
2595
2596 /// Sets whether or not the encoder will validate its output.
2597 pub fn validate(mut self, validate: bool) -> Self {
2598 self.validate = validate;
2599 self
2600 }
2601
2602 /// Sets whether to merge imports based on semver to the specified value.
2603 ///
2604 /// This affects how when to WIT worlds are merged together, for example
2605 /// from two different libraries, whether their imports are unified when the
2606 /// semver version ranges for interface allow it.
2607 ///
2608 /// This is enabled by default.
2609 pub fn merge_imports_based_on_semver(mut self, merge: bool) -> Self {
2610 self.merge_imports_based_on_semver = Some(merge);
2611 self
2612 }
2613
2614 /// Sets whether to reject the historical mangling/name scheme for core wasm
2615 /// imports/exports as they map to the component model.
2616 ///
2617 /// The `wit-component` crate supported a different set of names prior to
2618 /// WebAssembly/component-model#378 and this can be used to disable this
2619 /// support.
2620 ///
2621 /// This is disabled by default.
2622 pub fn reject_legacy_names(mut self, reject: bool) -> Self {
2623 self.reject_legacy_names = reject;
2624 self
2625 }
2626
2627 /// Specifies a new adapter which is used to translate from a historical
2628 /// wasm ABI to the canonical ABI and the `interface` provided.
2629 ///
2630 /// This is primarily used to polyfill, for example,
2631 /// `wasi_snapshot_preview1` with a component-model using interface. The
2632 /// `name` provided is the module name of the adapter that is being
2633 /// polyfilled, for example `"wasi_snapshot_preview1"`.
2634 ///
2635 /// The `bytes` provided is a core wasm module which implements the `name`
2636 /// interface in terms of the `interface` interface. This core wasm module
2637 /// is severely restricted in its shape, for example it cannot have any data
2638 /// segments or element segments.
2639 ///
2640 /// The `interface` provided is the component-model-using-interface that the
2641 /// wasm module specified by `bytes` imports. The `bytes` will then import
2642 /// `interface` and export functions to get imported from the module `name`
2643 /// in the core wasm that's being wrapped.
2644 pub fn adapter(self, name: &str, bytes: &[u8]) -> Result<Self> {
2645 self.library_or_adapter(name, bytes, None)
2646 }
2647
2648 /// Specifies a shared-everything library to link into the component.
2649 ///
2650 /// Unlike adapters, libraries _may_ have data and/or element segments, but
2651 /// they must operate on an imported memory and table, respectively. In
2652 /// this case, the correct amount of space is presumed to have been
2653 /// statically allocated in the main module's memory and table at the
2654 /// offsets which the segments target, e.g. as arranged by
2655 /// [super::linking::Linker].
2656 ///
2657 /// Libraries are treated similarly to adapters, except that they are not
2658 /// "minified" the way adapters are, and instantiation is controlled
2659 /// declaratively via the `library_info` parameter.
2660 pub fn library(self, name: &str, bytes: &[u8], library_info: LibraryInfo) -> Result<Self> {
2661 self.library_or_adapter(name, bytes, Some(library_info))
2662 }
2663
2664 fn library_or_adapter(
2665 mut self,
2666 name: &str,
2667 bytes: &[u8],
2668 library_info: Option<LibraryInfo>,
2669 ) -> Result<Self> {
2670 let (wasm, mut metadata) = self.decode(bytes)?;
2671 // Merge the adapter's document into our own document to have one large
2672 // document, and then afterwards merge worlds as well.
2673 //
2674 // Note that the `metadata` tracking import/export encodings is removed
2675 // since this adapter can get different lowerings and is allowed to
2676 // differ from the main module. This is then tracked within the
2677 // `Adapter` structure produced below.
2678 let adapter_metadata = mem::take(&mut metadata.metadata);
2679 let exports = self.merge_metadata(metadata).with_context(|| {
2680 format!("failed to merge WIT packages of adapter `{name}` into main packages")
2681 })?;
2682 if let Some(library_info) = &library_info {
2683 // Validate that all referenced modules can be resolved.
2684 for (_, instance) in &library_info.arguments {
2685 let resolve = |which: &_| match which {
2686 MainOrAdapter::Main => Ok(()),
2687 MainOrAdapter::Adapter(name) => {
2688 if self.adapters.contains_key(name.as_str()) {
2689 Ok(())
2690 } else {
2691 Err(anyhow!("instance refers to unknown adapter `{name}`"))
2692 }
2693 }
2694 };
2695
2696 match instance {
2697 Instance::MainOrAdapter(which) => resolve(which)?,
2698 Instance::Items(items) => {
2699 for item in items {
2700 resolve(&item.which)?;
2701 }
2702 }
2703 }
2704 }
2705 }
2706 self.adapters.insert(
2707 name.to_string(),
2708 Adapter {
2709 wasm: wasm.to_vec(),
2710 metadata: adapter_metadata,
2711 required_exports: exports,
2712 library_info,
2713 },
2714 );
2715 Ok(self)
2716 }
2717
2718 /// True if the realloc and stack allocation should use memory.grow
2719 /// The default is to use the main module realloc
2720 /// Can be useful if cabi_realloc cannot be called before the host
2721 /// runtime is initialized.
2722 pub fn realloc_via_memory_grow(mut self, value: bool) -> Self {
2723 self.realloc_via_memory_grow = value;
2724 self
2725 }
2726
2727 /// The instance import name map to use.
2728 ///
2729 /// This is used to rename instance imports in the final component.
2730 ///
2731 /// For example, if there is an instance import `foo:bar/baz` and it is
2732 /// desired that the import actually be an `unlocked-dep` name, then
2733 /// `foo:bar/baz` can be mapped to `unlocked-dep=<a:b/c@{>=x.y.z}>`.
2734 ///
2735 /// Note: the replacement names are not validated during encoding unless
2736 /// the `validate` option is set to true.
2737 pub fn import_name_map(mut self, map: HashMap<String, String>) -> Self {
2738 self.import_name_map = map;
2739 self
2740 }
2741
2742 /// Encode the component and return the bytes.
2743 pub fn encode(&mut self) -> Result<Vec<u8>> {
2744 if self.module.is_empty() {
2745 bail!("a module is required when encoding a component");
2746 }
2747
2748 if self.merge_imports_based_on_semver.unwrap_or(true) {
2749 self.metadata
2750 .resolve
2751 .merge_world_imports_based_on_semver(self.metadata.world)?;
2752 }
2753
2754 let world = ComponentWorld::new(self).context("failed to decode world from module")?;
2755 let mut state = EncodingState {
2756 component: ComponentBuilder::default(),
2757 module_index: None,
2758 instance_index: None,
2759 memory_index: None,
2760 shim_instance_index: None,
2761 fixups_module_index: None,
2762 adapter_modules: IndexMap::new(),
2763 adapter_instances: IndexMap::new(),
2764 import_type_map: HashMap::new(),
2765 import_func_type_map: HashMap::new(),
2766 export_type_map: HashMap::new(),
2767 export_func_type_map: HashMap::new(),
2768 imported_instances: Default::default(),
2769 imported_funcs: Default::default(),
2770 exported_instances: Default::default(),
2771 aliased_core_items: Default::default(),
2772 info: &world,
2773 };
2774 state.encode_imports(&self.import_name_map)?;
2775 state.encode_core_modules();
2776 state.encode_core_instantiation()?;
2777 state.encode_exports(CustomModule::Main)?;
2778 for name in self.adapters.keys() {
2779 state.encode_exports(CustomModule::Adapter(name))?;
2780 }
2781 state
2782 .component
2783 .raw_custom_section(&crate::base_producers().raw_custom_section());
2784 let bytes = state.component.finish();
2785
2786 if self.validate {
2787 Validator::new()
2788 .validate_all(&bytes)
2789 .context("failed to validate component output")?;
2790 }
2791
2792 Ok(bytes)
2793 }
2794}
2795
2796impl ComponentWorld<'_> {
2797 /// Convenience function to lookup a module's import map.
2798 fn imports_for(&self, module: CustomModule) -> &ImportMap {
2799 match module {
2800 CustomModule::Main => &self.info.imports,
2801 CustomModule::Adapter(name) => &self.adapters[name].info.imports,
2802 }
2803 }
2804
2805 /// Convenience function to lookup a module's export map.
2806 fn exports_for(&self, module: CustomModule) -> &ExportMap {
2807 match module {
2808 CustomModule::Main => &self.info.exports,
2809 CustomModule::Adapter(name) => &self.adapters[name].info.exports,
2810 }
2811 }
2812
2813 /// Convenience function to lookup a module's metadata.
2814 fn module_metadata_for(&self, module: CustomModule) -> &ModuleMetadata {
2815 match module {
2816 CustomModule::Main => &self.encoder.metadata.metadata,
2817 CustomModule::Adapter(name) => &self.encoder.adapters[name].metadata,
2818 }
2819 }
2820}
2821
2822#[cfg(all(test, feature = "dummy-module"))]
2823mod test {
2824 use super::*;
2825 use crate::{dummy_module, embed_component_metadata};
2826 use wit_parser::ManglingAndAbi;
2827
2828 #[test]
2829 fn it_renames_imports() {
2830 let mut resolve = Resolve::new();
2831 let pkg = resolve
2832 .push_str(
2833 "test.wit",
2834 r#"
2835package test:wit;
2836
2837interface i {
2838 f: func();
2839}
2840
2841world test {
2842 import i;
2843 import foo: interface {
2844 f: func();
2845 }
2846}
2847"#,
2848 )
2849 .unwrap();
2850 let world = resolve.select_world(pkg, None).unwrap();
2851
2852 let mut module = dummy_module(&resolve, world, ManglingAndAbi::Standard32);
2853
2854 embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8).unwrap();
2855
2856 let encoded = ComponentEncoder::default()
2857 .import_name_map(HashMap::from([
2858 (
2859 "foo".to_string(),
2860 "unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>".to_string(),
2861 ),
2862 (
2863 "test:wit/i".to_string(),
2864 "locked-dep=<foo:bar/i@1.2.3>".to_string(),
2865 ),
2866 ]))
2867 .module(&module)
2868 .unwrap()
2869 .validate(true)
2870 .encode()
2871 .unwrap();
2872
2873 let wat = wasmprinter::print_bytes(encoded).unwrap();
2874 assert!(wat.contains("unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>"));
2875 assert!(wat.contains("locked-dep=<foo:bar/i@1.2.3>"));
2876 }
2877}
2878