1use crate::StringEncoding;
75use crate::metadata::{self, Bindgen, ModuleMetadata};
76use crate::validation::{Export, ExportMap, Import, ImportInstance, ImportMap, PayloadInfo};
77use anyhow::{Context, Result, anyhow, bail};
78use indexmap::{IndexMap, IndexSet};
79use std::borrow::Cow;
80use std::collections::HashMap;
81use std::hash::Hash;
82use std::mem;
83use wasm_encoder::*;
84use wasmparser::{Validator, WasmFeatures};
85use wit_parser::{
86 Function, FunctionKind, InterfaceId, LiveTypes, Resolve, Stability, Type, TypeDefKind, TypeId,
87 TypeOwner, WorldItem, WorldKey,
88 abi::{AbiVariant, WasmSignature, WasmType},
89};
90
91const INDIRECT_TABLE_NAME: &str = "$imports";
92
93mod wit;
94pub use wit::{encode, encode_world};
95
96mod types;
97use types::{InstanceTypeEncoder, RootTypeEncoder, TypeEncodingMaps, ValtypeEncoder};
98mod world;
99use world::{ComponentWorld, ImportedInterface, Lowering};
100
101mod dedupe;
102pub(crate) use dedupe::ModuleImportMap;
103use wasm_metadata::AddMetadataField;
104
105fn to_val_type(ty: &WasmType) -> ValType {
106 match ty {
107 WasmType::I32 => ValType::I32,
108 WasmType::I64 => ValType::I64,
109 WasmType::F32 => ValType::F32,
110 WasmType::F64 => ValType::F64,
111 WasmType::Pointer => ValType::I32,
112 WasmType::PointerOrI64 => ValType::I64,
113 WasmType::Length => ValType::I32,
114 }
115}
116
117bitflags::bitflags! {
118 #[derive(Copy, Clone, Debug)]
121 pub struct RequiredOptions: u8 {
122 const MEMORY = 1 << 0;
125 const REALLOC = 1 << 1;
128 const STRING_ENCODING = 1 << 2;
131 const ASYNC = 1 << 3;
132 }
133}
134
135impl RequiredOptions {
136 fn for_import(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
137 let sig = resolve.wasm_signature(abi, func);
138 let mut ret = RequiredOptions::empty();
139 ret.add_lift(TypeContents::for_types(
141 resolve,
142 func.params.iter().map(|(_, t)| t),
143 ));
144 ret.add_lower(TypeContents::for_types(resolve, &func.result));
145
146 if sig.retptr || sig.indirect_params {
149 ret |= RequiredOptions::MEMORY;
150 }
151 if abi == AbiVariant::GuestImportAsync {
152 ret |= RequiredOptions::ASYNC;
153 }
154 ret
155 }
156
157 fn for_export(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
158 let sig = resolve.wasm_signature(abi, func);
159 let mut ret = RequiredOptions::empty();
160 ret.add_lower(TypeContents::for_types(
162 resolve,
163 func.params.iter().map(|(_, t)| t),
164 ));
165 ret.add_lift(TypeContents::for_types(resolve, &func.result));
166
167 if sig.retptr || sig.indirect_params {
171 ret |= RequiredOptions::MEMORY;
172 if sig.indirect_params {
173 ret |= RequiredOptions::REALLOC;
174 }
175 }
176 if let AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful = abi {
177 ret |= RequiredOptions::ASYNC;
178 }
179 ret
180 }
181
182 fn add_lower(&mut self, types: TypeContents) {
183 if types.contains(TypeContents::LIST) {
187 *self |= RequiredOptions::MEMORY | RequiredOptions::REALLOC;
188 }
189 if types.contains(TypeContents::STRING) {
190 *self |= RequiredOptions::MEMORY
191 | RequiredOptions::STRING_ENCODING
192 | RequiredOptions::REALLOC;
193 }
194 }
195
196 fn add_lift(&mut self, types: TypeContents) {
197 if types.contains(TypeContents::LIST) {
201 *self |= RequiredOptions::MEMORY;
202 }
203 if types.contains(TypeContents::STRING) {
204 *self |= RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING;
205 }
206 }
207
208 fn into_iter(
209 self,
210 encoding: StringEncoding,
211 memory_index: Option<u32>,
212 realloc_index: Option<u32>,
213 ) -> Result<impl ExactSizeIterator<Item = CanonicalOption>> {
214 #[derive(Default)]
215 struct Iter {
216 options: [Option<CanonicalOption>; 5],
217 current: usize,
218 count: usize,
219 }
220
221 impl Iter {
222 fn push(&mut self, option: CanonicalOption) {
223 assert!(self.count < self.options.len());
224 self.options[self.count] = Some(option);
225 self.count += 1;
226 }
227 }
228
229 impl Iterator for Iter {
230 type Item = CanonicalOption;
231
232 fn next(&mut self) -> Option<Self::Item> {
233 if self.current == self.count {
234 return None;
235 }
236 let option = self.options[self.current];
237 self.current += 1;
238 option
239 }
240
241 fn size_hint(&self) -> (usize, Option<usize>) {
242 (self.count - self.current, Some(self.count - self.current))
243 }
244 }
245
246 impl ExactSizeIterator for Iter {}
247
248 let mut iter = Iter::default();
249
250 if self.contains(RequiredOptions::MEMORY) {
251 iter.push(CanonicalOption::Memory(memory_index.ok_or_else(|| {
252 anyhow!("module does not export a memory named `memory`")
253 })?));
254 }
255
256 if self.contains(RequiredOptions::REALLOC) {
257 iter.push(CanonicalOption::Realloc(realloc_index.ok_or_else(
258 || anyhow!("module does not export a function named `cabi_realloc`"),
259 )?));
260 }
261
262 if self.contains(RequiredOptions::STRING_ENCODING) {
263 iter.push(encoding.into());
264 }
265
266 if self.contains(RequiredOptions::ASYNC) {
267 iter.push(CanonicalOption::Async);
268 }
269
270 Ok(iter)
271 }
272}
273
274bitflags::bitflags! {
275 struct TypeContents: u8 {
278 const STRING = 1 << 0;
279 const LIST = 1 << 1;
280 }
281}
282
283impl TypeContents {
284 fn for_types<'a>(resolve: &Resolve, types: impl IntoIterator<Item = &'a Type>) -> Self {
285 let mut cur = TypeContents::empty();
286 for ty in types {
287 cur |= Self::for_type(resolve, ty);
288 }
289 cur
290 }
291
292 fn for_optional_types<'a>(
293 resolve: &Resolve,
294 types: impl Iterator<Item = Option<&'a Type>>,
295 ) -> Self {
296 Self::for_types(resolve, types.flatten())
297 }
298
299 fn for_optional_type(resolve: &Resolve, ty: Option<&Type>) -> Self {
300 match ty {
301 Some(ty) => Self::for_type(resolve, ty),
302 None => Self::empty(),
303 }
304 }
305
306 fn for_type(resolve: &Resolve, ty: &Type) -> Self {
307 match ty {
308 Type::Id(id) => match &resolve.types[*id].kind {
309 TypeDefKind::Handle(h) => match h {
310 wit_parser::Handle::Own(_) => Self::empty(),
311 wit_parser::Handle::Borrow(_) => Self::empty(),
312 },
313 TypeDefKind::Resource => Self::empty(),
314 TypeDefKind::Record(r) => Self::for_types(resolve, r.fields.iter().map(|f| &f.ty)),
315 TypeDefKind::Tuple(t) => Self::for_types(resolve, t.types.iter()),
316 TypeDefKind::Flags(_) => Self::empty(),
317 TypeDefKind::Option(t) => Self::for_type(resolve, t),
318 TypeDefKind::Result(r) => {
319 Self::for_optional_type(resolve, r.ok.as_ref())
320 | Self::for_optional_type(resolve, r.err.as_ref())
321 }
322 TypeDefKind::Variant(v) => {
323 Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref()))
324 }
325 TypeDefKind::Enum(_) => Self::empty(),
326 TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::LIST,
327 TypeDefKind::FixedSizeList(t, _elements) => Self::for_type(resolve, t),
328 TypeDefKind::Type(t) => Self::for_type(resolve, t),
329 TypeDefKind::Future(_) => Self::empty(),
330 TypeDefKind::Stream(_) => Self::empty(),
331 TypeDefKind::Unknown => unreachable!(),
332 },
333 Type::String => Self::STRING,
334 _ => Self::empty(),
335 }
336 }
337}
338
339pub struct EncodingState<'a> {
341 component: ComponentBuilder,
343 module_index: Option<u32>,
347 instance_index: Option<u32>,
351 memory_index: Option<u32>,
355 shim_instance_index: Option<u32>,
359 fixups_module_index: Option<u32>,
363
364 adapter_modules: IndexMap<&'a str, u32>,
367 adapter_instances: IndexMap<&'a str, u32>,
369
370 imported_instances: IndexMap<InterfaceId, u32>,
372 imported_funcs: IndexMap<String, u32>,
373 exported_instances: IndexMap<InterfaceId, u32>,
374
375 import_type_encoding_maps: TypeEncodingMaps<'a>,
380 export_type_encoding_maps: TypeEncodingMaps<'a>,
381
382 aliased_core_items: HashMap<(u32, String), u32>,
388
389 info: &'a ComponentWorld<'a>,
391}
392
393impl<'a> EncodingState<'a> {
394 fn encode_core_modules(&mut self) {
395 assert!(self.module_index.is_none());
396 let idx = self.component.core_module_raw(&self.info.encoder.module);
397 self.module_index = Some(idx);
398
399 for (name, adapter) in self.info.adapters.iter() {
400 let mut add_meta = wasm_metadata::AddMetadata::default();
401 add_meta.name = AddMetadataField::Set(if adapter.library_info.is_some() {
402 name.to_string()
403 } else {
404 format!("wit-component:adapter:{name}")
405 });
406 let wasm = add_meta
407 .to_wasm(&adapter.wasm)
408 .expect("core wasm can get name added");
409 let idx = self.component.core_module_raw(&wasm);
410 let prev = self.adapter_modules.insert(name, idx);
411 assert!(prev.is_none());
412 }
413 }
414
415 fn root_import_type_encoder(
416 &mut self,
417 interface: Option<InterfaceId>,
418 ) -> RootTypeEncoder<'_, 'a> {
419 RootTypeEncoder {
420 state: self,
421 interface,
422 import_types: true,
423 }
424 }
425
426 fn root_export_type_encoder(
427 &mut self,
428 interface: Option<InterfaceId>,
429 ) -> RootTypeEncoder<'_, 'a> {
430 RootTypeEncoder {
431 state: self,
432 interface,
433 import_types: false,
434 }
435 }
436
437 fn instance_type_encoder(&mut self, interface: InterfaceId) -> InstanceTypeEncoder<'_, 'a> {
438 InstanceTypeEncoder {
439 state: self,
440 interface,
441 type_encoding_maps: Default::default(),
442 ty: Default::default(),
443 }
444 }
445
446 fn encode_imports(&mut self, name_map: &HashMap<String, String>) -> Result<()> {
447 let mut has_funcs = false;
448 for (name, info) in self.info.import_map.iter() {
449 match name {
450 Some(name) => {
451 self.encode_interface_import(name_map.get(name).unwrap_or(name), info)?
452 }
453 None => has_funcs = true,
454 }
455 }
456
457 let resolve = &self.info.encoder.metadata.resolve;
458 let world = &resolve.worlds[self.info.encoder.metadata.world];
459
460 for (_name, item) in world.imports.iter() {
463 if let WorldItem::Type(ty) = item {
464 self.root_import_type_encoder(None)
465 .encode_valtype(resolve, &Type::Id(*ty))?;
466 }
467 }
468
469 if has_funcs {
470 let info = &self.info.import_map[&None];
471 self.encode_root_import_funcs(info)?;
472 }
473 Ok(())
474 }
475
476 fn encode_interface_import(&mut self, name: &str, info: &ImportedInterface) -> Result<()> {
477 let resolve = &self.info.encoder.metadata.resolve;
478 let interface_id = info.interface.as_ref().unwrap();
479 let interface_id = *interface_id;
480 let interface = &resolve.interfaces[interface_id];
481 log::trace!("encoding imports for `{name}` as {:?}", interface_id);
482 let mut encoder = self.instance_type_encoder(interface_id);
483
484 if let Some(live) = encoder.state.info.live_type_imports.get(&interface_id) {
486 for ty in live {
487 log::trace!(
488 "encoding extra type {ty:?} name={:?}",
489 resolve.types[*ty].name
490 );
491 encoder.encode_valtype(resolve, &Type::Id(*ty))?;
492 }
493 }
494
495 for (_, func) in interface.functions.iter() {
498 if !(info
499 .lowerings
500 .contains_key(&(func.name.clone(), AbiVariant::GuestImport))
501 || info
502 .lowerings
503 .contains_key(&(func.name.clone(), AbiVariant::GuestImportAsync)))
504 {
505 continue;
506 }
507 log::trace!("encoding function type for `{}`", func.name);
508 let idx = encoder.encode_func_type(resolve, func)?;
509
510 encoder.ty.export(&func.name, ComponentTypeRef::Func(idx));
511 }
512
513 let ty = encoder.ty;
514 if ty.is_empty() {
517 return Ok(());
518 }
519 let instance_type_idx = self.component.type_instance(&ty);
520 let instance_idx = self
521 .component
522 .import(name, ComponentTypeRef::Instance(instance_type_idx));
523 let prev = self.imported_instances.insert(interface_id, instance_idx);
524 assert!(prev.is_none());
525 Ok(())
526 }
527
528 fn encode_root_import_funcs(&mut self, info: &ImportedInterface) -> Result<()> {
529 let resolve = &self.info.encoder.metadata.resolve;
530 let world = self.info.encoder.metadata.world;
531 for (name, item) in resolve.worlds[world].imports.iter() {
532 let func = match item {
533 WorldItem::Function(f) => f,
534 WorldItem::Interface { .. } | WorldItem::Type(_) => continue,
535 };
536 let name = resolve.name_world_key(name);
537 if !(info
538 .lowerings
539 .contains_key(&(name.clone(), AbiVariant::GuestImport))
540 || info
541 .lowerings
542 .contains_key(&(name.clone(), AbiVariant::GuestImportAsync)))
543 {
544 continue;
545 }
546 log::trace!("encoding function type for `{}`", func.name);
547 let idx = self
548 .root_import_type_encoder(None)
549 .encode_func_type(resolve, func)?;
550 let func_idx = self.component.import(&name, ComponentTypeRef::Func(idx));
551 let prev = self.imported_funcs.insert(name, func_idx);
552 assert!(prev.is_none());
553 }
554 Ok(())
555 }
556
557 fn alias_imported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
558 let ty = &self.info.encoder.metadata.resolve.types[id];
559 let name = ty.name.as_ref().expect("type must have a name");
560 let instance = self.imported_instances[&interface];
561 self.component
562 .alias_export(instance, name, ComponentExportKind::Type)
563 }
564
565 fn alias_exported_type(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
566 let ty = &self.info.encoder.metadata.resolve.types[id];
567 let name = ty.name.as_ref().expect("type must have a name");
568 let instance = self.exported_instances[&interface];
569 self.component
570 .alias_export(instance, name, ComponentExportKind::Type)
571 }
572
573 fn encode_core_instantiation(&mut self) -> Result<()> {
574 let shims = self.encode_shim_instantiation()?;
576
577 self.declare_types_for_imported_intrinsics(&shims)?;
581
582 self.instantiate_main_module(&shims)?;
586
587 let (before, after) = self
590 .info
591 .adapters
592 .iter()
593 .partition::<Vec<_>, _>(|(_, adapter)| {
594 !matches!(
595 adapter.library_info,
596 Some(LibraryInfo {
597 instantiate_after_shims: true,
598 ..
599 })
600 )
601 });
602
603 for (name, _adapter) in before {
604 self.instantiate_adapter_module(&shims, name)?;
605 }
606
607 self.encode_indirect_lowerings(&shims)?;
610
611 for (name, _adapter) in after {
612 self.instantiate_adapter_module(&shims, name)?;
613 }
614
615 self.encode_initialize_with_start()?;
616
617 Ok(())
618 }
619
620 fn lookup_resource_index(&mut self, id: TypeId) -> u32 {
621 let resolve = &self.info.encoder.metadata.resolve;
622 let ty = &resolve.types[id];
623 match ty.owner {
624 TypeOwner::World(_) => self.import_type_encoding_maps.id_to_index[&id],
628 TypeOwner::Interface(i) => {
629 let instance = self.imported_instances[&i];
630 let name = ty.name.as_ref().expect("resources must be named");
631 self.component
632 .alias_export(instance, name, ComponentExportKind::Type)
633 }
634 TypeOwner::None => panic!("resources must have an owner"),
635 }
636 }
637
638 fn encode_exports(&mut self, module: CustomModule) -> Result<()> {
639 let resolve = &self.info.encoder.metadata.resolve;
640 let exports = match module {
641 CustomModule::Main => &self.info.encoder.main_module_exports,
642 CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports,
643 };
644
645 if exports.is_empty() {
646 return Ok(());
647 }
648
649 let mut interface_func_core_names = IndexMap::new();
650 let mut world_func_core_names = IndexMap::new();
651 for (core_name, export) in self.info.exports_for(module).iter() {
652 match export {
653 Export::WorldFunc(_, name, _) => {
654 let prev = world_func_core_names.insert(name, core_name);
655 assert!(prev.is_none());
656 }
657 Export::InterfaceFunc(_, id, name, _) => {
658 let prev = interface_func_core_names
659 .entry(id)
660 .or_insert(IndexMap::new())
661 .insert(name.as_str(), core_name);
662 assert!(prev.is_none());
663 }
664 Export::WorldFuncCallback(..)
665 | Export::InterfaceFuncCallback(..)
666 | Export::WorldFuncPostReturn(..)
667 | Export::InterfaceFuncPostReturn(..)
668 | Export::ResourceDtor(..)
669 | Export::Memory
670 | Export::GeneralPurposeRealloc
671 | Export::GeneralPurposeExportRealloc
672 | Export::GeneralPurposeImportRealloc
673 | Export::Initialize
674 | Export::ReallocForAdapter => continue,
675 }
676 }
677
678 let world = &resolve.worlds[self.info.encoder.metadata.world];
679
680 for export_name in exports {
681 let export_string = resolve.name_world_key(export_name);
682 match &world.exports[export_name] {
683 WorldItem::Function(func) => {
684 let ty = self
685 .root_import_type_encoder(None)
686 .encode_func_type(resolve, func)?;
687 let core_name = world_func_core_names[&func.name];
688 let idx = self.encode_lift(module, &core_name, export_name, func, ty)?;
689 self.component
690 .export(&export_string, ComponentExportKind::Func, idx, None);
691 }
692 WorldItem::Interface { id, .. } => {
693 let core_names = interface_func_core_names.get(id);
694 self.encode_interface_export(
695 &export_string,
696 module,
697 export_name,
698 *id,
699 core_names,
700 )?;
701 }
702 WorldItem::Type(_) => unreachable!(),
703 }
704 }
705
706 Ok(())
707 }
708
709 fn encode_interface_export(
710 &mut self,
711 export_name: &str,
712 module: CustomModule<'_>,
713 key: &WorldKey,
714 export: InterfaceId,
715 interface_func_core_names: Option<&IndexMap<&str, &str>>,
716 ) -> Result<()> {
717 log::trace!("encode interface export `{export_name}`");
718 let resolve = &self.info.encoder.metadata.resolve;
719
720 let mut imports = Vec::new();
727 let mut root = self.root_export_type_encoder(Some(export));
728 for (_, func) in &resolve.interfaces[export].functions {
729 let core_name = interface_func_core_names.unwrap()[func.name.as_str()];
730 let ty = root.encode_func_type(resolve, func)?;
731 let func_index = root.state.encode_lift(module, &core_name, key, func, ty)?;
732 imports.push((
733 import_func_name(func),
734 ComponentExportKind::Func,
735 func_index,
736 ));
737 }
738
739 let mut nested = NestedComponentTypeEncoder {
743 component: ComponentBuilder::default(),
744 type_encoding_maps: Default::default(),
745 export_types: false,
746 interface: export,
747 state: self,
748 imports: IndexMap::new(),
749 };
750
751 let mut types_to_import = LiveTypes::default();
761 types_to_import.add_interface(resolve, export);
762 let exports_used = &nested.state.info.exports_used[&export];
763 for ty in types_to_import.iter() {
764 if let TypeOwner::Interface(owner) = resolve.types[ty].owner {
765 if owner == export {
766 continue;
769 }
770
771 let mut encoder = if exports_used.contains(&owner) {
774 nested.state.root_export_type_encoder(Some(export))
775 } else {
776 nested.state.root_import_type_encoder(Some(export))
777 };
778 encoder.encode_valtype(resolve, &Type::Id(ty))?;
779
780 nested.interface = owner;
784 nested.encode_valtype(resolve, &Type::Id(ty))?;
785 }
786 }
787 nested.interface = export;
788
789 let imported_type_maps = nested.type_encoding_maps.clone();
793
794 let mut resources = HashMap::new();
800 for (_name, ty) in resolve.interfaces[export].types.iter() {
801 if !matches!(resolve.types[*ty].kind, TypeDefKind::Resource) {
802 continue;
803 }
804 let idx = match nested.encode_valtype(resolve, &Type::Id(*ty))? {
805 ComponentValType::Type(idx) => idx,
806 _ => unreachable!(),
807 };
808 resources.insert(*ty, idx);
809 }
810
811 for (_, func) in resolve.interfaces[export].functions.iter() {
815 let ty = nested.encode_func_type(resolve, func)?;
816 nested
817 .component
818 .import(&import_func_name(func), ComponentTypeRef::Func(ty));
819 }
820
821 let reverse_map = nested
828 .type_encoding_maps
829 .id_to_index
830 .drain()
831 .map(|p| (p.1, p.0))
832 .collect::<HashMap<_, _>>();
833 nested.type_encoding_maps.def_to_index.clear();
834 for (name, idx) in nested.imports.drain(..) {
835 let id = reverse_map[&idx];
836 let owner = match resolve.types[id].owner {
837 TypeOwner::Interface(id) => id,
838 _ => unreachable!(),
839 };
840 let idx = if owner == export || exports_used.contains(&owner) {
841 log::trace!("consulting exports for {id:?}");
842 nested.state.export_type_encoding_maps.id_to_index[&id]
843 } else {
844 log::trace!("consulting imports for {id:?}");
845 nested.state.import_type_encoding_maps.id_to_index[&id]
846 };
847 imports.push((name, ComponentExportKind::Type, idx))
848 }
849
850 nested.type_encoding_maps = imported_type_maps;
855
856 nested.export_types = true;
863 nested.type_encoding_maps.func_type_map.clear();
864
865 for (_, id) in resolve.interfaces[export].types.iter() {
871 let ty = &resolve.types[*id];
872 match ty.kind {
873 TypeDefKind::Resource => {
874 let idx = nested.component.export(
875 ty.name.as_ref().expect("resources must be named"),
876 ComponentExportKind::Type,
877 resources[id],
878 None,
879 );
880 nested.type_encoding_maps.id_to_index.insert(*id, idx);
881 }
882 _ => {
883 nested.encode_valtype(resolve, &Type::Id(*id))?;
884 }
885 }
886 }
887
888 for (i, (_, func)) in resolve.interfaces[export].functions.iter().enumerate() {
889 let ty = nested.encode_func_type(resolve, func)?;
890 nested.component.export(
891 &func.name,
892 ComponentExportKind::Func,
893 i as u32,
894 Some(ComponentTypeRef::Func(ty)),
895 );
896 }
897
898 let component = nested.component;
902 let component_index = self.component.component(component);
903 let instance_index = self.component.instantiate(component_index, imports);
904 let idx = self.component.export(
905 export_name,
906 ComponentExportKind::Instance,
907 instance_index,
908 None,
909 );
910 let prev = self.exported_instances.insert(export, idx);
911 assert!(prev.is_none());
912
913 for (_name, id) in resolve.interfaces[export].types.iter() {
921 self.export_type_encoding_maps.id_to_index.remove(id);
922 self.export_type_encoding_maps
923 .def_to_index
924 .remove(&resolve.types[*id].kind);
925 }
926
927 return Ok(());
928
929 struct NestedComponentTypeEncoder<'state, 'a> {
930 component: ComponentBuilder,
931 type_encoding_maps: TypeEncodingMaps<'a>,
932 export_types: bool,
933 interface: InterfaceId,
934 state: &'state mut EncodingState<'a>,
935 imports: IndexMap<String, u32>,
936 }
937
938 impl<'a> ValtypeEncoder<'a> for NestedComponentTypeEncoder<'_, 'a> {
939 fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
940 self.component.type_defined()
941 }
942 fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
943 self.component.type_function()
944 }
945 fn export_type(&mut self, idx: u32, name: &'a str) -> Option<u32> {
946 if self.export_types {
947 Some(
948 self.component
949 .export(name, ComponentExportKind::Type, idx, None),
950 )
951 } else {
952 let name = self.unique_import_name(name);
953 let ret = self
954 .component
955 .import(&name, ComponentTypeRef::Type(TypeBounds::Eq(idx)));
956 self.imports.insert(name, ret);
957 Some(ret)
958 }
959 }
960 fn export_resource(&mut self, name: &'a str) -> u32 {
961 if self.export_types {
962 panic!("resources should already be exported")
963 } else {
964 let name = self.unique_import_name(name);
965 let ret = self
966 .component
967 .import(&name, ComponentTypeRef::Type(TypeBounds::SubResource));
968 self.imports.insert(name, ret);
969 ret
970 }
971 }
972 fn import_type(&mut self, _: InterfaceId, _id: TypeId) -> u32 {
973 unreachable!()
974 }
975 fn type_encoding_maps(&mut self) -> &mut TypeEncodingMaps<'a> {
976 &mut self.type_encoding_maps
977 }
978 fn interface(&self) -> Option<InterfaceId> {
979 Some(self.interface)
980 }
981 }
982
983 impl NestedComponentTypeEncoder<'_, '_> {
984 fn unique_import_name(&mut self, name: &str) -> String {
985 let mut name = format!("import-type-{name}");
986 let mut n = 0;
987 while self.imports.contains_key(&name) {
988 name = format!("{name}{n}");
989 n += 1;
990 }
991 name
992 }
993 }
994
995 fn import_func_name(f: &Function) -> String {
996 match f.kind {
997 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
998 format!("import-func-{}", f.item_name())
999 }
1000
1001 FunctionKind::Method(_)
1009 | FunctionKind::AsyncMethod(_)
1010 | FunctionKind::Static(_)
1011 | FunctionKind::AsyncStatic(_)
1012 | FunctionKind::Constructor(_) => {
1013 format!(
1014 "import-{}",
1015 f.name.replace('[', "").replace([']', '.', ' '], "-")
1016 )
1017 }
1018 }
1019 }
1020 }
1021
1022 fn encode_lift(
1023 &mut self,
1024 module: CustomModule<'_>,
1025 core_name: &str,
1026 key: &WorldKey,
1027 func: &Function,
1028 ty: u32,
1029 ) -> Result<u32> {
1030 let resolve = &self.info.encoder.metadata.resolve;
1031 let metadata = self.info.module_metadata_for(module);
1032 let instance_index = self.instance_for(module);
1033 let core_func_index = self.core_alias_export(instance_index, core_name, ExportKind::Func);
1034 let exports = self.info.exports_for(module);
1035
1036 let options = RequiredOptions::for_export(
1037 resolve,
1038 func,
1039 exports
1040 .abi(key, func)
1041 .ok_or_else(|| anyhow!("no ABI found for {}", func.name))?,
1042 );
1043
1044 let encoding = metadata
1045 .export_encodings
1046 .get(resolve, key, &func.name)
1047 .unwrap();
1048 let exports = self.info.exports_for(module);
1049 let realloc_index = exports
1050 .export_realloc_for(key, &func.name)
1051 .map(|name| self.core_alias_export(instance_index, name, ExportKind::Func));
1052 let mut options = options
1053 .into_iter(encoding, self.memory_index, realloc_index)?
1054 .collect::<Vec<_>>();
1055
1056 if let Some(post_return) = exports.post_return(key, func) {
1057 let post_return = self.core_alias_export(instance_index, post_return, ExportKind::Func);
1058 options.push(CanonicalOption::PostReturn(post_return));
1059 }
1060 if let Some(callback) = exports.callback(key, func) {
1061 let callback = self.core_alias_export(instance_index, callback, ExportKind::Func);
1062 options.push(CanonicalOption::Callback(callback));
1063 }
1064 let func_index = self.component.lift_func(core_func_index, ty, options);
1065 Ok(func_index)
1066 }
1067
1068 fn encode_shim_instantiation(&mut self) -> Result<Shims<'a>> {
1069 let mut ret = Shims::default();
1070
1071 ret.append_indirect(self.info, CustomModule::Main)
1072 .context("failed to register indirect shims for main module")?;
1073
1074 for (adapter_name, _adapter) in self.info.adapters.iter() {
1078 ret.append_indirect(self.info, CustomModule::Adapter(adapter_name))
1079 .with_context(|| {
1080 format!("failed to register indirect shims for adapter {adapter_name}")
1081 })?;
1082 }
1083
1084 if ret.shims.is_empty() {
1085 return Ok(ret);
1086 }
1087
1088 assert!(self.shim_instance_index.is_none());
1089 assert!(self.fixups_module_index.is_none());
1090
1091 let mut types = TypeSection::new();
1100 let mut tables = TableSection::new();
1101 let mut functions = FunctionSection::new();
1102 let mut exports = ExportSection::new();
1103 let mut code = CodeSection::new();
1104 let mut sigs = IndexMap::new();
1105 let mut imports_section = ImportSection::new();
1106 let mut elements = ElementSection::new();
1107 let mut func_indexes = Vec::new();
1108 let mut func_names = NameMap::new();
1109
1110 for (i, shim) in ret.shims.values().enumerate() {
1111 let i = i as u32;
1112 let type_index = *sigs.entry(&shim.sig).or_insert_with(|| {
1113 let index = types.len();
1114 types.ty().function(
1115 shim.sig.params.iter().map(to_val_type),
1116 shim.sig.results.iter().map(to_val_type),
1117 );
1118 index
1119 });
1120
1121 functions.function(type_index);
1122 Self::encode_shim_function(type_index, i, &mut code, shim.sig.params.len() as u32);
1123 exports.export(&shim.name, ExportKind::Func, i);
1124
1125 imports_section.import("", &shim.name, EntityType::Function(type_index));
1126 func_indexes.push(i);
1127 func_names.append(i, &shim.debug_name);
1128 }
1129 let mut names = NameSection::new();
1130 names.module("wit-component:shim");
1131 names.functions(&func_names);
1132
1133 let table_type = TableType {
1134 element_type: RefType::FUNCREF,
1135 minimum: ret.shims.len() as u64,
1136 maximum: Some(ret.shims.len() as u64),
1137 table64: false,
1138 shared: false,
1139 };
1140
1141 tables.table(table_type);
1142
1143 exports.export(INDIRECT_TABLE_NAME, ExportKind::Table, 0);
1144 imports_section.import("", INDIRECT_TABLE_NAME, table_type);
1145
1146 elements.active(
1147 None,
1148 &ConstExpr::i32_const(0),
1149 Elements::Functions(func_indexes.into()),
1150 );
1151
1152 let mut shim = Module::new();
1153 shim.section(&types);
1154 shim.section(&functions);
1155 shim.section(&tables);
1156 shim.section(&exports);
1157 shim.section(&code);
1158 shim.section(&RawCustomSection(
1159 &crate::base_producers().raw_custom_section(),
1160 ));
1161 shim.section(&names);
1162
1163 let mut fixups = Module::default();
1164 fixups.section(&types);
1165 fixups.section(&imports_section);
1166 fixups.section(&elements);
1167 fixups.section(&RawCustomSection(
1168 &crate::base_producers().raw_custom_section(),
1169 ));
1170
1171 let mut names = NameSection::new();
1172 names.module("wit-component:fixups");
1173 fixups.section(&names);
1174
1175 let shim_module_index = self.component.core_module(&shim);
1176 self.fixups_module_index = Some(self.component.core_module(&fixups));
1177 self.shim_instance_index = Some(self.component.core_instantiate(shim_module_index, []));
1178
1179 return Ok(ret);
1180 }
1181
1182 fn encode_shim_function(
1183 type_index: u32,
1184 func_index: u32,
1185 code: &mut CodeSection,
1186 param_count: u32,
1187 ) {
1188 let mut func = wasm_encoder::Function::new(std::iter::empty());
1189 for i in 0..param_count {
1190 func.instructions().local_get(i);
1191 }
1192 func.instructions().i32_const(func_index as i32);
1193 func.instructions().call_indirect(0, type_index);
1194 func.instructions().end();
1195 code.function(&func);
1196 }
1197
1198 fn encode_indirect_lowerings(&mut self, shims: &Shims<'_>) -> Result<()> {
1199 if shims.shims.is_empty() {
1200 return Ok(());
1201 }
1202
1203 let shim_instance_index = self
1204 .shim_instance_index
1205 .expect("must have an instantiated shim");
1206
1207 let table_index =
1208 self.core_alias_export(shim_instance_index, INDIRECT_TABLE_NAME, ExportKind::Table);
1209
1210 let resolve = &self.info.encoder.metadata.resolve;
1211
1212 let mut exports = Vec::new();
1213 exports.push((INDIRECT_TABLE_NAME, ExportKind::Table, table_index));
1214
1215 for shim in shims.shims.values() {
1216 let core_func_index = match &shim.kind {
1217 ShimKind::IndirectLowering {
1224 interface,
1225 index,
1226 realloc,
1227 encoding,
1228 } => {
1229 let interface = &self.info.import_map[interface];
1230 let ((name, _), _) = interface.lowerings.get_index(*index).unwrap();
1231 let func_index = match &interface.interface {
1232 Some(interface_id) => {
1233 let instance_index = self.imported_instances[interface_id];
1234 self.component.alias_export(
1235 instance_index,
1236 name,
1237 ComponentExportKind::Func,
1238 )
1239 }
1240 None => self.imported_funcs[name],
1241 };
1242
1243 let realloc = self
1244 .info
1245 .exports_for(*realloc)
1246 .import_realloc_for(interface.interface, name)
1247 .map(|name| {
1248 let instance = self.instance_for(*realloc);
1249 self.core_alias_export(instance, name, ExportKind::Func)
1250 });
1251
1252 self.component.lower_func(
1253 func_index,
1254 shim.options
1255 .into_iter(*encoding, self.memory_index, realloc)?,
1256 )
1257 }
1258
1259 ShimKind::Adapter { adapter, func } => {
1264 self.core_alias_export(self.adapter_instances[adapter], func, ExportKind::Func)
1265 }
1266
1267 ShimKind::ResourceDtor { module, export } => {
1272 self.core_alias_export(self.instance_for(*module), export, ExportKind::Func)
1273 }
1274
1275 ShimKind::PayloadFunc {
1276 for_module,
1277 info,
1278 kind,
1279 } => {
1280 let metadata = self.info.module_metadata_for(*for_module);
1281 let exports = self.info.exports_for(*for_module);
1282 let instance_index = self.instance_for(*for_module);
1283 let (encoding, realloc) = if info.imported {
1284 (
1285 metadata
1286 .import_encodings
1287 .get(resolve, &info.key, &info.function),
1288 exports.import_realloc_for(info.interface, &info.function),
1289 )
1290 } else {
1291 (
1292 metadata
1293 .export_encodings
1294 .get(resolve, &info.key, &info.function),
1295 exports.export_realloc_for(&info.key, &info.function),
1296 )
1297 };
1298 let encoding = encoding.unwrap_or(StringEncoding::UTF8);
1299 let realloc_index = realloc
1300 .map(|name| self.core_alias_export(instance_index, name, ExportKind::Func));
1301 let type_index = self.payload_type_index(info)?;
1302 let options =
1303 shim.options
1304 .into_iter(encoding, self.memory_index, realloc_index)?;
1305
1306 match kind {
1307 PayloadFuncKind::FutureWrite => {
1308 self.component.future_write(type_index, options)
1309 }
1310 PayloadFuncKind::FutureRead => {
1311 self.component.future_read(type_index, options)
1312 }
1313 PayloadFuncKind::StreamWrite => {
1314 self.component.stream_write(type_index, options)
1315 }
1316 PayloadFuncKind::StreamRead => {
1317 self.component.stream_read(type_index, options)
1318 }
1319 }
1320 }
1321
1322 ShimKind::WaitableSetWait { async_ } => self
1323 .component
1324 .waitable_set_wait(*async_, self.memory_index.unwrap()),
1325 ShimKind::WaitableSetPoll { async_ } => self
1326 .component
1327 .waitable_set_poll(*async_, self.memory_index.unwrap()),
1328 ShimKind::ErrorContextNew { encoding } => self.component.error_context_new(
1329 shim.options.into_iter(*encoding, self.memory_index, None)?,
1330 ),
1331 ShimKind::ErrorContextDebugMessage {
1332 for_module,
1333 encoding,
1334 } => {
1335 let instance_index = self.instance_for(*for_module);
1336 let realloc = self.info.exports_for(*for_module).import_realloc_fallback();
1337 let realloc_index = realloc
1338 .map(|r| self.core_alias_export(instance_index, r, ExportKind::Func));
1339
1340 self.component
1341 .error_context_debug_message(shim.options.into_iter(
1342 *encoding,
1343 self.memory_index,
1344 realloc_index,
1345 )?)
1346 }
1347 ShimKind::TaskReturn {
1348 interface,
1349 func,
1350 result,
1351 encoding,
1352 for_module,
1353 } => {
1354 let mut encoder = if interface.is_none() {
1357 self.root_import_type_encoder(*interface)
1358 } else {
1359 self.root_export_type_encoder(*interface)
1360 };
1361 let result = match result {
1362 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1363 None => None,
1364 };
1365
1366 let exports = self.info.exports_for(*for_module);
1367 let realloc = exports.import_realloc_for(*interface, func);
1368
1369 let instance_index = self.instance_for(*for_module);
1370 let realloc_index = realloc
1371 .map(|r| self.core_alias_export(instance_index, r, ExportKind::Func));
1372 let options =
1373 shim.options
1374 .into_iter(*encoding, self.memory_index, realloc_index)?;
1375 self.component.task_return(result, options)
1376 }
1377 };
1378
1379 exports.push((shim.name.as_str(), ExportKind::Func, core_func_index));
1380 }
1381
1382 let instance_index = self.component.core_instantiate_exports(exports);
1383 self.component.core_instantiate(
1384 self.fixups_module_index.expect("must have fixup module"),
1385 [("", ModuleArg::Instance(instance_index))],
1386 );
1387 Ok(())
1388 }
1389
1390 fn payload_type_index(&mut self, info: &PayloadInfo) -> Result<u32> {
1398 let resolve = &self.info.encoder.metadata.resolve;
1399 let ComponentValType::Type(type_index) = if info.imported || info.interface.is_none() {
1415 self.root_import_type_encoder(None)
1416 } else {
1417 self.root_export_type_encoder(info.interface)
1418 }
1419 .encode_valtype(resolve, &Type::Id(info.ty))?
1420 else {
1421 unreachable!()
1422 };
1423 Ok(type_index)
1424 }
1425
1426 fn declare_types_for_imported_intrinsics(&mut self, shims: &Shims<'_>) -> Result<()> {
1433 let resolve = &self.info.encoder.metadata.resolve;
1434 let world = &resolve.worlds[self.info.encoder.metadata.world];
1435
1436 let main_module_keys = self.info.encoder.main_module_exports.iter();
1439 let main_module_keys = main_module_keys.map(|key| (CustomModule::Main, key));
1440 let adapter_keys = self.info.encoder.adapters.iter().flat_map(|(name, info)| {
1441 info.required_exports
1442 .iter()
1443 .map(move |key| (CustomModule::Adapter(name), key))
1444 });
1445 for (for_module, key) in main_module_keys.chain(adapter_keys) {
1446 let id = match &world.exports[key] {
1447 WorldItem::Interface { id, .. } => *id,
1448 WorldItem::Type { .. } => unreachable!(),
1449 WorldItem::Function(_) => continue,
1450 };
1451
1452 for ty in resolve.interfaces[id].types.values() {
1453 match &resolve.types[*ty].kind {
1454 TypeDefKind::Resource => {
1458 let exports = self.info.exports_for(for_module);
1461 let dtor = exports.resource_dtor(*ty).map(|name| {
1462 let name = &shims.shims[&ShimKind::ResourceDtor {
1463 module: for_module,
1464 export: name,
1465 }]
1466 .name;
1467 let shim = self.shim_instance_index.unwrap();
1468 self.core_alias_export(shim, name, ExportKind::Func)
1469 });
1470
1471 let resource_idx = self.component.type_resource(ValType::I32, dtor);
1475 let prev = self
1476 .export_type_encoding_maps
1477 .id_to_index
1478 .insert(*ty, resource_idx);
1479 assert!(prev.is_none());
1480 }
1481 _other => {
1482 self.root_export_type_encoder(Some(id))
1483 .encode_valtype(resolve, &Type::Id(*ty))?;
1484 }
1485 }
1486 }
1487 }
1488 Ok(())
1489 }
1490
1491 fn instantiate_main_module(&mut self, shims: &Shims<'_>) -> Result<()> {
1494 assert!(self.instance_index.is_none());
1495
1496 let instance_index = self.instantiate_core_module(shims, CustomModule::Main)?;
1497
1498 if let Some(memory) = self.info.info.exports.memory() {
1499 self.memory_index =
1500 Some(self.core_alias_export(instance_index, memory, ExportKind::Memory));
1501 }
1502
1503 self.instance_index = Some(instance_index);
1504 Ok(())
1505 }
1506
1507 fn instantiate_adapter_module(&mut self, shims: &Shims<'_>, name: &'a str) -> Result<()> {
1510 let instance = self.instantiate_core_module(shims, CustomModule::Adapter(name))?;
1511 self.adapter_instances.insert(name, instance);
1512 Ok(())
1513 }
1514
1515 fn instantiate_core_module(
1522 &mut self,
1523 shims: &Shims,
1524 for_module: CustomModule<'_>,
1525 ) -> Result<u32> {
1526 let module = self.module_for(for_module);
1527
1528 let mut args = Vec::new();
1529 for (core_wasm_name, instance) in self.info.imports_for(for_module).modules() {
1530 match instance {
1531 ImportInstance::Names(names) => {
1537 let mut exports = Vec::new();
1538 for (name, import) in names {
1539 log::trace!(
1540 "attempting to materialize import of `{core_wasm_name}::{name}` for {for_module:?}"
1541 );
1542 let (kind, index) = self
1543 .materialize_import(&shims, for_module, import)
1544 .with_context(|| {
1545 format!("failed to satisfy import `{core_wasm_name}::{name}`")
1546 })?;
1547 exports.push((name.as_str(), kind, index));
1548 }
1549 let index = self.component.core_instantiate_exports(exports);
1550 args.push((core_wasm_name.as_str(), ModuleArg::Instance(index)));
1551 }
1552
1553 ImportInstance::Whole(which) => {
1556 let instance = self.instance_for(which.to_custom_module());
1557 args.push((core_wasm_name.as_str(), ModuleArg::Instance(instance)));
1558 }
1559 }
1560 }
1561
1562 Ok(self.component.core_instantiate(module, args))
1564 }
1565
1566 fn materialize_import(
1573 &mut self,
1574 shims: &Shims<'_>,
1575 for_module: CustomModule<'_>,
1576 import: &'a Import,
1577 ) -> Result<(ExportKind, u32)> {
1578 let resolve = &self.info.encoder.metadata.resolve;
1579 match import {
1580 Import::AdapterExport {
1583 adapter,
1584 func,
1585 ty: _,
1586 } => {
1587 assert!(self.info.encoder.adapters.contains_key(adapter));
1588 Ok(self.materialize_shim_import(shims, &ShimKind::Adapter { adapter, func }))
1589 }
1590
1591 Import::MainModuleMemory => {
1594 let index = self
1595 .memory_index
1596 .ok_or_else(|| anyhow!("main module cannot import memory"))?;
1597 Ok((ExportKind::Memory, index))
1598 }
1599
1600 Import::MainModuleExport { name, kind } => {
1602 let instance = self.instance_index.unwrap();
1603 let index = self.core_alias_export(instance, name, *kind);
1604 Ok((*kind, index))
1605 }
1606
1607 Import::Item(item) => {
1611 let instance = self.instance_for(item.which.to_custom_module());
1612 let index = self.core_alias_export(instance, &item.name, item.kind);
1613 Ok((item.kind, index))
1614 }
1615
1616 Import::ExportedResourceDrop(_key, id) => {
1622 let index = self
1623 .component
1624 .resource_drop(self.export_type_encoding_maps.id_to_index[id]);
1625 Ok((ExportKind::Func, index))
1626 }
1627 Import::ExportedResourceRep(_key, id) => {
1628 let index = self
1629 .component
1630 .resource_rep(self.export_type_encoding_maps.id_to_index[id]);
1631 Ok((ExportKind::Func, index))
1632 }
1633 Import::ExportedResourceNew(_key, id) => {
1634 let index = self
1635 .component
1636 .resource_new(self.export_type_encoding_maps.id_to_index[id]);
1637 Ok((ExportKind::Func, index))
1638 }
1639
1640 Import::ImportedResourceDrop(key, iface, id) => {
1645 let ty = &resolve.types[*id];
1646 let name = ty.name.as_ref().unwrap();
1647 self.materialize_wit_import(
1648 shims,
1649 for_module,
1650 iface.map(|_| resolve.name_world_key(key)),
1651 &format!("{name}_drop"),
1652 key,
1653 AbiVariant::GuestImport,
1654 )
1655 }
1656 Import::ExportedTaskReturn(key, interface, func, result) => {
1657 let (options, _sig) = task_return_options_and_type(resolve, *result);
1658 if options.is_empty() {
1659 let mut encoder = if interface.is_none() {
1665 self.root_import_type_encoder(*interface)
1666 } else {
1667 self.root_export_type_encoder(*interface)
1668 };
1669
1670 let result = match result {
1671 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1672 None => None,
1673 };
1674 let index = self.component.task_return(result, []);
1675 Ok((ExportKind::Func, index))
1676 } else {
1677 let metadata = &self.info.encoder.metadata.metadata;
1678 let encoding = metadata.export_encodings.get(resolve, key, func).unwrap();
1679 Ok(self.materialize_shim_import(
1680 shims,
1681 &ShimKind::TaskReturn {
1682 for_module,
1683 interface: *interface,
1684 func,
1685 result: *result,
1686 encoding,
1687 },
1688 ))
1689 }
1690 }
1691 Import::BackpressureSet => {
1692 let index = self.component.backpressure_set();
1693 Ok((ExportKind::Func, index))
1694 }
1695 Import::WaitableSetWait { async_ } => {
1696 Ok(self
1697 .materialize_shim_import(shims, &ShimKind::WaitableSetWait { async_: *async_ }))
1698 }
1699 Import::WaitableSetPoll { async_ } => {
1700 Ok(self
1701 .materialize_shim_import(shims, &ShimKind::WaitableSetPoll { async_: *async_ }))
1702 }
1703 Import::Yield { async_ } => {
1704 let index = self.component.yield_(*async_);
1705 Ok((ExportKind::Func, index))
1706 }
1707 Import::SubtaskDrop => {
1708 let index = self.component.subtask_drop();
1709 Ok((ExportKind::Func, index))
1710 }
1711 Import::SubtaskCancel { async_ } => {
1712 let index = self.component.subtask_cancel(*async_);
1713 Ok((ExportKind::Func, index))
1714 }
1715 Import::StreamNew(info) => {
1716 let ty = self.payload_type_index(info)?;
1717 let index = self.component.stream_new(ty);
1718 Ok((ExportKind::Func, index))
1719 }
1720 Import::StreamRead { info, .. } => Ok(self.materialize_payload_import(
1721 shims,
1722 for_module,
1723 info,
1724 PayloadFuncKind::StreamRead,
1725 )),
1726 Import::StreamWrite { info, .. } => Ok(self.materialize_payload_import(
1727 shims,
1728 for_module,
1729 info,
1730 PayloadFuncKind::StreamWrite,
1731 )),
1732 Import::StreamCancelRead { info, async_ } => {
1733 let ty = self.payload_type_index(info)?;
1734 let index = self.component.stream_cancel_read(ty, *async_);
1735 Ok((ExportKind::Func, index))
1736 }
1737 Import::StreamCancelWrite { info, async_ } => {
1738 let ty = self.payload_type_index(info)?;
1739 let index = self.component.stream_cancel_write(ty, *async_);
1740 Ok((ExportKind::Func, index))
1741 }
1742 Import::StreamDropReadable(info) => {
1743 let type_index = self.payload_type_index(info)?;
1744 let index = self.component.stream_drop_readable(type_index);
1745 Ok((ExportKind::Func, index))
1746 }
1747 Import::StreamDropWritable(info) => {
1748 let type_index = self.payload_type_index(info)?;
1749 let index = self.component.stream_drop_writable(type_index);
1750 Ok((ExportKind::Func, index))
1751 }
1752 Import::FutureNew(info) => {
1753 let ty = self.payload_type_index(info)?;
1754 let index = self.component.future_new(ty);
1755 Ok((ExportKind::Func, index))
1756 }
1757 Import::FutureRead { info, .. } => Ok(self.materialize_payload_import(
1758 shims,
1759 for_module,
1760 info,
1761 PayloadFuncKind::FutureRead,
1762 )),
1763 Import::FutureWrite { info, .. } => Ok(self.materialize_payload_import(
1764 shims,
1765 for_module,
1766 info,
1767 PayloadFuncKind::FutureWrite,
1768 )),
1769 Import::FutureCancelRead { info, async_ } => {
1770 let ty = self.payload_type_index(info)?;
1771 let index = self.component.future_cancel_read(ty, *async_);
1772 Ok((ExportKind::Func, index))
1773 }
1774 Import::FutureCancelWrite { info, async_ } => {
1775 let ty = self.payload_type_index(info)?;
1776 let index = self.component.future_cancel_write(ty, *async_);
1777 Ok((ExportKind::Func, index))
1778 }
1779 Import::FutureDropReadable(info) => {
1780 let type_index = self.payload_type_index(info)?;
1781 let index = self.component.future_drop_readable(type_index);
1782 Ok((ExportKind::Func, index))
1783 }
1784 Import::FutureDropWritable(info) => {
1785 let type_index = self.payload_type_index(info)?;
1786 let index = self.component.future_drop_writable(type_index);
1787 Ok((ExportKind::Func, index))
1788 }
1789 Import::ErrorContextNew { encoding } => Ok(self.materialize_shim_import(
1790 shims,
1791 &ShimKind::ErrorContextNew {
1792 encoding: *encoding,
1793 },
1794 )),
1795 Import::ErrorContextDebugMessage { encoding } => Ok(self.materialize_shim_import(
1796 shims,
1797 &ShimKind::ErrorContextDebugMessage {
1798 for_module,
1799 encoding: *encoding,
1800 },
1801 )),
1802 Import::ErrorContextDrop => {
1803 let index = self.component.error_context_drop();
1804 Ok((ExportKind::Func, index))
1805 }
1806 Import::WorldFunc(key, name, abi) => {
1807 self.materialize_wit_import(shims, for_module, None, name, key, *abi)
1808 }
1809 Import::InterfaceFunc(key, _, name, abi) => self.materialize_wit_import(
1810 shims,
1811 for_module,
1812 Some(resolve.name_world_key(key)),
1813 name,
1814 key,
1815 *abi,
1816 ),
1817
1818 Import::WaitableSetNew => {
1819 let index = self.component.waitable_set_new();
1820 Ok((ExportKind::Func, index))
1821 }
1822 Import::WaitableSetDrop => {
1823 let index = self.component.waitable_set_drop();
1824 Ok((ExportKind::Func, index))
1825 }
1826 Import::WaitableJoin => {
1827 let index = self.component.waitable_join();
1828 Ok((ExportKind::Func, index))
1829 }
1830 Import::ContextGet(n) => {
1831 let index = self.component.context_get(*n);
1832 Ok((ExportKind::Func, index))
1833 }
1834 Import::ContextSet(n) => {
1835 let index = self.component.context_set(*n);
1836 Ok((ExportKind::Func, index))
1837 }
1838 Import::ExportedTaskCancel => {
1839 let index = self.component.task_cancel();
1840 Ok((ExportKind::Func, index))
1841 }
1842 }
1843 }
1844
1845 fn materialize_shim_import(&mut self, shims: &Shims<'_>, kind: &ShimKind) -> (ExportKind, u32) {
1848 let index = self.core_alias_export(
1849 self.shim_instance_index
1850 .expect("shim should be instantiated"),
1851 &shims.shims[kind].name,
1852 ExportKind::Func,
1853 );
1854 (ExportKind::Func, index)
1855 }
1856
1857 fn materialize_payload_import(
1860 &mut self,
1861 shims: &Shims<'_>,
1862 for_module: CustomModule<'_>,
1863 info: &PayloadInfo,
1864 kind: PayloadFuncKind,
1865 ) -> (ExportKind, u32) {
1866 self.materialize_shim_import(
1867 shims,
1868 &ShimKind::PayloadFunc {
1869 for_module,
1870 info,
1871 kind,
1872 },
1873 )
1874 }
1875
1876 fn materialize_wit_import(
1879 &mut self,
1880 shims: &Shims<'_>,
1881 for_module: CustomModule<'_>,
1882 interface_key: Option<String>,
1883 name: &String,
1884 key: &WorldKey,
1885 abi: AbiVariant,
1886 ) -> Result<(ExportKind, u32)> {
1887 let resolve = &self.info.encoder.metadata.resolve;
1888 let import = &self.info.import_map[&interface_key];
1889 let (index, _, lowering) = import.lowerings.get_full(&(name.clone(), abi)).unwrap();
1890 let metadata = self.info.module_metadata_for(for_module);
1891
1892 let index = match lowering {
1893 Lowering::Direct => {
1896 let func_index = match &import.interface {
1897 Some(interface) => {
1898 let instance_index = self.imported_instances[interface];
1899 self.component
1900 .alias_export(instance_index, name, ComponentExportKind::Func)
1901 }
1902 None => self.imported_funcs[name],
1903 };
1904 self.component.lower_func(
1905 func_index,
1906 if let AbiVariant::GuestImportAsync = abi {
1907 vec![CanonicalOption::Async]
1908 } else {
1909 Vec::new()
1910 },
1911 )
1912 }
1913
1914 Lowering::Indirect { .. } => {
1918 let encoding = metadata.import_encodings.get(resolve, key, name).unwrap();
1919 return Ok(self.materialize_shim_import(
1920 shims,
1921 &ShimKind::IndirectLowering {
1922 interface: interface_key,
1923 index,
1924 realloc: for_module,
1925 encoding,
1926 },
1927 ));
1928 }
1929
1930 Lowering::ResourceDrop(id) => {
1933 let resource_idx = self.lookup_resource_index(*id);
1934 self.component.resource_drop(resource_idx)
1935 }
1936 };
1937 Ok((ExportKind::Func, index))
1938 }
1939
1940 fn encode_initialize_with_start(&mut self) -> Result<()> {
1959 let initialize = match self.info.info.exports.initialize() {
1960 Some(name) => name,
1961 None => return Ok(()),
1964 };
1965 let initialize_index =
1966 self.core_alias_export(self.instance_index.unwrap(), initialize, ExportKind::Func);
1967 let mut shim = Module::default();
1968 let mut section = TypeSection::new();
1969 section.ty().function([], []);
1970 shim.section(§ion);
1971 let mut section = ImportSection::new();
1972 section.import("", "", EntityType::Function(0));
1973 shim.section(§ion);
1974 shim.section(&StartSection { function_index: 0 });
1975
1976 let shim_module_index = self.component.core_module(&shim);
1981 let shim_args_instance_index =
1982 self.component
1983 .core_instantiate_exports([("", ExportKind::Func, initialize_index)]);
1984 self.component.core_instantiate(
1985 shim_module_index,
1986 [("", ModuleArg::Instance(shim_args_instance_index))],
1987 );
1988 Ok(())
1989 }
1990
1991 fn instance_for(&self, module: CustomModule) -> u32 {
1994 match module {
1995 CustomModule::Main => self.instance_index.expect("instantiated by now"),
1996 CustomModule::Adapter(name) => self.adapter_instances[name],
1997 }
1998 }
1999
2000 fn module_for(&self, module: CustomModule) -> u32 {
2003 match module {
2004 CustomModule::Main => self.module_index.unwrap(),
2005 CustomModule::Adapter(name) => self.adapter_modules[name],
2006 }
2007 }
2008
2009 fn core_alias_export(&mut self, instance: u32, name: &str, kind: ExportKind) -> u32 {
2012 *self
2013 .aliased_core_items
2014 .entry((instance, name.to_string()))
2015 .or_insert_with(|| self.component.core_alias_export(instance, name, kind))
2016 }
2017}
2018
2019#[derive(Default)]
2037struct Shims<'a> {
2038 shims: IndexMap<ShimKind<'a>, Shim<'a>>,
2040}
2041
2042struct Shim<'a> {
2043 options: RequiredOptions,
2046
2047 name: String,
2051
2052 debug_name: String,
2055
2056 kind: ShimKind<'a>,
2058
2059 sig: WasmSignature,
2061}
2062
2063#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2066enum PayloadFuncKind {
2067 FutureWrite,
2068 FutureRead,
2069 StreamWrite,
2070 StreamRead,
2071}
2072
2073#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2074enum ShimKind<'a> {
2075 IndirectLowering {
2079 interface: Option<String>,
2081 index: usize,
2083 realloc: CustomModule<'a>,
2085 encoding: StringEncoding,
2087 },
2088 Adapter {
2091 adapter: &'a str,
2093 func: &'a str,
2095 },
2096 ResourceDtor {
2099 module: CustomModule<'a>,
2101 export: &'a str,
2103 },
2104 PayloadFunc {
2108 for_module: CustomModule<'a>,
2111 info: &'a PayloadInfo,
2116 kind: PayloadFuncKind,
2118 },
2119 WaitableSetWait { async_: bool },
2123 WaitableSetPoll { async_: bool },
2127 TaskReturn {
2129 interface: Option<InterfaceId>,
2132 func: &'a str,
2135 result: Option<Type>,
2137 for_module: CustomModule<'a>,
2139 encoding: StringEncoding,
2141 },
2142 ErrorContextNew {
2146 encoding: StringEncoding,
2148 },
2149 ErrorContextDebugMessage {
2153 for_module: CustomModule<'a>,
2155 encoding: StringEncoding,
2157 },
2158}
2159
2160#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
2170enum CustomModule<'a> {
2171 Main,
2174 Adapter(&'a str),
2177}
2178
2179impl<'a> Shims<'a> {
2180 fn append_indirect(
2185 &mut self,
2186 world: &'a ComponentWorld<'a>,
2187 for_module: CustomModule<'a>,
2188 ) -> Result<()> {
2189 let module_imports = world.imports_for(for_module);
2190 let module_exports = world.exports_for(for_module);
2191 let resolve = &world.encoder.metadata.resolve;
2192
2193 for (module, field, import) in module_imports.imports() {
2194 match import {
2195 Import::ImportedResourceDrop(..)
2198 | Import::MainModuleMemory
2199 | Import::MainModuleExport { .. }
2200 | Import::Item(_)
2201 | Import::ExportedResourceDrop(..)
2202 | Import::ExportedResourceRep(..)
2203 | Import::ExportedResourceNew(..)
2204 | Import::ExportedTaskCancel
2205 | Import::ErrorContextDrop
2206 | Import::BackpressureSet
2207 | Import::Yield { .. }
2208 | Import::SubtaskDrop
2209 | Import::SubtaskCancel { .. }
2210 | Import::FutureNew(..)
2211 | Import::StreamNew(..)
2212 | Import::FutureCancelRead { .. }
2213 | Import::FutureCancelWrite { .. }
2214 | Import::FutureDropWritable { .. }
2215 | Import::FutureDropReadable { .. }
2216 | Import::StreamCancelRead { .. }
2217 | Import::StreamCancelWrite { .. }
2218 | Import::StreamDropWritable { .. }
2219 | Import::StreamDropReadable { .. }
2220 | Import::WaitableSetNew
2221 | Import::WaitableSetDrop
2222 | Import::WaitableJoin
2223 | Import::ContextGet(_)
2224 | Import::ContextSet(_) => {}
2225
2226 Import::ExportedTaskReturn(key, interface, func, ty) => {
2230 let (options, sig) = task_return_options_and_type(resolve, *ty);
2231 if options.is_empty() {
2232 continue;
2233 }
2234 let name = self.shims.len().to_string();
2235 let encoding = world
2236 .module_metadata_for(for_module)
2237 .export_encodings
2238 .get(resolve, key, func)
2239 .ok_or_else(|| {
2240 anyhow::anyhow!(
2241 "missing component metadata for export of \
2242 `{module}::{field}`"
2243 )
2244 })?;
2245 self.push(Shim {
2246 name,
2247 debug_name: format!("task-return-{func}"),
2248 options,
2249 kind: ShimKind::TaskReturn {
2250 interface: *interface,
2251 func,
2252 result: *ty,
2253 for_module,
2254 encoding,
2255 },
2256 sig,
2257 });
2258 }
2259
2260 Import::FutureWrite { async_, info } => {
2261 self.append_indirect_payload_push(
2262 resolve,
2263 for_module,
2264 module,
2265 *async_,
2266 info,
2267 PayloadFuncKind::FutureWrite,
2268 vec![WasmType::I32; 2],
2269 vec![WasmType::I32],
2270 );
2271 }
2272 Import::FutureRead { async_, info } => {
2273 self.append_indirect_payload_push(
2274 resolve,
2275 for_module,
2276 module,
2277 *async_,
2278 info,
2279 PayloadFuncKind::FutureRead,
2280 vec![WasmType::I32; 2],
2281 vec![WasmType::I32],
2282 );
2283 }
2284 Import::StreamWrite { async_, info } => {
2285 self.append_indirect_payload_push(
2286 resolve,
2287 for_module,
2288 module,
2289 *async_,
2290 info,
2291 PayloadFuncKind::StreamWrite,
2292 vec![WasmType::I32; 3],
2293 vec![WasmType::I32],
2294 );
2295 }
2296 Import::StreamRead { async_, info } => {
2297 self.append_indirect_payload_push(
2298 resolve,
2299 for_module,
2300 module,
2301 *async_,
2302 info,
2303 PayloadFuncKind::StreamRead,
2304 vec![WasmType::I32; 3],
2305 vec![WasmType::I32],
2306 );
2307 }
2308
2309 Import::WaitableSetWait { async_ } => {
2310 let name = self.shims.len().to_string();
2311 self.push(Shim {
2312 name,
2313 debug_name: "waitable-set.wait".to_string(),
2314 options: RequiredOptions::empty(),
2315 kind: ShimKind::WaitableSetWait { async_: *async_ },
2316 sig: WasmSignature {
2317 params: vec![WasmType::I32; 2],
2318 results: vec![WasmType::I32],
2319 indirect_params: false,
2320 retptr: false,
2321 },
2322 });
2323 }
2324
2325 Import::WaitableSetPoll { async_ } => {
2326 let name = self.shims.len().to_string();
2327 self.push(Shim {
2328 name,
2329 debug_name: "waitable-set.poll".to_string(),
2330 options: RequiredOptions::empty(),
2331 kind: ShimKind::WaitableSetPoll { async_: *async_ },
2332 sig: WasmSignature {
2333 params: vec![WasmType::I32; 2],
2334 results: vec![WasmType::I32],
2335 indirect_params: false,
2336 retptr: false,
2337 },
2338 });
2339 }
2340
2341 Import::ErrorContextNew { encoding } => {
2342 let name = self.shims.len().to_string();
2343 self.push(Shim {
2344 name,
2345 debug_name: "error-new".to_string(),
2346 options: RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING,
2347 kind: ShimKind::ErrorContextNew {
2348 encoding: *encoding,
2349 },
2350 sig: WasmSignature {
2351 params: vec![WasmType::I32; 2],
2352 results: vec![WasmType::I32],
2353 indirect_params: false,
2354 retptr: false,
2355 },
2356 });
2357 }
2358
2359 Import::ErrorContextDebugMessage { encoding } => {
2360 let name = self.shims.len().to_string();
2361 self.push(Shim {
2362 name,
2363 debug_name: "error-debug-message".to_string(),
2364 options: RequiredOptions::MEMORY
2365 | RequiredOptions::STRING_ENCODING
2366 | RequiredOptions::REALLOC,
2367 kind: ShimKind::ErrorContextDebugMessage {
2368 for_module,
2369 encoding: *encoding,
2370 },
2371 sig: WasmSignature {
2372 params: vec![WasmType::I32; 2],
2373 results: vec![],
2374 indirect_params: false,
2375 retptr: false,
2376 },
2377 });
2378 }
2379
2380 Import::AdapterExport { adapter, func, ty } => {
2383 let name = self.shims.len().to_string();
2384 log::debug!("shim {name} is adapter `{module}::{field}`");
2385 self.push(Shim {
2386 name,
2387 debug_name: format!("adapt-{module}-{field}"),
2388 options: RequiredOptions::MEMORY,
2392 kind: ShimKind::Adapter { adapter, func },
2393 sig: WasmSignature {
2394 params: ty.params().iter().map(to_wasm_type).collect(),
2395 results: ty.results().iter().map(to_wasm_type).collect(),
2396 indirect_params: false,
2397 retptr: false,
2398 },
2399 });
2400
2401 fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType {
2402 match ty {
2403 wasmparser::ValType::I32 => WasmType::I32,
2404 wasmparser::ValType::I64 => WasmType::I64,
2405 wasmparser::ValType::F32 => WasmType::F32,
2406 wasmparser::ValType::F64 => WasmType::F64,
2407 _ => unreachable!(),
2408 }
2409 }
2410 }
2411
2412 Import::InterfaceFunc(key, _, name, abi) => {
2416 self.append_indirect_wit_func(
2417 world,
2418 for_module,
2419 module,
2420 field,
2421 key,
2422 name,
2423 Some(resolve.name_world_key(key)),
2424 *abi,
2425 )?;
2426 }
2427 Import::WorldFunc(key, name, abi) => {
2428 self.append_indirect_wit_func(
2429 world, for_module, module, field, key, name, None, *abi,
2430 )?;
2431 }
2432 }
2433 }
2434
2435 for (export_name, export) in module_exports.iter() {
2441 let id = match export {
2442 Export::ResourceDtor(id) => id,
2443 _ => continue,
2444 };
2445 let resource = resolve.types[*id].name.as_ref().unwrap();
2446 let name = self.shims.len().to_string();
2447 self.push(Shim {
2448 name,
2449 debug_name: format!("dtor-{resource}"),
2450 options: RequiredOptions::empty(),
2451 kind: ShimKind::ResourceDtor {
2452 module: for_module,
2453 export: export_name,
2454 },
2455 sig: WasmSignature {
2456 params: vec![WasmType::I32],
2457 results: Vec::new(),
2458 indirect_params: false,
2459 retptr: false,
2460 },
2461 });
2462 }
2463
2464 Ok(())
2465 }
2466
2467 fn append_indirect_payload_push(
2470 &mut self,
2471 resolve: &Resolve,
2472 for_module: CustomModule<'a>,
2473 module: &str,
2474 async_: bool,
2475 info: &'a PayloadInfo,
2476 kind: PayloadFuncKind,
2477 params: Vec<WasmType>,
2478 results: Vec<WasmType>,
2479 ) {
2480 let debug_name = format!("{module}-{}", info.name);
2481 let name = self.shims.len().to_string();
2482
2483 let payload = info.payload(resolve);
2484 let (wit_param, wit_result) = match kind {
2485 PayloadFuncKind::StreamRead | PayloadFuncKind::FutureRead => (None, payload),
2486 PayloadFuncKind::StreamWrite | PayloadFuncKind::FutureWrite => (payload, None),
2487 };
2488 self.push(Shim {
2489 name,
2490 debug_name,
2491 options: RequiredOptions::MEMORY
2492 | RequiredOptions::for_import(
2493 resolve,
2494 &Function {
2495 name: String::new(),
2496 kind: FunctionKind::Freestanding,
2497 params: match wit_param {
2498 Some(ty) => vec![("a".to_string(), ty)],
2499 None => Vec::new(),
2500 },
2501 result: wit_result,
2502 docs: Default::default(),
2503 stability: Stability::Unknown,
2504 },
2505 if async_ {
2506 AbiVariant::GuestImportAsync
2507 } else {
2508 AbiVariant::GuestImport
2509 },
2510 ),
2511 kind: ShimKind::PayloadFunc {
2512 for_module,
2513 info,
2514 kind,
2515 },
2516 sig: WasmSignature {
2517 params,
2518 results,
2519 indirect_params: false,
2520 retptr: false,
2521 },
2522 });
2523 }
2524
2525 fn append_indirect_wit_func(
2528 &mut self,
2529 world: &'a ComponentWorld<'a>,
2530 for_module: CustomModule<'a>,
2531 module: &str,
2532 field: &str,
2533 key: &WorldKey,
2534 name: &String,
2535 interface_key: Option<String>,
2536 abi: AbiVariant,
2537 ) -> Result<()> {
2538 let resolve = &world.encoder.metadata.resolve;
2539 let metadata = world.module_metadata_for(for_module);
2540 let interface = &world.import_map[&interface_key];
2541 let (index, _, lowering) = interface.lowerings.get_full(&(name.clone(), abi)).unwrap();
2542 let shim_name = self.shims.len().to_string();
2543 match lowering {
2544 Lowering::Direct | Lowering::ResourceDrop(_) => {}
2545
2546 Lowering::Indirect { sig, options } => {
2547 log::debug!(
2548 "shim {shim_name} is import `{module}::{field}` lowering {index} `{name}`",
2549 );
2550 let encoding = metadata
2551 .import_encodings
2552 .get(resolve, key, name)
2553 .ok_or_else(|| {
2554 anyhow::anyhow!(
2555 "missing component metadata for import of \
2556 `{module}::{field}`"
2557 )
2558 })?;
2559 self.push(Shim {
2560 name: shim_name,
2561 debug_name: format!("indirect-{module}-{field}"),
2562 options: *options,
2563 kind: ShimKind::IndirectLowering {
2564 interface: interface_key,
2565 index,
2566 realloc: for_module,
2567 encoding,
2568 },
2569 sig: sig.clone(),
2570 });
2571 }
2572 }
2573
2574 Ok(())
2575 }
2576
2577 fn push(&mut self, shim: Shim<'a>) {
2578 if !self.shims.contains_key(&shim.kind) {
2582 self.shims.insert(shim.kind.clone(), shim);
2583 }
2584 }
2585}
2586
2587fn task_return_options_and_type(
2588 resolve: &Resolve,
2589 ty: Option<Type>,
2590) -> (RequiredOptions, WasmSignature) {
2591 let func_tmp = Function {
2592 name: String::new(),
2593 kind: FunctionKind::Freestanding,
2594 params: match ty {
2595 Some(ty) => vec![("a".to_string(), ty)],
2596 None => Vec::new(),
2597 },
2598 result: None,
2599 docs: Default::default(),
2600 stability: Stability::Unknown,
2601 };
2602 let abi = AbiVariant::GuestImport;
2603 let options = RequiredOptions::for_import(resolve, &func_tmp, abi);
2604 let sig = resolve.wasm_signature(abi, &func_tmp);
2605 (options, sig)
2606}
2607
2608#[derive(Clone, Debug)]
2610pub struct Item {
2611 pub alias: String,
2612 pub kind: ExportKind,
2613 pub which: MainOrAdapter,
2614 pub name: String,
2615}
2616
2617#[derive(Debug, PartialEq, Clone)]
2619pub enum MainOrAdapter {
2620 Main,
2621 Adapter(String),
2622}
2623
2624impl MainOrAdapter {
2625 fn to_custom_module(&self) -> CustomModule<'_> {
2626 match self {
2627 MainOrAdapter::Main => CustomModule::Main,
2628 MainOrAdapter::Adapter(s) => CustomModule::Adapter(s),
2629 }
2630 }
2631}
2632
2633#[derive(Clone)]
2635pub enum Instance {
2636 MainOrAdapter(MainOrAdapter),
2638
2639 Items(Vec<Item>),
2641}
2642
2643#[derive(Clone)]
2646pub struct LibraryInfo {
2647 pub instantiate_after_shims: bool,
2649
2650 pub arguments: Vec<(String, Instance)>,
2652}
2653
2654pub(super) struct Adapter {
2656 wasm: Vec<u8>,
2658
2659 metadata: ModuleMetadata,
2661
2662 required_exports: IndexSet<WorldKey>,
2665
2666 library_info: Option<LibraryInfo>,
2671}
2672
2673#[derive(Default)]
2675pub struct ComponentEncoder {
2676 module: Vec<u8>,
2677 module_import_map: Option<ModuleImportMap>,
2678 pub(super) metadata: Bindgen,
2679 validate: bool,
2680 pub(super) main_module_exports: IndexSet<WorldKey>,
2681 pub(super) adapters: IndexMap<String, Adapter>,
2682 import_name_map: HashMap<String, String>,
2683 realloc_via_memory_grow: bool,
2684 merge_imports_based_on_semver: Option<bool>,
2685 pub(super) reject_legacy_names: bool,
2686}
2687
2688impl ComponentEncoder {
2689 pub fn module(mut self, module: &[u8]) -> Result<Self> {
2695 let (wasm, metadata) = self.decode(module.as_ref())?;
2696 let (wasm, module_import_map) = ModuleImportMap::new(wasm)?;
2697 let exports = self
2698 .merge_metadata(metadata)
2699 .context("failed merge WIT metadata for module with previous metadata")?;
2700 self.main_module_exports.extend(exports);
2701 self.module = if let Some(producers) = &self.metadata.producers {
2702 producers.add_to_wasm(&wasm)?
2703 } else {
2704 wasm.to_vec()
2705 };
2706 self.module_import_map = module_import_map;
2707 Ok(self)
2708 }
2709
2710 fn decode<'a>(&self, wasm: &'a [u8]) -> Result<(Cow<'a, [u8]>, Bindgen)> {
2711 let (bytes, metadata) = metadata::decode(wasm)?;
2712 match bytes {
2713 Some(wasm) => Ok((Cow::Owned(wasm), metadata)),
2714 None => Ok((Cow::Borrowed(wasm), metadata)),
2715 }
2716 }
2717
2718 fn merge_metadata(&mut self, metadata: Bindgen) -> Result<IndexSet<WorldKey>> {
2719 self.metadata.merge(metadata)
2720 }
2721
2722 pub fn validate(mut self, validate: bool) -> Self {
2724 self.validate = validate;
2725 self
2726 }
2727
2728 pub fn merge_imports_based_on_semver(mut self, merge: bool) -> Self {
2736 self.merge_imports_based_on_semver = Some(merge);
2737 self
2738 }
2739
2740 pub fn reject_legacy_names(mut self, reject: bool) -> Self {
2749 self.reject_legacy_names = reject;
2750 self
2751 }
2752
2753 pub fn adapter(self, name: &str, bytes: &[u8]) -> Result<Self> {
2771 self.library_or_adapter(name, bytes, None)
2772 }
2773
2774 pub fn library(self, name: &str, bytes: &[u8], library_info: LibraryInfo) -> Result<Self> {
2787 self.library_or_adapter(name, bytes, Some(library_info))
2788 }
2789
2790 fn library_or_adapter(
2791 mut self,
2792 name: &str,
2793 bytes: &[u8],
2794 library_info: Option<LibraryInfo>,
2795 ) -> Result<Self> {
2796 let (wasm, mut metadata) = self.decode(bytes)?;
2797 let adapter_metadata = mem::take(&mut metadata.metadata);
2805 let exports = self.merge_metadata(metadata).with_context(|| {
2806 format!("failed to merge WIT packages of adapter `{name}` into main packages")
2807 })?;
2808 if let Some(library_info) = &library_info {
2809 for (_, instance) in &library_info.arguments {
2811 let resolve = |which: &_| match which {
2812 MainOrAdapter::Main => Ok(()),
2813 MainOrAdapter::Adapter(name) => {
2814 if self.adapters.contains_key(name.as_str()) {
2815 Ok(())
2816 } else {
2817 Err(anyhow!("instance refers to unknown adapter `{name}`"))
2818 }
2819 }
2820 };
2821
2822 match instance {
2823 Instance::MainOrAdapter(which) => resolve(which)?,
2824 Instance::Items(items) => {
2825 for item in items {
2826 resolve(&item.which)?;
2827 }
2828 }
2829 }
2830 }
2831 }
2832 self.adapters.insert(
2833 name.to_string(),
2834 Adapter {
2835 wasm: wasm.to_vec(),
2836 metadata: adapter_metadata,
2837 required_exports: exports,
2838 library_info,
2839 },
2840 );
2841 Ok(self)
2842 }
2843
2844 pub fn realloc_via_memory_grow(mut self, value: bool) -> Self {
2849 self.realloc_via_memory_grow = value;
2850 self
2851 }
2852
2853 pub fn import_name_map(mut self, map: HashMap<String, String>) -> Self {
2864 self.import_name_map = map;
2865 self
2866 }
2867
2868 pub fn encode(&mut self) -> Result<Vec<u8>> {
2870 if self.module.is_empty() {
2871 bail!("a module is required when encoding a component");
2872 }
2873
2874 if self.merge_imports_based_on_semver.unwrap_or(true) {
2875 self.metadata
2876 .resolve
2877 .merge_world_imports_based_on_semver(self.metadata.world)?;
2878 }
2879
2880 let world = ComponentWorld::new(self).context("failed to decode world from module")?;
2881 let mut state = EncodingState {
2882 component: ComponentBuilder::default(),
2883 module_index: None,
2884 instance_index: None,
2885 memory_index: None,
2886 shim_instance_index: None,
2887 fixups_module_index: None,
2888 adapter_modules: IndexMap::new(),
2889 adapter_instances: IndexMap::new(),
2890 import_type_encoding_maps: Default::default(),
2891 export_type_encoding_maps: Default::default(),
2892 imported_instances: Default::default(),
2893 imported_funcs: Default::default(),
2894 exported_instances: Default::default(),
2895 aliased_core_items: Default::default(),
2896 info: &world,
2897 };
2898 state.encode_imports(&self.import_name_map)?;
2899 state.encode_core_modules();
2900 state.encode_core_instantiation()?;
2901 state.encode_exports(CustomModule::Main)?;
2902 for name in self.adapters.keys() {
2903 state.encode_exports(CustomModule::Adapter(name))?;
2904 }
2905 state
2906 .component
2907 .raw_custom_section(&crate::base_producers().raw_custom_section());
2908 let bytes = state.component.finish();
2909
2910 if self.validate {
2911 Validator::new_with_features(WasmFeatures::all())
2912 .validate_all(&bytes)
2913 .context("failed to validate component output")?;
2914 }
2915
2916 Ok(bytes)
2917 }
2918}
2919
2920impl ComponentWorld<'_> {
2921 fn imports_for(&self, module: CustomModule) -> &ImportMap {
2923 match module {
2924 CustomModule::Main => &self.info.imports,
2925 CustomModule::Adapter(name) => &self.adapters[name].info.imports,
2926 }
2927 }
2928
2929 fn exports_for(&self, module: CustomModule) -> &ExportMap {
2931 match module {
2932 CustomModule::Main => &self.info.exports,
2933 CustomModule::Adapter(name) => &self.adapters[name].info.exports,
2934 }
2935 }
2936
2937 fn module_metadata_for(&self, module: CustomModule) -> &ModuleMetadata {
2939 match module {
2940 CustomModule::Main => &self.encoder.metadata.metadata,
2941 CustomModule::Adapter(name) => &self.encoder.adapters[name].metadata,
2942 }
2943 }
2944}
2945
2946#[cfg(all(test, feature = "dummy-module"))]
2947mod test {
2948 use super::*;
2949 use crate::{dummy_module, embed_component_metadata};
2950 use wit_parser::ManglingAndAbi;
2951
2952 #[test]
2953 fn it_renames_imports() {
2954 let mut resolve = Resolve::new();
2955 let pkg = resolve
2956 .push_str(
2957 "test.wit",
2958 r#"
2959package test:wit;
2960
2961interface i {
2962 f: func();
2963}
2964
2965world test {
2966 import i;
2967 import foo: interface {
2968 f: func();
2969 }
2970}
2971"#,
2972 )
2973 .unwrap();
2974 let world = resolve.select_world(pkg, None).unwrap();
2975
2976 let mut module = dummy_module(&resolve, world, ManglingAndAbi::Standard32);
2977
2978 embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8).unwrap();
2979
2980 let encoded = ComponentEncoder::default()
2981 .import_name_map(HashMap::from([
2982 (
2983 "foo".to_string(),
2984 "unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>".to_string(),
2985 ),
2986 (
2987 "test:wit/i".to_string(),
2988 "locked-dep=<foo:bar/i@1.2.3>".to_string(),
2989 ),
2990 ]))
2991 .module(&module)
2992 .unwrap()
2993 .validate(true)
2994 .encode()
2995 .unwrap();
2996
2997 let wat = wasmprinter::print_bytes(encoded).unwrap();
2998 assert!(wat.contains("unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>"));
2999 assert!(wat.contains("locked-dep=<foo:bar/i@1.2.3>"));
3000 }
3001}