1use crate::StringEncoding;
75use crate::metadata::{self, Bindgen, ModuleMetadata};
76use crate::validation::{
77 Export, ExportMap, Import, ImportInstance, ImportMap, PayloadInfo, PayloadType,
78};
79use anyhow::{Context, Result, anyhow, bail};
80use indexmap::{IndexMap, IndexSet};
81use std::borrow::Cow;
82use std::collections::HashMap;
83use std::hash::Hash;
84use std::mem;
85use wasm_encoder::*;
86use wasmparser::{Validator, WasmFeatures};
87use wit_parser::{
88 Function, FunctionKind, InterfaceId, LiveTypes, Param, Resolve, Stability, Type, TypeDefKind,
89 TypeId, TypeOwner, WorldItem, WorldKey,
90 abi::{AbiVariant, WasmSignature, WasmType},
91};
92
93const INDIRECT_TABLE_NAME: &str = "$imports";
94
95mod wit;
96pub use wit::{encode, encode_world};
97
98mod types;
99use types::{InstanceTypeEncoder, RootTypeEncoder, TypeEncodingMaps, ValtypeEncoder};
100mod world;
101use world::{ComponentWorld, ImportedInterface, Lowering};
102
103mod dedupe;
104pub(crate) use dedupe::ModuleImportMap;
105use wasm_metadata::AddMetadataField;
106
107fn to_val_type(ty: &WasmType) -> ValType {
108 match ty {
109 WasmType::I32 => ValType::I32,
110 WasmType::I64 => ValType::I64,
111 WasmType::F32 => ValType::F32,
112 WasmType::F64 => ValType::F64,
113 WasmType::Pointer => ValType::I32,
114 WasmType::PointerOrI64 => ValType::I64,
115 WasmType::Length => ValType::I32,
116 }
117}
118
119fn import_func_name(f: &Function) -> String {
120 match f.kind {
121 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
122 format!("import-func-{}", f.item_name())
123 }
124
125 FunctionKind::Method(_)
133 | FunctionKind::AsyncMethod(_)
134 | FunctionKind::Static(_)
135 | FunctionKind::AsyncStatic(_)
136 | FunctionKind::Constructor(_) => {
137 format!(
138 "import-{}",
139 f.name.replace('[', "").replace([']', '.', ' '], "-")
140 )
141 }
142 }
143}
144
145bitflags::bitflags! {
146 #[derive(Copy, Clone, Debug)]
149 pub struct RequiredOptions: u8 {
150 const MEMORY = 1 << 0;
153 const REALLOC = 1 << 1;
156 const STRING_ENCODING = 1 << 2;
159 const ASYNC = 1 << 3;
160 }
161}
162
163impl RequiredOptions {
164 fn for_import(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
165 let sig = resolve.wasm_signature(abi, func);
166 let mut ret = RequiredOptions::empty();
167 ret.add_lift(TypeContents::for_types(
169 resolve,
170 func.params.iter().map(|p| &p.ty),
171 ));
172 ret.add_lower(TypeContents::for_types(resolve, &func.result));
173
174 if sig.retptr || sig.indirect_params {
177 ret |= RequiredOptions::MEMORY;
178 }
179 if abi == AbiVariant::GuestImportAsync {
180 ret |= RequiredOptions::ASYNC;
181 }
182 ret
183 }
184
185 fn for_export(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
186 let sig = resolve.wasm_signature(abi, func);
187 let mut ret = RequiredOptions::empty();
188 ret.add_lower(TypeContents::for_types(
190 resolve,
191 func.params.iter().map(|p| &p.ty),
192 ));
193 ret.add_lift(TypeContents::for_types(resolve, &func.result));
194
195 if sig.retptr || sig.indirect_params {
199 ret |= RequiredOptions::MEMORY;
200 if sig.indirect_params {
201 ret |= RequiredOptions::REALLOC;
202 }
203 }
204 if let AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful = abi {
205 ret |= RequiredOptions::ASYNC;
206 ret |= task_return_options_and_type(resolve, func).0;
207 }
208 ret
209 }
210
211 fn add_lower(&mut self, types: TypeContents) {
212 if types.contains(TypeContents::NEEDS_MEMORY) {
216 *self |= RequiredOptions::MEMORY | RequiredOptions::REALLOC;
217 }
218 if types.contains(TypeContents::STRING) {
219 *self |= RequiredOptions::MEMORY
220 | RequiredOptions::STRING_ENCODING
221 | RequiredOptions::REALLOC;
222 }
223 }
224
225 fn add_lift(&mut self, types: TypeContents) {
226 if types.contains(TypeContents::NEEDS_MEMORY) {
230 *self |= RequiredOptions::MEMORY;
231 }
232 if types.contains(TypeContents::STRING) {
233 *self |= RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING;
234 }
235 }
236
237 fn into_iter(
238 self,
239 encoding: StringEncoding,
240 memory_index: Option<u32>,
241 realloc_index: Option<u32>,
242 ) -> Result<impl ExactSizeIterator<Item = CanonicalOption>> {
243 #[derive(Default)]
244 struct Iter {
245 options: [Option<CanonicalOption>; 5],
246 current: usize,
247 count: usize,
248 }
249
250 impl Iter {
251 fn push(&mut self, option: CanonicalOption) {
252 assert!(self.count < self.options.len());
253 self.options[self.count] = Some(option);
254 self.count += 1;
255 }
256 }
257
258 impl Iterator for Iter {
259 type Item = CanonicalOption;
260
261 fn next(&mut self) -> Option<Self::Item> {
262 if self.current == self.count {
263 return None;
264 }
265 let option = self.options[self.current];
266 self.current += 1;
267 option
268 }
269
270 fn size_hint(&self) -> (usize, Option<usize>) {
271 (self.count - self.current, Some(self.count - self.current))
272 }
273 }
274
275 impl ExactSizeIterator for Iter {}
276
277 let mut iter = Iter::default();
278
279 if self.contains(RequiredOptions::MEMORY) {
280 iter.push(CanonicalOption::Memory(memory_index.ok_or_else(|| {
281 anyhow!("module does not export a memory named `memory`")
282 })?));
283 }
284
285 if self.contains(RequiredOptions::REALLOC) {
286 iter.push(CanonicalOption::Realloc(realloc_index.ok_or_else(
287 || anyhow!("module does not export a function named `cabi_realloc`"),
288 )?));
289 }
290
291 if self.contains(RequiredOptions::STRING_ENCODING) {
292 iter.push(encoding.into());
293 }
294
295 if self.contains(RequiredOptions::ASYNC) {
296 iter.push(CanonicalOption::Async);
297 }
298
299 Ok(iter)
300 }
301}
302
303bitflags::bitflags! {
304 struct TypeContents: u8 {
307 const STRING = 1 << 0;
308 const NEEDS_MEMORY = 1 << 1;
309 }
310}
311
312impl TypeContents {
313 fn for_types<'a>(resolve: &Resolve, types: impl IntoIterator<Item = &'a Type>) -> Self {
314 let mut cur = TypeContents::empty();
315 for ty in types {
316 cur |= Self::for_type(resolve, ty);
317 }
318 cur
319 }
320
321 fn for_optional_types<'a>(
322 resolve: &Resolve,
323 types: impl Iterator<Item = Option<&'a Type>>,
324 ) -> Self {
325 Self::for_types(resolve, types.flatten())
326 }
327
328 fn for_optional_type(resolve: &Resolve, ty: Option<&Type>) -> Self {
329 match ty {
330 Some(ty) => Self::for_type(resolve, ty),
331 None => Self::empty(),
332 }
333 }
334
335 fn for_type(resolve: &Resolve, ty: &Type) -> Self {
336 match ty {
337 Type::Id(id) => match &resolve.types[*id].kind {
338 TypeDefKind::Handle(h) => match h {
339 wit_parser::Handle::Own(_) => Self::empty(),
340 wit_parser::Handle::Borrow(_) => Self::empty(),
341 },
342 TypeDefKind::Resource => Self::empty(),
343 TypeDefKind::Record(r) => Self::for_types(resolve, r.fields.iter().map(|f| &f.ty)),
344 TypeDefKind::Tuple(t) => Self::for_types(resolve, t.types.iter()),
345 TypeDefKind::Flags(_) => Self::empty(),
346 TypeDefKind::Option(t) => Self::for_type(resolve, t),
347 TypeDefKind::Result(r) => {
348 Self::for_optional_type(resolve, r.ok.as_ref())
349 | Self::for_optional_type(resolve, r.err.as_ref())
350 }
351 TypeDefKind::Variant(v) => {
352 Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref()))
353 }
354 TypeDefKind::Enum(_) => Self::empty(),
355 TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::NEEDS_MEMORY,
356 TypeDefKind::Map(k, v) => {
357 Self::for_type(resolve, k) | Self::for_type(resolve, v) | Self::NEEDS_MEMORY
358 }
359 TypeDefKind::FixedLengthList(t, _elements) => Self::for_type(resolve, t),
360 TypeDefKind::Type(t) => Self::for_type(resolve, t),
361 TypeDefKind::Future(_) => Self::empty(),
362 TypeDefKind::Stream(_) => Self::empty(),
363 TypeDefKind::Unknown => unreachable!(),
364 },
365 Type::String => Self::STRING,
366 _ => Self::empty(),
367 }
368 }
369}
370
371pub struct EncodingState<'a> {
373 component: ComponentBuilder,
375 module_index: Option<u32>,
379 instance_index: Option<u32>,
383 memory_index: Option<u32>,
387 shim_instance_index: Option<u32>,
391 fixups_module_index: Option<u32>,
395
396 adapter_modules: IndexMap<&'a str, u32>,
399 adapter_instances: IndexMap<&'a str, u32>,
401
402 instances: IndexMap<InterfaceId, u32>,
404 imported_funcs: IndexMap<String, u32>,
405
406 type_encoding_maps: TypeEncodingMaps<'a>,
411
412 aliased_core_items: HashMap<(u32, String), u32>,
418
419 info: &'a ComponentWorld<'a>,
421
422 export_task_initialization_wrappers: HashMap<String, u32>,
425}
426
427impl<'a> EncodingState<'a> {
428 fn encode_core_modules(&mut self) {
429 assert!(self.module_index.is_none());
430 let idx = self
431 .component
432 .core_module_raw(Some("main"), &self.info.encoder.module);
433 self.module_index = Some(idx);
434
435 for (name, adapter) in self.info.adapters.iter() {
436 let debug_name = if adapter.library_info.is_some() {
437 name.to_string()
438 } else {
439 format!("wit-component:adapter:{name}")
440 };
441 let idx = if self.info.encoder.debug_names {
442 let mut add_meta = wasm_metadata::AddMetadata::default();
443 add_meta.name = AddMetadataField::Set(debug_name.clone());
444 let wasm = add_meta
445 .to_wasm(&adapter.wasm)
446 .expect("core wasm can get name added");
447 self.component.core_module_raw(Some(&debug_name), &wasm)
448 } else {
449 self.component
450 .core_module_raw(Some(&debug_name), &adapter.wasm)
451 };
452 let prev = self.adapter_modules.insert(name, idx);
453 assert!(prev.is_none());
454 }
455 }
456
457 fn root_import_type_encoder(
458 &mut self,
459 interface: Option<InterfaceId>,
460 ) -> RootTypeEncoder<'_, 'a> {
461 RootTypeEncoder {
462 state: self,
463 interface,
464 import_types: true,
465 }
466 }
467
468 fn root_export_type_encoder(
469 &mut self,
470 interface: Option<InterfaceId>,
471 ) -> RootTypeEncoder<'_, 'a> {
472 RootTypeEncoder {
473 state: self,
474 interface,
475 import_types: false,
476 }
477 }
478
479 fn instance_type_encoder(&mut self, interface: InterfaceId) -> InstanceTypeEncoder<'_, 'a> {
480 InstanceTypeEncoder {
481 state: self,
482 interface,
483 type_encoding_maps: Default::default(),
484 ty: Default::default(),
485 }
486 }
487
488 fn encode_imports(&mut self, name_map: &HashMap<String, String>) -> Result<()> {
489 let mut has_funcs = false;
490 for (name, info) in self.info.import_map.iter() {
491 match name {
492 Some(name) => {
493 self.encode_interface_import(name_map.get(name).unwrap_or(name), info)?
494 }
495 None => has_funcs = true,
496 }
497 }
498
499 let resolve = &self.info.encoder.metadata.resolve;
500 let world = &resolve.worlds[self.info.encoder.metadata.world];
501
502 for (_name, item) in world.imports.iter() {
505 if let WorldItem::Type { id, .. } = item {
506 self.root_import_type_encoder(None)
507 .encode_valtype(resolve, &Type::Id(*id))?;
508 }
509 }
510
511 if has_funcs {
512 let info = &self.info.import_map[&None];
513 self.encode_root_import_funcs(info)?;
514 }
515 Ok(())
516 }
517
518 fn encode_interface_import(&mut self, name: &str, info: &ImportedInterface) -> Result<()> {
519 let resolve = &self.info.encoder.metadata.resolve;
520 let interface_id = info.interface.as_ref().unwrap();
521 let interface_id = *interface_id;
522 let interface = &resolve.interfaces[interface_id];
523 log::trace!("encoding imports for `{name}` as {interface_id:?}");
524 let mut encoder = self.instance_type_encoder(interface_id);
525
526 if let Some(live) = encoder.state.info.live_type_imports.get(&interface_id) {
528 for ty in live {
529 log::trace!(
530 "encoding extra type {ty:?} name={:?}",
531 resolve.types[*ty].name
532 );
533 encoder.encode_valtype(resolve, &Type::Id(*ty))?;
534 }
535 }
536
537 for (_, func) in interface.functions.iter() {
540 if !(info
541 .lowerings
542 .contains_key(&(func.name.clone(), AbiVariant::GuestImport))
543 || info
544 .lowerings
545 .contains_key(&(func.name.clone(), AbiVariant::GuestImportAsync)))
546 {
547 continue;
548 }
549 log::trace!("encoding function type for `{}`", func.name);
550 let idx = encoder.encode_func_type(resolve, func)?;
551
552 encoder.ty.export(
553 crate::encoding::types::extern_name(&func.name, func.external_id.as_deref()),
554 ComponentTypeRef::Func(idx),
555 );
556 }
557
558 let ty = encoder.ty;
559 if ty.is_empty() {
562 return Ok(());
563 }
564 let instance_type_idx = self
565 .component
566 .type_instance(Some(&format!("ty-{name}")), &ty);
567 let instance_idx = self.component.import(
568 wasm_encoder::ComponentExternName {
569 name: name.into(),
570 implements: info.implements.as_deref().map(|s| s.into()),
571 external_id: info.external_id.as_deref().map(|s| s.into()),
572 version_suffix: None,
573 },
574 ComponentTypeRef::Instance(instance_type_idx),
575 );
576 let prev = self.instances.insert(interface_id, instance_idx);
577 assert!(prev.is_none());
578 Ok(())
579 }
580
581 fn encode_root_import_funcs(&mut self, info: &ImportedInterface) -> Result<()> {
582 let resolve = &self.info.encoder.metadata.resolve;
583 let world = self.info.encoder.metadata.world;
584 for (name, item) in resolve.worlds[world].imports.iter() {
585 let func = match item {
586 WorldItem::Function(f) => f,
587 WorldItem::Interface { .. } | WorldItem::Type { .. } => continue,
588 };
589 let name = resolve.name_world_key(name);
590 if !(info
591 .lowerings
592 .contains_key(&(name.clone(), AbiVariant::GuestImport))
593 || info
594 .lowerings
595 .contains_key(&(name.clone(), AbiVariant::GuestImportAsync)))
596 {
597 continue;
598 }
599 log::trace!("encoding function type for `{}`", func.name);
600 let idx = self
601 .root_import_type_encoder(None)
602 .encode_func_type(resolve, func)?;
603 let func_idx = self.component.import(
604 crate::encoding::types::extern_name(name.as_str(), func.external_id.as_deref()),
605 ComponentTypeRef::Func(idx),
606 );
607 let prev = self.imported_funcs.insert(name, func_idx);
608 assert!(prev.is_none());
609 }
610 Ok(())
611 }
612
613 fn alias_instance_type_export(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
614 let ty = &self.info.encoder.metadata.resolve.types[id];
615 let name = ty.name.as_ref().expect("type must have a name");
616 let instance = self.instances[&interface];
617 self.component
618 .alias_export(instance, name, ComponentExportKind::Type)
619 }
620
621 fn encode_core_instantiation(&mut self) -> Result<()> {
622 let shims = self.encode_shim_instantiation()?;
624
625 self.declare_types_for_imported_intrinsics(&shims)?;
629
630 self.instantiate_main_module(&shims)?;
634
635 let (before, after) = self
638 .info
639 .adapters
640 .iter()
641 .partition::<Vec<_>, _>(|(_, adapter)| {
642 !matches!(
643 adapter.library_info,
644 Some(LibraryInfo {
645 instantiate_after_shims: true,
646 ..
647 })
648 )
649 });
650
651 for (name, _adapter) in before {
652 self.instantiate_adapter_module(&shims, name)?;
653 }
654
655 self.encode_indirect_lowerings(&shims)?;
658
659 for (name, _adapter) in after {
660 self.instantiate_adapter_module(&shims, name)?;
661 }
662
663 self.encode_initialize_with_start()?;
664
665 self.create_export_task_initialization_wrappers()?;
668
669 Ok(())
670 }
671
672 fn lookup_resource_index(&mut self, id: TypeId) -> u32 {
673 let resolve = &self.info.encoder.metadata.resolve;
674 let ty = &resolve.types[id];
675 match ty.owner {
676 TypeOwner::World(_) => self.type_encoding_maps.id_to_index[&id],
680 TypeOwner::Interface(i) => {
681 let instance = self.instances[&i];
682 let name = ty.name.as_ref().expect("resources must be named");
683 self.component
684 .alias_export(instance, name, ComponentExportKind::Type)
685 }
686 TypeOwner::None => panic!("resources must have an owner"),
687 }
688 }
689
690 fn encode_exports(&mut self, module: CustomModule) -> Result<()> {
691 let resolve = &self.info.encoder.metadata.resolve;
692 let exports = match module {
693 CustomModule::Main => &self.info.encoder.main_module_exports,
694 CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports,
695 };
696
697 if exports.is_empty() {
698 return Ok(());
699 }
700
701 let mut interface_func_core_names = IndexMap::new();
702 let mut world_func_core_names = IndexMap::new();
703 for (core_name, export) in self.info.exports_for(module).iter() {
704 match export {
705 Export::WorldFunc(_, name, _) => {
706 let prev = world_func_core_names.insert(name, core_name);
707 assert!(prev.is_none());
708 }
709 Export::InterfaceFunc(key, _, name, _) => {
710 let prev = interface_func_core_names
711 .entry(key)
712 .or_insert(IndexMap::new())
713 .insert(name.as_str(), core_name);
714 assert!(prev.is_none());
715 }
716 Export::WorldFuncCallback(..)
717 | Export::InterfaceFuncCallback(..)
718 | Export::WorldFuncPostReturn(..)
719 | Export::InterfaceFuncPostReturn(..)
720 | Export::ResourceDtor(..)
721 | Export::Memory
722 | Export::GeneralPurposeRealloc
723 | Export::GeneralPurposeExportRealloc
724 | Export::GeneralPurposeImportRealloc
725 | Export::Initialize
726 | Export::ReallocForAdapter
727 | Export::IndirectFunctionTable
728 | Export::WasmInitTask
729 | Export::WasmInitAsyncTask => continue,
730 }
731 }
732
733 let world = &resolve.worlds[self.info.encoder.metadata.world];
734
735 for export_name in exports {
736 let export_string = resolve.name_world_key(export_name);
737 match &world.exports[export_name] {
738 WorldItem::Function(func) => {
739 let ty = self
740 .root_import_type_encoder(None)
741 .encode_func_type(resolve, func)?;
742 let core_name = world_func_core_names[&func.name];
743 let idx = self.encode_lift(module, &core_name, export_name, func, ty)?;
744 self.component.export(
745 crate::encoding::types::extern_name(
746 &export_string,
747 func.external_id.as_deref(),
748 ),
749 ComponentExportKind::Func,
750 idx,
751 None,
752 );
753 }
754 item @ WorldItem::Interface { id, .. } => {
755 let core_names = interface_func_core_names.get(export_name);
756 self.encode_interface_export(
757 &export_string,
758 module,
759 export_name,
760 item,
761 *id,
762 core_names,
763 )?;
764 }
765 WorldItem::Type { .. } => unreachable!(),
766 }
767 }
768
769 Ok(())
770 }
771
772 fn encode_interface_export(
773 &mut self,
774 export_name: &str,
775 module: CustomModule<'_>,
776 key: &WorldKey,
777 item: &WorldItem,
778 export: InterfaceId,
779 interface_func_core_names: Option<&IndexMap<&str, &str>>,
780 ) -> Result<()> {
781 log::trace!("encode interface export `{export_name}`");
782 let resolve = &self.info.encoder.metadata.resolve;
783
784 let mut imports = Vec::new();
791 let mut root = self.root_export_type_encoder(Some(export));
792 for (_, func) in &resolve.interfaces[export].functions {
793 let core_name = interface_func_core_names.unwrap()[func.name.as_str()];
794 let ty = root.encode_func_type(resolve, func)?;
795 let func_index = root.state.encode_lift(module, &core_name, key, func, ty)?;
796 imports.push((
797 import_func_name(func),
798 ComponentExportKind::Func,
799 func_index,
800 ));
801 }
802
803 let mut nested = NestedComponentTypeEncoder {
807 component: ComponentBuilder::default(),
808 type_encoding_maps: Default::default(),
809 export_types: false,
810 interface: export,
811 state: self,
812 imports: IndexMap::new(),
813 };
814
815 let mut types_to_import = LiveTypes::default();
825 types_to_import.add_interface(resolve, export);
826 let exports_used = &nested.state.info.exports_used[&export];
827 for ty in types_to_import.iter() {
828 if let TypeOwner::Interface(owner) = resolve.types[ty].owner {
829 if owner == export {
830 continue;
833 }
834
835 let mut encoder = if exports_used.contains(&owner) {
838 nested.state.root_export_type_encoder(Some(export))
839 } else {
840 nested.state.root_import_type_encoder(Some(export))
841 };
842 encoder.encode_valtype(resolve, &Type::Id(ty))?;
843
844 nested.interface = owner;
848 nested.encode_valtype(resolve, &Type::Id(ty))?;
849 }
850 }
851 nested.interface = export;
852
853 let imported_type_maps = nested.type_encoding_maps.clone();
857
858 let mut resources = HashMap::new();
864 for (_name, ty) in resolve.interfaces[export].types.iter() {
865 if !matches!(resolve.types[*ty].kind, TypeDefKind::Resource) {
866 continue;
867 }
868 let idx = match nested.encode_valtype(resolve, &Type::Id(*ty))? {
869 ComponentValType::Type(idx) => idx,
870 _ => unreachable!(),
871 };
872 resources.insert(*ty, idx);
873 }
874
875 for (_, func) in resolve.interfaces[export].functions.iter() {
879 let ty = nested.encode_func_type(resolve, func)?;
880 nested
881 .component
882 .import(&import_func_name(func), ComponentTypeRef::Func(ty));
883 }
884
885 let reverse_map = nested
892 .type_encoding_maps
893 .id_to_index
894 .drain()
895 .map(|p| (p.1, p.0))
896 .collect::<HashMap<_, _>>();
897 nested.type_encoding_maps.def_to_index.clear();
898 for (name, idx) in nested.imports.drain(..) {
899 let id = reverse_map[&idx];
900 let idx = nested.state.type_encoding_maps.id_to_index[&id];
901 imports.push((name, ComponentExportKind::Type, idx))
902 }
903
904 nested.type_encoding_maps = imported_type_maps;
909
910 nested.export_types = true;
917 nested.type_encoding_maps.func_type_map.clear();
918
919 for (_, id) in resolve.interfaces[export].types.iter() {
925 let ty = &resolve.types[*id];
926 match ty.kind {
927 TypeDefKind::Resource => {
928 let idx = nested.component.export(
929 crate::encoding::types::extern_name(
930 ty.name.as_ref().expect("resources must be named"),
931 ty.external_id.as_deref(),
932 ),
933 ComponentExportKind::Type,
934 resources[id],
935 None,
936 );
937 nested.type_encoding_maps.id_to_index.insert(*id, idx);
938 }
939 _ => {
940 nested.encode_valtype(resolve, &Type::Id(*id))?;
941 }
942 }
943 }
944
945 for (i, (_, func)) in resolve.interfaces[export].functions.iter().enumerate() {
946 let ty = nested.encode_func_type(resolve, func)?;
947 nested.component.export(
948 crate::encoding::types::extern_name(&func.name, func.external_id.as_deref()),
949 ComponentExportKind::Func,
950 i as u32,
951 Some(ComponentTypeRef::Func(ty)),
952 );
953 }
954
955 let component = nested.component;
959 let component_index = self
960 .component
961 .component(Some(&format!("{export_name}-shim-component")), component);
962 let instance_index = self.component.instantiate(
963 Some(&format!("{export_name}-shim-instance")),
964 component_index,
965 imports,
966 );
967 let idx = self.component.export(
968 wasm_encoder::ComponentExternName {
969 name: export_name.into(),
970 implements: resolve.implements_value(key, item).map(|s| s.into()),
971 external_id: resolve.external_id_value(key, item).map(|s| s.into()),
972 version_suffix: None,
973 },
974 ComponentExportKind::Instance,
975 instance_index,
976 None,
977 );
978 let prev = self.instances.insert(export, idx);
979 assert!(prev.is_none());
980
981 for (_name, id) in resolve.interfaces[export].types.iter() {
989 self.type_encoding_maps.id_to_index.remove(id);
990 self.type_encoding_maps
991 .def_to_index
992 .remove(&resolve.types[*id].kind);
993 }
994
995 return Ok(());
996
997 struct NestedComponentTypeEncoder<'state, 'a> {
998 component: ComponentBuilder,
999 type_encoding_maps: TypeEncodingMaps<'a>,
1000 export_types: bool,
1001 interface: InterfaceId,
1002 state: &'state mut EncodingState<'a>,
1003 imports: IndexMap<String, u32>,
1004 }
1005
1006 impl<'a> ValtypeEncoder<'a> for NestedComponentTypeEncoder<'_, 'a> {
1007 fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
1008 self.component.type_defined(None)
1009 }
1010 fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
1011 self.component.type_function(None)
1012 }
1013 fn export_type(
1014 &mut self,
1015 idx: u32,
1016 name: wasm_encoder::ComponentExternName<'a>,
1017 ) -> Option<u32> {
1018 if self.export_types {
1019 Some(
1020 self.component
1021 .export(name, ComponentExportKind::Type, idx, None),
1022 )
1023 } else {
1024 let name = self.unique_import_name(&name.name);
1025 let ret = self
1026 .component
1027 .import(&name, ComponentTypeRef::Type(TypeBounds::Eq(idx)));
1028 self.imports.insert(name, ret);
1029 Some(ret)
1030 }
1031 }
1032 fn export_resource(&mut self, name: wasm_encoder::ComponentExternName<'a>) -> u32 {
1033 if self.export_types {
1034 panic!("resources should already be exported")
1035 } else {
1036 let name = self.unique_import_name(&name.name);
1037 let ret = self
1038 .component
1039 .import(&name, ComponentTypeRef::Type(TypeBounds::SubResource));
1040 self.imports.insert(name, ret);
1041 ret
1042 }
1043 }
1044 fn import_type(&mut self, _: InterfaceId, _id: TypeId) -> u32 {
1045 unreachable!()
1046 }
1047 fn type_encoding_maps(&mut self) -> &mut TypeEncodingMaps<'a> {
1048 &mut self.type_encoding_maps
1049 }
1050 fn interface(&self) -> Option<InterfaceId> {
1051 Some(self.interface)
1052 }
1053 }
1054
1055 impl NestedComponentTypeEncoder<'_, '_> {
1056 fn unique_import_name(&mut self, name: &str) -> String {
1057 let mut name = format!("import-type-{name}");
1058 let mut n = 0;
1059 while self.imports.contains_key(&name) {
1060 name = format!("{name}{n}");
1061 n += 1;
1062 }
1063 name
1064 }
1065 }
1066 }
1067
1068 fn encode_lift(
1069 &mut self,
1070 module: CustomModule<'_>,
1071 core_name: &str,
1072 key: &WorldKey,
1073 func: &Function,
1074 ty: u32,
1075 ) -> Result<u32> {
1076 let resolve = &self.info.encoder.metadata.resolve;
1077 let metadata = self.info.module_metadata_for(module);
1078 let instance_index = self.instance_for(module);
1079 let core_func_index =
1082 if let Some(&wrapper_idx) = self.export_task_initialization_wrappers.get(core_name) {
1083 wrapper_idx
1084 } else {
1085 self.core_alias_export(Some(core_name), instance_index, core_name, ExportKind::Func)
1086 };
1087 let exports = self.info.exports_for(module);
1088
1089 let options = RequiredOptions::for_export(
1090 resolve,
1091 func,
1092 exports
1093 .abi(key, func)
1094 .ok_or_else(|| anyhow!("no ABI found for {}", func.name))?,
1095 );
1096
1097 let encoding = metadata
1098 .export_encodings
1099 .get(resolve, key, &func.name)
1100 .unwrap();
1101 let exports = self.info.exports_for(module);
1102 let realloc_index = exports
1103 .export_realloc_for(key, &func.name)
1104 .map(|name| self.core_alias_export(Some(name), instance_index, name, ExportKind::Func));
1105 let mut options = options
1106 .into_iter(encoding, self.memory_index, realloc_index)?
1107 .collect::<Vec<_>>();
1108
1109 if let Some(post_return) = exports.post_return(key, func) {
1110 let post_return = self.core_alias_export(
1111 Some(post_return),
1112 instance_index,
1113 post_return,
1114 ExportKind::Func,
1115 );
1116 options.push(CanonicalOption::PostReturn(post_return));
1117 }
1118 if let Some(callback) = exports.callback(key, func) {
1119 let callback =
1120 self.core_alias_export(Some(callback), instance_index, callback, ExportKind::Func);
1121 options.push(CanonicalOption::Callback(callback));
1122 }
1123 let func_index = self
1124 .component
1125 .lift_func(Some(&func.name), core_func_index, ty, options);
1126 Ok(func_index)
1127 }
1128
1129 fn encode_shim_instantiation(&mut self) -> Result<Shims<'a>> {
1130 let mut ret = Shims::default();
1131
1132 ret.append_indirect(self.info, CustomModule::Main)
1133 .context("failed to register indirect shims for main module")?;
1134
1135 for (adapter_name, _adapter) in self.info.adapters.iter() {
1139 ret.append_indirect(self.info, CustomModule::Adapter(adapter_name))
1140 .with_context(|| {
1141 format!("failed to register indirect shims for adapter {adapter_name}")
1142 })?;
1143 }
1144
1145 if ret.shims.is_empty() {
1146 return Ok(ret);
1147 }
1148
1149 assert!(self.shim_instance_index.is_none());
1150 assert!(self.fixups_module_index.is_none());
1151
1152 let mut types = TypeSection::new();
1161 let mut tables = TableSection::new();
1162 let mut functions = FunctionSection::new();
1163 let mut exports = ExportSection::new();
1164 let mut code = CodeSection::new();
1165 let mut sigs = IndexMap::new();
1166 let mut imports_section = ImportSection::new();
1167 let mut elements = ElementSection::new();
1168 let mut func_indexes = Vec::new();
1169 let mut func_names = NameMap::new();
1170
1171 for (i, shim) in ret.shims.values().enumerate() {
1172 let i = i as u32;
1173 let type_index = *sigs.entry(&shim.sig).or_insert_with(|| {
1174 let index = types.len();
1175 types.ty().function(
1176 shim.sig.params.iter().map(to_val_type),
1177 shim.sig.results.iter().map(to_val_type),
1178 );
1179 index
1180 });
1181
1182 functions.function(type_index);
1183 Self::encode_shim_function(type_index, i, &mut code, shim.sig.params.len() as u32);
1184 exports.export(&shim.name, ExportKind::Func, i);
1185
1186 imports_section.import("", &shim.name, EntityType::Function(type_index));
1187 func_indexes.push(i);
1188 func_names.append(i, &shim.debug_name);
1189 }
1190 let mut names = NameSection::new();
1191 names.module("wit-component:shim");
1192 names.functions(&func_names);
1193
1194 let table_type = TableType {
1195 element_type: RefType::FUNCREF,
1196 minimum: ret.shims.len() as u64,
1197 maximum: Some(ret.shims.len() as u64),
1198 table64: false,
1199 shared: false,
1200 };
1201
1202 tables.table(table_type);
1203
1204 exports.export(INDIRECT_TABLE_NAME, ExportKind::Table, 0);
1205 imports_section.import("", INDIRECT_TABLE_NAME, table_type);
1206
1207 elements.active(
1208 None,
1209 &ConstExpr::i32_const(0),
1210 Elements::Functions(func_indexes.into()),
1211 );
1212
1213 let mut shim = Module::new();
1214 shim.section(&types);
1215 shim.section(&functions);
1216 shim.section(&tables);
1217 shim.section(&exports);
1218 shim.section(&code);
1219 shim.section(&RawCustomSection(
1220 &crate::base_producers().raw_custom_section(),
1221 ));
1222 if self.info.encoder.debug_names {
1223 shim.section(&names);
1224 }
1225
1226 let mut fixups = Module::default();
1227 fixups.section(&types);
1228 fixups.section(&imports_section);
1229 fixups.section(&elements);
1230 fixups.section(&RawCustomSection(
1231 &crate::base_producers().raw_custom_section(),
1232 ));
1233
1234 if self.info.encoder.debug_names {
1235 let mut names = NameSection::new();
1236 names.module("wit-component:fixups");
1237 fixups.section(&names);
1238 }
1239
1240 let shim_module_index = self
1241 .component
1242 .core_module(Some("wit-component-shim-module"), &shim);
1243 let fixup_index = self
1244 .component
1245 .core_module(Some("wit-component-fixup"), &fixups);
1246 self.fixups_module_index = Some(fixup_index);
1247 let shim_instance = self.component.core_instantiate(
1248 Some("wit-component-shim-instance"),
1249 shim_module_index,
1250 [],
1251 );
1252 self.shim_instance_index = Some(shim_instance);
1253
1254 return Ok(ret);
1255 }
1256
1257 fn encode_shim_function(
1258 type_index: u32,
1259 func_index: u32,
1260 code: &mut CodeSection,
1261 param_count: u32,
1262 ) {
1263 let mut func = wasm_encoder::Function::new(std::iter::empty());
1264 for i in 0..param_count {
1265 func.instructions().local_get(i);
1266 }
1267 func.instructions().i32_const(func_index as i32);
1268 func.instructions().call_indirect(0, type_index);
1269 func.instructions().end();
1270 code.function(&func);
1271 }
1272
1273 fn encode_indirect_lowerings(&mut self, shims: &Shims<'_>) -> Result<()> {
1274 if shims.shims.is_empty() {
1275 return Ok(());
1276 }
1277
1278 let shim_instance_index = self
1279 .shim_instance_index
1280 .expect("must have an instantiated shim");
1281
1282 let table_index = self.core_alias_export(
1283 Some("shim table"),
1284 shim_instance_index,
1285 INDIRECT_TABLE_NAME,
1286 ExportKind::Table,
1287 );
1288
1289 let resolve = &self.info.encoder.metadata.resolve;
1290
1291 let mut exports = Vec::new();
1292 exports.push((INDIRECT_TABLE_NAME, ExportKind::Table, table_index));
1293
1294 for shim in shims.shims.values() {
1295 let core_func_index = match &shim.kind {
1296 ShimKind::IndirectLowering {
1303 interface,
1304 index,
1305 realloc,
1306 encoding,
1307 } => {
1308 let interface = &self.info.import_map[interface];
1309 let ((name, _), _) = interface.lowerings.get_index(*index).unwrap();
1310 let func_index = match &interface.interface {
1311 Some(interface_id) => {
1312 let instance_index = self.instances[interface_id];
1313 self.component.alias_export(
1314 instance_index,
1315 name,
1316 ComponentExportKind::Func,
1317 )
1318 }
1319 None => self.imported_funcs[name],
1320 };
1321
1322 let realloc = self
1323 .info
1324 .exports_for(*realloc)
1325 .import_realloc_for(interface.interface, name)
1326 .map(|name| {
1327 let instance = self.instance_for(*realloc);
1328 self.core_alias_export(
1329 Some("realloc"),
1330 instance,
1331 name,
1332 ExportKind::Func,
1333 )
1334 });
1335
1336 self.component.lower_func(
1337 Some(&shim.debug_name),
1338 func_index,
1339 shim.options
1340 .into_iter(*encoding, self.memory_index, realloc)?,
1341 )
1342 }
1343
1344 ShimKind::Adapter { adapter, func } => self.core_alias_export(
1349 Some(func),
1350 self.adapter_instances[adapter],
1351 func,
1352 ExportKind::Func,
1353 ),
1354
1355 ShimKind::ResourceDtor { module, export } => self.core_alias_export(
1360 Some(export),
1361 self.instance_for(*module),
1362 export,
1363 ExportKind::Func,
1364 ),
1365
1366 ShimKind::PayloadFunc {
1367 for_module,
1368 info,
1369 kind,
1370 } => {
1371 let metadata = self.info.module_metadata_for(*for_module);
1372 let exports = self.info.exports_for(*for_module);
1373 let instance_index = self.instance_for(*for_module);
1374 let (encoding, realloc) = match &info.ty {
1375 PayloadType::Type { function, .. } => {
1376 if info.imported {
1377 (
1378 metadata.import_encodings.get(resolve, &info.key, function),
1379 exports.import_realloc_for(info.interface, function),
1380 )
1381 } else {
1382 (
1383 metadata.export_encodings.get(resolve, &info.key, function),
1384 exports.export_realloc_for(&info.key, function),
1385 )
1386 }
1387 }
1388 PayloadType::UnitFuture | PayloadType::UnitStream => (None, None),
1389 };
1390 let encoding = encoding.unwrap_or(StringEncoding::UTF8);
1391 let realloc_index = realloc.map(|name| {
1392 self.core_alias_export(
1393 Some("realloc"),
1394 instance_index,
1395 name,
1396 ExportKind::Func,
1397 )
1398 });
1399 let type_index = self.payload_type_index(info)?;
1400 let options =
1401 shim.options
1402 .into_iter(encoding, self.memory_index, realloc_index)?;
1403
1404 match kind {
1405 PayloadFuncKind::FutureWrite => {
1406 self.component.future_write(type_index, options)
1407 }
1408 PayloadFuncKind::FutureRead => {
1409 self.component.future_read(type_index, options)
1410 }
1411 PayloadFuncKind::StreamWrite => {
1412 self.component.stream_write(type_index, options)
1413 }
1414 PayloadFuncKind::StreamRead => {
1415 self.component.stream_read(type_index, options)
1416 }
1417 }
1418 }
1419
1420 ShimKind::WaitableSetWait { cancellable } => self
1421 .component
1422 .waitable_set_wait(*cancellable, self.memory_index.unwrap()),
1423 ShimKind::WaitableSetPoll { cancellable } => self
1424 .component
1425 .waitable_set_poll(*cancellable, self.memory_index.unwrap()),
1426 ShimKind::ErrorContextNew { encoding } => self.component.error_context_new(
1427 shim.options.into_iter(*encoding, self.memory_index, None)?,
1428 ),
1429 ShimKind::ErrorContextDebugMessage {
1430 for_module,
1431 encoding,
1432 } => {
1433 let instance_index = self.instance_for(*for_module);
1434 let realloc = self.info.exports_for(*for_module).import_realloc_fallback();
1435 let realloc_index = realloc.map(|r| {
1436 self.core_alias_export(Some("realloc"), instance_index, r, ExportKind::Func)
1437 });
1438
1439 self.component
1440 .error_context_debug_message(shim.options.into_iter(
1441 *encoding,
1442 self.memory_index,
1443 realloc_index,
1444 )?)
1445 }
1446 ShimKind::TaskReturn {
1447 interface,
1448 func,
1449 result,
1450 encoding,
1451 for_module,
1452 } => {
1453 let mut encoder = if interface.is_none() {
1456 self.root_import_type_encoder(*interface)
1457 } else {
1458 self.root_export_type_encoder(*interface)
1459 };
1460 let result = match result {
1461 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1462 None => None,
1463 };
1464
1465 let exports = self.info.exports_for(*for_module);
1466 let realloc = exports.import_realloc_for(*interface, func);
1467
1468 let instance_index = self.instance_for(*for_module);
1469 let realloc_index = realloc.map(|r| {
1470 self.core_alias_export(Some("realloc"), instance_index, r, ExportKind::Func)
1471 });
1472 let options =
1473 shim.options
1474 .into_iter(*encoding, self.memory_index, realloc_index)?;
1475 self.component.task_return(result, options)
1476 }
1477 ShimKind::ThreadNewIndirect { func_ty } => {
1478 let (func_ty_idx, f) = self.component.core_type(Some("thread-start"));
1480 f.core().func_type(func_ty);
1481
1482 let exports = self.info.exports_for(CustomModule::Main);
1485 let instance_index = self.instance_for(CustomModule::Main);
1486 let table_idx = exports.indirect_function_table().map(|table| {
1487 self.core_alias_export(
1488 Some("indirect-function-table"),
1489 instance_index,
1490 table,
1491 ExportKind::Table,
1492 )
1493 }).ok_or_else(|| {
1494 anyhow!(
1495 "table __indirect_function_table must be an exported funcref table for thread.new-indirect"
1496 )
1497 })?;
1498
1499 self.component.thread_new_indirect(func_ty_idx, table_idx)
1500 }
1501 };
1502
1503 exports.push((shim.name.as_str(), ExportKind::Func, core_func_index));
1504 }
1505
1506 let instance_index = self
1507 .component
1508 .core_instantiate_exports(Some("fixup-args"), exports);
1509 self.component.core_instantiate(
1510 Some("fixup"),
1511 self.fixups_module_index.expect("must have fixup module"),
1512 [("", ModuleArg::Instance(instance_index))],
1513 );
1514 Ok(())
1515 }
1516
1517 fn payload_type_index(&mut self, info: &PayloadInfo) -> Result<u32> {
1525 let resolve = &self.info.encoder.metadata.resolve;
1526 let mut encoder = if info.imported || info.interface.is_none() {
1542 self.root_import_type_encoder(None)
1543 } else {
1544 self.root_export_type_encoder(info.interface)
1545 };
1546 match info.ty {
1547 PayloadType::Type { id, .. } => match encoder.encode_valtype(resolve, &Type::Id(id))? {
1548 ComponentValType::Type(index) => Ok(index),
1549 ComponentValType::Primitive(_) => unreachable!(),
1550 },
1551 PayloadType::UnitFuture => Ok(encoder.encode_unit_future()),
1552 PayloadType::UnitStream => Ok(encoder.encode_unit_stream()),
1553 }
1554 }
1555
1556 fn declare_types_for_imported_intrinsics(&mut self, shims: &Shims<'_>) -> Result<()> {
1563 let resolve = &self.info.encoder.metadata.resolve;
1564 let world = &resolve.worlds[self.info.encoder.metadata.world];
1565
1566 let main_module_keys = self.info.encoder.main_module_exports.iter();
1569 let main_module_keys = main_module_keys.map(|key| (CustomModule::Main, key));
1570 let adapter_keys = self.info.encoder.adapters.iter().flat_map(|(name, info)| {
1571 info.required_exports
1572 .iter()
1573 .map(move |key| (CustomModule::Adapter(name), key))
1574 });
1575 for (for_module, key) in main_module_keys.chain(adapter_keys) {
1576 let id = match &world.exports[key] {
1577 WorldItem::Interface { id, .. } => *id,
1578 WorldItem::Type { .. } => unreachable!(),
1579 WorldItem::Function(_) => continue,
1580 };
1581
1582 for ty in resolve.interfaces[id].types.values() {
1583 let def = &resolve.types[*ty];
1584 match &def.kind {
1585 TypeDefKind::Resource => {
1589 let exports = self.info.exports_for(for_module);
1592 let dtor = exports.resource_dtor(*ty).map(|name| {
1593 let shim = &shims.shims[&ShimKind::ResourceDtor {
1594 module: for_module,
1595 export: name,
1596 }];
1597 let index = self.shim_instance_index.unwrap();
1598 self.core_alias_export(
1599 Some(&shim.debug_name),
1600 index,
1601 &shim.name,
1602 ExportKind::Func,
1603 )
1604 });
1605
1606 let resource_idx = self.component.type_resource(
1610 Some(def.name.as_ref().unwrap()),
1611 ValType::I32,
1612 dtor,
1613 );
1614 let prev = self
1615 .type_encoding_maps
1616 .id_to_index
1617 .insert(*ty, resource_idx);
1618 assert!(prev.is_none());
1619 }
1620 _other => {
1621 self.root_export_type_encoder(Some(id))
1622 .encode_valtype(resolve, &Type::Id(*ty))?;
1623 }
1624 }
1625 }
1626 }
1627 Ok(())
1628 }
1629
1630 fn instantiate_main_module(&mut self, shims: &Shims<'_>) -> Result<()> {
1633 assert!(self.instance_index.is_none());
1634
1635 let instance_index = self.instantiate_core_module(shims, CustomModule::Main)?;
1636
1637 if let Some(memory) = self.info.info.exports.memory() {
1638 self.memory_index = Some(self.core_alias_export(
1639 Some("memory"),
1640 instance_index,
1641 memory,
1642 ExportKind::Memory,
1643 ));
1644 }
1645
1646 self.instance_index = Some(instance_index);
1647 Ok(())
1648 }
1649
1650 fn instantiate_adapter_module(&mut self, shims: &Shims<'_>, name: &'a str) -> Result<()> {
1653 let instance = self.instantiate_core_module(shims, CustomModule::Adapter(name))?;
1654 self.adapter_instances.insert(name, instance);
1655 Ok(())
1656 }
1657
1658 fn instantiate_core_module(
1665 &mut self,
1666 shims: &Shims,
1667 for_module: CustomModule<'_>,
1668 ) -> Result<u32> {
1669 let module = self.module_for(for_module);
1670
1671 let mut args = Vec::new();
1672 for (core_wasm_name, instance) in self.info.imports_for(for_module).modules() {
1673 match instance {
1674 ImportInstance::Names(names) => {
1680 let mut exports = Vec::new();
1681 for (name, import) in names {
1682 log::trace!(
1683 "attempting to materialize import of `{core_wasm_name}::{name}` for {for_module:?}"
1684 );
1685 let (kind, index) = self
1686 .materialize_import(&shims, for_module, import)
1687 .with_context(|| {
1688 format!("failed to satisfy import `{core_wasm_name}::{name}`")
1689 })?;
1690 exports.push((name.as_str(), kind, index));
1691 }
1692 let index = self
1693 .component
1694 .core_instantiate_exports(Some(core_wasm_name), exports);
1695 args.push((core_wasm_name.as_str(), ModuleArg::Instance(index)));
1696 }
1697
1698 ImportInstance::Whole(which) => {
1701 let instance = self.instance_for(which.to_custom_module());
1702 args.push((core_wasm_name.as_str(), ModuleArg::Instance(instance)));
1703 }
1704 }
1705 }
1706
1707 Ok(self
1709 .component
1710 .core_instantiate(Some(for_module.debug_name()), module, args))
1711 }
1712
1713 fn materialize_import(
1720 &mut self,
1721 shims: &Shims<'_>,
1722 for_module: CustomModule<'_>,
1723 import: &'a Import,
1724 ) -> Result<(ExportKind, u32)> {
1725 let resolve = &self.info.encoder.metadata.resolve;
1726 match import {
1727 Import::AdapterExport {
1730 adapter,
1731 func,
1732 ty: _,
1733 } => {
1734 assert!(self.info.encoder.adapters.contains_key(adapter));
1735 Ok(self.materialize_shim_import(shims, &ShimKind::Adapter { adapter, func }))
1736 }
1737
1738 Import::MainModuleMemory => {
1741 let index = self
1742 .memory_index
1743 .ok_or_else(|| anyhow!("main module cannot import memory"))?;
1744 Ok((ExportKind::Memory, index))
1745 }
1746
1747 Import::MainModuleExport { name, kind } => {
1749 let instance = self.instance_index.unwrap();
1750 let index = self.core_alias_export(Some(name), instance, name, *kind);
1751 Ok((*kind, index))
1752 }
1753
1754 Import::Item(item) => {
1758 let instance = self.instance_for(item.which.to_custom_module());
1759 let index =
1760 self.core_alias_export(Some(&item.name), instance, &item.name, item.kind);
1761 Ok((item.kind, index))
1762 }
1763
1764 Import::ExportedResourceDrop(_key, id) => {
1770 let index = self
1771 .component
1772 .resource_drop(self.type_encoding_maps.id_to_index[id]);
1773 Ok((ExportKind::Func, index))
1774 }
1775 Import::ExportedResourceRep(_key, id) => {
1776 let index = self
1777 .component
1778 .resource_rep(self.type_encoding_maps.id_to_index[id]);
1779 Ok((ExportKind::Func, index))
1780 }
1781 Import::ExportedResourceNew(_key, id) => {
1782 let index = self
1783 .component
1784 .resource_new(self.type_encoding_maps.id_to_index[id]);
1785 Ok((ExportKind::Func, index))
1786 }
1787
1788 Import::ImportedResourceDrop(key, iface, id) => {
1793 let ty = &resolve.types[*id];
1794 let name = ty.name.as_ref().unwrap();
1795 self.materialize_wit_import(
1796 shims,
1797 for_module,
1798 iface.map(|_| resolve.name_world_key(key)),
1799 &format!("{name}_drop"),
1800 key,
1801 AbiVariant::GuestImport,
1802 )
1803 }
1804 Import::ExportedTaskReturn(key, interface, func) => {
1805 let (options, _sig) = task_return_options_and_type(resolve, func);
1806 let result_ty = func.result;
1807 if options.is_empty() {
1808 let mut encoder = if interface.is_none() {
1814 self.root_import_type_encoder(*interface)
1815 } else {
1816 self.root_export_type_encoder(*interface)
1817 };
1818
1819 let result = match result_ty.as_ref() {
1820 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1821 None => None,
1822 };
1823 let index = self.component.task_return(result, []);
1824 Ok((ExportKind::Func, index))
1825 } else {
1826 let metadata = &self.info.module_metadata_for(for_module);
1827 let encoding = metadata
1828 .export_encodings
1829 .get(resolve, key, &func.name)
1830 .unwrap();
1831 Ok(self.materialize_shim_import(
1832 shims,
1833 &ShimKind::TaskReturn {
1834 for_module,
1835 interface: *interface,
1836 func: &func.name,
1837 result: result_ty,
1838 encoding,
1839 },
1840 ))
1841 }
1842 }
1843 Import::BackpressureInc => {
1844 let index = self.component.backpressure_inc();
1845 Ok((ExportKind::Func, index))
1846 }
1847 Import::BackpressureDec => {
1848 let index = self.component.backpressure_dec();
1849 Ok((ExportKind::Func, index))
1850 }
1851 Import::WaitableSetWait { cancellable } => Ok(self.materialize_shim_import(
1852 shims,
1853 &ShimKind::WaitableSetWait {
1854 cancellable: *cancellable,
1855 },
1856 )),
1857 Import::WaitableSetPoll { cancellable } => Ok(self.materialize_shim_import(
1858 shims,
1859 &ShimKind::WaitableSetPoll {
1860 cancellable: *cancellable,
1861 },
1862 )),
1863 Import::SubtaskDrop => {
1864 let index = self.component.subtask_drop();
1865 Ok((ExportKind::Func, index))
1866 }
1867 Import::SubtaskCancel { async_ } => {
1868 let index = self.component.subtask_cancel(*async_);
1869 Ok((ExportKind::Func, index))
1870 }
1871 Import::StreamNew(info) => {
1872 let ty = self.payload_type_index(info)?;
1873 let index = self.component.stream_new(ty);
1874 Ok((ExportKind::Func, index))
1875 }
1876 Import::StreamRead { info, .. } => Ok(self.materialize_payload_import(
1877 shims,
1878 for_module,
1879 info,
1880 PayloadFuncKind::StreamRead,
1881 )),
1882 Import::StreamWrite { info, .. } => Ok(self.materialize_payload_import(
1883 shims,
1884 for_module,
1885 info,
1886 PayloadFuncKind::StreamWrite,
1887 )),
1888 Import::StreamCancelRead { info, async_ } => {
1889 let ty = self.payload_type_index(info)?;
1890 let index = self.component.stream_cancel_read(ty, *async_);
1891 Ok((ExportKind::Func, index))
1892 }
1893 Import::StreamCancelWrite { info, async_ } => {
1894 let ty = self.payload_type_index(info)?;
1895 let index = self.component.stream_cancel_write(ty, *async_);
1896 Ok((ExportKind::Func, index))
1897 }
1898 Import::StreamDropReadable(info) => {
1899 let type_index = self.payload_type_index(info)?;
1900 let index = self.component.stream_drop_readable(type_index);
1901 Ok((ExportKind::Func, index))
1902 }
1903 Import::StreamDropWritable(info) => {
1904 let type_index = self.payload_type_index(info)?;
1905 let index = self.component.stream_drop_writable(type_index);
1906 Ok((ExportKind::Func, index))
1907 }
1908 Import::FutureNew(info) => {
1909 let ty = self.payload_type_index(info)?;
1910 let index = self.component.future_new(ty);
1911 Ok((ExportKind::Func, index))
1912 }
1913 Import::FutureRead { info, .. } => Ok(self.materialize_payload_import(
1914 shims,
1915 for_module,
1916 info,
1917 PayloadFuncKind::FutureRead,
1918 )),
1919 Import::FutureWrite { info, .. } => Ok(self.materialize_payload_import(
1920 shims,
1921 for_module,
1922 info,
1923 PayloadFuncKind::FutureWrite,
1924 )),
1925 Import::FutureCancelRead { info, async_ } => {
1926 let ty = self.payload_type_index(info)?;
1927 let index = self.component.future_cancel_read(ty, *async_);
1928 Ok((ExportKind::Func, index))
1929 }
1930 Import::FutureCancelWrite { info, async_ } => {
1931 let ty = self.payload_type_index(info)?;
1932 let index = self.component.future_cancel_write(ty, *async_);
1933 Ok((ExportKind::Func, index))
1934 }
1935 Import::FutureDropReadable(info) => {
1936 let type_index = self.payload_type_index(info)?;
1937 let index = self.component.future_drop_readable(type_index);
1938 Ok((ExportKind::Func, index))
1939 }
1940 Import::FutureDropWritable(info) => {
1941 let type_index = self.payload_type_index(info)?;
1942 let index = self.component.future_drop_writable(type_index);
1943 Ok((ExportKind::Func, index))
1944 }
1945 Import::ErrorContextNew { encoding } => Ok(self.materialize_shim_import(
1946 shims,
1947 &ShimKind::ErrorContextNew {
1948 encoding: *encoding,
1949 },
1950 )),
1951 Import::ErrorContextDebugMessage { encoding } => Ok(self.materialize_shim_import(
1952 shims,
1953 &ShimKind::ErrorContextDebugMessage {
1954 for_module,
1955 encoding: *encoding,
1956 },
1957 )),
1958 Import::ErrorContextDrop => {
1959 let index = self.component.error_context_drop();
1960 Ok((ExportKind::Func, index))
1961 }
1962 Import::WorldFunc(key, name, abi) => {
1963 self.materialize_wit_import(shims, for_module, None, name, key, *abi)
1964 }
1965 Import::InterfaceFunc(key, _, name, abi) => self.materialize_wit_import(
1966 shims,
1967 for_module,
1968 Some(resolve.name_world_key(key)),
1969 name,
1970 key,
1971 *abi,
1972 ),
1973
1974 Import::WaitableSetNew => {
1975 let index = self.component.waitable_set_new();
1976 Ok((ExportKind::Func, index))
1977 }
1978 Import::WaitableSetDrop => {
1979 let index = self.component.waitable_set_drop();
1980 Ok((ExportKind::Func, index))
1981 }
1982 Import::WaitableJoin => {
1983 let index = self.component.waitable_join();
1984 Ok((ExportKind::Func, index))
1985 }
1986 Import::ContextGet { ty, slot } => {
1987 let index = self.component.context_get((*ty).try_into()?, *slot);
1988 Ok((ExportKind::Func, index))
1989 }
1990 Import::ContextSet { ty, slot } => {
1991 let index = self.component.context_set((*ty).try_into()?, *slot);
1992 Ok((ExportKind::Func, index))
1993 }
1994 Import::ExportedTaskCancel => {
1995 let index = self.component.task_cancel();
1996 Ok((ExportKind::Func, index))
1997 }
1998 Import::ThreadIndex => {
1999 let index = self.component.thread_index();
2000 Ok((ExportKind::Func, index))
2001 }
2002 Import::ThreadNewIndirect => Ok(self.materialize_shim_import(
2003 shims,
2004 &ShimKind::ThreadNewIndirect {
2005 func_ty: FuncType::new([ValType::I32], []),
2007 },
2008 )),
2009 Import::ThreadResumeLater => {
2010 let index = self.component.thread_resume_later();
2011 Ok((ExportKind::Func, index))
2012 }
2013 Import::ThreadSuspend { cancellable } => {
2014 let index = self.component.thread_suspend(*cancellable);
2015 Ok((ExportKind::Func, index))
2016 }
2017 Import::ThreadYield { cancellable } => {
2018 let index = self.component.thread_yield(*cancellable);
2019 Ok((ExportKind::Func, index))
2020 }
2021 Import::ThreadSuspendThenResume { cancellable } => {
2022 let index = self.component.thread_suspend_then_resume(*cancellable);
2023 Ok((ExportKind::Func, index))
2024 }
2025 Import::ThreadYieldThenResume { cancellable } => {
2026 let index = self.component.thread_yield_then_resume(*cancellable);
2027 Ok((ExportKind::Func, index))
2028 }
2029 Import::ThreadSuspendThenPromote { cancellable } => {
2030 let index = self.component.thread_suspend_then_promote(*cancellable);
2031 Ok((ExportKind::Func, index))
2032 }
2033 Import::ThreadYieldThenPromote { cancellable } => {
2034 let index = self.component.thread_yield_then_promote(*cancellable);
2035 Ok((ExportKind::Func, index))
2036 }
2037 }
2038 }
2039
2040 fn materialize_shim_import(&mut self, shims: &Shims<'_>, kind: &ShimKind) -> (ExportKind, u32) {
2043 let index = self.core_alias_export(
2044 Some(&shims.shims[kind].debug_name),
2045 self.shim_instance_index
2046 .expect("shim should be instantiated"),
2047 &shims.shims[kind].name,
2048 ExportKind::Func,
2049 );
2050 (ExportKind::Func, index)
2051 }
2052
2053 fn materialize_payload_import(
2056 &mut self,
2057 shims: &Shims<'_>,
2058 for_module: CustomModule<'_>,
2059 info: &PayloadInfo,
2060 kind: PayloadFuncKind,
2061 ) -> (ExportKind, u32) {
2062 self.materialize_shim_import(
2063 shims,
2064 &ShimKind::PayloadFunc {
2065 for_module,
2066 info,
2067 kind,
2068 },
2069 )
2070 }
2071
2072 fn materialize_wit_import(
2075 &mut self,
2076 shims: &Shims<'_>,
2077 for_module: CustomModule<'_>,
2078 interface_key: Option<String>,
2079 name: &String,
2080 key: &WorldKey,
2081 abi: AbiVariant,
2082 ) -> Result<(ExportKind, u32)> {
2083 let resolve = &self.info.encoder.metadata.resolve;
2084 let import = &self.info.import_map[&interface_key];
2085 let (index, _, lowering) = import.lowerings.get_full(&(name.clone(), abi)).unwrap();
2086 let metadata = self.info.module_metadata_for(for_module);
2087
2088 let index = match lowering {
2089 Lowering::Direct => {
2092 let func_index = match &import.interface {
2093 Some(interface) => {
2094 let instance_index = self.instances[interface];
2095 self.component
2096 .alias_export(instance_index, name, ComponentExportKind::Func)
2097 }
2098 None => self.imported_funcs[name],
2099 };
2100 self.component.lower_func(
2101 Some(name),
2102 func_index,
2103 if let AbiVariant::GuestImportAsync = abi {
2104 vec![CanonicalOption::Async]
2105 } else {
2106 Vec::new()
2107 },
2108 )
2109 }
2110
2111 Lowering::Indirect { .. } => {
2115 let encoding = metadata.import_encodings.get(resolve, key, name).unwrap();
2116 return Ok(self.materialize_shim_import(
2117 shims,
2118 &ShimKind::IndirectLowering {
2119 interface: interface_key,
2120 index,
2121 realloc: for_module,
2122 encoding,
2123 },
2124 ));
2125 }
2126
2127 Lowering::ResourceDrop(id) => {
2130 let resource_idx = self.lookup_resource_index(*id);
2131 self.component.resource_drop(resource_idx)
2132 }
2133 };
2134 Ok((ExportKind::Func, index))
2135 }
2136
2137 fn encode_initialize_with_start(&mut self) -> Result<()> {
2156 let initialize = match self.info.info.exports.initialize() {
2157 Some(name) => name,
2158 None => return Ok(()),
2161 };
2162 let init_task = self.info.info.exports.wasm_init_task();
2163 let initialize_index = self.core_alias_export(
2164 Some("start"),
2165 self.instance_index.unwrap(),
2166 initialize,
2167 ExportKind::Func,
2168 );
2169 let init_task_index = init_task.map(|name| {
2170 self.core_alias_export(
2171 Some("init-task-for-start"),
2172 self.instance_index.unwrap(),
2173 name,
2174 ExportKind::Func,
2175 )
2176 });
2177 let mut shim = Module::default();
2178 let mut section = TypeSection::new();
2179 section.ty().function([], []);
2180 shim.section(§ion);
2181
2182 let mut section = ImportSection::new();
2183 section.import("", "", EntityType::Function(0));
2184 if init_task.is_some() {
2185 section.import("", "init", EntityType::Function(0));
2186 }
2187 shim.section(§ion);
2188
2189 if init_task.is_some() {
2190 let mut functions = FunctionSection::new();
2191 functions.function(0);
2192 shim.section(&functions);
2193 }
2194
2195 shim.section(&StartSection {
2196 function_index: if init_task.is_some() { 2 } else { 0 },
2197 });
2198
2199 if init_task.is_some() {
2200 let mut code = CodeSection::new();
2201 let mut func = wasm_encoder::Function::new([]);
2202 func.instructions().call(1);
2203 func.instructions().call(0);
2204 func.instructions().end();
2205 code.function(&func);
2206 shim.section(&code);
2207 }
2208
2209 let shim_module_index = self.component.core_module(Some("start-shim-module"), &shim);
2214 let mut shim_args = vec![("", ExportKind::Func, initialize_index)];
2215 if let Some(i) = init_task_index {
2216 shim_args.push(("init", ExportKind::Func, i));
2217 }
2218 let shim_args_instance_index = self
2219 .component
2220 .core_instantiate_exports(Some("start-shim-args"), shim_args);
2221 self.component.core_instantiate(
2222 Some("start-shim-instance"),
2223 shim_module_index,
2224 [("", ModuleArg::Instance(shim_args_instance_index))],
2225 );
2226 Ok(())
2227 }
2228
2229 fn instance_for(&self, module: CustomModule) -> u32 {
2232 match module {
2233 CustomModule::Main => self.instance_index.expect("instantiated by now"),
2234 CustomModule::Adapter(name) => self.adapter_instances[name],
2235 }
2236 }
2237
2238 fn module_for(&self, module: CustomModule) -> u32 {
2241 match module {
2242 CustomModule::Main => self.module_index.unwrap(),
2243 CustomModule::Adapter(name) => self.adapter_modules[name],
2244 }
2245 }
2246
2247 fn core_alias_export(
2250 &mut self,
2251 debug_name: Option<&str>,
2252 instance: u32,
2253 name: &str,
2254 kind: ExportKind,
2255 ) -> u32 {
2256 *self
2257 .aliased_core_items
2258 .entry((instance, name.to_string()))
2259 .or_insert_with(|| {
2260 self.component
2261 .core_alias_export(debug_name, instance, name, kind)
2262 })
2263 }
2264
2265 fn create_export_task_initialization_wrappers(&mut self) -> Result<()> {
2275 let instance_index = self.instance_index.unwrap();
2276 let resolve = &self.info.encoder.metadata.resolve;
2277 let world = &resolve.worlds[self.info.encoder.metadata.world];
2278 let exports = self.info.exports_for(CustomModule::Main);
2279
2280 let wasm_init_task_export = exports.wasm_init_task();
2281 let wasm_init_async_task_export = exports.wasm_init_async_task();
2282 if wasm_init_task_export.is_none() || wasm_init_async_task_export.is_none() {
2283 return Ok(());
2286 }
2287 let wasm_init_task = wasm_init_task_export.unwrap();
2288 let wasm_init_async_task = wasm_init_async_task_export.unwrap();
2289
2290 let funcs_to_wrap: Vec<_> = exports
2293 .iter()
2294 .map(|v| (instance_index, v))
2295 .chain(self.info.adapters.iter().flat_map(|(name, adapter)| {
2296 let instance_index = self.adapter_instances[name];
2297 adapter
2298 .info
2299 .exports
2300 .iter()
2301 .map(move |v| (instance_index, v))
2302 }))
2303 .flat_map(|(index, (core_name, export))| match export {
2304 Export::WorldFunc(key, _, abi) => match &world.exports[key] {
2305 WorldItem::Function(f) => Some((index, core_name, f, abi)),
2306 _ => None,
2307 },
2308 Export::InterfaceFunc(_, id, func_name, abi) => {
2309 let func = &resolve.interfaces[*id].functions[func_name.as_str()];
2310 Some((index, core_name, func, abi))
2311 }
2312 _ => None,
2313 })
2314 .collect();
2315
2316 if funcs_to_wrap.is_empty() {
2317 return Ok(());
2319 }
2320
2321 let mut types = TypeSection::new();
2323 let mut imports = ImportSection::new();
2324 let mut functions = FunctionSection::new();
2325 let mut exports_section = ExportSection::new();
2326 let mut code = CodeSection::new();
2327
2328 types.ty().function([], []);
2330 let wasm_init_task_type_idx = 0;
2331
2332 imports.import(
2334 "",
2335 wasm_init_task,
2336 EntityType::Function(wasm_init_task_type_idx),
2337 );
2338 imports.import(
2339 "",
2340 wasm_init_async_task,
2341 EntityType::Function(wasm_init_task_type_idx),
2342 );
2343 let wasm_init_task_func_idx = 0u32;
2344 let wasm_init_async_task_func_idx = 1u32;
2345
2346 let mut type_indices = HashMap::new();
2347 let mut next_type_idx = 1u32;
2348 let mut next_func_idx = 2u32;
2349
2350 struct FuncInfo<'a> {
2352 name: &'a str,
2353 type_idx: u32,
2354 orig_func_idx: u32,
2355 is_async: bool,
2356 n_params: usize,
2357 }
2358 let mut func_info = Vec::new();
2359 for &(_, name, func, abi) in funcs_to_wrap.iter() {
2360 let sig = resolve.wasm_signature(*abi, func);
2361 let type_idx = *type_indices.entry(sig.clone()).or_insert_with(|| {
2362 let idx = next_type_idx;
2363 types.ty().function(
2364 sig.params.iter().map(to_val_type),
2365 sig.results.iter().map(to_val_type),
2366 );
2367 next_type_idx += 1;
2368 idx
2369 });
2370
2371 imports.import("", &import_func_name(func), EntityType::Function(type_idx));
2372 let orig_func_idx = next_func_idx;
2373 next_func_idx += 1;
2374
2375 func_info.push(FuncInfo {
2376 name,
2377 type_idx,
2378 orig_func_idx,
2379 is_async: abi.is_async(),
2380 n_params: sig.params.len(),
2381 });
2382 }
2383
2384 for info in func_info.iter() {
2386 let wrapper_func_idx = next_func_idx;
2387 functions.function(info.type_idx);
2388
2389 let mut func = wasm_encoder::Function::new([]);
2390 if info.is_async {
2391 func.instruction(&Instruction::Call(wasm_init_async_task_func_idx));
2392 } else {
2393 func.instruction(&Instruction::Call(wasm_init_task_func_idx));
2394 }
2395 for i in 0..info.n_params as u32 {
2396 func.instruction(&Instruction::LocalGet(i));
2397 }
2398 func.instruction(&Instruction::Call(info.orig_func_idx));
2399 func.instruction(&Instruction::End);
2400 code.function(&func);
2401
2402 exports_section.export(info.name, ExportKind::Func, wrapper_func_idx);
2403 next_func_idx += 1;
2404 }
2405
2406 let mut wrapper_module = Module::new();
2407 wrapper_module.section(&types);
2408 wrapper_module.section(&imports);
2409 wrapper_module.section(&functions);
2410 wrapper_module.section(&exports_section);
2411 wrapper_module.section(&code);
2412
2413 let wrapper_module_idx = self
2414 .component
2415 .core_module(Some("init-task-wrappers"), &wrapper_module);
2416
2417 let mut wrapper_imports = Vec::new();
2419 let init_idx = self.core_alias_export(
2420 Some(wasm_init_task),
2421 instance_index,
2422 wasm_init_task,
2423 ExportKind::Func,
2424 );
2425 let init_async_idx = self.core_alias_export(
2426 Some(wasm_init_async_task),
2427 instance_index,
2428 wasm_init_async_task,
2429 ExportKind::Func,
2430 );
2431 wrapper_imports.push((wasm_init_task.into(), ExportKind::Func, init_idx));
2432 wrapper_imports.push((
2433 wasm_init_async_task.into(),
2434 ExportKind::Func,
2435 init_async_idx,
2436 ));
2437
2438 for (instance_index, name, func, _) in &funcs_to_wrap {
2440 let orig_idx =
2441 self.core_alias_export(Some(name), *instance_index, name, ExportKind::Func);
2442 wrapper_imports.push((import_func_name(func), ExportKind::Func, orig_idx));
2443 }
2444
2445 let wrapper_args_idx = self.component.core_instantiate_exports(
2446 Some("init-task-wrappers-args"),
2447 wrapper_imports.iter().map(|(n, k, i)| (n.as_str(), *k, *i)),
2448 );
2449
2450 let wrapper_instance = self.component.core_instantiate(
2451 Some("init-task-wrappers-instance"),
2452 wrapper_module_idx,
2453 [("", ModuleArg::Instance(wrapper_args_idx))],
2454 );
2455
2456 for (_, name, _, _) in funcs_to_wrap {
2458 let wrapper_idx =
2459 self.core_alias_export(Some(&name), wrapper_instance, &name, ExportKind::Func);
2460 self.export_task_initialization_wrappers
2461 .insert(name.into(), wrapper_idx);
2462 }
2463
2464 Ok(())
2465 }
2466}
2467
2468#[derive(Default)]
2486struct Shims<'a> {
2487 shims: IndexMap<ShimKind<'a>, Shim<'a>>,
2489}
2490
2491struct Shim<'a> {
2492 options: RequiredOptions,
2495
2496 name: String,
2500
2501 debug_name: String,
2504
2505 kind: ShimKind<'a>,
2507
2508 sig: WasmSignature,
2510}
2511
2512#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2515enum PayloadFuncKind {
2516 FutureWrite,
2517 FutureRead,
2518 StreamWrite,
2519 StreamRead,
2520}
2521
2522#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2523enum ShimKind<'a> {
2524 IndirectLowering {
2528 interface: Option<String>,
2530 index: usize,
2532 realloc: CustomModule<'a>,
2534 encoding: StringEncoding,
2536 },
2537 Adapter {
2540 adapter: &'a str,
2542 func: &'a str,
2544 },
2545 ResourceDtor {
2548 module: CustomModule<'a>,
2550 export: &'a str,
2552 },
2553 PayloadFunc {
2557 for_module: CustomModule<'a>,
2560 info: &'a PayloadInfo,
2565 kind: PayloadFuncKind,
2567 },
2568 WaitableSetWait { cancellable: bool },
2572 WaitableSetPoll { cancellable: bool },
2576 TaskReturn {
2578 interface: Option<InterfaceId>,
2581 func: &'a str,
2584 result: Option<Type>,
2586 for_module: CustomModule<'a>,
2588 encoding: StringEncoding,
2590 },
2591 ErrorContextNew {
2595 encoding: StringEncoding,
2597 },
2598 ErrorContextDebugMessage {
2602 for_module: CustomModule<'a>,
2604 encoding: StringEncoding,
2606 },
2607 ThreadNewIndirect {
2610 func_ty: FuncType,
2612 },
2613}
2614
2615#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
2625enum CustomModule<'a> {
2626 Main,
2629 Adapter(&'a str),
2632}
2633
2634impl<'a> CustomModule<'a> {
2635 fn debug_name(&self) -> &'a str {
2636 match self {
2637 CustomModule::Main => "main",
2638 CustomModule::Adapter(s) => s,
2639 }
2640 }
2641}
2642
2643impl<'a> Shims<'a> {
2644 fn append_indirect(
2649 &mut self,
2650 world: &'a ComponentWorld<'a>,
2651 for_module: CustomModule<'a>,
2652 ) -> Result<()> {
2653 let module_imports = world.imports_for(for_module);
2654 let module_exports = world.exports_for(for_module);
2655 let resolve = &world.encoder.metadata.resolve;
2656
2657 for (module, field, import) in module_imports.imports() {
2658 match import {
2659 Import::ImportedResourceDrop(..)
2662 | Import::MainModuleMemory
2663 | Import::MainModuleExport { .. }
2664 | Import::Item(_)
2665 | Import::ExportedResourceDrop(..)
2666 | Import::ExportedResourceRep(..)
2667 | Import::ExportedResourceNew(..)
2668 | Import::ExportedTaskCancel
2669 | Import::ErrorContextDrop
2670 | Import::BackpressureInc
2671 | Import::BackpressureDec
2672 | Import::SubtaskDrop
2673 | Import::SubtaskCancel { .. }
2674 | Import::FutureNew(..)
2675 | Import::StreamNew(..)
2676 | Import::FutureCancelRead { .. }
2677 | Import::FutureCancelWrite { .. }
2678 | Import::FutureDropWritable { .. }
2679 | Import::FutureDropReadable { .. }
2680 | Import::StreamCancelRead { .. }
2681 | Import::StreamCancelWrite { .. }
2682 | Import::StreamDropWritable { .. }
2683 | Import::StreamDropReadable { .. }
2684 | Import::WaitableSetNew
2685 | Import::WaitableSetDrop
2686 | Import::WaitableJoin
2687 | Import::ContextGet { .. }
2688 | Import::ContextSet { .. }
2689 | Import::ThreadIndex
2690 | Import::ThreadResumeLater
2691 | Import::ThreadSuspend { .. }
2692 | Import::ThreadYield { .. }
2693 | Import::ThreadSuspendThenResume { .. }
2694 | Import::ThreadYieldThenResume { .. }
2695 | Import::ThreadSuspendThenPromote { .. }
2696 | Import::ThreadYieldThenPromote { .. } => {}
2697
2698 Import::ExportedTaskReturn(key, interface, func) => {
2702 let (options, sig) = task_return_options_and_type(resolve, func);
2703 if options.is_empty() {
2704 continue;
2705 }
2706 let name = self.shims.len().to_string();
2707 let encoding = world
2708 .module_metadata_for(for_module)
2709 .export_encodings
2710 .get(resolve, key, &func.name)
2711 .ok_or_else(|| {
2712 anyhow::anyhow!(
2713 "missing component metadata for export of \
2714 `{module}::{field}`"
2715 )
2716 })?;
2717 self.push(Shim {
2718 name,
2719 debug_name: format!("task-return-{}", func.name),
2720 options,
2721 kind: ShimKind::TaskReturn {
2722 interface: *interface,
2723 func: &func.name,
2724 result: func.result,
2725 for_module,
2726 encoding,
2727 },
2728 sig,
2729 });
2730 }
2731
2732 Import::FutureWrite { async_, info } => {
2733 self.append_indirect_payload_push(
2734 resolve,
2735 for_module,
2736 module,
2737 *async_,
2738 info,
2739 PayloadFuncKind::FutureWrite,
2740 vec![WasmType::I32; 2],
2741 vec![WasmType::I32],
2742 );
2743 }
2744 Import::FutureRead { async_, info } => {
2745 self.append_indirect_payload_push(
2746 resolve,
2747 for_module,
2748 module,
2749 *async_,
2750 info,
2751 PayloadFuncKind::FutureRead,
2752 vec![WasmType::I32; 2],
2753 vec![WasmType::I32],
2754 );
2755 }
2756 Import::StreamWrite { async_, info } => {
2757 self.append_indirect_payload_push(
2758 resolve,
2759 for_module,
2760 module,
2761 *async_,
2762 info,
2763 PayloadFuncKind::StreamWrite,
2764 vec![WasmType::I32; 3],
2765 vec![WasmType::I32],
2766 );
2767 }
2768 Import::StreamRead { async_, info } => {
2769 self.append_indirect_payload_push(
2770 resolve,
2771 for_module,
2772 module,
2773 *async_,
2774 info,
2775 PayloadFuncKind::StreamRead,
2776 vec![WasmType::I32; 3],
2777 vec![WasmType::I32],
2778 );
2779 }
2780
2781 Import::WaitableSetWait { cancellable } => {
2782 let name = self.shims.len().to_string();
2783 self.push(Shim {
2784 name,
2785 debug_name: "waitable-set.wait".to_string(),
2786 options: RequiredOptions::empty(),
2787 kind: ShimKind::WaitableSetWait {
2788 cancellable: *cancellable,
2789 },
2790 sig: WasmSignature {
2791 params: vec![WasmType::I32; 2],
2792 results: vec![WasmType::I32],
2793 indirect_params: false,
2794 retptr: false,
2795 },
2796 });
2797 }
2798
2799 Import::WaitableSetPoll { cancellable } => {
2800 let name = self.shims.len().to_string();
2801 self.push(Shim {
2802 name,
2803 debug_name: "waitable-set.poll".to_string(),
2804 options: RequiredOptions::empty(),
2805 kind: ShimKind::WaitableSetPoll {
2806 cancellable: *cancellable,
2807 },
2808 sig: WasmSignature {
2809 params: vec![WasmType::I32; 2],
2810 results: vec![WasmType::I32],
2811 indirect_params: false,
2812 retptr: false,
2813 },
2814 });
2815 }
2816
2817 Import::ErrorContextNew { encoding } => {
2818 let name = self.shims.len().to_string();
2819 self.push(Shim {
2820 name,
2821 debug_name: "error-new".to_string(),
2822 options: RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING,
2823 kind: ShimKind::ErrorContextNew {
2824 encoding: *encoding,
2825 },
2826 sig: WasmSignature {
2827 params: vec![WasmType::I32; 2],
2828 results: vec![WasmType::I32],
2829 indirect_params: false,
2830 retptr: false,
2831 },
2832 });
2833 }
2834
2835 Import::ErrorContextDebugMessage { encoding } => {
2836 let name = self.shims.len().to_string();
2837 self.push(Shim {
2838 name,
2839 debug_name: "error-debug-message".to_string(),
2840 options: RequiredOptions::MEMORY
2841 | RequiredOptions::STRING_ENCODING
2842 | RequiredOptions::REALLOC,
2843 kind: ShimKind::ErrorContextDebugMessage {
2844 for_module,
2845 encoding: *encoding,
2846 },
2847 sig: WasmSignature {
2848 params: vec![WasmType::I32; 2],
2849 results: vec![],
2850 indirect_params: false,
2851 retptr: false,
2852 },
2853 });
2854 }
2855
2856 Import::ThreadNewIndirect => {
2857 let name = self.shims.len().to_string();
2858 self.push(Shim {
2859 name,
2860 debug_name: "thread.new-indirect".to_string(),
2861 options: RequiredOptions::empty(),
2862 kind: ShimKind::ThreadNewIndirect {
2863 func_ty: FuncType::new([ValType::I32], vec![]),
2865 },
2866 sig: WasmSignature {
2867 params: vec![WasmType::I32; 2],
2868 results: vec![WasmType::I32],
2869 indirect_params: false,
2870 retptr: false,
2871 },
2872 });
2873 }
2874
2875 Import::AdapterExport { adapter, func, ty } => {
2878 let name = self.shims.len().to_string();
2879 log::debug!("shim {name} is adapter `{module}::{field}`");
2880 self.push(Shim {
2881 name,
2882 debug_name: format!("adapt-{module}-{field}"),
2883 options: RequiredOptions::MEMORY,
2887 kind: ShimKind::Adapter { adapter, func },
2888 sig: WasmSignature {
2889 params: ty.params().iter().map(to_wasm_type).collect(),
2890 results: ty.results().iter().map(to_wasm_type).collect(),
2891 indirect_params: false,
2892 retptr: false,
2893 },
2894 });
2895
2896 fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType {
2897 match ty {
2898 wasmparser::ValType::I32 => WasmType::I32,
2899 wasmparser::ValType::I64 => WasmType::I64,
2900 wasmparser::ValType::F32 => WasmType::F32,
2901 wasmparser::ValType::F64 => WasmType::F64,
2902 _ => unreachable!(),
2903 }
2904 }
2905 }
2906
2907 Import::InterfaceFunc(key, _, name, abi) => {
2911 self.append_indirect_wit_func(
2912 world,
2913 for_module,
2914 module,
2915 field,
2916 key,
2917 name,
2918 Some(resolve.name_world_key(key)),
2919 *abi,
2920 )?;
2921 }
2922 Import::WorldFunc(key, name, abi) => {
2923 self.append_indirect_wit_func(
2924 world, for_module, module, field, key, name, None, *abi,
2925 )?;
2926 }
2927 }
2928 }
2929
2930 for (export_name, export) in module_exports.iter() {
2936 let id = match export {
2937 Export::ResourceDtor(id) => id,
2938 _ => continue,
2939 };
2940 let resource = resolve.types[*id].name.as_ref().unwrap();
2941 let name = self.shims.len().to_string();
2942 self.push(Shim {
2943 name,
2944 debug_name: format!("dtor-{resource}"),
2945 options: RequiredOptions::empty(),
2946 kind: ShimKind::ResourceDtor {
2947 module: for_module,
2948 export: export_name,
2949 },
2950 sig: WasmSignature {
2951 params: vec![WasmType::I32],
2952 results: Vec::new(),
2953 indirect_params: false,
2954 retptr: false,
2955 },
2956 });
2957 }
2958
2959 Ok(())
2960 }
2961
2962 fn append_indirect_payload_push(
2965 &mut self,
2966 resolve: &Resolve,
2967 for_module: CustomModule<'a>,
2968 module: &str,
2969 async_: bool,
2970 info: &'a PayloadInfo,
2971 kind: PayloadFuncKind,
2972 params: Vec<WasmType>,
2973 results: Vec<WasmType>,
2974 ) {
2975 let debug_name = format!("{module}-{}", info.name);
2976 let name = self.shims.len().to_string();
2977
2978 let payload = info.payload(resolve);
2979 let (wit_param, wit_result) = match kind {
2980 PayloadFuncKind::StreamRead | PayloadFuncKind::FutureRead => (None, payload),
2981 PayloadFuncKind::StreamWrite | PayloadFuncKind::FutureWrite => (payload, None),
2982 };
2983 self.push(Shim {
2984 name,
2985 debug_name,
2986 options: RequiredOptions::MEMORY
2987 | RequiredOptions::for_import(
2988 resolve,
2989 &Function {
2990 name: String::new(),
2991 kind: FunctionKind::Freestanding,
2992 params: match wit_param {
2993 Some(ty) => vec![Param {
2994 name: "a".to_string(),
2995 ty,
2996 span: Default::default(),
2997 }],
2998 None => Vec::new(),
2999 },
3000 result: wit_result,
3001 docs: Default::default(),
3002 stability: Stability::Unknown,
3003 span: Default::default(),
3004 external_id: None,
3005 },
3006 if async_ {
3007 AbiVariant::GuestImportAsync
3008 } else {
3009 AbiVariant::GuestImport
3010 },
3011 ),
3012 kind: ShimKind::PayloadFunc {
3013 for_module,
3014 info,
3015 kind,
3016 },
3017 sig: WasmSignature {
3018 params,
3019 results,
3020 indirect_params: false,
3021 retptr: false,
3022 },
3023 });
3024 }
3025
3026 fn append_indirect_wit_func(
3029 &mut self,
3030 world: &'a ComponentWorld<'a>,
3031 for_module: CustomModule<'a>,
3032 module: &str,
3033 field: &str,
3034 key: &WorldKey,
3035 name: &String,
3036 interface_key: Option<String>,
3037 abi: AbiVariant,
3038 ) -> Result<()> {
3039 let resolve = &world.encoder.metadata.resolve;
3040 let metadata = world.module_metadata_for(for_module);
3041 let interface = &world.import_map[&interface_key];
3042 let (index, _, lowering) = interface.lowerings.get_full(&(name.clone(), abi)).unwrap();
3043 let shim_name = self.shims.len().to_string();
3044 match lowering {
3045 Lowering::Direct | Lowering::ResourceDrop(_) => {}
3046
3047 Lowering::Indirect { sig, options } => {
3048 log::debug!(
3049 "shim {shim_name} is import `{module}::{field}` lowering {index} `{name}`",
3050 );
3051 let encoding = metadata
3052 .import_encodings
3053 .get(resolve, key, name)
3054 .ok_or_else(|| {
3055 anyhow::anyhow!(
3056 "missing component metadata for import of \
3057 `{module}::{field}`"
3058 )
3059 })?;
3060 self.push(Shim {
3061 name: shim_name,
3062 debug_name: format!("indirect-{module}-{field}"),
3063 options: *options,
3064 kind: ShimKind::IndirectLowering {
3065 interface: interface_key,
3066 index,
3067 realloc: for_module,
3068 encoding,
3069 },
3070 sig: sig.clone(),
3071 });
3072 }
3073 }
3074
3075 Ok(())
3076 }
3077
3078 fn push(&mut self, shim: Shim<'a>) {
3079 if !self.shims.contains_key(&shim.kind) {
3083 self.shims.insert(shim.kind.clone(), shim);
3084 }
3085 }
3086}
3087
3088fn task_return_options_and_type(
3089 resolve: &Resolve,
3090 func: &Function,
3091) -> (RequiredOptions, WasmSignature) {
3092 let func_tmp = Function {
3093 name: String::new(),
3094 kind: FunctionKind::Freestanding,
3095 params: match &func.result {
3096 Some(ty) => vec![Param {
3097 name: "a".to_string(),
3098 ty: *ty,
3099 span: Default::default(),
3100 }],
3101 None => Vec::new(),
3102 },
3103 result: None,
3104 docs: Default::default(),
3105 stability: Stability::Unknown,
3106 span: Default::default(),
3107 external_id: None,
3108 };
3109 let abi = AbiVariant::GuestImport;
3110 let mut options = RequiredOptions::for_import(resolve, func, abi);
3111 options.remove(RequiredOptions::REALLOC);
3113 let sig = resolve.wasm_signature(abi, &func_tmp);
3114 (options, sig)
3115}
3116
3117#[derive(Clone, Debug)]
3119pub struct Item {
3120 pub alias: String,
3121 pub kind: ExportKind,
3122 pub which: MainOrAdapter,
3123 pub name: String,
3124}
3125
3126#[derive(Debug, PartialEq, Clone)]
3128pub enum MainOrAdapter {
3129 Main,
3130 Adapter(String),
3131}
3132
3133impl MainOrAdapter {
3134 fn to_custom_module(&self) -> CustomModule<'_> {
3135 match self {
3136 MainOrAdapter::Main => CustomModule::Main,
3137 MainOrAdapter::Adapter(s) => CustomModule::Adapter(s),
3138 }
3139 }
3140}
3141
3142#[derive(Clone)]
3144pub enum Instance {
3145 MainOrAdapter(MainOrAdapter),
3147
3148 Items(Vec<Item>),
3150}
3151
3152#[derive(Clone)]
3155pub struct LibraryInfo {
3156 pub instantiate_after_shims: bool,
3158
3159 pub arguments: Vec<(String, Instance)>,
3161}
3162
3163pub(super) struct Adapter {
3165 wasm: Vec<u8>,
3167
3168 metadata: ModuleMetadata,
3170
3171 required_exports: IndexSet<WorldKey>,
3174
3175 library_info: Option<LibraryInfo>,
3180}
3181
3182#[derive(Default)]
3184pub struct ComponentEncoder {
3185 module: Vec<u8>,
3186 module_import_map: Option<ModuleImportMap>,
3187 pub(super) metadata: Bindgen,
3188 validate: bool,
3189 pub(super) main_module_exports: IndexSet<WorldKey>,
3190 pub(super) adapters: IndexMap<String, Adapter>,
3191 import_name_map: HashMap<String, String>,
3192 realloc_via_memory_grow: bool,
3193 merge_imports_based_on_semver: Option<bool>,
3194 pub(super) reject_legacy_names: bool,
3195 debug_names: bool,
3196}
3197
3198impl ComponentEncoder {
3199 pub fn module(mut self, module: &[u8]) -> Result<Self> {
3205 let (wasm, metadata) = self.decode(module.as_ref())?;
3206 let (wasm, module_import_map) = ModuleImportMap::new(wasm)?;
3207 let exports = self
3208 .merge_metadata(metadata)
3209 .context("failed merge WIT metadata for module with previous metadata")?;
3210 self.main_module_exports.extend(exports);
3211 self.module = if let Some(producers) = &self.metadata.producers {
3212 producers.add_to_wasm(&wasm)?
3213 } else {
3214 wasm.to_vec()
3215 };
3216 self.module_import_map = module_import_map;
3217 Ok(self)
3218 }
3219
3220 fn decode<'a>(&self, wasm: &'a [u8]) -> Result<(Cow<'a, [u8]>, Bindgen)> {
3221 let (bytes, metadata) = metadata::decode(wasm)?;
3222 match bytes {
3223 Some(wasm) => Ok((Cow::Owned(wasm), metadata)),
3224 None => Ok((Cow::Borrowed(wasm), metadata)),
3225 }
3226 }
3227
3228 fn merge_metadata(&mut self, metadata: Bindgen) -> Result<IndexSet<WorldKey>> {
3229 self.metadata.merge(metadata)
3230 }
3231
3232 pub fn validate(mut self, validate: bool) -> Self {
3234 self.validate = validate;
3235 self
3236 }
3237
3238 pub fn debug_names(mut self, debug_names: bool) -> Self {
3240 self.debug_names = debug_names;
3241 self
3242 }
3243
3244 pub fn merge_imports_based_on_semver(mut self, merge: bool) -> Self {
3252 self.merge_imports_based_on_semver = Some(merge);
3253 self
3254 }
3255
3256 pub fn reject_legacy_names(mut self, reject: bool) -> Self {
3265 self.reject_legacy_names = reject;
3266 self
3267 }
3268
3269 pub fn adapter(self, name: &str, bytes: &[u8]) -> Result<Self> {
3287 self.library_or_adapter(name, bytes, None)
3288 }
3289
3290 pub fn library(self, name: &str, bytes: &[u8], library_info: LibraryInfo) -> Result<Self> {
3303 self.library_or_adapter(name, bytes, Some(library_info))
3304 }
3305
3306 fn library_or_adapter(
3307 mut self,
3308 name: &str,
3309 bytes: &[u8],
3310 library_info: Option<LibraryInfo>,
3311 ) -> Result<Self> {
3312 let (wasm, mut metadata) = self.decode(bytes)?;
3313 let adapter_metadata = mem::take(&mut metadata.metadata);
3321 let exports = self.merge_metadata(metadata).with_context(|| {
3322 format!("failed to merge WIT packages of adapter `{name}` into main packages")
3323 })?;
3324 if let Some(library_info) = &library_info {
3325 for (_, instance) in &library_info.arguments {
3327 let resolve = |which: &_| match which {
3328 MainOrAdapter::Main => Ok(()),
3329 MainOrAdapter::Adapter(name) => {
3330 if self.adapters.contains_key(name.as_str()) {
3331 Ok(())
3332 } else {
3333 Err(anyhow!("instance refers to unknown adapter `{name}`"))
3334 }
3335 }
3336 };
3337
3338 match instance {
3339 Instance::MainOrAdapter(which) => resolve(which)?,
3340 Instance::Items(items) => {
3341 for item in items {
3342 resolve(&item.which)?;
3343 }
3344 }
3345 }
3346 }
3347 }
3348 self.adapters.insert(
3349 name.to_string(),
3350 Adapter {
3351 wasm: wasm.to_vec(),
3352 metadata: adapter_metadata,
3353 required_exports: exports,
3354 library_info,
3355 },
3356 );
3357 Ok(self)
3358 }
3359
3360 pub fn realloc_via_memory_grow(mut self, value: bool) -> Self {
3365 self.realloc_via_memory_grow = value;
3366 self
3367 }
3368
3369 pub fn import_name_map(mut self, map: HashMap<String, String>) -> Self {
3380 self.import_name_map = map;
3381 self
3382 }
3383
3384 pub fn encode(&mut self) -> Result<Vec<u8>> {
3386 if self.module.is_empty() {
3387 bail!("a module is required when encoding a component");
3388 }
3389
3390 if self.merge_imports_based_on_semver.unwrap_or(true) {
3391 self.metadata
3392 .resolve
3393 .merge_world_imports_based_on_semver(self.metadata.world)?;
3394 }
3395
3396 self.finalize_resolve_with_nominal_ids();
3397
3398 let world = ComponentWorld::new(self).context("failed to decode world from module")?;
3399 let mut state = EncodingState {
3400 component: ComponentBuilder::default(),
3401 module_index: None,
3402 instance_index: None,
3403 memory_index: None,
3404 shim_instance_index: None,
3405 fixups_module_index: None,
3406 adapter_modules: IndexMap::new(),
3407 adapter_instances: IndexMap::new(),
3408 type_encoding_maps: Default::default(),
3409 instances: Default::default(),
3410 imported_funcs: Default::default(),
3411 aliased_core_items: Default::default(),
3412 info: &world,
3413 export_task_initialization_wrappers: HashMap::new(),
3414 };
3415 state.encode_imports(&self.import_name_map)?;
3416 state.encode_core_modules();
3417 state.encode_core_instantiation()?;
3418 state.encode_exports(CustomModule::Main)?;
3419 for name in self.adapters.keys() {
3420 state.encode_exports(CustomModule::Adapter(name))?;
3421 }
3422 state.component.append_names();
3423 state
3424 .component
3425 .raw_custom_section(&crate::base_producers().raw_custom_section());
3426 let bytes = state.component.finish();
3427
3428 if self.validate {
3429 Validator::new_with_features(WasmFeatures::all())
3430 .validate_all(&bytes)
3431 .context("failed to validate component output")?;
3432 }
3433
3434 Ok(bytes)
3435 }
3436
3437 fn finalize_resolve_with_nominal_ids(&mut self) {
3446 let world = &self.metadata.resolve.worlds[self.metadata.world];
3453 let main_module_exports = self
3454 .main_module_exports
3455 .iter()
3456 .map(|i| world.exports.get_index_of(i).unwrap())
3457 .collect::<Vec<_>>();
3458 let adapter_exports = self
3459 .adapters
3460 .values()
3461 .map(|adapter| {
3462 adapter
3463 .required_exports
3464 .iter()
3465 .map(|i| world.exports.get_index_of(i).unwrap())
3466 .collect::<Vec<_>>()
3467 })
3468 .collect::<Vec<_>>();
3469
3470 self.metadata
3474 .resolve
3475 .generate_nominal_type_ids(self.metadata.world);
3476
3477 self.main_module_exports.clear();
3480 let world = &self.metadata.resolve.worlds[self.metadata.world];
3481 for index in main_module_exports {
3482 let (key, _) = world.exports.get_index(index).unwrap();
3483 self.main_module_exports.insert(key.clone());
3484 }
3485 for (exports, adapter) in adapter_exports.into_iter().zip(self.adapters.values_mut()) {
3486 adapter.required_exports.clear();
3487 for index in exports {
3488 let (key, _) = world.exports.get_index(index).unwrap();
3489 adapter.required_exports.insert(key.clone());
3490 }
3491 }
3492 }
3493}
3494
3495impl ComponentWorld<'_> {
3496 fn imports_for(&self, module: CustomModule) -> &ImportMap {
3498 match module {
3499 CustomModule::Main => &self.info.imports,
3500 CustomModule::Adapter(name) => &self.adapters[name].info.imports,
3501 }
3502 }
3503
3504 fn exports_for(&self, module: CustomModule) -> &ExportMap {
3506 match module {
3507 CustomModule::Main => &self.info.exports,
3508 CustomModule::Adapter(name) => &self.adapters[name].info.exports,
3509 }
3510 }
3511
3512 fn module_metadata_for(&self, module: CustomModule) -> &ModuleMetadata {
3514 match module {
3515 CustomModule::Main => &self.encoder.metadata.metadata,
3516 CustomModule::Adapter(name) => &self.encoder.adapters[name].metadata,
3517 }
3518 }
3519}
3520
3521#[cfg(all(test, feature = "dummy-module"))]
3522mod test {
3523 use super::*;
3524 use crate::{dummy_module, embed_component_metadata};
3525 use wit_parser::ManglingAndAbi;
3526
3527 #[test]
3528 fn it_renames_imports() {
3529 let mut resolve = Resolve::new();
3530 let pkg = resolve
3531 .push_str(
3532 "test.wit",
3533 r#"
3534package test:wit;
3535
3536interface i {
3537 f: func();
3538}
3539
3540world test {
3541 import i;
3542 import foo: interface {
3543 f: func();
3544 }
3545}
3546"#,
3547 )
3548 .unwrap();
3549 let world = resolve.select_world(&[pkg], None).unwrap();
3550
3551 let mut module = dummy_module(&resolve, world, ManglingAndAbi::Standard32);
3552
3553 embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8).unwrap();
3554
3555 let encoded = ComponentEncoder::default()
3556 .import_name_map(HashMap::from([
3557 (
3558 "foo".to_string(),
3559 "unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>".to_string(),
3560 ),
3561 (
3562 "test:wit/i".to_string(),
3563 "locked-dep=<foo:bar/i@1.2.3>".to_string(),
3564 ),
3565 ]))
3566 .module(&module)
3567 .unwrap()
3568 .validate(true)
3569 .encode()
3570 .unwrap();
3571
3572 let wat = wasmprinter::print_bytes(encoded).unwrap();
3573 assert!(wat.contains("unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>"));
3574 assert!(wat.contains("locked-dep=<foo:bar/i@1.2.3>"));
3575 }
3576}