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, Resolve, Stability, Type, TypeDefKind, TypeId,
89 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
119bitflags::bitflags! {
120 #[derive(Copy, Clone, Debug)]
123 pub struct RequiredOptions: u8 {
124 const MEMORY = 1 << 0;
127 const REALLOC = 1 << 1;
130 const STRING_ENCODING = 1 << 2;
133 const ASYNC = 1 << 3;
134 }
135}
136
137impl RequiredOptions {
138 fn for_import(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
139 let sig = resolve.wasm_signature(abi, func);
140 let mut ret = RequiredOptions::empty();
141 ret.add_lift(TypeContents::for_types(
143 resolve,
144 func.params.iter().map(|(_, t)| t),
145 ));
146 ret.add_lower(TypeContents::for_types(resolve, &func.result));
147
148 if sig.retptr || sig.indirect_params {
151 ret |= RequiredOptions::MEMORY;
152 }
153 if abi == AbiVariant::GuestImportAsync {
154 ret |= RequiredOptions::ASYNC;
155 }
156 ret
157 }
158
159 fn for_export(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
160 let sig = resolve.wasm_signature(abi, func);
161 let mut ret = RequiredOptions::empty();
162 ret.add_lower(TypeContents::for_types(
164 resolve,
165 func.params.iter().map(|(_, t)| t),
166 ));
167 ret.add_lift(TypeContents::for_types(resolve, &func.result));
168
169 if sig.retptr || sig.indirect_params {
173 ret |= RequiredOptions::MEMORY;
174 if sig.indirect_params {
175 ret |= RequiredOptions::REALLOC;
176 }
177 }
178 if let AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful = abi {
179 ret |= RequiredOptions::ASYNC;
180 ret |= task_return_options_and_type(resolve, func.result).0;
181 }
182 ret
183 }
184
185 fn add_lower(&mut self, types: TypeContents) {
186 if types.contains(TypeContents::LIST) {
190 *self |= RequiredOptions::MEMORY | RequiredOptions::REALLOC;
191 }
192 if types.contains(TypeContents::STRING) {
193 *self |= RequiredOptions::MEMORY
194 | RequiredOptions::STRING_ENCODING
195 | RequiredOptions::REALLOC;
196 }
197 }
198
199 fn add_lift(&mut self, types: TypeContents) {
200 if types.contains(TypeContents::LIST) {
204 *self |= RequiredOptions::MEMORY;
205 }
206 if types.contains(TypeContents::STRING) {
207 *self |= RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING;
208 }
209 }
210
211 fn into_iter(
212 self,
213 encoding: StringEncoding,
214 memory_index: Option<u32>,
215 realloc_index: Option<u32>,
216 ) -> Result<impl ExactSizeIterator<Item = CanonicalOption>> {
217 #[derive(Default)]
218 struct Iter {
219 options: [Option<CanonicalOption>; 5],
220 current: usize,
221 count: usize,
222 }
223
224 impl Iter {
225 fn push(&mut self, option: CanonicalOption) {
226 assert!(self.count < self.options.len());
227 self.options[self.count] = Some(option);
228 self.count += 1;
229 }
230 }
231
232 impl Iterator for Iter {
233 type Item = CanonicalOption;
234
235 fn next(&mut self) -> Option<Self::Item> {
236 if self.current == self.count {
237 return None;
238 }
239 let option = self.options[self.current];
240 self.current += 1;
241 option
242 }
243
244 fn size_hint(&self) -> (usize, Option<usize>) {
245 (self.count - self.current, Some(self.count - self.current))
246 }
247 }
248
249 impl ExactSizeIterator for Iter {}
250
251 let mut iter = Iter::default();
252
253 if self.contains(RequiredOptions::MEMORY) {
254 iter.push(CanonicalOption::Memory(memory_index.ok_or_else(|| {
255 anyhow!("module does not export a memory named `memory`")
256 })?));
257 }
258
259 if self.contains(RequiredOptions::REALLOC) {
260 iter.push(CanonicalOption::Realloc(realloc_index.ok_or_else(
261 || anyhow!("module does not export a function named `cabi_realloc`"),
262 )?));
263 }
264
265 if self.contains(RequiredOptions::STRING_ENCODING) {
266 iter.push(encoding.into());
267 }
268
269 if self.contains(RequiredOptions::ASYNC) {
270 iter.push(CanonicalOption::Async);
271 }
272
273 Ok(iter)
274 }
275}
276
277bitflags::bitflags! {
278 struct TypeContents: u8 {
281 const STRING = 1 << 0;
282 const LIST = 1 << 1;
283 }
284}
285
286impl TypeContents {
287 fn for_types<'a>(resolve: &Resolve, types: impl IntoIterator<Item = &'a Type>) -> Self {
288 let mut cur = TypeContents::empty();
289 for ty in types {
290 cur |= Self::for_type(resolve, ty);
291 }
292 cur
293 }
294
295 fn for_optional_types<'a>(
296 resolve: &Resolve,
297 types: impl Iterator<Item = Option<&'a Type>>,
298 ) -> Self {
299 Self::for_types(resolve, types.flatten())
300 }
301
302 fn for_optional_type(resolve: &Resolve, ty: Option<&Type>) -> Self {
303 match ty {
304 Some(ty) => Self::for_type(resolve, ty),
305 None => Self::empty(),
306 }
307 }
308
309 fn for_type(resolve: &Resolve, ty: &Type) -> Self {
310 match ty {
311 Type::Id(id) => match &resolve.types[*id].kind {
312 TypeDefKind::Handle(h) => match h {
313 wit_parser::Handle::Own(_) => Self::empty(),
314 wit_parser::Handle::Borrow(_) => Self::empty(),
315 },
316 TypeDefKind::Resource => Self::empty(),
317 TypeDefKind::Record(r) => Self::for_types(resolve, r.fields.iter().map(|f| &f.ty)),
318 TypeDefKind::Tuple(t) => Self::for_types(resolve, t.types.iter()),
319 TypeDefKind::Flags(_) => Self::empty(),
320 TypeDefKind::Option(t) => Self::for_type(resolve, t),
321 TypeDefKind::Result(r) => {
322 Self::for_optional_type(resolve, r.ok.as_ref())
323 | Self::for_optional_type(resolve, r.err.as_ref())
324 }
325 TypeDefKind::Variant(v) => {
326 Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref()))
327 }
328 TypeDefKind::Enum(_) => Self::empty(),
329 TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST,
330 TypeDefKind::FixedSizeList(t, _elements) => Self::for_type(resolve, t),
331 TypeDefKind::Type(t) => Self::for_type(resolve, t),
332 TypeDefKind::Future(_) => Self::empty(),
333 TypeDefKind::Stream(_) => Self::empty(),
334 TypeDefKind::Unknown => unreachable!(),
335 },
336 Type::String => Self::STRING,
337 _ => Self::empty(),
338 }
339 }
340}
341
342pub struct EncodingState<'a> {
344 component: ComponentBuilder,
346 module_index: Option<u32>,
350 instance_index: Option<u32>,
354 memory_index: Option<u32>,
358 shim_instance_index: Option<u32>,
362 fixups_module_index: Option<u32>,
366
367 adapter_modules: IndexMap<&'a str, u32>,
370 adapter_instances: IndexMap<&'a str, u32>,
372
373 imported_instances: IndexMap<InterfaceId, u32>,
375 imported_funcs: IndexMap<String, u32>,
376 exported_instances: IndexMap<InterfaceId, u32>,
377
378 import_type_encoding_maps: TypeEncodingMaps<'a>,
383 export_type_encoding_maps: TypeEncodingMaps<'a>,
384
385 aliased_core_items: HashMap<(u32, String), u32>,
391
392 info: &'a ComponentWorld<'a>,
394}
395
396impl<'a> EncodingState<'a> {
397 fn encode_core_modules(&mut self) {
398 assert!(self.module_index.is_none());
399 let idx = self
400 .component
401 .core_module_raw(Some("main"), &self.info.encoder.module);
402 self.module_index = Some(idx);
403
404 for (name, adapter) in self.info.adapters.iter() {
405 let debug_name = if adapter.library_info.is_some() {
406 name.to_string()
407 } else {
408 format!("wit-component:adapter:{name}")
409 };
410 let idx = if self.info.encoder.debug_names {
411 let mut add_meta = wasm_metadata::AddMetadata::default();
412 add_meta.name = AddMetadataField::Set(debug_name.clone());
413 let wasm = add_meta
414 .to_wasm(&adapter.wasm)
415 .expect("core wasm can get name added");
416 self.component.core_module_raw(Some(&debug_name), &wasm)
417 } else {
418 self.component
419 .core_module_raw(Some(&debug_name), &adapter.wasm)
420 };
421 let prev = self.adapter_modules.insert(name, idx);
422 assert!(prev.is_none());
423 }
424 }
425
426 fn root_import_type_encoder(
427 &mut self,
428 interface: Option<InterfaceId>,
429 ) -> RootTypeEncoder<'_, 'a> {
430 RootTypeEncoder {
431 state: self,
432 interface,
433 import_types: true,
434 }
435 }
436
437 fn root_export_type_encoder(
438 &mut self,
439 interface: Option<InterfaceId>,
440 ) -> RootTypeEncoder<'_, 'a> {
441 RootTypeEncoder {
442 state: self,
443 interface,
444 import_types: false,
445 }
446 }
447
448 fn instance_type_encoder(&mut self, interface: InterfaceId) -> InstanceTypeEncoder<'_, 'a> {
449 InstanceTypeEncoder {
450 state: self,
451 interface,
452 type_encoding_maps: Default::default(),
453 ty: Default::default(),
454 }
455 }
456
457 fn encode_imports(&mut self, name_map: &HashMap<String, String>) -> Result<()> {
458 let mut has_funcs = false;
459 for (name, info) in self.info.import_map.iter() {
460 match name {
461 Some(name) => {
462 self.encode_interface_import(name_map.get(name).unwrap_or(name), info)?
463 }
464 None => has_funcs = true,
465 }
466 }
467
468 let resolve = &self.info.encoder.metadata.resolve;
469 let world = &resolve.worlds[self.info.encoder.metadata.world];
470
471 for (_name, item) in world.imports.iter() {
474 if let WorldItem::Type(ty) = item {
475 self.root_import_type_encoder(None)
476 .encode_valtype(resolve, &Type::Id(*ty))?;
477 }
478 }
479
480 if has_funcs {
481 let info = &self.info.import_map[&None];
482 self.encode_root_import_funcs(info)?;
483 }
484 Ok(())
485 }
486
487 fn encode_interface_import(&mut self, name: &str, info: &ImportedInterface) -> Result<()> {
488 let resolve = &self.info.encoder.metadata.resolve;
489 let interface_id = info.interface.as_ref().unwrap();
490 let interface_id = *interface_id;
491 let interface = &resolve.interfaces[interface_id];
492 log::trace!("encoding imports for `{name}` as {interface_id:?}");
493 let mut encoder = self.instance_type_encoder(interface_id);
494
495 if let Some(live) = encoder.state.info.live_type_imports.get(&interface_id) {
497 for ty in live {
498 log::trace!(
499 "encoding extra type {ty:?} name={:?}",
500 resolve.types[*ty].name
501 );
502 encoder.encode_valtype(resolve, &Type::Id(*ty))?;
503 }
504 }
505
506 for (_, func) in interface.functions.iter() {
509 if !(info
510 .lowerings
511 .contains_key(&(func.name.clone(), AbiVariant::GuestImport))
512 || info
513 .lowerings
514 .contains_key(&(func.name.clone(), AbiVariant::GuestImportAsync)))
515 {
516 continue;
517 }
518 log::trace!("encoding function type for `{}`", func.name);
519 let idx = encoder.encode_func_type(resolve, func)?;
520
521 encoder.ty.export(&func.name, ComponentTypeRef::Func(idx));
522 }
523
524 let ty = encoder.ty;
525 if ty.is_empty() {
528 return Ok(());
529 }
530 let instance_type_idx = self
531 .component
532 .type_instance(Some(&format!("ty-{name}")), &ty);
533 let instance_idx = self
534 .component
535 .import(name, ComponentTypeRef::Instance(instance_type_idx));
536 let prev = self.imported_instances.insert(interface_id, instance_idx);
537 assert!(prev.is_none());
538 Ok(())
539 }
540
541 fn encode_root_import_funcs(&mut self, info: &ImportedInterface) -> Result<()> {
542 let resolve = &self.info.encoder.metadata.resolve;
543 let world = self.info.encoder.metadata.world;
544 for (name, item) in resolve.worlds[world].imports.iter() {
545 let func = match item {
546 WorldItem::Function(f) => f,
547 WorldItem::Interface { .. } | WorldItem::Type(_) => continue,
548 };
549 let name = resolve.name_world_key(name);
550 if !(info
551 .lowerings
552 .contains_key(&(name.clone(), AbiVariant::GuestImport))
553 || info
554 .lowerings
555 .contains_key(&(name.clone(), AbiVariant::GuestImportAsync)))
556 {
557 continue;
558 }
559 log::trace!("encoding function type for `{}`", func.name);
560 let idx = self
561 .root_import_type_encoder(None)
562 .encode_func_type(resolve, func)?;
563 let func_idx = self.component.import(&name, ComponentTypeRef::Func(idx));
564 let prev = self.imported_funcs.insert(name, func_idx);
565 assert!(prev.is_none());
566 }
567 Ok(())
568 }
569
570 fn alias_imported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
571 let ty = &self.info.encoder.metadata.resolve.types[id];
572 let name = ty.name.as_ref().expect("type must have a name");
573 let instance = self.imported_instances[&interface];
574 self.component
575 .alias_export(instance, name, ComponentExportKind::Type)
576 }
577
578 fn alias_exported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
579 let ty = &self.info.encoder.metadata.resolve.types[id];
580 let name = ty.name.as_ref().expect("type must have a name");
581 let instance = self.exported_instances[&interface];
582 self.component
583 .alias_export(instance, name, ComponentExportKind::Type)
584 }
585
586 fn encode_core_instantiation(&mut self) -> Result<()> {
587 let shims = self.encode_shim_instantiation()?;
589
590 self.declare_types_for_imported_intrinsics(&shims)?;
594
595 self.instantiate_main_module(&shims)?;
599
600 let (before, after) = self
603 .info
604 .adapters
605 .iter()
606 .partition::<Vec<_>, _>(|(_, adapter)| {
607 !matches!(
608 adapter.library_info,
609 Some(LibraryInfo {
610 instantiate_after_shims: true,
611 ..
612 })
613 )
614 });
615
616 for (name, _adapter) in before {
617 self.instantiate_adapter_module(&shims, name)?;
618 }
619
620 self.encode_indirect_lowerings(&shims)?;
623
624 for (name, _adapter) in after {
625 self.instantiate_adapter_module(&shims, name)?;
626 }
627
628 self.encode_initialize_with_start()?;
629
630 Ok(())
631 }
632
633 fn lookup_resource_index(&mut self, id: TypeId) -> u32 {
634 let resolve = &self.info.encoder.metadata.resolve;
635 let ty = &resolve.types[id];
636 match ty.owner {
637 TypeOwner::World(_) => self.import_type_encoding_maps.id_to_index[&id],
641 TypeOwner::Interface(i) => {
642 let instance = self.imported_instances[&i];
643 let name = ty.name.as_ref().expect("resources must be named");
644 self.component
645 .alias_export(instance, name, ComponentExportKind::Type)
646 }
647 TypeOwner::None => panic!("resources must have an owner"),
648 }
649 }
650
651 fn encode_exports(&mut self, module: CustomModule) -> Result<()> {
652 let resolve = &self.info.encoder.metadata.resolve;
653 let exports = match module {
654 CustomModule::Main => &self.info.encoder.main_module_exports,
655 CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports,
656 };
657
658 if exports.is_empty() {
659 return Ok(());
660 }
661
662 let mut interface_func_core_names = IndexMap::new();
663 let mut world_func_core_names = IndexMap::new();
664 for (core_name, export) in self.info.exports_for(module).iter() {
665 match export {
666 Export::WorldFunc(_, name, _) => {
667 let prev = world_func_core_names.insert(name, core_name);
668 assert!(prev.is_none());
669 }
670 Export::InterfaceFunc(_, id, name, _) => {
671 let prev = interface_func_core_names
672 .entry(id)
673 .or_insert(IndexMap::new())
674 .insert(name.as_str(), core_name);
675 assert!(prev.is_none());
676 }
677 Export::WorldFuncCallback(..)
678 | Export::InterfaceFuncCallback(..)
679 | Export::WorldFuncPostReturn(..)
680 | Export::InterfaceFuncPostReturn(..)
681 | Export::ResourceDtor(..)
682 | Export::Memory
683 | Export::GeneralPurposeRealloc
684 | Export::GeneralPurposeExportRealloc
685 | Export::GeneralPurposeImportRealloc
686 | Export::Initialize
687 | Export::ReallocForAdapter
688 | Export::IndirectFunctionTable => continue,
689 }
690 }
691
692 let world = &resolve.worlds[self.info.encoder.metadata.world];
693
694 for export_name in exports {
695 let export_string = resolve.name_world_key(export_name);
696 match &world.exports[export_name] {
697 WorldItem::Function(func) => {
698 let ty = self
699 .root_import_type_encoder(None)
700 .encode_func_type(resolve, func)?;
701 let core_name = world_func_core_names[&func.name];
702 let idx = self.encode_lift(module, &core_name, export_name, func, ty)?;
703 self.component
704 .export(&export_string, ComponentExportKind::Func, idx, None);
705 }
706 WorldItem::Interface { id, .. } => {
707 let core_names = interface_func_core_names.get(id);
708 self.encode_interface_export(
709 &export_string,
710 module,
711 export_name,
712 *id,
713 core_names,
714 )?;
715 }
716 WorldItem::Type(_) => unreachable!(),
717 }
718 }
719
720 Ok(())
721 }
722
723 fn encode_interface_export(
724 &mut self,
725 export_name: &str,
726 module: CustomModule<'_>,
727 key: &WorldKey,
728 export: InterfaceId,
729 interface_func_core_names: Option<&IndexMap<&str, &str>>,
730 ) -> Result<()> {
731 log::trace!("encode interface export `{export_name}`");
732 let resolve = &self.info.encoder.metadata.resolve;
733
734 let mut imports = Vec::new();
741 let mut root = self.root_export_type_encoder(Some(export));
742 for (_, func) in &resolve.interfaces[export].functions {
743 let core_name = interface_func_core_names.unwrap()[func.name.as_str()];
744 let ty = root.encode_func_type(resolve, func)?;
745 let func_index = root.state.encode_lift(module, &core_name, key, func, ty)?;
746 imports.push((
747 import_func_name(func),
748 ComponentExportKind::Func,
749 func_index,
750 ));
751 }
752
753 let mut nested = NestedComponentTypeEncoder {
757 component: ComponentBuilder::default(),
758 type_encoding_maps: Default::default(),
759 export_types: false,
760 interface: export,
761 state: self,
762 imports: IndexMap::new(),
763 };
764
765 let mut types_to_import = LiveTypes::default();
775 types_to_import.add_interface(resolve, export);
776 let exports_used = &nested.state.info.exports_used[&export];
777 for ty in types_to_import.iter() {
778 if let TypeOwner::Interface(owner) = resolve.types[ty].owner {
779 if owner == export {
780 continue;
783 }
784
785 let mut encoder = if exports_used.contains(&owner) {
788 nested.state.root_export_type_encoder(Some(export))
789 } else {
790 nested.state.root_import_type_encoder(Some(export))
791 };
792 encoder.encode_valtype(resolve, &Type::Id(ty))?;
793
794 nested.interface = owner;
798 nested.encode_valtype(resolve, &Type::Id(ty))?;
799 }
800 }
801 nested.interface = export;
802
803 let imported_type_maps = nested.type_encoding_maps.clone();
807
808 let mut resources = HashMap::new();
814 for (_name, ty) in resolve.interfaces[export].types.iter() {
815 if !matches!(resolve.types[*ty].kind, TypeDefKind::Resource) {
816 continue;
817 }
818 let idx = match nested.encode_valtype(resolve, &Type::Id(*ty))? {
819 ComponentValType::Type(idx) => idx,
820 _ => unreachable!(),
821 };
822 resources.insert(*ty, idx);
823 }
824
825 for (_, func) in resolve.interfaces[export].functions.iter() {
829 let ty = nested.encode_func_type(resolve, func)?;
830 nested
831 .component
832 .import(&import_func_name(func), ComponentTypeRef::Func(ty));
833 }
834
835 let reverse_map = nested
842 .type_encoding_maps
843 .id_to_index
844 .drain()
845 .map(|p| (p.1, p.0))
846 .collect::<HashMap<_, _>>();
847 nested.type_encoding_maps.def_to_index.clear();
848 for (name, idx) in nested.imports.drain(..) {
849 let id = reverse_map[&idx];
850 let owner = match resolve.types[id].owner {
851 TypeOwner::Interface(id) => id,
852 _ => unreachable!(),
853 };
854 let idx = if owner == export || exports_used.contains(&owner) {
855 log::trace!("consulting exports for {id:?}");
856 nested.state.export_type_encoding_maps.id_to_index[&id]
857 } else {
858 log::trace!("consulting imports for {id:?}");
859 nested.state.import_type_encoding_maps.id_to_index[&id]
860 };
861 imports.push((name, ComponentExportKind::Type, idx))
862 }
863
864 nested.type_encoding_maps = imported_type_maps;
869
870 nested.export_types = true;
877 nested.type_encoding_maps.func_type_map.clear();
878
879 for (_, id) in resolve.interfaces[export].types.iter() {
885 let ty = &resolve.types[*id];
886 match ty.kind {
887 TypeDefKind::Resource => {
888 let idx = nested.component.export(
889 ty.name.as_ref().expect("resources must be named"),
890 ComponentExportKind::Type,
891 resources[id],
892 None,
893 );
894 nested.type_encoding_maps.id_to_index.insert(*id, idx);
895 }
896 _ => {
897 nested.encode_valtype(resolve, &Type::Id(*id))?;
898 }
899 }
900 }
901
902 for (i, (_, func)) in resolve.interfaces[export].functions.iter().enumerate() {
903 let ty = nested.encode_func_type(resolve, func)?;
904 nested.component.export(
905 &func.name,
906 ComponentExportKind::Func,
907 i as u32,
908 Some(ComponentTypeRef::Func(ty)),
909 );
910 }
911
912 let component = nested.component;
916 let component_index = self
917 .component
918 .component(Some(&format!("{export_name}-shim-component")), component);
919 let instance_index = self.component.instantiate(
920 Some(&format!("{export_name}-shim-instance")),
921 component_index,
922 imports,
923 );
924 let idx = self.component.export(
925 export_name,
926 ComponentExportKind::Instance,
927 instance_index,
928 None,
929 );
930 let prev = self.exported_instances.insert(export, idx);
931 assert!(prev.is_none());
932
933 for (_name, id) in resolve.interfaces[export].types.iter() {
941 self.export_type_encoding_maps.id_to_index.remove(id);
942 self.export_type_encoding_maps
943 .def_to_index
944 .remove(&resolve.types[*id].kind);
945 }
946
947 return Ok(());
948
949 struct NestedComponentTypeEncoder<'state, 'a> {
950 component: ComponentBuilder,
951 type_encoding_maps: TypeEncodingMaps<'a>,
952 export_types: bool,
953 interface: InterfaceId,
954 state: &'state mut EncodingState<'a>,
955 imports: IndexMap<String, u32>,
956 }
957
958 impl<'a> ValtypeEncoder<'a> for NestedComponentTypeEncoder<'_, 'a> {
959 fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
960 self.component.type_defined(None)
961 }
962 fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
963 self.component.type_function(None)
964 }
965 fn export_type(&mut self, idx: u32, name: &'a str) -> Option<u32> {
966 if self.export_types {
967 Some(
968 self.component
969 .export(name, ComponentExportKind::Type, idx, None),
970 )
971 } else {
972 let name = self.unique_import_name(name);
973 let ret = self
974 .component
975 .import(&name, ComponentTypeRef::Type(TypeBounds::Eq(idx)));
976 self.imports.insert(name, ret);
977 Some(ret)
978 }
979 }
980 fn export_resource(&mut self, name: &'a str) -> u32 {
981 if self.export_types {
982 panic!("resources should already be exported")
983 } else {
984 let name = self.unique_import_name(name);
985 let ret = self
986 .component
987 .import(&name, ComponentTypeRef::Type(TypeBounds::SubResource));
988 self.imports.insert(name, ret);
989 ret
990 }
991 }
992 fn import_type(&mut self, _: InterfaceId, _id: TypeId) -> u32 {
993 unreachable!()
994 }
995 fn type_encoding_maps(&mut self) -> &mut TypeEncodingMaps<'a> {
996 &mut self.type_encoding_maps
997 }
998 fn interface(&self) -> Option<InterfaceId> {
999 Some(self.interface)
1000 }
1001 }
1002
1003 impl NestedComponentTypeEncoder<'_, '_> {
1004 fn unique_import_name(&mut self, name: &str) -> String {
1005 let mut name = format!("import-type-{name}");
1006 let mut n = 0;
1007 while self.imports.contains_key(&name) {
1008 name = format!("{name}{n}");
1009 n += 1;
1010 }
1011 name
1012 }
1013 }
1014
1015 fn import_func_name(f: &Function) -> String {
1016 match f.kind {
1017 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
1018 format!("import-func-{}", f.item_name())
1019 }
1020
1021 FunctionKind::Method(_)
1029 | FunctionKind::AsyncMethod(_)
1030 | FunctionKind::Static(_)
1031 | FunctionKind::AsyncStatic(_)
1032 | FunctionKind::Constructor(_) => {
1033 format!(
1034 "import-{}",
1035 f.name.replace('[', "").replace([']', '.', ' '], "-")
1036 )
1037 }
1038 }
1039 }
1040 }
1041
1042 fn encode_lift(
1043 &mut self,
1044 module: CustomModule<'_>,
1045 core_name: &str,
1046 key: &WorldKey,
1047 func: &Function,
1048 ty: u32,
1049 ) -> Result<u32> {
1050 let resolve = &self.info.encoder.metadata.resolve;
1051 let metadata = self.info.module_metadata_for(module);
1052 let instance_index = self.instance_for(module);
1053 let core_func_index =
1054 self.core_alias_export(Some(core_name), instance_index, core_name, ExportKind::Func);
1055 let exports = self.info.exports_for(module);
1056
1057 let options = RequiredOptions::for_export(
1058 resolve,
1059 func,
1060 exports
1061 .abi(key, func)
1062 .ok_or_else(|| anyhow!("no ABI found for {}", func.name))?,
1063 );
1064
1065 let encoding = metadata
1066 .export_encodings
1067 .get(resolve, key, &func.name)
1068 .unwrap();
1069 let exports = self.info.exports_for(module);
1070 let realloc_index = exports
1071 .export_realloc_for(key, &func.name)
1072 .map(|name| self.core_alias_export(Some(name), instance_index, name, ExportKind::Func));
1073 let mut options = options
1074 .into_iter(encoding, self.memory_index, realloc_index)?
1075 .collect::<Vec<_>>();
1076
1077 if let Some(post_return) = exports.post_return(key, func) {
1078 let post_return = self.core_alias_export(
1079 Some(post_return),
1080 instance_index,
1081 post_return,
1082 ExportKind::Func,
1083 );
1084 options.push(CanonicalOption::PostReturn(post_return));
1085 }
1086 if let Some(callback) = exports.callback(key, func) {
1087 let callback =
1088 self.core_alias_export(Some(callback), instance_index, callback, ExportKind::Func);
1089 options.push(CanonicalOption::Callback(callback));
1090 }
1091 let func_index = self
1092 .component
1093 .lift_func(Some(&func.name), core_func_index, ty, options);
1094 Ok(func_index)
1095 }
1096
1097 fn encode_shim_instantiation(&mut self) -> Result<Shims<'a>> {
1098 let mut ret = Shims::default();
1099
1100 ret.append_indirect(self.info, CustomModule::Main)
1101 .context("failed to register indirect shims for main module")?;
1102
1103 for (adapter_name, _adapter) in self.info.adapters.iter() {
1107 ret.append_indirect(self.info, CustomModule::Adapter(adapter_name))
1108 .with_context(|| {
1109 format!("failed to register indirect shims for adapter {adapter_name}")
1110 })?;
1111 }
1112
1113 if ret.shims.is_empty() {
1114 return Ok(ret);
1115 }
1116
1117 assert!(self.shim_instance_index.is_none());
1118 assert!(self.fixups_module_index.is_none());
1119
1120 let mut types = TypeSection::new();
1129 let mut tables = TableSection::new();
1130 let mut functions = FunctionSection::new();
1131 let mut exports = ExportSection::new();
1132 let mut code = CodeSection::new();
1133 let mut sigs = IndexMap::new();
1134 let mut imports_section = ImportSection::new();
1135 let mut elements = ElementSection::new();
1136 let mut func_indexes = Vec::new();
1137 let mut func_names = NameMap::new();
1138
1139 for (i, shim) in ret.shims.values().enumerate() {
1140 let i = i as u32;
1141 let type_index = *sigs.entry(&shim.sig).or_insert_with(|| {
1142 let index = types.len();
1143 types.ty().function(
1144 shim.sig.params.iter().map(to_val_type),
1145 shim.sig.results.iter().map(to_val_type),
1146 );
1147 index
1148 });
1149
1150 functions.function(type_index);
1151 Self::encode_shim_function(type_index, i, &mut code, shim.sig.params.len() as u32);
1152 exports.export(&shim.name, ExportKind::Func, i);
1153
1154 imports_section.import("", &shim.name, EntityType::Function(type_index));
1155 func_indexes.push(i);
1156 func_names.append(i, &shim.debug_name);
1157 }
1158 let mut names = NameSection::new();
1159 names.module("wit-component:shim");
1160 names.functions(&func_names);
1161
1162 let table_type = TableType {
1163 element_type: RefType::FUNCREF,
1164 minimum: ret.shims.len() as u64,
1165 maximum: Some(ret.shims.len() as u64),
1166 table64: false,
1167 shared: false,
1168 };
1169
1170 tables.table(table_type);
1171
1172 exports.export(INDIRECT_TABLE_NAME, ExportKind::Table, 0);
1173 imports_section.import("", INDIRECT_TABLE_NAME, table_type);
1174
1175 elements.active(
1176 None,
1177 &ConstExpr::i32_const(0),
1178 Elements::Functions(func_indexes.into()),
1179 );
1180
1181 let mut shim = Module::new();
1182 shim.section(&types);
1183 shim.section(&functions);
1184 shim.section(&tables);
1185 shim.section(&exports);
1186 shim.section(&code);
1187 shim.section(&RawCustomSection(
1188 &crate::base_producers().raw_custom_section(),
1189 ));
1190 if self.info.encoder.debug_names {
1191 shim.section(&names);
1192 }
1193
1194 let mut fixups = Module::default();
1195 fixups.section(&types);
1196 fixups.section(&imports_section);
1197 fixups.section(&elements);
1198 fixups.section(&RawCustomSection(
1199 &crate::base_producers().raw_custom_section(),
1200 ));
1201
1202 if self.info.encoder.debug_names {
1203 let mut names = NameSection::new();
1204 names.module("wit-component:fixups");
1205 fixups.section(&names);
1206 }
1207
1208 let shim_module_index = self
1209 .component
1210 .core_module(Some("wit-component-shim-module"), &shim);
1211 let fixup_index = self
1212 .component
1213 .core_module(Some("wit-component-fixup"), &fixups);
1214 self.fixups_module_index = Some(fixup_index);
1215 let shim_instance = self.component.core_instantiate(
1216 Some("wit-component-shim-instance"),
1217 shim_module_index,
1218 [],
1219 );
1220 self.shim_instance_index = Some(shim_instance);
1221
1222 return Ok(ret);
1223 }
1224
1225 fn encode_shim_function(
1226 type_index: u32,
1227 func_index: u32,
1228 code: &mut CodeSection,
1229 param_count: u32,
1230 ) {
1231 let mut func = wasm_encoder::Function::new(std::iter::empty());
1232 for i in 0..param_count {
1233 func.instructions().local_get(i);
1234 }
1235 func.instructions().i32_const(func_index as i32);
1236 func.instructions().call_indirect(0, type_index);
1237 func.instructions().end();
1238 code.function(&func);
1239 }
1240
1241 fn encode_indirect_lowerings(&mut self, shims: &Shims<'_>) -> Result<()> {
1242 if shims.shims.is_empty() {
1243 return Ok(());
1244 }
1245
1246 let shim_instance_index = self
1247 .shim_instance_index
1248 .expect("must have an instantiated shim");
1249
1250 let table_index = self.core_alias_export(
1251 Some("shim table"),
1252 shim_instance_index,
1253 INDIRECT_TABLE_NAME,
1254 ExportKind::Table,
1255 );
1256
1257 let resolve = &self.info.encoder.metadata.resolve;
1258
1259 let mut exports = Vec::new();
1260 exports.push((INDIRECT_TABLE_NAME, ExportKind::Table, table_index));
1261
1262 for shim in shims.shims.values() {
1263 let core_func_index = match &shim.kind {
1264 ShimKind::IndirectLowering {
1271 interface,
1272 index,
1273 realloc,
1274 encoding,
1275 } => {
1276 let interface = &self.info.import_map[interface];
1277 let ((name, _), _) = interface.lowerings.get_index(*index).unwrap();
1278 let func_index = match &interface.interface {
1279 Some(interface_id) => {
1280 let instance_index = self.imported_instances[interface_id];
1281 self.component.alias_export(
1282 instance_index,
1283 name,
1284 ComponentExportKind::Func,
1285 )
1286 }
1287 None => self.imported_funcs[name],
1288 };
1289
1290 let realloc = self
1291 .info
1292 .exports_for(*realloc)
1293 .import_realloc_for(interface.interface, name)
1294 .map(|name| {
1295 let instance = self.instance_for(*realloc);
1296 self.core_alias_export(
1297 Some("realloc"),
1298 instance,
1299 name,
1300 ExportKind::Func,
1301 )
1302 });
1303
1304 self.component.lower_func(
1305 Some(&shim.debug_name),
1306 func_index,
1307 shim.options
1308 .into_iter(*encoding, self.memory_index, realloc)?,
1309 )
1310 }
1311
1312 ShimKind::Adapter { adapter, func } => self.core_alias_export(
1317 Some(func),
1318 self.adapter_instances[adapter],
1319 func,
1320 ExportKind::Func,
1321 ),
1322
1323 ShimKind::ResourceDtor { module, export } => self.core_alias_export(
1328 Some(export),
1329 self.instance_for(*module),
1330 export,
1331 ExportKind::Func,
1332 ),
1333
1334 ShimKind::PayloadFunc {
1335 for_module,
1336 info,
1337 kind,
1338 } => {
1339 let metadata = self.info.module_metadata_for(*for_module);
1340 let exports = self.info.exports_for(*for_module);
1341 let instance_index = self.instance_for(*for_module);
1342 let (encoding, realloc) = match &info.ty {
1343 PayloadType::Type { function, .. } => {
1344 if info.imported {
1345 (
1346 metadata.import_encodings.get(resolve, &info.key, function),
1347 exports.import_realloc_for(info.interface, function),
1348 )
1349 } else {
1350 (
1351 metadata.export_encodings.get(resolve, &info.key, function),
1352 exports.export_realloc_for(&info.key, function),
1353 )
1354 }
1355 }
1356 PayloadType::UnitFuture | PayloadType::UnitStream => (None, None),
1357 };
1358 let encoding = encoding.unwrap_or(StringEncoding::UTF8);
1359 let realloc_index = realloc.map(|name| {
1360 self.core_alias_export(
1361 Some("realloc"),
1362 instance_index,
1363 name,
1364 ExportKind::Func,
1365 )
1366 });
1367 let type_index = self.payload_type_index(info)?;
1368 let options =
1369 shim.options
1370 .into_iter(encoding, self.memory_index, realloc_index)?;
1371
1372 match kind {
1373 PayloadFuncKind::FutureWrite => {
1374 self.component.future_write(type_index, options)
1375 }
1376 PayloadFuncKind::FutureRead => {
1377 self.component.future_read(type_index, options)
1378 }
1379 PayloadFuncKind::StreamWrite => {
1380 self.component.stream_write(type_index, options)
1381 }
1382 PayloadFuncKind::StreamRead => {
1383 self.component.stream_read(type_index, options)
1384 }
1385 }
1386 }
1387
1388 ShimKind::WaitableSetWait { cancellable } => self
1389 .component
1390 .waitable_set_wait(*cancellable, self.memory_index.unwrap()),
1391 ShimKind::WaitableSetPoll { cancellable } => self
1392 .component
1393 .waitable_set_poll(*cancellable, self.memory_index.unwrap()),
1394 ShimKind::ErrorContextNew { encoding } => self.component.error_context_new(
1395 shim.options.into_iter(*encoding, self.memory_index, None)?,
1396 ),
1397 ShimKind::ErrorContextDebugMessage {
1398 for_module,
1399 encoding,
1400 } => {
1401 let instance_index = self.instance_for(*for_module);
1402 let realloc = self.info.exports_for(*for_module).import_realloc_fallback();
1403 let realloc_index = realloc.map(|r| {
1404 self.core_alias_export(Some("realloc"), instance_index, r, ExportKind::Func)
1405 });
1406
1407 self.component
1408 .error_context_debug_message(shim.options.into_iter(
1409 *encoding,
1410 self.memory_index,
1411 realloc_index,
1412 )?)
1413 }
1414 ShimKind::TaskReturn {
1415 interface,
1416 func,
1417 result,
1418 encoding,
1419 for_module,
1420 } => {
1421 let mut encoder = if interface.is_none() {
1424 self.root_import_type_encoder(*interface)
1425 } else {
1426 self.root_export_type_encoder(*interface)
1427 };
1428 let result = match result {
1429 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1430 None => None,
1431 };
1432
1433 let exports = self.info.exports_for(*for_module);
1434 let realloc = exports.import_realloc_for(*interface, func);
1435
1436 let instance_index = self.instance_for(*for_module);
1437 let realloc_index = realloc.map(|r| {
1438 self.core_alias_export(Some("realloc"), instance_index, r, ExportKind::Func)
1439 });
1440 let options =
1441 shim.options
1442 .into_iter(*encoding, self.memory_index, realloc_index)?;
1443 self.component.task_return(result, options)
1444 }
1445 ShimKind::ThreadNewIndirect {
1446 for_module,
1447 func_ty,
1448 } => {
1449 let (func_ty_idx, f) = self.component.core_type(Some("thread-start"));
1451 f.core().func_type(func_ty);
1452
1453 let exports = self.info.exports_for(*for_module);
1456 let instance_index = self.instance_for(*for_module);
1457 let table_idx = exports.indirect_function_table().map(|table| {
1458 self.core_alias_export(
1459 Some("indirect-function-table"),
1460 instance_index,
1461 table,
1462 ExportKind::Table,
1463 )
1464 }).ok_or_else(|| {
1465 anyhow!(
1466 "table __indirect_function_table must be an exported funcref table for thread.new-indirect"
1467 )
1468 })?;
1469
1470 self.component.thread_new_indirect(func_ty_idx, table_idx)
1471 }
1472 };
1473
1474 exports.push((shim.name.as_str(), ExportKind::Func, core_func_index));
1475 }
1476
1477 let instance_index = self
1478 .component
1479 .core_instantiate_exports(Some("fixup-args"), exports);
1480 self.component.core_instantiate(
1481 Some("fixup"),
1482 self.fixups_module_index.expect("must have fixup module"),
1483 [("", ModuleArg::Instance(instance_index))],
1484 );
1485 Ok(())
1486 }
1487
1488 fn payload_type_index(&mut self, info: &PayloadInfo) -> Result<u32> {
1496 let resolve = &self.info.encoder.metadata.resolve;
1497 let mut encoder = if info.imported || info.interface.is_none() {
1513 self.root_import_type_encoder(None)
1514 } else {
1515 self.root_export_type_encoder(info.interface)
1516 };
1517 match info.ty {
1518 PayloadType::Type { id, .. } => match encoder.encode_valtype(resolve, &Type::Id(id))? {
1519 ComponentValType::Type(index) => Ok(index),
1520 ComponentValType::Primitive(_) => unreachable!(),
1521 },
1522 PayloadType::UnitFuture => Ok(encoder.encode_unit_future()),
1523 PayloadType::UnitStream => Ok(encoder.encode_unit_stream()),
1524 }
1525 }
1526
1527 fn declare_types_for_imported_intrinsics(&mut self, shims: &Shims<'_>) -> Result<()> {
1534 let resolve = &self.info.encoder.metadata.resolve;
1535 let world = &resolve.worlds[self.info.encoder.metadata.world];
1536
1537 let main_module_keys = self.info.encoder.main_module_exports.iter();
1540 let main_module_keys = main_module_keys.map(|key| (CustomModule::Main, key));
1541 let adapter_keys = self.info.encoder.adapters.iter().flat_map(|(name, info)| {
1542 info.required_exports
1543 .iter()
1544 .map(move |key| (CustomModule::Adapter(name), key))
1545 });
1546 for (for_module, key) in main_module_keys.chain(adapter_keys) {
1547 let id = match &world.exports[key] {
1548 WorldItem::Interface { id, .. } => *id,
1549 WorldItem::Type { .. } => unreachable!(),
1550 WorldItem::Function(_) => continue,
1551 };
1552
1553 for ty in resolve.interfaces[id].types.values() {
1554 let def = &resolve.types[*ty];
1555 match &def.kind {
1556 TypeDefKind::Resource => {
1560 let exports = self.info.exports_for(for_module);
1563 let dtor = exports.resource_dtor(*ty).map(|name| {
1564 let shim = &shims.shims[&ShimKind::ResourceDtor {
1565 module: for_module,
1566 export: name,
1567 }];
1568 let index = self.shim_instance_index.unwrap();
1569 self.core_alias_export(
1570 Some(&shim.debug_name),
1571 index,
1572 &shim.name,
1573 ExportKind::Func,
1574 )
1575 });
1576
1577 let resource_idx = self.component.type_resource(
1581 Some(def.name.as_ref().unwrap()),
1582 ValType::I32,
1583 dtor,
1584 );
1585 let prev = self
1586 .export_type_encoding_maps
1587 .id_to_index
1588 .insert(*ty, resource_idx);
1589 assert!(prev.is_none());
1590 }
1591 _other => {
1592 self.root_export_type_encoder(Some(id))
1593 .encode_valtype(resolve, &Type::Id(*ty))?;
1594 }
1595 }
1596 }
1597 }
1598 Ok(())
1599 }
1600
1601 fn instantiate_main_module(&mut self, shims: &Shims<'_>) -> Result<()> {
1604 assert!(self.instance_index.is_none());
1605
1606 let instance_index = self.instantiate_core_module(shims, CustomModule::Main)?;
1607
1608 if let Some(memory) = self.info.info.exports.memory() {
1609 self.memory_index = Some(self.core_alias_export(
1610 Some("memory"),
1611 instance_index,
1612 memory,
1613 ExportKind::Memory,
1614 ));
1615 }
1616
1617 self.instance_index = Some(instance_index);
1618 Ok(())
1619 }
1620
1621 fn instantiate_adapter_module(&mut self, shims: &Shims<'_>, name: &'a str) -> Result<()> {
1624 let instance = self.instantiate_core_module(shims, CustomModule::Adapter(name))?;
1625 self.adapter_instances.insert(name, instance);
1626 Ok(())
1627 }
1628
1629 fn instantiate_core_module(
1636 &mut self,
1637 shims: &Shims,
1638 for_module: CustomModule<'_>,
1639 ) -> Result<u32> {
1640 let module = self.module_for(for_module);
1641
1642 let mut args = Vec::new();
1643 for (core_wasm_name, instance) in self.info.imports_for(for_module).modules() {
1644 match instance {
1645 ImportInstance::Names(names) => {
1651 let mut exports = Vec::new();
1652 for (name, import) in names {
1653 log::trace!(
1654 "attempting to materialize import of `{core_wasm_name}::{name}` for {for_module:?}"
1655 );
1656 let (kind, index) = self
1657 .materialize_import(&shims, for_module, import)
1658 .with_context(|| {
1659 format!("failed to satisfy import `{core_wasm_name}::{name}`")
1660 })?;
1661 exports.push((name.as_str(), kind, index));
1662 }
1663 let index = self
1664 .component
1665 .core_instantiate_exports(Some(core_wasm_name), exports);
1666 args.push((core_wasm_name.as_str(), ModuleArg::Instance(index)));
1667 }
1668
1669 ImportInstance::Whole(which) => {
1672 let instance = self.instance_for(which.to_custom_module());
1673 args.push((core_wasm_name.as_str(), ModuleArg::Instance(instance)));
1674 }
1675 }
1676 }
1677
1678 Ok(self
1680 .component
1681 .core_instantiate(Some(for_module.debug_name()), module, args))
1682 }
1683
1684 fn materialize_import(
1691 &mut self,
1692 shims: &Shims<'_>,
1693 for_module: CustomModule<'_>,
1694 import: &'a Import,
1695 ) -> Result<(ExportKind, u32)> {
1696 let resolve = &self.info.encoder.metadata.resolve;
1697 match import {
1698 Import::AdapterExport {
1701 adapter,
1702 func,
1703 ty: _,
1704 } => {
1705 assert!(self.info.encoder.adapters.contains_key(adapter));
1706 Ok(self.materialize_shim_import(shims, &ShimKind::Adapter { adapter, func }))
1707 }
1708
1709 Import::MainModuleMemory => {
1712 let index = self
1713 .memory_index
1714 .ok_or_else(|| anyhow!("main module cannot import memory"))?;
1715 Ok((ExportKind::Memory, index))
1716 }
1717
1718 Import::MainModuleExport { name, kind } => {
1720 let instance = self.instance_index.unwrap();
1721 let index = self.core_alias_export(Some(name), instance, name, *kind);
1722 Ok((*kind, index))
1723 }
1724
1725 Import::Item(item) => {
1729 let instance = self.instance_for(item.which.to_custom_module());
1730 let index =
1731 self.core_alias_export(Some(&item.name), instance, &item.name, item.kind);
1732 Ok((item.kind, index))
1733 }
1734
1735 Import::ExportedResourceDrop(_key, id) => {
1741 let index = self
1742 .component
1743 .resource_drop(self.export_type_encoding_maps.id_to_index[id]);
1744 Ok((ExportKind::Func, index))
1745 }
1746 Import::ExportedResourceRep(_key, id) => {
1747 let index = self
1748 .component
1749 .resource_rep(self.export_type_encoding_maps.id_to_index[id]);
1750 Ok((ExportKind::Func, index))
1751 }
1752 Import::ExportedResourceNew(_key, id) => {
1753 let index = self
1754 .component
1755 .resource_new(self.export_type_encoding_maps.id_to_index[id]);
1756 Ok((ExportKind::Func, index))
1757 }
1758
1759 Import::ImportedResourceDrop(key, iface, id) => {
1764 let ty = &resolve.types[*id];
1765 let name = ty.name.as_ref().unwrap();
1766 self.materialize_wit_import(
1767 shims,
1768 for_module,
1769 iface.map(|_| resolve.name_world_key(key)),
1770 &format!("{name}_drop"),
1771 key,
1772 AbiVariant::GuestImport,
1773 )
1774 }
1775 Import::ExportedTaskReturn(key, interface, func, result) => {
1776 let (options, _sig) = task_return_options_and_type(resolve, *result);
1777 if options.is_empty() {
1778 let mut encoder = if interface.is_none() {
1784 self.root_import_type_encoder(*interface)
1785 } else {
1786 self.root_export_type_encoder(*interface)
1787 };
1788
1789 let result = match result {
1790 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1791 None => None,
1792 };
1793 let index = self.component.task_return(result, []);
1794 Ok((ExportKind::Func, index))
1795 } else {
1796 let metadata = &self.info.module_metadata_for(for_module);
1797 let encoding = metadata.export_encodings.get(resolve, key, func).unwrap();
1798 Ok(self.materialize_shim_import(
1799 shims,
1800 &ShimKind::TaskReturn {
1801 for_module,
1802 interface: *interface,
1803 func,
1804 result: *result,
1805 encoding,
1806 },
1807 ))
1808 }
1809 }
1810 Import::BackpressureSet => {
1811 let index = self.component.backpressure_set();
1812 Ok((ExportKind::Func, index))
1813 }
1814 Import::BackpressureInc => {
1815 let index = self.component.backpressure_inc();
1816 Ok((ExportKind::Func, index))
1817 }
1818 Import::BackpressureDec => {
1819 let index = self.component.backpressure_dec();
1820 Ok((ExportKind::Func, index))
1821 }
1822 Import::WaitableSetWait { cancellable } => Ok(self.materialize_shim_import(
1823 shims,
1824 &ShimKind::WaitableSetWait {
1825 cancellable: *cancellable,
1826 },
1827 )),
1828 Import::WaitableSetPoll { cancellable } => Ok(self.materialize_shim_import(
1829 shims,
1830 &ShimKind::WaitableSetPoll {
1831 cancellable: *cancellable,
1832 },
1833 )),
1834 Import::ThreadYield { cancellable } => {
1835 let index = self.component.thread_yield(*cancellable);
1836 Ok((ExportKind::Func, index))
1837 }
1838 Import::SubtaskDrop => {
1839 let index = self.component.subtask_drop();
1840 Ok((ExportKind::Func, index))
1841 }
1842 Import::SubtaskCancel { async_ } => {
1843 let index = self.component.subtask_cancel(*async_);
1844 Ok((ExportKind::Func, index))
1845 }
1846 Import::StreamNew(info) => {
1847 let ty = self.payload_type_index(info)?;
1848 let index = self.component.stream_new(ty);
1849 Ok((ExportKind::Func, index))
1850 }
1851 Import::StreamRead { info, .. } => Ok(self.materialize_payload_import(
1852 shims,
1853 for_module,
1854 info,
1855 PayloadFuncKind::StreamRead,
1856 )),
1857 Import::StreamWrite { info, .. } => Ok(self.materialize_payload_import(
1858 shims,
1859 for_module,
1860 info,
1861 PayloadFuncKind::StreamWrite,
1862 )),
1863 Import::StreamCancelRead { info, async_ } => {
1864 let ty = self.payload_type_index(info)?;
1865 let index = self.component.stream_cancel_read(ty, *async_);
1866 Ok((ExportKind::Func, index))
1867 }
1868 Import::StreamCancelWrite { info, async_ } => {
1869 let ty = self.payload_type_index(info)?;
1870 let index = self.component.stream_cancel_write(ty, *async_);
1871 Ok((ExportKind::Func, index))
1872 }
1873 Import::StreamDropReadable(info) => {
1874 let type_index = self.payload_type_index(info)?;
1875 let index = self.component.stream_drop_readable(type_index);
1876 Ok((ExportKind::Func, index))
1877 }
1878 Import::StreamDropWritable(info) => {
1879 let type_index = self.payload_type_index(info)?;
1880 let index = self.component.stream_drop_writable(type_index);
1881 Ok((ExportKind::Func, index))
1882 }
1883 Import::FutureNew(info) => {
1884 let ty = self.payload_type_index(info)?;
1885 let index = self.component.future_new(ty);
1886 Ok((ExportKind::Func, index))
1887 }
1888 Import::FutureRead { info, .. } => Ok(self.materialize_payload_import(
1889 shims,
1890 for_module,
1891 info,
1892 PayloadFuncKind::FutureRead,
1893 )),
1894 Import::FutureWrite { info, .. } => Ok(self.materialize_payload_import(
1895 shims,
1896 for_module,
1897 info,
1898 PayloadFuncKind::FutureWrite,
1899 )),
1900 Import::FutureCancelRead { info, async_ } => {
1901 let ty = self.payload_type_index(info)?;
1902 let index = self.component.future_cancel_read(ty, *async_);
1903 Ok((ExportKind::Func, index))
1904 }
1905 Import::FutureCancelWrite { info, async_ } => {
1906 let ty = self.payload_type_index(info)?;
1907 let index = self.component.future_cancel_write(ty, *async_);
1908 Ok((ExportKind::Func, index))
1909 }
1910 Import::FutureDropReadable(info) => {
1911 let type_index = self.payload_type_index(info)?;
1912 let index = self.component.future_drop_readable(type_index);
1913 Ok((ExportKind::Func, index))
1914 }
1915 Import::FutureDropWritable(info) => {
1916 let type_index = self.payload_type_index(info)?;
1917 let index = self.component.future_drop_writable(type_index);
1918 Ok((ExportKind::Func, index))
1919 }
1920 Import::ErrorContextNew { encoding } => Ok(self.materialize_shim_import(
1921 shims,
1922 &ShimKind::ErrorContextNew {
1923 encoding: *encoding,
1924 },
1925 )),
1926 Import::ErrorContextDebugMessage { encoding } => Ok(self.materialize_shim_import(
1927 shims,
1928 &ShimKind::ErrorContextDebugMessage {
1929 for_module,
1930 encoding: *encoding,
1931 },
1932 )),
1933 Import::ErrorContextDrop => {
1934 let index = self.component.error_context_drop();
1935 Ok((ExportKind::Func, index))
1936 }
1937 Import::WorldFunc(key, name, abi) => {
1938 self.materialize_wit_import(shims, for_module, None, name, key, *abi)
1939 }
1940 Import::InterfaceFunc(key, _, name, abi) => self.materialize_wit_import(
1941 shims,
1942 for_module,
1943 Some(resolve.name_world_key(key)),
1944 name,
1945 key,
1946 *abi,
1947 ),
1948
1949 Import::WaitableSetNew => {
1950 let index = self.component.waitable_set_new();
1951 Ok((ExportKind::Func, index))
1952 }
1953 Import::WaitableSetDrop => {
1954 let index = self.component.waitable_set_drop();
1955 Ok((ExportKind::Func, index))
1956 }
1957 Import::WaitableJoin => {
1958 let index = self.component.waitable_join();
1959 Ok((ExportKind::Func, index))
1960 }
1961 Import::ContextGet(n) => {
1962 let index = self.component.context_get(*n);
1963 Ok((ExportKind::Func, index))
1964 }
1965 Import::ContextSet(n) => {
1966 let index = self.component.context_set(*n);
1967 Ok((ExportKind::Func, index))
1968 }
1969 Import::ExportedTaskCancel => {
1970 let index = self.component.task_cancel();
1971 Ok((ExportKind::Func, index))
1972 }
1973 Import::ThreadIndex => {
1974 let index = self.component.thread_index();
1975 Ok((ExportKind::Func, index))
1976 }
1977 Import::ThreadNewIndirect => Ok(self.materialize_shim_import(
1978 shims,
1979 &ShimKind::ThreadNewIndirect {
1980 for_module,
1981 func_ty: FuncType::new([ValType::I32], []),
1983 },
1984 )),
1985 Import::ThreadSwitchTo { cancellable } => {
1986 let index = self.component.thread_switch_to(*cancellable);
1987 Ok((ExportKind::Func, index))
1988 }
1989 Import::ThreadSuspend { cancellable } => {
1990 let index = self.component.thread_suspend(*cancellable);
1991 Ok((ExportKind::Func, index))
1992 }
1993 Import::ThreadResumeLater => {
1994 let index = self.component.thread_resume_later();
1995 Ok((ExportKind::Func, index))
1996 }
1997 Import::ThreadYieldTo { cancellable } => {
1998 let index = self.component.thread_yield_to(*cancellable);
1999 Ok((ExportKind::Func, index))
2000 }
2001 }
2002 }
2003
2004 fn materialize_shim_import(&mut self, shims: &Shims<'_>, kind: &ShimKind) -> (ExportKind, u32) {
2007 let index = self.core_alias_export(
2008 Some(&shims.shims[kind].debug_name),
2009 self.shim_instance_index
2010 .expect("shim should be instantiated"),
2011 &shims.shims[kind].name,
2012 ExportKind::Func,
2013 );
2014 (ExportKind::Func, index)
2015 }
2016
2017 fn materialize_payload_import(
2020 &mut self,
2021 shims: &Shims<'_>,
2022 for_module: CustomModule<'_>,
2023 info: &PayloadInfo,
2024 kind: PayloadFuncKind,
2025 ) -> (ExportKind, u32) {
2026 self.materialize_shim_import(
2027 shims,
2028 &ShimKind::PayloadFunc {
2029 for_module,
2030 info,
2031 kind,
2032 },
2033 )
2034 }
2035
2036 fn materialize_wit_import(
2039 &mut self,
2040 shims: &Shims<'_>,
2041 for_module: CustomModule<'_>,
2042 interface_key: Option<String>,
2043 name: &String,
2044 key: &WorldKey,
2045 abi: AbiVariant,
2046 ) -> Result<(ExportKind, u32)> {
2047 let resolve = &self.info.encoder.metadata.resolve;
2048 let import = &self.info.import_map[&interface_key];
2049 let (index, _, lowering) = import.lowerings.get_full(&(name.clone(), abi)).unwrap();
2050 let metadata = self.info.module_metadata_for(for_module);
2051
2052 let index = match lowering {
2053 Lowering::Direct => {
2056 let func_index = match &import.interface {
2057 Some(interface) => {
2058 let instance_index = self.imported_instances[interface];
2059 self.component
2060 .alias_export(instance_index, name, ComponentExportKind::Func)
2061 }
2062 None => self.imported_funcs[name],
2063 };
2064 self.component.lower_func(
2065 Some(name),
2066 func_index,
2067 if let AbiVariant::GuestImportAsync = abi {
2068 vec![CanonicalOption::Async]
2069 } else {
2070 Vec::new()
2071 },
2072 )
2073 }
2074
2075 Lowering::Indirect { .. } => {
2079 let encoding = metadata.import_encodings.get(resolve, key, name).unwrap();
2080 return Ok(self.materialize_shim_import(
2081 shims,
2082 &ShimKind::IndirectLowering {
2083 interface: interface_key,
2084 index,
2085 realloc: for_module,
2086 encoding,
2087 },
2088 ));
2089 }
2090
2091 Lowering::ResourceDrop(id) => {
2094 let resource_idx = self.lookup_resource_index(*id);
2095 self.component.resource_drop(resource_idx)
2096 }
2097 };
2098 Ok((ExportKind::Func, index))
2099 }
2100
2101 fn encode_initialize_with_start(&mut self) -> Result<()> {
2120 let initialize = match self.info.info.exports.initialize() {
2121 Some(name) => name,
2122 None => return Ok(()),
2125 };
2126 let initialize_index = self.core_alias_export(
2127 Some("start"),
2128 self.instance_index.unwrap(),
2129 initialize,
2130 ExportKind::Func,
2131 );
2132 let mut shim = Module::default();
2133 let mut section = TypeSection::new();
2134 section.ty().function([], []);
2135 shim.section(§ion);
2136 let mut section = ImportSection::new();
2137 section.import("", "", EntityType::Function(0));
2138 shim.section(§ion);
2139 shim.section(&StartSection { function_index: 0 });
2140
2141 let shim_module_index = self.component.core_module(Some("start-shim-module"), &shim);
2146 let shim_args_instance_index = self.component.core_instantiate_exports(
2147 Some("start-shim-args"),
2148 [("", ExportKind::Func, initialize_index)],
2149 );
2150 self.component.core_instantiate(
2151 Some("start-shim-instance"),
2152 shim_module_index,
2153 [("", ModuleArg::Instance(shim_args_instance_index))],
2154 );
2155 Ok(())
2156 }
2157
2158 fn instance_for(&self, module: CustomModule) -> u32 {
2161 match module {
2162 CustomModule::Main => self.instance_index.expect("instantiated by now"),
2163 CustomModule::Adapter(name) => self.adapter_instances[name],
2164 }
2165 }
2166
2167 fn module_for(&self, module: CustomModule) -> u32 {
2170 match module {
2171 CustomModule::Main => self.module_index.unwrap(),
2172 CustomModule::Adapter(name) => self.adapter_modules[name],
2173 }
2174 }
2175
2176 fn core_alias_export(
2179 &mut self,
2180 debug_name: Option<&str>,
2181 instance: u32,
2182 name: &str,
2183 kind: ExportKind,
2184 ) -> u32 {
2185 *self
2186 .aliased_core_items
2187 .entry((instance, name.to_string()))
2188 .or_insert_with(|| {
2189 self.component
2190 .core_alias_export(debug_name, instance, name, kind)
2191 })
2192 }
2193}
2194
2195#[derive(Default)]
2213struct Shims<'a> {
2214 shims: IndexMap<ShimKind<'a>, Shim<'a>>,
2216}
2217
2218struct Shim<'a> {
2219 options: RequiredOptions,
2222
2223 name: String,
2227
2228 debug_name: String,
2231
2232 kind: ShimKind<'a>,
2234
2235 sig: WasmSignature,
2237}
2238
2239#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2242enum PayloadFuncKind {
2243 FutureWrite,
2244 FutureRead,
2245 StreamWrite,
2246 StreamRead,
2247}
2248
2249#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2250enum ShimKind<'a> {
2251 IndirectLowering {
2255 interface: Option<String>,
2257 index: usize,
2259 realloc: CustomModule<'a>,
2261 encoding: StringEncoding,
2263 },
2264 Adapter {
2267 adapter: &'a str,
2269 func: &'a str,
2271 },
2272 ResourceDtor {
2275 module: CustomModule<'a>,
2277 export: &'a str,
2279 },
2280 PayloadFunc {
2284 for_module: CustomModule<'a>,
2287 info: &'a PayloadInfo,
2292 kind: PayloadFuncKind,
2294 },
2295 WaitableSetWait { cancellable: bool },
2299 WaitableSetPoll { cancellable: bool },
2303 TaskReturn {
2305 interface: Option<InterfaceId>,
2308 func: &'a str,
2311 result: Option<Type>,
2313 for_module: CustomModule<'a>,
2315 encoding: StringEncoding,
2317 },
2318 ErrorContextNew {
2322 encoding: StringEncoding,
2324 },
2325 ErrorContextDebugMessage {
2329 for_module: CustomModule<'a>,
2331 encoding: StringEncoding,
2333 },
2334 ThreadNewIndirect {
2337 for_module: CustomModule<'a>,
2339 func_ty: FuncType,
2341 },
2342}
2343
2344#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
2354enum CustomModule<'a> {
2355 Main,
2358 Adapter(&'a str),
2361}
2362
2363impl<'a> CustomModule<'a> {
2364 fn debug_name(&self) -> &'a str {
2365 match self {
2366 CustomModule::Main => "main",
2367 CustomModule::Adapter(s) => s,
2368 }
2369 }
2370}
2371
2372impl<'a> Shims<'a> {
2373 fn append_indirect(
2378 &mut self,
2379 world: &'a ComponentWorld<'a>,
2380 for_module: CustomModule<'a>,
2381 ) -> Result<()> {
2382 let module_imports = world.imports_for(for_module);
2383 let module_exports = world.exports_for(for_module);
2384 let resolve = &world.encoder.metadata.resolve;
2385
2386 for (module, field, import) in module_imports.imports() {
2387 match import {
2388 Import::ImportedResourceDrop(..)
2391 | Import::MainModuleMemory
2392 | Import::MainModuleExport { .. }
2393 | Import::Item(_)
2394 | Import::ExportedResourceDrop(..)
2395 | Import::ExportedResourceRep(..)
2396 | Import::ExportedResourceNew(..)
2397 | Import::ExportedTaskCancel
2398 | Import::ErrorContextDrop
2399 | Import::BackpressureSet
2400 | Import::BackpressureInc
2401 | Import::BackpressureDec
2402 | Import::ThreadYield { .. }
2403 | Import::SubtaskDrop
2404 | Import::SubtaskCancel { .. }
2405 | Import::FutureNew(..)
2406 | Import::StreamNew(..)
2407 | Import::FutureCancelRead { .. }
2408 | Import::FutureCancelWrite { .. }
2409 | Import::FutureDropWritable { .. }
2410 | Import::FutureDropReadable { .. }
2411 | Import::StreamCancelRead { .. }
2412 | Import::StreamCancelWrite { .. }
2413 | Import::StreamDropWritable { .. }
2414 | Import::StreamDropReadable { .. }
2415 | Import::WaitableSetNew
2416 | Import::WaitableSetDrop
2417 | Import::WaitableJoin
2418 | Import::ContextGet(_)
2419 | Import::ContextSet(_)
2420 | Import::ThreadIndex
2421 | Import::ThreadSwitchTo { .. }
2422 | Import::ThreadSuspend { .. }
2423 | Import::ThreadResumeLater
2424 | Import::ThreadYieldTo { .. } => {}
2425
2426 Import::ExportedTaskReturn(key, interface, func, ty) => {
2430 let (options, sig) = task_return_options_and_type(resolve, *ty);
2431 if options.is_empty() {
2432 continue;
2433 }
2434 let name = self.shims.len().to_string();
2435 let encoding = world
2436 .module_metadata_for(for_module)
2437 .export_encodings
2438 .get(resolve, key, func)
2439 .ok_or_else(|| {
2440 anyhow::anyhow!(
2441 "missing component metadata for export of \
2442 `{module}::{field}`"
2443 )
2444 })?;
2445 self.push(Shim {
2446 name,
2447 debug_name: format!("task-return-{func}"),
2448 options,
2449 kind: ShimKind::TaskReturn {
2450 interface: *interface,
2451 func,
2452 result: *ty,
2453 for_module,
2454 encoding,
2455 },
2456 sig,
2457 });
2458 }
2459
2460 Import::FutureWrite { async_, info } => {
2461 self.append_indirect_payload_push(
2462 resolve,
2463 for_module,
2464 module,
2465 *async_,
2466 info,
2467 PayloadFuncKind::FutureWrite,
2468 vec![WasmType::I32; 2],
2469 vec![WasmType::I32],
2470 );
2471 }
2472 Import::FutureRead { async_, info } => {
2473 self.append_indirect_payload_push(
2474 resolve,
2475 for_module,
2476 module,
2477 *async_,
2478 info,
2479 PayloadFuncKind::FutureRead,
2480 vec![WasmType::I32; 2],
2481 vec![WasmType::I32],
2482 );
2483 }
2484 Import::StreamWrite { async_, info } => {
2485 self.append_indirect_payload_push(
2486 resolve,
2487 for_module,
2488 module,
2489 *async_,
2490 info,
2491 PayloadFuncKind::StreamWrite,
2492 vec![WasmType::I32; 3],
2493 vec![WasmType::I32],
2494 );
2495 }
2496 Import::StreamRead { async_, info } => {
2497 self.append_indirect_payload_push(
2498 resolve,
2499 for_module,
2500 module,
2501 *async_,
2502 info,
2503 PayloadFuncKind::StreamRead,
2504 vec![WasmType::I32; 3],
2505 vec![WasmType::I32],
2506 );
2507 }
2508
2509 Import::WaitableSetWait { cancellable } => {
2510 let name = self.shims.len().to_string();
2511 self.push(Shim {
2512 name,
2513 debug_name: "waitable-set.wait".to_string(),
2514 options: RequiredOptions::empty(),
2515 kind: ShimKind::WaitableSetWait {
2516 cancellable: *cancellable,
2517 },
2518 sig: WasmSignature {
2519 params: vec![WasmType::I32; 2],
2520 results: vec![WasmType::I32],
2521 indirect_params: false,
2522 retptr: false,
2523 },
2524 });
2525 }
2526
2527 Import::WaitableSetPoll { cancellable } => {
2528 let name = self.shims.len().to_string();
2529 self.push(Shim {
2530 name,
2531 debug_name: "waitable-set.poll".to_string(),
2532 options: RequiredOptions::empty(),
2533 kind: ShimKind::WaitableSetPoll {
2534 cancellable: *cancellable,
2535 },
2536 sig: WasmSignature {
2537 params: vec![WasmType::I32; 2],
2538 results: vec![WasmType::I32],
2539 indirect_params: false,
2540 retptr: false,
2541 },
2542 });
2543 }
2544
2545 Import::ErrorContextNew { encoding } => {
2546 let name = self.shims.len().to_string();
2547 self.push(Shim {
2548 name,
2549 debug_name: "error-new".to_string(),
2550 options: RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING,
2551 kind: ShimKind::ErrorContextNew {
2552 encoding: *encoding,
2553 },
2554 sig: WasmSignature {
2555 params: vec![WasmType::I32; 2],
2556 results: vec![WasmType::I32],
2557 indirect_params: false,
2558 retptr: false,
2559 },
2560 });
2561 }
2562
2563 Import::ErrorContextDebugMessage { encoding } => {
2564 let name = self.shims.len().to_string();
2565 self.push(Shim {
2566 name,
2567 debug_name: "error-debug-message".to_string(),
2568 options: RequiredOptions::MEMORY
2569 | RequiredOptions::STRING_ENCODING
2570 | RequiredOptions::REALLOC,
2571 kind: ShimKind::ErrorContextDebugMessage {
2572 for_module,
2573 encoding: *encoding,
2574 },
2575 sig: WasmSignature {
2576 params: vec![WasmType::I32; 2],
2577 results: vec![],
2578 indirect_params: false,
2579 retptr: false,
2580 },
2581 });
2582 }
2583
2584 Import::ThreadNewIndirect => {
2585 let name = self.shims.len().to_string();
2586 self.push(Shim {
2587 name,
2588 debug_name: "thread.new-indirect".to_string(),
2589 options: RequiredOptions::empty(),
2590 kind: ShimKind::ThreadNewIndirect {
2591 for_module,
2592 func_ty: FuncType::new([ValType::I32], vec![]),
2594 },
2595 sig: WasmSignature {
2596 params: vec![WasmType::I32; 2],
2597 results: vec![WasmType::I32],
2598 indirect_params: false,
2599 retptr: false,
2600 },
2601 });
2602 }
2603
2604 Import::AdapterExport { adapter, func, ty } => {
2607 let name = self.shims.len().to_string();
2608 log::debug!("shim {name} is adapter `{module}::{field}`");
2609 self.push(Shim {
2610 name,
2611 debug_name: format!("adapt-{module}-{field}"),
2612 options: RequiredOptions::MEMORY,
2616 kind: ShimKind::Adapter { adapter, func },
2617 sig: WasmSignature {
2618 params: ty.params().iter().map(to_wasm_type).collect(),
2619 results: ty.results().iter().map(to_wasm_type).collect(),
2620 indirect_params: false,
2621 retptr: false,
2622 },
2623 });
2624
2625 fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType {
2626 match ty {
2627 wasmparser::ValType::I32 => WasmType::I32,
2628 wasmparser::ValType::I64 => WasmType::I64,
2629 wasmparser::ValType::F32 => WasmType::F32,
2630 wasmparser::ValType::F64 => WasmType::F64,
2631 _ => unreachable!(),
2632 }
2633 }
2634 }
2635
2636 Import::InterfaceFunc(key, _, name, abi) => {
2640 self.append_indirect_wit_func(
2641 world,
2642 for_module,
2643 module,
2644 field,
2645 key,
2646 name,
2647 Some(resolve.name_world_key(key)),
2648 *abi,
2649 )?;
2650 }
2651 Import::WorldFunc(key, name, abi) => {
2652 self.append_indirect_wit_func(
2653 world, for_module, module, field, key, name, None, *abi,
2654 )?;
2655 }
2656 }
2657 }
2658
2659 for (export_name, export) in module_exports.iter() {
2665 let id = match export {
2666 Export::ResourceDtor(id) => id,
2667 _ => continue,
2668 };
2669 let resource = resolve.types[*id].name.as_ref().unwrap();
2670 let name = self.shims.len().to_string();
2671 self.push(Shim {
2672 name,
2673 debug_name: format!("dtor-{resource}"),
2674 options: RequiredOptions::empty(),
2675 kind: ShimKind::ResourceDtor {
2676 module: for_module,
2677 export: export_name,
2678 },
2679 sig: WasmSignature {
2680 params: vec![WasmType::I32],
2681 results: Vec::new(),
2682 indirect_params: false,
2683 retptr: false,
2684 },
2685 });
2686 }
2687
2688 Ok(())
2689 }
2690
2691 fn append_indirect_payload_push(
2694 &mut self,
2695 resolve: &Resolve,
2696 for_module: CustomModule<'a>,
2697 module: &str,
2698 async_: bool,
2699 info: &'a PayloadInfo,
2700 kind: PayloadFuncKind,
2701 params: Vec<WasmType>,
2702 results: Vec<WasmType>,
2703 ) {
2704 let debug_name = format!("{module}-{}", info.name);
2705 let name = self.shims.len().to_string();
2706
2707 let payload = info.payload(resolve);
2708 let (wit_param, wit_result) = match kind {
2709 PayloadFuncKind::StreamRead | PayloadFuncKind::FutureRead => (None, payload),
2710 PayloadFuncKind::StreamWrite | PayloadFuncKind::FutureWrite => (payload, None),
2711 };
2712 self.push(Shim {
2713 name,
2714 debug_name,
2715 options: RequiredOptions::MEMORY
2716 | RequiredOptions::for_import(
2717 resolve,
2718 &Function {
2719 name: String::new(),
2720 kind: FunctionKind::Freestanding,
2721 params: match wit_param {
2722 Some(ty) => vec![("a".to_string(), ty)],
2723 None => Vec::new(),
2724 },
2725 result: wit_result,
2726 docs: Default::default(),
2727 stability: Stability::Unknown,
2728 },
2729 if async_ {
2730 AbiVariant::GuestImportAsync
2731 } else {
2732 AbiVariant::GuestImport
2733 },
2734 ),
2735 kind: ShimKind::PayloadFunc {
2736 for_module,
2737 info,
2738 kind,
2739 },
2740 sig: WasmSignature {
2741 params,
2742 results,
2743 indirect_params: false,
2744 retptr: false,
2745 },
2746 });
2747 }
2748
2749 fn append_indirect_wit_func(
2752 &mut self,
2753 world: &'a ComponentWorld<'a>,
2754 for_module: CustomModule<'a>,
2755 module: &str,
2756 field: &str,
2757 key: &WorldKey,
2758 name: &String,
2759 interface_key: Option<String>,
2760 abi: AbiVariant,
2761 ) -> Result<()> {
2762 let resolve = &world.encoder.metadata.resolve;
2763 let metadata = world.module_metadata_for(for_module);
2764 let interface = &world.import_map[&interface_key];
2765 let (index, _, lowering) = interface.lowerings.get_full(&(name.clone(), abi)).unwrap();
2766 let shim_name = self.shims.len().to_string();
2767 match lowering {
2768 Lowering::Direct | Lowering::ResourceDrop(_) => {}
2769
2770 Lowering::Indirect { sig, options } => {
2771 log::debug!(
2772 "shim {shim_name} is import `{module}::{field}` lowering {index} `{name}`",
2773 );
2774 let encoding = metadata
2775 .import_encodings
2776 .get(resolve, key, name)
2777 .ok_or_else(|| {
2778 anyhow::anyhow!(
2779 "missing component metadata for import of \
2780 `{module}::{field}`"
2781 )
2782 })?;
2783 self.push(Shim {
2784 name: shim_name,
2785 debug_name: format!("indirect-{module}-{field}"),
2786 options: *options,
2787 kind: ShimKind::IndirectLowering {
2788 interface: interface_key,
2789 index,
2790 realloc: for_module,
2791 encoding,
2792 },
2793 sig: sig.clone(),
2794 });
2795 }
2796 }
2797
2798 Ok(())
2799 }
2800
2801 fn push(&mut self, shim: Shim<'a>) {
2802 if !self.shims.contains_key(&shim.kind) {
2806 self.shims.insert(shim.kind.clone(), shim);
2807 }
2808 }
2809}
2810
2811fn task_return_options_and_type(
2812 resolve: &Resolve,
2813 ty: Option<Type>,
2814) -> (RequiredOptions, WasmSignature) {
2815 let func_tmp = Function {
2816 name: String::new(),
2817 kind: FunctionKind::Freestanding,
2818 params: match ty {
2819 Some(ty) => vec![("a".to_string(), ty)],
2820 None => Vec::new(),
2821 },
2822 result: None,
2823 docs: Default::default(),
2824 stability: Stability::Unknown,
2825 };
2826 let abi = AbiVariant::GuestImport;
2827 let options = RequiredOptions::for_import(resolve, &func_tmp, abi);
2828 let sig = resolve.wasm_signature(abi, &func_tmp);
2829 (options, sig)
2830}
2831
2832#[derive(Clone, Debug)]
2834pub struct Item {
2835 pub alias: String,
2836 pub kind: ExportKind,
2837 pub which: MainOrAdapter,
2838 pub name: String,
2839}
2840
2841#[derive(Debug, PartialEq, Clone)]
2843pub enum MainOrAdapter {
2844 Main,
2845 Adapter(String),
2846}
2847
2848impl MainOrAdapter {
2849 fn to_custom_module(&self) -> CustomModule<'_> {
2850 match self {
2851 MainOrAdapter::Main => CustomModule::Main,
2852 MainOrAdapter::Adapter(s) => CustomModule::Adapter(s),
2853 }
2854 }
2855}
2856
2857#[derive(Clone)]
2859pub enum Instance {
2860 MainOrAdapter(MainOrAdapter),
2862
2863 Items(Vec<Item>),
2865}
2866
2867#[derive(Clone)]
2870pub struct LibraryInfo {
2871 pub instantiate_after_shims: bool,
2873
2874 pub arguments: Vec<(String, Instance)>,
2876}
2877
2878pub(super) struct Adapter {
2880 wasm: Vec<u8>,
2882
2883 metadata: ModuleMetadata,
2885
2886 required_exports: IndexSet<WorldKey>,
2889
2890 library_info: Option<LibraryInfo>,
2895}
2896
2897#[derive(Default)]
2899pub struct ComponentEncoder {
2900 module: Vec<u8>,
2901 module_import_map: Option<ModuleImportMap>,
2902 pub(super) metadata: Bindgen,
2903 validate: bool,
2904 pub(super) main_module_exports: IndexSet<WorldKey>,
2905 pub(super) adapters: IndexMap<String, Adapter>,
2906 import_name_map: HashMap<String, String>,
2907 realloc_via_memory_grow: bool,
2908 merge_imports_based_on_semver: Option<bool>,
2909 pub(super) reject_legacy_names: bool,
2910 debug_names: bool,
2911}
2912
2913impl ComponentEncoder {
2914 pub fn module(mut self, module: &[u8]) -> Result<Self> {
2920 let (wasm, metadata) = self.decode(module.as_ref())?;
2921 let (wasm, module_import_map) = ModuleImportMap::new(wasm)?;
2922 let exports = self
2923 .merge_metadata(metadata)
2924 .context("failed merge WIT metadata for module with previous metadata")?;
2925 self.main_module_exports.extend(exports);
2926 self.module = if let Some(producers) = &self.metadata.producers {
2927 producers.add_to_wasm(&wasm)?
2928 } else {
2929 wasm.to_vec()
2930 };
2931 self.module_import_map = module_import_map;
2932 Ok(self)
2933 }
2934
2935 fn decode<'a>(&self, wasm: &'a [u8]) -> Result<(Cow<'a, [u8]>, Bindgen)> {
2936 let (bytes, metadata) = metadata::decode(wasm)?;
2937 match bytes {
2938 Some(wasm) => Ok((Cow::Owned(wasm), metadata)),
2939 None => Ok((Cow::Borrowed(wasm), metadata)),
2940 }
2941 }
2942
2943 fn merge_metadata(&mut self, metadata: Bindgen) -> Result<IndexSet<WorldKey>> {
2944 self.metadata.merge(metadata)
2945 }
2946
2947 pub fn validate(mut self, validate: bool) -> Self {
2949 self.validate = validate;
2950 self
2951 }
2952
2953 pub fn debug_names(mut self, debug_names: bool) -> Self {
2955 self.debug_names = debug_names;
2956 self
2957 }
2958
2959 pub fn merge_imports_based_on_semver(mut self, merge: bool) -> Self {
2967 self.merge_imports_based_on_semver = Some(merge);
2968 self
2969 }
2970
2971 pub fn reject_legacy_names(mut self, reject: bool) -> Self {
2980 self.reject_legacy_names = reject;
2981 self
2982 }
2983
2984 pub fn adapter(self, name: &str, bytes: &[u8]) -> Result<Self> {
3002 self.library_or_adapter(name, bytes, None)
3003 }
3004
3005 pub fn library(self, name: &str, bytes: &[u8], library_info: LibraryInfo) -> Result<Self> {
3018 self.library_or_adapter(name, bytes, Some(library_info))
3019 }
3020
3021 fn library_or_adapter(
3022 mut self,
3023 name: &str,
3024 bytes: &[u8],
3025 library_info: Option<LibraryInfo>,
3026 ) -> Result<Self> {
3027 let (wasm, mut metadata) = self.decode(bytes)?;
3028 let adapter_metadata = mem::take(&mut metadata.metadata);
3036 let exports = self.merge_metadata(metadata).with_context(|| {
3037 format!("failed to merge WIT packages of adapter `{name}` into main packages")
3038 })?;
3039 if let Some(library_info) = &library_info {
3040 for (_, instance) in &library_info.arguments {
3042 let resolve = |which: &_| match which {
3043 MainOrAdapter::Main => Ok(()),
3044 MainOrAdapter::Adapter(name) => {
3045 if self.adapters.contains_key(name.as_str()) {
3046 Ok(())
3047 } else {
3048 Err(anyhow!("instance refers to unknown adapter `{name}`"))
3049 }
3050 }
3051 };
3052
3053 match instance {
3054 Instance::MainOrAdapter(which) => resolve(which)?,
3055 Instance::Items(items) => {
3056 for item in items {
3057 resolve(&item.which)?;
3058 }
3059 }
3060 }
3061 }
3062 }
3063 self.adapters.insert(
3064 name.to_string(),
3065 Adapter {
3066 wasm: wasm.to_vec(),
3067 metadata: adapter_metadata,
3068 required_exports: exports,
3069 library_info,
3070 },
3071 );
3072 Ok(self)
3073 }
3074
3075 pub fn realloc_via_memory_grow(mut self, value: bool) -> Self {
3080 self.realloc_via_memory_grow = value;
3081 self
3082 }
3083
3084 pub fn import_name_map(mut self, map: HashMap<String, String>) -> Self {
3095 self.import_name_map = map;
3096 self
3097 }
3098
3099 pub fn encode(&mut self) -> Result<Vec<u8>> {
3101 if self.module.is_empty() {
3102 bail!("a module is required when encoding a component");
3103 }
3104
3105 if self.merge_imports_based_on_semver.unwrap_or(true) {
3106 self.metadata
3107 .resolve
3108 .merge_world_imports_based_on_semver(self.metadata.world)?;
3109 }
3110
3111 let world = ComponentWorld::new(self).context("failed to decode world from module")?;
3112 let mut state = EncodingState {
3113 component: ComponentBuilder::default(),
3114 module_index: None,
3115 instance_index: None,
3116 memory_index: None,
3117 shim_instance_index: None,
3118 fixups_module_index: None,
3119 adapter_modules: IndexMap::new(),
3120 adapter_instances: IndexMap::new(),
3121 import_type_encoding_maps: Default::default(),
3122 export_type_encoding_maps: Default::default(),
3123 imported_instances: Default::default(),
3124 imported_funcs: Default::default(),
3125 exported_instances: Default::default(),
3126 aliased_core_items: Default::default(),
3127 info: &world,
3128 };
3129 state.encode_imports(&self.import_name_map)?;
3130 state.encode_core_modules();
3131 state.encode_core_instantiation()?;
3132 state.encode_exports(CustomModule::Main)?;
3133 for name in self.adapters.keys() {
3134 state.encode_exports(CustomModule::Adapter(name))?;
3135 }
3136 state.component.append_names();
3137 state
3138 .component
3139 .raw_custom_section(&crate::base_producers().raw_custom_section());
3140 let bytes = state.component.finish();
3141
3142 if self.validate {
3143 Validator::new_with_features(WasmFeatures::all())
3144 .validate_all(&bytes)
3145 .context("failed to validate component output")?;
3146 }
3147
3148 Ok(bytes)
3149 }
3150}
3151
3152impl ComponentWorld<'_> {
3153 fn imports_for(&self, module: CustomModule) -> &ImportMap {
3155 match module {
3156 CustomModule::Main => &self.info.imports,
3157 CustomModule::Adapter(name) => &self.adapters[name].info.imports,
3158 }
3159 }
3160
3161 fn exports_for(&self, module: CustomModule) -> &ExportMap {
3163 match module {
3164 CustomModule::Main => &self.info.exports,
3165 CustomModule::Adapter(name) => &self.adapters[name].info.exports,
3166 }
3167 }
3168
3169 fn module_metadata_for(&self, module: CustomModule) -> &ModuleMetadata {
3171 match module {
3172 CustomModule::Main => &self.encoder.metadata.metadata,
3173 CustomModule::Adapter(name) => &self.encoder.adapters[name].metadata,
3174 }
3175 }
3176}
3177
3178#[cfg(all(test, feature = "dummy-module"))]
3179mod test {
3180 use super::*;
3181 use crate::{dummy_module, embed_component_metadata};
3182 use wit_parser::ManglingAndAbi;
3183
3184 #[test]
3185 fn it_renames_imports() {
3186 let mut resolve = Resolve::new();
3187 let pkg = resolve
3188 .push_str(
3189 "test.wit",
3190 r#"
3191package test:wit;
3192
3193interface i {
3194 f: func();
3195}
3196
3197world test {
3198 import i;
3199 import foo: interface {
3200 f: func();
3201 }
3202}
3203"#,
3204 )
3205 .unwrap();
3206 let world = resolve.select_world(&[pkg], None).unwrap();
3207
3208 let mut module = dummy_module(&resolve, world, ManglingAndAbi::Standard32);
3209
3210 embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8).unwrap();
3211
3212 let encoded = ComponentEncoder::default()
3213 .import_name_map(HashMap::from([
3214 (
3215 "foo".to_string(),
3216 "unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>".to_string(),
3217 ),
3218 (
3219 "test:wit/i".to_string(),
3220 "locked-dep=<foo:bar/i@1.2.3>".to_string(),
3221 ),
3222 ]))
3223 .module(&module)
3224 .unwrap()
3225 .validate(true)
3226 .encode()
3227 .unwrap();
3228
3229 let wat = wasmprinter::print_bytes(encoded).unwrap();
3230 assert!(wat.contains("unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>"));
3231 assert!(wat.contains("locked-dep=<foo:bar/i@1.2.3>"));
3232 }
3233}