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::reencode::{Reencode, RoundtripReencoder};
86use wasm_encoder::*;
87use wasmparser::{Validator, WasmFeatures};
88use wit_parser::{
89 Function, FunctionKind, InterfaceId, LiveTypes, Param, Resolve, Stability, Type, TypeDefKind,
90 TypeId, TypeOwner, WorldItem, WorldKey,
91 abi::{AbiVariant, WasmSignature, WasmType},
92};
93
94const INDIRECT_TABLE_NAME: &str = "$imports";
95const SHIM_MEMORY_NAME: &str = "$memory";
96const TLS_BASE_GET: &str = "$get-tls-base";
97const TLS_BASE_SET: &str = "$set-tls-base";
98
99pub(crate) mod fixup;
100
101mod wit;
102pub use wit::{encode, encode_world};
103
104mod types;
105use types::{InstanceTypeEncoder, RootTypeEncoder, TypeEncodingMaps, ValtypeEncoder};
106mod world;
107use world::{ComponentWorld, ImportedInterface, Lowering};
108
109mod dedupe;
110pub(crate) use dedupe::ModuleImportMap;
111use wasm_metadata::AddMetadataField;
112
113fn to_val_type(ty: &WasmType) -> ValType {
114 match ty {
115 WasmType::I32 => ValType::I32,
116 WasmType::I64 => ValType::I64,
117 WasmType::F32 => ValType::F32,
118 WasmType::F64 => ValType::F64,
119 WasmType::Pointer => ValType::I32,
120 WasmType::PointerOrI64 => ValType::I64,
121 WasmType::Length => ValType::I32,
122 }
123}
124
125fn import_func_name(f: &Function) -> String {
126 match f.kind {
127 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
128 format!("import-func-{}", f.item_name())
129 }
130
131 FunctionKind::Method(_)
139 | FunctionKind::AsyncMethod(_)
140 | FunctionKind::Static(_)
141 | FunctionKind::AsyncStatic(_)
142 | FunctionKind::Constructor(_) => {
143 format!(
144 "import-{}",
145 f.name.replace('[', "").replace([']', '.', ' '], "-")
146 )
147 }
148 }
149}
150
151bitflags::bitflags! {
152 #[derive(Copy, Clone, Debug)]
155 pub struct RequiredOptions: u8 {
156 const MEMORY = 1 << 0;
159 const REALLOC = 1 << 1;
162 const STRING_ENCODING = 1 << 2;
165 const ASYNC = 1 << 3;
166 }
167}
168
169impl RequiredOptions {
170 fn for_import(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
171 let sig = resolve.wasm_signature(abi, func);
172 let mut ret = RequiredOptions::empty();
173 ret.add_lift(TypeContents::for_types(
175 resolve,
176 func.params.iter().map(|p| &p.ty),
177 ));
178 ret.add_lower(TypeContents::for_types(resolve, &func.result));
179
180 if sig.retptr || sig.indirect_params {
183 ret |= RequiredOptions::MEMORY;
184 }
185 if abi == AbiVariant::GuestImportAsync {
186 ret |= RequiredOptions::ASYNC;
187 }
188 ret
189 }
190
191 fn for_export(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
192 let sig = resolve.wasm_signature(abi, func);
193 let mut ret = RequiredOptions::empty();
194 ret.add_lower(TypeContents::for_types(
196 resolve,
197 func.params.iter().map(|p| &p.ty),
198 ));
199 ret.add_lift(TypeContents::for_types(resolve, &func.result));
200
201 if sig.retptr || sig.indirect_params {
205 ret |= RequiredOptions::MEMORY;
206 if sig.indirect_params {
207 ret |= RequiredOptions::REALLOC;
208 }
209 }
210 if let AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful = abi {
211 ret |= RequiredOptions::ASYNC;
212 ret |= task_return_options_and_type(resolve, func).0;
213 }
214 ret
215 }
216
217 fn for_payload(
218 resolve: &Resolve,
219 info: &PayloadInfo,
220 kind: &PayloadFuncKind,
221 async_: bool,
222 ) -> RequiredOptions {
223 let payload = info.payload(resolve);
224 let (wit_param, wit_result) = match kind {
225 PayloadFuncKind::StreamRead | PayloadFuncKind::FutureRead => (None, payload),
226 PayloadFuncKind::StreamWrite | PayloadFuncKind::FutureWrite => (payload, None),
227 };
228 RequiredOptions::MEMORY
229 | RequiredOptions::for_import(
230 resolve,
231 &Function {
232 name: String::new(),
233 kind: FunctionKind::Freestanding,
234 params: match wit_param {
235 Some(ty) => vec![Param {
236 name: "a".to_string(),
237 ty,
238 span: Default::default(),
239 }],
240 None => Vec::new(),
241 },
242 result: wit_result,
243 docs: Default::default(),
244 stability: Stability::Unknown,
245 span: Default::default(),
246 external_id: None,
247 },
248 if async_ {
249 AbiVariant::GuestImportAsync
250 } else {
251 AbiVariant::GuestImport
252 },
253 )
254 }
255
256 fn add_lower(&mut self, types: TypeContents) {
257 if types.contains(TypeContents::NEEDS_MEMORY) {
261 *self |= RequiredOptions::MEMORY | RequiredOptions::REALLOC;
262 }
263 if types.contains(TypeContents::STRING) {
264 *self |= RequiredOptions::MEMORY
265 | RequiredOptions::STRING_ENCODING
266 | RequiredOptions::REALLOC;
267 }
268 }
269
270 fn add_lift(&mut self, types: TypeContents) {
271 if types.contains(TypeContents::NEEDS_MEMORY) {
275 *self |= RequiredOptions::MEMORY;
276 }
277 if types.contains(TypeContents::STRING) {
278 *self |= RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING;
279 }
280 }
281
282 fn into_iter(
283 self,
284 encoding: StringEncoding,
285 memory_index: Option<u32>,
286 realloc_index: Option<u32>,
287 ) -> Result<impl ExactSizeIterator<Item = CanonicalOption>> {
288 #[derive(Default)]
289 struct Iter {
290 options: [Option<CanonicalOption>; 5],
291 current: usize,
292 count: usize,
293 }
294
295 impl Iter {
296 fn push(&mut self, option: CanonicalOption) {
297 assert!(self.count < self.options.len());
298 self.options[self.count] = Some(option);
299 self.count += 1;
300 }
301 }
302
303 impl Iterator for Iter {
304 type Item = CanonicalOption;
305
306 fn next(&mut self) -> Option<Self::Item> {
307 if self.current == self.count {
308 return None;
309 }
310 let option = self.options[self.current];
311 self.current += 1;
312 option
313 }
314
315 fn size_hint(&self) -> (usize, Option<usize>) {
316 (self.count - self.current, Some(self.count - self.current))
317 }
318 }
319
320 impl ExactSizeIterator for Iter {}
321
322 let mut iter = Iter::default();
323
324 if self.contains(RequiredOptions::MEMORY) {
325 iter.push(CanonicalOption::Memory(memory_index.ok_or_else(|| {
326 anyhow!("module does not export a memory named `memory`")
327 })?));
328 }
329
330 if self.contains(RequiredOptions::REALLOC) {
331 iter.push(CanonicalOption::Realloc(realloc_index.ok_or_else(
332 || anyhow!("module does not export a function named `cabi_realloc`"),
333 )?));
334 }
335
336 if self.contains(RequiredOptions::STRING_ENCODING) {
337 iter.push(encoding.into());
338 }
339
340 if self.contains(RequiredOptions::ASYNC) {
341 iter.push(CanonicalOption::Async);
342 }
343
344 Ok(iter)
345 }
346}
347
348bitflags::bitflags! {
349 struct TypeContents: u8 {
352 const STRING = 1 << 0;
353 const NEEDS_MEMORY = 1 << 1;
354 }
355}
356
357impl TypeContents {
358 fn for_types<'a>(resolve: &Resolve, types: impl IntoIterator<Item = &'a Type>) -> Self {
359 let mut cur = TypeContents::empty();
360 for ty in types {
361 cur |= Self::for_type(resolve, ty);
362 }
363 cur
364 }
365
366 fn for_optional_types<'a>(
367 resolve: &Resolve,
368 types: impl Iterator<Item = Option<&'a Type>>,
369 ) -> Self {
370 Self::for_types(resolve, types.flatten())
371 }
372
373 fn for_optional_type(resolve: &Resolve, ty: Option<&Type>) -> Self {
374 match ty {
375 Some(ty) => Self::for_type(resolve, ty),
376 None => Self::empty(),
377 }
378 }
379
380 fn for_type(resolve: &Resolve, ty: &Type) -> Self {
381 match ty {
382 Type::Id(id) => match &resolve.types[*id].kind {
383 TypeDefKind::Handle(h) => match h {
384 wit_parser::Handle::Own(_) => Self::empty(),
385 wit_parser::Handle::Borrow(_) => Self::empty(),
386 },
387 TypeDefKind::Resource => Self::empty(),
388 TypeDefKind::Record(r) => Self::for_types(resolve, r.fields.iter().map(|f| &f.ty)),
389 TypeDefKind::Tuple(t) => Self::for_types(resolve, t.types.iter()),
390 TypeDefKind::Flags(_) => Self::empty(),
391 TypeDefKind::Option(t) => Self::for_type(resolve, t),
392 TypeDefKind::Result(r) => {
393 Self::for_optional_type(resolve, r.ok.as_ref())
394 | Self::for_optional_type(resolve, r.err.as_ref())
395 }
396 TypeDefKind::Variant(v) => {
397 Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref()))
398 }
399 TypeDefKind::Enum(_) => Self::empty(),
400 TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::NEEDS_MEMORY,
401 TypeDefKind::Map(k, v) => {
402 Self::for_type(resolve, k) | Self::for_type(resolve, v) | Self::NEEDS_MEMORY
403 }
404 TypeDefKind::FixedLengthList(t, _elements) => Self::for_type(resolve, t),
405 TypeDefKind::Type(t) => Self::for_type(resolve, t),
406 TypeDefKind::Future(_) => Self::empty(),
407 TypeDefKind::Stream(_) => Self::empty(),
408 TypeDefKind::Unknown => unreachable!(),
409 },
410 Type::String => Self::STRING,
411 _ => Self::empty(),
412 }
413 }
414}
415
416pub struct EncodingState<'a> {
418 component: ComponentBuilder,
420 module_index: Option<u32>,
424 instance_index: Option<u32>,
428 memory_index: Option<u32>,
432 shim_instance_index: Option<u32>,
436
437 adapter_modules: IndexMap<&'a str, u32>,
440 adapter_instances: IndexMap<&'a str, u32>,
442
443 instances: IndexMap<InterfaceId, u32>,
445 imported_funcs: IndexMap<String, u32>,
446
447 type_encoding_maps: TypeEncodingMaps<'a>,
452
453 aliased_core_items: HashMap<(u32, String), u32>,
459
460 info: &'a ComponentWorld<'a>,
462
463 export_task_initialization_wrappers: HashMap<(fixup::ImportedInstance, String), u32>,
470}
471
472impl<'a> EncodingState<'a> {
473 fn encode_core_modules(&mut self) {
474 assert!(self.module_index.is_none());
475 let idx = self
476 .component
477 .core_module_raw(Some("main"), &self.info.encoder.module);
478 self.module_index = Some(idx);
479
480 for (name, adapter) in self.info.adapters.iter() {
481 let debug_name = if adapter.library_info.is_some() {
482 name.to_string()
483 } else {
484 format!("wit-component:adapter:{name}")
485 };
486 let idx = if self.info.encoder.debug_names {
487 let mut add_meta = wasm_metadata::AddMetadata::default();
488 add_meta.name = AddMetadataField::Set(debug_name.clone());
489 let wasm = add_meta
490 .to_wasm(&adapter.wasm)
491 .expect("core wasm can get name added");
492 self.component.core_module_raw(Some(&debug_name), &wasm)
493 } else {
494 self.component
495 .core_module_raw(Some(&debug_name), &adapter.wasm)
496 };
497 let prev = self.adapter_modules.insert(name, idx);
498 assert!(prev.is_none());
499 }
500 }
501
502 fn root_import_type_encoder(
503 &mut self,
504 interface: Option<InterfaceId>,
505 ) -> RootTypeEncoder<'_, 'a> {
506 RootTypeEncoder {
507 state: self,
508 interface,
509 import_types: true,
510 }
511 }
512
513 fn root_export_type_encoder(
514 &mut self,
515 interface: Option<InterfaceId>,
516 ) -> RootTypeEncoder<'_, 'a> {
517 RootTypeEncoder {
518 state: self,
519 interface,
520 import_types: false,
521 }
522 }
523
524 fn instance_type_encoder(&mut self, interface: InterfaceId) -> InstanceTypeEncoder<'_, 'a> {
525 InstanceTypeEncoder {
526 state: self,
527 interface,
528 type_encoding_maps: Default::default(),
529 ty: Default::default(),
530 }
531 }
532
533 fn encode_imports(&mut self, name_map: &HashMap<String, String>) -> Result<()> {
534 let mut has_funcs = false;
535 for (name, info) in self.info.import_map.iter() {
536 match name {
537 Some(name) => {
538 self.encode_interface_import(name_map.get(name).unwrap_or(name), info)?
539 }
540 None => has_funcs = true,
541 }
542 }
543
544 let resolve = &self.info.encoder.metadata.resolve;
545 let world = &resolve.worlds[self.info.encoder.metadata.world];
546
547 for (_name, item) in world.imports.iter() {
550 if let WorldItem::Type { id, .. } = item {
551 self.root_import_type_encoder(None)
552 .encode_valtype(resolve, &Type::Id(*id))?;
553 }
554 }
555
556 if has_funcs {
557 let info = &self.info.import_map[&None];
558 self.encode_root_import_funcs(info)?;
559 }
560 Ok(())
561 }
562
563 fn encode_interface_import(&mut self, name: &str, info: &ImportedInterface) -> Result<()> {
564 let resolve = &self.info.encoder.metadata.resolve;
565 let interface_id = info.interface.as_ref().unwrap();
566 let interface_id = *interface_id;
567 let interface = &resolve.interfaces[interface_id];
568 log::trace!("encoding imports for `{name}` as {interface_id:?}");
569 let mut encoder = self.instance_type_encoder(interface_id);
570
571 if let Some(live) = encoder.state.info.live_type_imports.get(&interface_id) {
573 for ty in live {
574 log::trace!(
575 "encoding extra type {ty:?} name={:?}",
576 resolve.types[*ty].name
577 );
578 encoder.encode_valtype(resolve, &Type::Id(*ty))?;
579 }
580 }
581
582 for (_, func) in interface.functions.iter() {
585 if !(info
586 .lowerings
587 .contains_key(&(func.name.clone(), AbiVariant::GuestImport))
588 || info
589 .lowerings
590 .contains_key(&(func.name.clone(), AbiVariant::GuestImportAsync)))
591 {
592 continue;
593 }
594 log::trace!("encoding function type for `{}`", func.name);
595 let idx = encoder.encode_func_type(resolve, func)?;
596
597 encoder.ty.export(
598 crate::encoding::types::extern_name(&func.name, func.external_id.as_deref()),
599 ComponentTypeRef::Func(idx),
600 );
601 }
602
603 let ty = encoder.ty;
604 if ty.is_empty() {
607 return Ok(());
608 }
609 let instance_type_idx = self
610 .component
611 .type_instance(Some(&format!("ty-{name}")), &ty);
612 let instance_idx = self.component.import(
613 wasm_encoder::ComponentExternName {
614 name: name.into(),
615 implements: info.implements.as_deref().map(|s| s.into()),
616 external_id: info.external_id.as_deref().map(|s| s.into()),
617 version_suffix: None,
618 },
619 ComponentTypeRef::Instance(instance_type_idx),
620 );
621 let prev = self.instances.insert(interface_id, instance_idx);
622 assert!(prev.is_none());
623 Ok(())
624 }
625
626 fn encode_root_import_funcs(&mut self, info: &ImportedInterface) -> Result<()> {
627 let resolve = &self.info.encoder.metadata.resolve;
628 let world = self.info.encoder.metadata.world;
629 for (name, item) in resolve.worlds[world].imports.iter() {
630 let func = match item {
631 WorldItem::Function(f) => f,
632 WorldItem::Interface { .. } | WorldItem::Type { .. } => continue,
633 };
634 let name = resolve.name_world_key(name);
635 if !(info
636 .lowerings
637 .contains_key(&(name.clone(), AbiVariant::GuestImport))
638 || info
639 .lowerings
640 .contains_key(&(name.clone(), AbiVariant::GuestImportAsync)))
641 {
642 continue;
643 }
644 log::trace!("encoding function type for `{}`", func.name);
645 let idx = self
646 .root_import_type_encoder(None)
647 .encode_func_type(resolve, func)?;
648 let func_idx = self.component.import(
649 crate::encoding::types::extern_name(name.as_str(), func.external_id.as_deref()),
650 ComponentTypeRef::Func(idx),
651 );
652 let prev = self.imported_funcs.insert(name, func_idx);
653 assert!(prev.is_none());
654 }
655 Ok(())
656 }
657
658 fn alias_instance_type_export(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
659 let ty = &self.info.encoder.metadata.resolve.types[id];
660 let name = ty.name.as_ref().expect("type must have a name");
661 let instance = self.instances[&interface];
662 self.component
663 .alias_export(instance, name, ComponentExportKind::Type)
664 }
665
666 fn encode_core_instantiation(
667 &mut self,
668 fixup_hook: Option<&mut dyn FnMut(&mut fixup::FixupModule) -> Result<()>>,
669 ) -> Result<()> {
670 let (shims, mut fixups) = self.encode_shim_instantiation()?;
672
673 self.declare_types_for_imported_intrinsics(&shims)?;
677
678 self.instantiate_main_module(&shims)?;
682
683 for (name, _adapter) in self.info.adapters.iter() {
684 self.instantiate_adapter_module(&shims, name)?;
685 }
686
687 if let Some(initialize) = self.info.info.exports.initialize() {
688 fixups.add_initialize(initialize)?;
689 }
690
691 if let Some(hook) = fixup_hook {
692 hook(&mut fixups)?;
693 }
694
695 fixups.instantiate(&shims, self)?;
698
699 Ok(())
700 }
701
702 fn lookup_resource_index(&mut self, id: TypeId) -> u32 {
703 let resolve = &self.info.encoder.metadata.resolve;
704 let ty = &resolve.types[id];
705 match ty.owner {
706 TypeOwner::World(_) => self.type_encoding_maps.id_to_index[&id],
710 TypeOwner::Interface(i) => {
711 let instance = self.instances[&i];
712 let name = ty.name.as_ref().expect("resources must be named");
713 self.component
714 .alias_export(instance, name, ComponentExportKind::Type)
715 }
716 TypeOwner::None => panic!("resources must have an owner"),
717 }
718 }
719
720 fn encode_exports(&mut self, module: CustomModule) -> Result<()> {
721 let resolve = &self.info.encoder.metadata.resolve;
722 let exports = match module {
723 CustomModule::Main => &self.info.encoder.main_module_exports,
724 CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports,
725 };
726
727 if exports.is_empty() {
728 return Ok(());
729 }
730
731 let mut interface_func_core_names = IndexMap::new();
732 let mut world_func_core_names = IndexMap::new();
733 for (core_name, export) in self.info.exports_for(module).iter() {
734 match export {
735 Export::WorldFunc(_, name, _) => {
736 let prev = world_func_core_names.insert(name, core_name);
737 assert!(prev.is_none());
738 }
739 Export::InterfaceFunc(key, _, name, _) => {
740 let prev = interface_func_core_names
741 .entry(key)
742 .or_insert(IndexMap::new())
743 .insert(name.as_str(), core_name);
744 assert!(prev.is_none());
745 }
746 Export::WorldFuncCallback(..)
747 | Export::InterfaceFuncCallback(..)
748 | Export::WorldFuncPostReturn(..)
749 | Export::InterfaceFuncPostReturn(..)
750 | Export::ResourceDtor(..)
751 | Export::Memory
752 | Export::GeneralPurposeRealloc
753 | Export::GeneralPurposeExportRealloc
754 | Export::GeneralPurposeImportRealloc
755 | Export::Initialize
756 | Export::ReallocForAdapter
757 | Export::IndirectFunctionTable
758 | Export::WasmTaskHook => continue,
759 }
760 }
761
762 let world = &resolve.worlds[self.info.encoder.metadata.world];
763
764 for export_name in exports {
765 let export_string = resolve.name_world_key(export_name);
766 match &world.exports[export_name] {
767 WorldItem::Function(func) => {
768 let ty = self
769 .root_import_type_encoder(None)
770 .encode_func_type(resolve, func)?;
771 let core_name = world_func_core_names[&func.name];
772 let idx = self.encode_lift(module, &core_name, export_name, func, ty)?;
773 self.component.export(
774 crate::encoding::types::extern_name(
775 &export_string,
776 func.external_id.as_deref(),
777 ),
778 ComponentExportKind::Func,
779 idx,
780 None,
781 );
782 }
783 item @ WorldItem::Interface { id, .. } => {
784 let core_names = interface_func_core_names.get(export_name);
785 self.encode_interface_export(
786 &export_string,
787 module,
788 export_name,
789 item,
790 *id,
791 core_names,
792 )?;
793 }
794 WorldItem::Type { .. } => unreachable!(),
795 }
796 }
797
798 Ok(())
799 }
800
801 fn encode_interface_export(
802 &mut self,
803 export_name: &str,
804 module: CustomModule<'_>,
805 key: &WorldKey,
806 item: &WorldItem,
807 export: InterfaceId,
808 interface_func_core_names: Option<&IndexMap<&str, &str>>,
809 ) -> Result<()> {
810 log::trace!("encode interface export `{export_name}`");
811 let resolve = &self.info.encoder.metadata.resolve;
812
813 let mut imports = Vec::new();
820 let mut root = self.root_export_type_encoder(Some(export));
821 for (_, func) in &resolve.interfaces[export].functions {
822 let core_name = interface_func_core_names.unwrap()[func.name.as_str()];
823 let ty = root.encode_func_type(resolve, func)?;
824 let func_index = root.state.encode_lift(module, &core_name, key, func, ty)?;
825 imports.push((
826 import_func_name(func),
827 ComponentExportKind::Func,
828 func_index,
829 ));
830 }
831
832 let mut nested = NestedComponentTypeEncoder {
836 component: ComponentBuilder::default(),
837 type_encoding_maps: Default::default(),
838 export_types: false,
839 interface: export,
840 state: self,
841 imports: IndexMap::new(),
842 };
843
844 let mut types_to_import = LiveTypes::default();
854 types_to_import.add_interface(resolve, export);
855 let exports_used = &nested.state.info.exports_used[&export];
856 for ty in types_to_import.iter() {
857 if let TypeOwner::Interface(owner) = resolve.types[ty].owner {
858 if owner == export {
859 continue;
862 }
863
864 let mut encoder = if exports_used.contains(&owner) {
867 nested.state.root_export_type_encoder(Some(export))
868 } else {
869 nested.state.root_import_type_encoder(Some(export))
870 };
871 encoder.encode_valtype(resolve, &Type::Id(ty))?;
872
873 nested.interface = owner;
877 nested.encode_valtype(resolve, &Type::Id(ty))?;
878 }
879 }
880 nested.interface = export;
881
882 let imported_type_maps = nested.type_encoding_maps.clone();
886
887 let mut resources = HashMap::new();
893 for (_name, ty) in resolve.interfaces[export].types.iter() {
894 if !matches!(resolve.types[*ty].kind, TypeDefKind::Resource) {
895 continue;
896 }
897 let idx = match nested.encode_valtype(resolve, &Type::Id(*ty))? {
898 ComponentValType::Type(idx) => idx,
899 _ => unreachable!(),
900 };
901 resources.insert(*ty, idx);
902 }
903
904 for (_, func) in resolve.interfaces[export].functions.iter() {
908 let ty = nested.encode_func_type(resolve, func)?;
909 nested
910 .component
911 .import(&import_func_name(func), ComponentTypeRef::Func(ty));
912 }
913
914 let reverse_map = nested
921 .type_encoding_maps
922 .id_to_index
923 .drain()
924 .map(|p| (p.1, p.0))
925 .collect::<HashMap<_, _>>();
926 nested.type_encoding_maps.def_to_index.clear();
927 for (name, idx) in nested.imports.drain(..) {
928 let id = reverse_map[&idx];
929 let idx = nested.state.type_encoding_maps.id_to_index[&id];
930 imports.push((name, ComponentExportKind::Type, idx))
931 }
932
933 nested.type_encoding_maps = imported_type_maps;
938
939 nested.export_types = true;
946 nested.type_encoding_maps.func_type_map.clear();
947
948 for (_, id) in resolve.interfaces[export].types.iter() {
954 let ty = &resolve.types[*id];
955 match ty.kind {
956 TypeDefKind::Resource => {
957 let idx = nested.component.export(
958 crate::encoding::types::extern_name(
959 ty.name.as_ref().expect("resources must be named"),
960 ty.external_id.as_deref(),
961 ),
962 ComponentExportKind::Type,
963 resources[id],
964 None,
965 );
966 nested.type_encoding_maps.id_to_index.insert(*id, idx);
967 }
968 _ => {
969 nested.encode_valtype(resolve, &Type::Id(*id))?;
970 }
971 }
972 }
973
974 for (i, (_, func)) in resolve.interfaces[export].functions.iter().enumerate() {
975 let ty = nested.encode_func_type(resolve, func)?;
976 nested.component.export(
977 crate::encoding::types::extern_name(&func.name, func.external_id.as_deref()),
978 ComponentExportKind::Func,
979 i as u32,
980 Some(ComponentTypeRef::Func(ty)),
981 );
982 }
983
984 let component = nested.component;
988 let component_index = self
989 .component
990 .component(Some(&format!("{export_name}-shim-component")), component);
991 let instance_index = self.component.instantiate(
992 Some(&format!("{export_name}-shim-instance")),
993 component_index,
994 imports,
995 );
996 let idx = self.component.export(
997 wasm_encoder::ComponentExternName {
998 name: export_name.into(),
999 implements: resolve.implements_value(key, item).map(|s| s.into()),
1000 external_id: resolve.external_id_value(key, item).map(|s| s.into()),
1001 version_suffix: None,
1002 },
1003 ComponentExportKind::Instance,
1004 instance_index,
1005 None,
1006 );
1007 let prev = self.instances.insert(export, idx);
1008 assert!(prev.is_none());
1009
1010 for (_name, id) in resolve.interfaces[export].types.iter() {
1018 self.type_encoding_maps.id_to_index.remove(id);
1019 self.type_encoding_maps
1020 .def_to_index
1021 .remove(&resolve.types[*id].kind);
1022 }
1023
1024 return Ok(());
1025
1026 struct NestedComponentTypeEncoder<'state, 'a> {
1027 component: ComponentBuilder,
1028 type_encoding_maps: TypeEncodingMaps<'a>,
1029 export_types: bool,
1030 interface: InterfaceId,
1031 state: &'state mut EncodingState<'a>,
1032 imports: IndexMap<String, u32>,
1033 }
1034
1035 impl<'a> ValtypeEncoder<'a> for NestedComponentTypeEncoder<'_, 'a> {
1036 fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
1037 self.component.type_defined(None)
1038 }
1039 fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
1040 self.component.type_function(None)
1041 }
1042 fn export_type(
1043 &mut self,
1044 idx: u32,
1045 name: wasm_encoder::ComponentExternName<'a>,
1046 ) -> Option<u32> {
1047 if self.export_types {
1048 Some(
1049 self.component
1050 .export(name, ComponentExportKind::Type, idx, None),
1051 )
1052 } else {
1053 let name = self.unique_import_name(&name.name);
1054 let ret = self
1055 .component
1056 .import(&name, ComponentTypeRef::Type(TypeBounds::Eq(idx)));
1057 self.imports.insert(name, ret);
1058 Some(ret)
1059 }
1060 }
1061 fn export_resource(&mut self, name: wasm_encoder::ComponentExternName<'a>) -> u32 {
1062 if self.export_types {
1063 panic!("resources should already be exported")
1064 } else {
1065 let name = self.unique_import_name(&name.name);
1066 let ret = self
1067 .component
1068 .import(&name, ComponentTypeRef::Type(TypeBounds::SubResource));
1069 self.imports.insert(name, ret);
1070 ret
1071 }
1072 }
1073 fn import_type(&mut self, _: InterfaceId, _id: TypeId) -> u32 {
1074 unreachable!()
1075 }
1076 fn type_encoding_maps(&mut self) -> &mut TypeEncodingMaps<'a> {
1077 &mut self.type_encoding_maps
1078 }
1079 fn interface(&self) -> Option<InterfaceId> {
1080 Some(self.interface)
1081 }
1082 }
1083
1084 impl NestedComponentTypeEncoder<'_, '_> {
1085 fn unique_import_name(&mut self, name: &str) -> String {
1086 let mut name = format!("import-type-{name}");
1087 let mut n = 0;
1088 while self.imports.contains_key(&name) {
1089 name = format!("{name}{n}");
1090 n += 1;
1091 }
1092 name
1093 }
1094 }
1095 }
1096
1097 fn encode_lift(
1098 &mut self,
1099 module: CustomModule<'_>,
1100 core_name: &str,
1101 key: &WorldKey,
1102 func: &Function,
1103 ty: u32,
1104 ) -> Result<u32> {
1105 let resolve = &self.info.encoder.metadata.resolve;
1106 let metadata = self.info.module_metadata_for(module);
1107
1108 let core_alias_export =
1109 |me: &mut Self, core_name: &str| me.hooked_core_alias_export(module, core_name);
1110
1111 let core_func_index = core_alias_export(self, core_name);
1112 let exports = self.info.exports_for(module);
1113
1114 let options = RequiredOptions::for_export(
1115 resolve,
1116 func,
1117 exports
1118 .abi(key, func)
1119 .ok_or_else(|| anyhow!("no ABI found for {}", func.name))?,
1120 );
1121
1122 let encoding = metadata
1123 .export_encodings
1124 .get(resolve, key, &func.name)
1125 .unwrap();
1126 let exports = self.info.exports_for(module);
1127 let realloc_index = if options.contains(RequiredOptions::REALLOC) {
1128 let realloc = exports.export_realloc_for(key, &func.name);
1129 resolve_realloc(self.info, module, realloc)
1130 .map(|(module, name)| self.hooked_core_alias_export(module, name))
1131 } else {
1132 None
1133 };
1134 let mut options = options
1135 .into_iter(encoding, self.memory_index, realloc_index)?
1136 .collect::<Vec<_>>();
1137
1138 if let Some(post_return) = exports.post_return(key, func) {
1139 let post_return = core_alias_export(self, post_return);
1140 options.push(CanonicalOption::PostReturn(post_return));
1141 }
1142 if let Some(callback) = exports.callback(key, func) {
1143 let callback = core_alias_export(self, callback);
1144 options.push(CanonicalOption::Callback(callback));
1145 }
1146 let func_index = self
1147 .component
1148 .lift_func(Some(&func.name), core_func_index, ty, options);
1149 Ok(func_index)
1150 }
1151
1152 fn encode_shim_instantiation(&mut self) -> Result<(Shims<'a>, fixup::FixupModule)> {
1153 let mut ret = Shims::default();
1154 let mut fixups = fixup::FixupModule::default();
1155
1156 ret.append_indirect(self.info, CustomModule::Main)
1157 .context("failed to register indirect shims for main module")?;
1158
1159 for (adapter_name, _adapter) in self.info.adapters.iter() {
1163 ret.append_indirect(self.info, CustomModule::Adapter(adapter_name))
1164 .with_context(|| {
1165 format!("failed to register indirect shims for adapter {adapter_name}")
1166 })?;
1167 }
1168
1169 let tls_base_global_type = if self.info.can_use_context_slot_1() {
1172 None
1173 } else {
1174 let infos = [&self.info.info]
1175 .into_iter()
1176 .chain(self.info.adapters.values().map(|a| &a.info));
1177 let mut ret = None;
1178 for info in infos {
1179 for (_, _, import) in info.imports.imports() {
1180 let ty = match import {
1181 Import::TlsBaseGet { ty } | Import::TlsBaseSet { ty } => *ty,
1182 _ => continue,
1183 };
1184 let prev = *ret.get_or_insert(ty);
1185 if prev != ty {
1186 bail!("conflicting TLS base pointer types `{prev}` and `{ty}`");
1187 }
1188 }
1189 }
1190 match ret {
1191 Some(ret) => Some(ret.try_into()?),
1192 None => None,
1193 }
1194 };
1195
1196 if ret.shims.is_empty()
1197 && self.info.info.imports.imported_memory().is_none()
1198 && tls_base_global_type.is_none()
1199 {
1200 return Ok((ret, fixups));
1201 }
1202
1203 assert!(self.shim_instance_index.is_none());
1204
1205 let mut types = TypeSection::new();
1212 let mut shim_globals = GlobalSection::new();
1213 let mut shim_tables = TableSection::new();
1214 let mut shim_memories = MemorySection::new();
1215 let mut shim_functions = FunctionSection::new();
1216 let mut shim_exports = ExportSection::new();
1217 let mut shim_code = CodeSection::new();
1218 let mut sigs = IndexMap::new();
1219 let mut trapping_stubs = IndexMap::new();
1220 let mut func_indexes = Vec::new();
1221 let mut func_names = NameMap::new();
1222
1223 let mut intern_type =
1224 |types: &mut TypeSection, params: Vec<ValType>, results: Vec<ValType>| {
1225 *sigs
1226 .entry((params, results))
1227 .or_insert_with_key(|(params, results)| {
1228 let index = types.len();
1229 types
1230 .ty()
1231 .function(params.iter().copied(), results.iter().copied());
1232 index
1233 })
1234 };
1235
1236 for shim in ret.shims.values() {
1237 let type_index = intern_type(
1238 &mut types,
1239 shim.sig.params.iter().map(to_val_type).collect(),
1240 shim.sig.results.iter().map(to_val_type).collect(),
1241 );
1242
1243 let trapping_stub = if self.info.encoder.shim_return_call_ref {
1244 Some(*trapping_stubs.entry(type_index).or_insert_with(|| {
1247 let mut stub = wasm_encoder::Function::new(std::iter::empty());
1248 stub.instructions().unreachable().end();
1249 let index = shim_code.len();
1250 shim_functions.function(type_index);
1251 shim_code.function(&stub);
1252 func_names.append(index, "trap stub before initialization");
1253 index
1254 }))
1255 } else {
1256 None
1257 };
1258
1259 let func_index = shim_functions.len();
1260 shim_functions.function(type_index);
1261 let mut func = wasm_encoder::Function::new(std::iter::empty());
1262 for i in 0..shim.sig.params.len() {
1263 func.instructions().local_get(i as u32);
1264 }
1265 fixups.add_shim(&self.info.encoder, shim)?;
1266 if self.info.encoder.shim_return_call_ref {
1267 let global = shim_globals.len();
1270 let ty = GlobalType {
1271 val_type: RefType {
1272 nullable: false,
1273 heap_type: HeapType::Concrete(type_index),
1274 }
1275 .into(),
1276 mutable: true,
1277 shared: false,
1278 };
1279 let global_name = format!("g{}", shim.name);
1280 shim_globals.global(ty, &ConstExpr::ref_func(trapping_stub.unwrap()));
1281 shim_exports.export(&global_name, ExportKind::Global, global);
1282
1283 func.instructions().global_get(global);
1284 func.instructions().return_call_ref(type_index);
1285 } else {
1286 func.instructions().i32_const(func_index as i32);
1287 func.instructions().call_indirect(0, type_index);
1288 }
1289 func.instructions().end();
1290 shim_code.function(&func);
1291 shim_exports.export(&shim.name, ExportKind::Func, func_index);
1292
1293 func_indexes.push(func_index);
1294 func_names.append(func_index, &shim.debug_name);
1295 }
1296
1297 if !ret.shims.is_empty() && !self.info.encoder.shim_return_call_ref {
1298 let table_type = TableType {
1299 element_type: RefType::FUNCREF,
1300 minimum: ret.shims.len() as u64,
1301 maximum: Some(ret.shims.len() as u64),
1302 table64: false,
1303 shared: false,
1304 };
1305
1306 shim_tables.table(table_type);
1307 shim_exports.export(INDIRECT_TABLE_NAME, ExportKind::Table, 0);
1308 }
1309
1310 if let Some(ty) = self.info.info.imports.imported_memory() {
1313 shim_memories.memory(RoundtripReencoder.memory_type(ty)?);
1314 shim_exports.export(SHIM_MEMORY_NAME, ExportKind::Memory, 0);
1315 }
1316
1317 if let Some(ty) = tls_base_global_type {
1321 let get_ty = intern_type(&mut types, Vec::new(), vec![ty]);
1322 let set_ty = intern_type(&mut types, vec![ty], Vec::new());
1323
1324 let global = shim_globals.len();
1325 shim_globals.global(
1326 GlobalType {
1327 val_type: ty,
1328 mutable: true,
1329 shared: false,
1330 },
1331 &match ty {
1332 ValType::I64 => ConstExpr::i64_const(0),
1333 ValType::I32 => ConstExpr::i32_const(0),
1334 _ => unreachable!(),
1335 },
1336 );
1337
1338 let get = shim_functions.len();
1339 shim_functions.function(get_ty);
1340 let mut func = wasm_encoder::Function::new(std::iter::empty());
1341 func.instructions().global_get(global).end();
1342 shim_code.function(&func);
1343 shim_exports.export(TLS_BASE_GET, ExportKind::Func, get);
1344 func_names.append(get, TLS_BASE_GET);
1345
1346 let set = shim_functions.len();
1347 shim_functions.function(set_ty);
1348 let mut func = wasm_encoder::Function::new(std::iter::empty());
1349 func.instructions().local_get(0).global_set(global).end();
1350 shim_code.function(&func);
1351 shim_exports.export(TLS_BASE_SET, ExportKind::Func, set);
1352 func_names.append(set, TLS_BASE_SET);
1353 }
1354
1355 let mut shim_names = NameSection::new();
1356 shim_names.module("wit-component:shim");
1357 shim_names.functions(&func_names);
1358
1359 let mut shim = Module::new();
1360 shim.section(&types);
1361 if !shim_functions.is_empty() {
1362 shim.section(&shim_functions);
1363 }
1364 if !shim_tables.is_empty() {
1365 shim.section(&shim_tables);
1366 }
1367 if !shim_memories.is_empty() {
1368 shim.section(&shim_memories);
1369 }
1370 if !shim_globals.is_empty() {
1371 shim.section(&shim_globals);
1372 }
1373 if !shim_exports.is_empty() {
1374 shim.section(&shim_exports);
1375 }
1376 if !shim_code.is_empty() {
1377 shim.section(&shim_code);
1378 }
1379 shim.section(&RawCustomSection(
1380 &crate::base_producers().raw_custom_section(),
1381 ));
1382 if self.info.encoder.debug_names {
1383 shim.section(&shim_names);
1384 }
1385
1386 let shim_module_index = self
1387 .component
1388 .core_module(Some("wit-component-shim-module"), &shim);
1389
1390 let shim_instance = self.component.core_instantiate(
1391 Some("wit-component-shim-instance"),
1392 shim_module_index,
1393 [],
1394 );
1395 self.shim_instance_index = Some(shim_instance);
1396
1397 if self.info.info.imports.imported_memory().is_some() {
1400 assert!(self.memory_index.is_none());
1401 self.memory_index = Some(self.core_alias_export(
1402 Some("memory"),
1403 shim_instance,
1404 SHIM_MEMORY_NAME,
1405 ExportKind::Memory,
1406 ));
1407 }
1408
1409 Ok((ret, fixups))
1410 }
1411
1412 fn encode_shim(&mut self, shims: &Shims<'_>, shim: &Shim<'_>) -> Result<u32> {
1413 let resolve = &self.info.encoder.metadata.resolve;
1414 Ok(match &shim.kind {
1415 ShimKind::IndirectLowering {
1422 interface,
1423 index,
1424 realloc,
1425 encoding,
1426 } => {
1427 let interface = &self.info.import_map[interface];
1428 let ((name, _), _) = interface.lowerings.get_index(*index).unwrap();
1429 let func_index = match &interface.interface {
1430 Some(interface_id) => {
1431 let instance_index = self.instances[interface_id];
1432 self.component
1433 .alias_export(instance_index, name, ComponentExportKind::Func)
1434 }
1435 None => self.imported_funcs[name],
1436 };
1437
1438 let realloc_export = self
1439 .info
1440 .exports_for(*realloc)
1441 .import_realloc_for(interface.interface, name);
1442 let realloc = self.realloc_index(
1443 shims,
1444 *realloc,
1445 ReallocSite::AfterInstantiation,
1446 shim.options,
1447 realloc_export,
1448 );
1449
1450 self.component.lower_func(
1451 Some(&shim.debug_name),
1452 func_index,
1453 shim.options
1454 .into_iter(*encoding, self.memory_index, realloc)?,
1455 )
1456 }
1457
1458 ShimKind::Adapter { adapter, func } => self.core_alias_export(
1463 Some(func),
1464 self.adapter_instances[adapter],
1465 func,
1466 ExportKind::Func,
1467 ),
1468
1469 ShimKind::ResourceDtor { module, export } => self.core_alias_export(
1474 Some(export),
1475 self.instance_for(*module),
1476 export,
1477 ExportKind::Func,
1478 ),
1479
1480 ShimKind::PayloadFunc {
1481 for_module,
1482 info,
1483 kind,
1484 } => self.encode_payload_func(
1485 shims,
1486 for_module,
1487 info,
1488 kind,
1489 shim.options,
1490 ReallocSite::AfterInstantiation,
1491 )?,
1492
1493 ShimKind::WaitableSetWait => {
1494 self.component.waitable_set_wait(self.memory_index.unwrap())
1495 }
1496 ShimKind::WaitableSetPoll => {
1497 self.component.waitable_set_poll(self.memory_index.unwrap())
1498 }
1499 ShimKind::ErrorContextNew { encoding } => self
1500 .component
1501 .error_context_new(shim.options.into_iter(*encoding, self.memory_index, None)?),
1502 ShimKind::ErrorContextDebugMessage {
1503 for_module,
1504 encoding,
1505 } => {
1506 let realloc = self.info.exports_for(*for_module).import_realloc_fallback();
1507 let realloc_index = self.realloc_index(
1508 shims,
1509 *for_module,
1510 ReallocSite::AfterInstantiation,
1511 shim.options,
1512 realloc,
1513 );
1514
1515 self.component
1516 .error_context_debug_message(shim.options.into_iter(
1517 *encoding,
1518 self.memory_index,
1519 realloc_index,
1520 )?)
1521 }
1522 ShimKind::TaskReturn {
1523 interface,
1524 func,
1525 result,
1526 encoding,
1527 for_module,
1528 } => {
1529 let mut encoder = if interface.is_none() {
1532 self.root_import_type_encoder(*interface)
1533 } else {
1534 self.root_export_type_encoder(*interface)
1535 };
1536 let result = match result {
1537 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1538 None => None,
1539 };
1540
1541 let exports = self.info.exports_for(*for_module);
1542 let realloc = exports.import_realloc_for(*interface, func);
1543
1544 let instance_index = self.instance_for(*for_module);
1545 let realloc_index = realloc.map(|r| {
1546 self.core_alias_export(Some("realloc"), instance_index, r, ExportKind::Func)
1547 });
1548 let options =
1549 shim.options
1550 .into_iter(*encoding, self.memory_index, realloc_index)?;
1551 self.component.task_return(result, options)
1552 }
1553 ShimKind::ThreadNewIndirect { func_ty } => {
1554 let (func_ty_idx, f) = self.component.core_type(Some("thread-start"));
1556 f.core().func_type(func_ty);
1557
1558 let exports = self.info.exports_for(CustomModule::Main);
1561 let instance_index = self.instance_for(CustomModule::Main);
1562 let table_idx = exports.indirect_function_table().map(|table| {
1563 self.core_alias_export(
1564 Some("indirect-function-table"),
1565 instance_index,
1566 table,
1567 ExportKind::Table,
1568 )
1569 }).ok_or_else(|| {
1570 anyhow!(
1571 "table __indirect_function_table must be an exported funcref table for thread.new-indirect"
1572 )
1573 })?;
1574
1575 self.component.thread_new_indirect(func_ty_idx, table_idx)
1576 }
1577
1578 ShimKind::Realloc { module, export } => {
1579 let instance = self.instance_for(*module);
1580 self.core_alias_export(Some(export), instance, export, ExportKind::Func)
1581 }
1582 })
1583 }
1584
1585 fn encode_payload_func(
1586 &mut self,
1587 shims: &Shims<'_>,
1588 for_module: &CustomModule,
1589 info: &PayloadInfo,
1590 kind: &PayloadFuncKind,
1591 options: RequiredOptions,
1592 site: ReallocSite,
1593 ) -> Result<u32> {
1594 let resolve = &self.info.encoder.metadata.resolve;
1595 let metadata = self.info.module_metadata_for(*for_module);
1596 let encoding = match &info.ty {
1597 PayloadType::Type { function, .. } => {
1598 if info.imported {
1599 metadata.import_encodings.get(resolve, &info.key, function)
1600 } else {
1601 metadata.export_encodings.get(resolve, &info.key, function)
1602 }
1603 }
1604 PayloadType::UnitFuture | PayloadType::UnitStream => None,
1605 };
1606 let realloc = payload_realloc_name(self.info, *for_module, info);
1607 let encoding = encoding.unwrap_or(StringEncoding::UTF8);
1608 let realloc_index = self.realloc_index(shims, *for_module, site, options, realloc);
1609 let type_index = self.payload_type_index(info)?;
1610 let options = options.into_iter(encoding, self.memory_index, realloc_index)?;
1611
1612 Ok(match kind {
1613 PayloadFuncKind::FutureWrite => self.component.future_write(type_index, options),
1614 PayloadFuncKind::FutureRead => self.component.future_read(type_index, options),
1615 PayloadFuncKind::StreamWrite => self.component.stream_write(type_index, options),
1616 PayloadFuncKind::StreamRead => self.component.stream_read(type_index, options),
1617 })
1618 }
1619
1620 fn payload_type_index(&mut self, info: &PayloadInfo) -> Result<u32> {
1628 let resolve = &self.info.encoder.metadata.resolve;
1629 let mut encoder = if info.imported || info.interface.is_none() {
1645 self.root_import_type_encoder(None)
1646 } else {
1647 self.root_export_type_encoder(info.interface)
1648 };
1649 match info.ty {
1650 PayloadType::Type { id, .. } => match encoder.encode_valtype(resolve, &Type::Id(id))? {
1651 ComponentValType::Type(index) => Ok(index),
1652 ComponentValType::Primitive(_) => unreachable!(),
1653 },
1654 PayloadType::UnitFuture => Ok(encoder.encode_unit_future()),
1655 PayloadType::UnitStream => Ok(encoder.encode_unit_stream()),
1656 }
1657 }
1658
1659 fn declare_types_for_imported_intrinsics(&mut self, shims: &Shims<'_>) -> Result<()> {
1666 let resolve = &self.info.encoder.metadata.resolve;
1667 let world = &resolve.worlds[self.info.encoder.metadata.world];
1668
1669 let main_module_keys = self.info.encoder.main_module_exports.iter();
1672 let main_module_keys = main_module_keys.map(|key| (CustomModule::Main, key));
1673 let adapter_keys = self.info.encoder.adapters.iter().flat_map(|(name, info)| {
1674 info.required_exports
1675 .iter()
1676 .map(move |key| (CustomModule::Adapter(name), key))
1677 });
1678 for (for_module, key) in main_module_keys.chain(adapter_keys) {
1679 let id = match &world.exports[key] {
1680 WorldItem::Interface { id, .. } => *id,
1681 WorldItem::Type { .. } => unreachable!(),
1682 WorldItem::Function(_) => continue,
1683 };
1684
1685 for ty in resolve.interfaces[id].types.values() {
1686 let def = &resolve.types[*ty];
1687 match &def.kind {
1688 TypeDefKind::Resource => {
1692 let exports = self.info.exports_for(for_module);
1695 let dtor = exports.resource_dtor(*ty).map(|name| {
1696 let shim = &shims.shims[&ShimKind::ResourceDtor {
1697 module: for_module,
1698 export: name,
1699 }];
1700 let index = self.shim_instance_index.unwrap();
1701 self.core_alias_export(
1702 Some(&shim.debug_name),
1703 index,
1704 &shim.name,
1705 ExportKind::Func,
1706 )
1707 });
1708
1709 let resource_idx = self.component.type_resource(
1713 Some(def.name.as_ref().unwrap()),
1714 ValType::I32,
1715 dtor,
1716 );
1717 let prev = self
1718 .type_encoding_maps
1719 .id_to_index
1720 .insert(*ty, resource_idx);
1721 assert!(prev.is_none());
1722 }
1723 _other => {
1724 self.root_export_type_encoder(Some(id))
1725 .encode_valtype(resolve, &Type::Id(*ty))?;
1726 }
1727 }
1728 }
1729 }
1730 Ok(())
1731 }
1732
1733 fn instantiate_main_module(&mut self, shims: &Shims<'_>) -> Result<()> {
1736 assert!(self.instance_index.is_none());
1737
1738 let instance_index = self.instantiate_core_module(shims, CustomModule::Main)?;
1739
1740 if self.memory_index.is_none() {
1743 if let Some(memory) = self.info.info.exports.memory() {
1744 self.memory_index = Some(self.core_alias_export(
1745 Some("memory"),
1746 instance_index,
1747 memory,
1748 ExportKind::Memory,
1749 ));
1750 }
1751 }
1752
1753 self.instance_index = Some(instance_index);
1754 Ok(())
1755 }
1756
1757 fn instantiate_adapter_module(&mut self, shims: &Shims<'_>, name: &'a str) -> Result<()> {
1760 let instance = self.instantiate_core_module(shims, CustomModule::Adapter(name))?;
1761 self.adapter_instances.insert(name, instance);
1762 Ok(())
1763 }
1764
1765 fn instantiate_core_module(
1772 &mut self,
1773 shims: &Shims,
1774 for_module: CustomModule<'_>,
1775 ) -> Result<u32> {
1776 let module = self.module_for(for_module);
1777
1778 let mut args = Vec::new();
1779 for (core_wasm_name, instance) in self.info.imports_for(for_module).modules() {
1780 match instance {
1781 ImportInstance::Names(names) => {
1787 let mut exports = Vec::new();
1788 for (name, import) in names {
1789 log::trace!(
1790 "attempting to materialize import of `{core_wasm_name}::{name}` for {for_module:?}"
1791 );
1792 let (kind, index) = self
1793 .materialize_import(&shims, for_module, import)
1794 .with_context(|| {
1795 format!("failed to satisfy import `{core_wasm_name}::{name}`")
1796 })?;
1797 exports.push((name.as_str(), kind, index));
1798 }
1799 let index = self
1800 .component
1801 .core_instantiate_exports(Some(core_wasm_name), exports);
1802 args.push((core_wasm_name.as_str(), ModuleArg::Instance(index)));
1803 }
1804
1805 ImportInstance::Whole(which) => {
1808 let instance = self.instance_for(which.to_custom_module());
1809 args.push((core_wasm_name.as_str(), ModuleArg::Instance(instance)));
1810 }
1811 }
1812 }
1813
1814 Ok(self
1816 .component
1817 .core_instantiate(Some(for_module.debug_name()), module, args))
1818 }
1819
1820 fn materialize_import(
1827 &mut self,
1828 shims: &Shims<'_>,
1829 for_module: CustomModule<'_>,
1830 import: &'a Import,
1831 ) -> Result<(ExportKind, u32)> {
1832 let resolve = &self.info.encoder.metadata.resolve;
1833 match import {
1834 Import::AdapterExport {
1837 adapter,
1838 func,
1839 ty: _,
1840 } => {
1841 assert!(self.info.encoder.adapters.contains_key(adapter));
1842 Ok(self.materialize_shim_import(shims, &ShimKind::Adapter { adapter, func }))
1843 }
1844
1845 Import::MainModuleMemory(_) => {
1848 let index = self
1849 .memory_index
1850 .ok_or_else(|| anyhow!("main module cannot import memory"))?;
1851 Ok((ExportKind::Memory, index))
1852 }
1853
1854 Import::MainModuleExport { name, kind } => {
1856 let instance = self.instance_index.unwrap();
1857 let index = self.core_alias_export(Some(name), instance, name, *kind);
1858 Ok((*kind, index))
1859 }
1860
1861 Import::Item(item) => {
1865 let instance = self.instance_for(item.which.to_custom_module());
1866 let index =
1867 self.core_alias_export(Some(&item.name), instance, &item.name, item.kind);
1868 Ok((item.kind, index))
1869 }
1870
1871 Import::ExportedResourceDrop(_key, id) => {
1877 let index = self
1878 .component
1879 .resource_drop(self.type_encoding_maps.id_to_index[id]);
1880 Ok((ExportKind::Func, index))
1881 }
1882 Import::ExportedResourceRep(_key, id) => {
1883 let index = self
1884 .component
1885 .resource_rep(self.type_encoding_maps.id_to_index[id]);
1886 Ok((ExportKind::Func, index))
1887 }
1888 Import::ExportedResourceNew(_key, id) => {
1889 let index = self
1890 .component
1891 .resource_new(self.type_encoding_maps.id_to_index[id]);
1892 Ok((ExportKind::Func, index))
1893 }
1894
1895 Import::ImportedResourceDrop(key, iface, id) => {
1900 let ty = &resolve.types[*id];
1901 let name = ty.name.as_ref().unwrap();
1902 self.materialize_wit_import(
1903 shims,
1904 for_module,
1905 iface.map(|_| resolve.name_world_key(key)),
1906 &format!("{name}_drop"),
1907 key,
1908 AbiVariant::GuestImport,
1909 )
1910 }
1911 Import::ExportedTaskReturn(key, interface, func) => {
1912 let (options, _sig) = task_return_options_and_type(resolve, func);
1913 let result_ty = func.result;
1914 if options.is_empty() || self.memory_index.is_some() {
1915 let mut encoder = if interface.is_none() {
1921 self.root_import_type_encoder(*interface)
1922 } else {
1923 self.root_export_type_encoder(*interface)
1924 };
1925
1926 let result = match result_ty.as_ref() {
1927 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1928 None => None,
1929 };
1930 let metadata = &self.info.module_metadata_for(for_module);
1931 let encoding = metadata
1932 .export_encodings
1933 .get(resolve, key, &func.name)
1934 .ok_or_else(|| {
1935 anyhow!("missing component metadata for export of `{}`", func.name)
1936 })?;
1937 let options = options
1938 .into_iter(encoding, self.memory_index, None)?
1939 .collect::<Vec<_>>();
1940 let index = self.component.task_return(result, options);
1941 Ok((ExportKind::Func, index))
1942 } else {
1943 let metadata = &self.info.module_metadata_for(for_module);
1944 let encoding = metadata
1945 .export_encodings
1946 .get(resolve, key, &func.name)
1947 .unwrap();
1948 Ok(self.materialize_shim_import(
1949 shims,
1950 &ShimKind::TaskReturn {
1951 for_module,
1952 interface: *interface,
1953 func: &func.name,
1954 result: result_ty,
1955 encoding,
1956 },
1957 ))
1958 }
1959 }
1960 Import::BackpressureInc => {
1961 let index = self.component.backpressure_inc();
1962 Ok((ExportKind::Func, index))
1963 }
1964 Import::BackpressureDec => {
1965 let index = self.component.backpressure_dec();
1966 Ok((ExportKind::Func, index))
1967 }
1968 Import::WaitableSetWait => {
1969 if let Some(memory) = self.memory_index {
1970 let index = self.component.waitable_set_wait(memory);
1971 return Ok((ExportKind::Func, index));
1972 }
1973 Ok(self.materialize_shim_import(shims, &ShimKind::WaitableSetWait))
1974 }
1975 Import::WaitableSetPoll => {
1976 if let Some(memory) = self.memory_index {
1977 let index = self.component.waitable_set_poll(memory);
1978 return Ok((ExportKind::Func, index));
1979 }
1980 Ok(self.materialize_shim_import(shims, &ShimKind::WaitableSetPoll))
1981 }
1982 Import::SubtaskDrop => {
1983 let index = self.component.subtask_drop();
1984 Ok((ExportKind::Func, index))
1985 }
1986 Import::SubtaskCancel { async_ } => {
1987 let index = self.component.subtask_cancel(*async_);
1988 Ok((ExportKind::Func, index))
1989 }
1990 Import::StreamNew(info) => {
1991 let ty = self.payload_type_index(info)?;
1992 let index = self.component.stream_new(ty);
1993 Ok((ExportKind::Func, index))
1994 }
1995 Import::StreamRead { info, async_ } => self.materialize_payload_import(
1996 shims,
1997 for_module,
1998 info,
1999 PayloadFuncKind::StreamRead,
2000 *async_,
2001 ),
2002 Import::StreamWrite { info, async_ } => self.materialize_payload_import(
2003 shims,
2004 for_module,
2005 info,
2006 PayloadFuncKind::StreamWrite,
2007 *async_,
2008 ),
2009 Import::StreamCancelRead { info, async_ } => {
2010 let ty = self.payload_type_index(info)?;
2011 let index = self.component.stream_cancel_read(ty, *async_);
2012 Ok((ExportKind::Func, index))
2013 }
2014 Import::StreamCancelWrite { info, async_ } => {
2015 let ty = self.payload_type_index(info)?;
2016 let index = self.component.stream_cancel_write(ty, *async_);
2017 Ok((ExportKind::Func, index))
2018 }
2019 Import::StreamDropReadable(info) => {
2020 let type_index = self.payload_type_index(info)?;
2021 let index = self.component.stream_drop_readable(type_index);
2022 Ok((ExportKind::Func, index))
2023 }
2024 Import::StreamDropWritable(info) => {
2025 let type_index = self.payload_type_index(info)?;
2026 let index = self.component.stream_drop_writable(type_index);
2027 Ok((ExportKind::Func, index))
2028 }
2029 Import::FutureNew(info) => {
2030 let ty = self.payload_type_index(info)?;
2031 let index = self.component.future_new(ty);
2032 Ok((ExportKind::Func, index))
2033 }
2034 Import::FutureRead { info, async_ } => self.materialize_payload_import(
2035 shims,
2036 for_module,
2037 info,
2038 PayloadFuncKind::FutureRead,
2039 *async_,
2040 ),
2041 Import::FutureWrite { info, async_ } => self.materialize_payload_import(
2042 shims,
2043 for_module,
2044 info,
2045 PayloadFuncKind::FutureWrite,
2046 *async_,
2047 ),
2048 Import::FutureCancelRead { info, async_ } => {
2049 let ty = self.payload_type_index(info)?;
2050 let index = self.component.future_cancel_read(ty, *async_);
2051 Ok((ExportKind::Func, index))
2052 }
2053 Import::FutureCancelWrite { info, async_ } => {
2054 let ty = self.payload_type_index(info)?;
2055 let index = self.component.future_cancel_write(ty, *async_);
2056 Ok((ExportKind::Func, index))
2057 }
2058 Import::FutureDropReadable(info) => {
2059 let type_index = self.payload_type_index(info)?;
2060 let index = self.component.future_drop_readable(type_index);
2061 Ok((ExportKind::Func, index))
2062 }
2063 Import::FutureDropWritable(info) => {
2064 let type_index = self.payload_type_index(info)?;
2065 let index = self.component.future_drop_writable(type_index);
2066 Ok((ExportKind::Func, index))
2067 }
2068 Import::ErrorContextNew { encoding } => {
2069 if self.memory_index.is_some() {
2070 let options = (RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING)
2071 .into_iter(*encoding, self.memory_index, None)?;
2072 let index = self.component.error_context_new(options);
2073 return Ok((ExportKind::Func, index));
2074 }
2075 Ok(self.materialize_shim_import(
2076 shims,
2077 &ShimKind::ErrorContextNew {
2078 encoding: *encoding,
2079 },
2080 ))
2081 }
2082 Import::ErrorContextDebugMessage { encoding } => Ok(self.materialize_shim_import(
2083 shims,
2084 &ShimKind::ErrorContextDebugMessage {
2085 for_module,
2086 encoding: *encoding,
2087 },
2088 )),
2089 Import::ErrorContextDrop => {
2090 let index = self.component.error_context_drop();
2091 Ok((ExportKind::Func, index))
2092 }
2093 Import::WorldFunc(key, name, abi) => {
2094 self.materialize_wit_import(shims, for_module, None, name, key, *abi)
2095 }
2096 Import::InterfaceFunc(key, _, name, abi) => self.materialize_wit_import(
2097 shims,
2098 for_module,
2099 Some(resolve.name_world_key(key)),
2100 name,
2101 key,
2102 *abi,
2103 ),
2104
2105 Import::WaitableSetNew => {
2106 let index = self.component.waitable_set_new();
2107 Ok((ExportKind::Func, index))
2108 }
2109 Import::WaitableSetDrop => {
2110 let index = self.component.waitable_set_drop();
2111 Ok((ExportKind::Func, index))
2112 }
2113 Import::WaitableJoin => {
2114 let index = self.component.waitable_join();
2115 Ok((ExportKind::Func, index))
2116 }
2117 Import::ContextGet { ty, slot } => {
2118 let index = self.component.context_get((*ty).try_into()?, *slot);
2119 Ok((ExportKind::Func, index))
2120 }
2121 Import::ContextSet { ty, slot } => {
2122 let index = self.component.context_set((*ty).try_into()?, *slot);
2123 Ok((ExportKind::Func, index))
2124 }
2125 Import::TlsBaseGet { ty } => Ok((
2126 ExportKind::Func,
2127 self.materialize_tls_base_import(false, (*ty).try_into()?),
2128 )),
2129 Import::TlsBaseSet { ty } => Ok((
2130 ExportKind::Func,
2131 self.materialize_tls_base_import(true, (*ty).try_into()?),
2132 )),
2133 Import::ExportedTaskCancel => {
2134 let index = self.component.task_cancel();
2135 Ok((ExportKind::Func, index))
2136 }
2137 Import::ThreadIndex => {
2138 let index = self.component.thread_index();
2139 Ok((ExportKind::Func, index))
2140 }
2141 Import::ThreadNewIndirect => Ok(self.materialize_shim_import(
2142 shims,
2143 &ShimKind::ThreadNewIndirect {
2144 func_ty: FuncType::new([ValType::I32], []),
2146 },
2147 )),
2148 Import::ThreadResumeLater => {
2149 let index = self.component.thread_resume_later();
2150 Ok((ExportKind::Func, index))
2151 }
2152 Import::ThreadSuspend => {
2153 let index = self.component.thread_suspend();
2154 Ok((ExportKind::Func, index))
2155 }
2156 Import::ThreadYield => {
2157 let index = self.component.thread_yield();
2158 Ok((ExportKind::Func, index))
2159 }
2160 Import::ThreadSuspendThenResume => {
2161 let index = self.component.thread_suspend_then_resume();
2162 Ok((ExportKind::Func, index))
2163 }
2164 Import::ThreadYieldThenResume => {
2165 let index = self.component.thread_yield_then_resume();
2166 Ok((ExportKind::Func, index))
2167 }
2168 Import::ThreadSuspendThenPromote => {
2169 let index = self.component.thread_suspend_then_promote();
2170 Ok((ExportKind::Func, index))
2171 }
2172 Import::ThreadYieldThenPromote => {
2173 let index = self.component.thread_yield_then_promote();
2174 Ok((ExportKind::Func, index))
2175 }
2176 }
2177 }
2178
2179 fn materialize_tls_base_import(&mut self, set: bool, ty: ValType) -> u32 {
2183 if self.info.can_use_context_slot_1() {
2184 if set {
2185 self.component.context_set(ty, 1)
2186 } else {
2187 self.component.context_get(ty, 1)
2188 }
2189 } else {
2190 let name = if set { TLS_BASE_SET } else { TLS_BASE_GET };
2191 self.core_alias_export(
2192 Some(name),
2193 self.shim_instance_index.unwrap(),
2194 name,
2195 ExportKind::Func,
2196 )
2197 }
2198 }
2199
2200 fn materialize_shim_import(&mut self, shims: &Shims<'_>, kind: &ShimKind) -> (ExportKind, u32) {
2203 let index = self.core_alias_export(
2204 Some(&shims.shims[kind].debug_name),
2205 self.shim_instance_index
2206 .expect("shim should be instantiated"),
2207 &shims.shims[kind].name,
2208 ExportKind::Func,
2209 );
2210 (ExportKind::Func, index)
2211 }
2212
2213 fn materialize_payload_import(
2216 &mut self,
2217 shims: &Shims<'_>,
2218 for_module: CustomModule<'_>,
2219 info: &PayloadInfo,
2220 kind: PayloadFuncKind,
2221 async_: bool,
2222 ) -> Result<(ExportKind, u32)> {
2223 let shim_kind = ShimKind::PayloadFunc {
2224 for_module,
2225 info,
2226 kind,
2227 };
2228 if shims.shims.get(&shim_kind).is_some() {
2229 return Ok(self.materialize_shim_import(shims, &shim_kind));
2230 }
2231 let resolve = &self.info.encoder.metadata.resolve;
2232 let options = RequiredOptions::for_payload(resolve, info, &kind, async_);
2233 let func = self.encode_payload_func(
2234 shims,
2235 &for_module,
2236 info,
2237 &kind,
2238 options,
2239 ReallocSite::BeforeInstantiation,
2240 )?;
2241 Ok((ExportKind::Func, func))
2242 }
2243
2244 fn materialize_wit_import(
2247 &mut self,
2248 shims: &Shims<'_>,
2249 for_module: CustomModule<'_>,
2250 interface_key: Option<String>,
2251 name: &String,
2252 key: &WorldKey,
2253 abi: AbiVariant,
2254 ) -> Result<(ExportKind, u32)> {
2255 let resolve = &self.info.encoder.metadata.resolve;
2256 let import = &self.info.import_map[&interface_key];
2257 let (index, _, lowering) = import.lowerings.get_full(&(name.clone(), abi)).unwrap();
2258 let metadata = self.info.module_metadata_for(for_module);
2259
2260 let index = match lowering {
2261 Lowering::Direct { options } => {
2264 let func_index = match &import.interface {
2265 Some(interface) => {
2266 let instance_index = self.instances[interface];
2267 self.component
2268 .alias_export(instance_index, name, ComponentExportKind::Func)
2269 }
2270 None => self.imported_funcs[name],
2271 };
2272 let encoding = metadata
2273 .import_encodings
2274 .get(resolve, key, name)
2275 .ok_or_else(|| anyhow!("missing component metadata for import of `{name}`"))?;
2276 let realloc = self
2277 .info
2278 .exports_for(for_module)
2279 .import_realloc_for(import.interface, name);
2280 let realloc = self.realloc_index(
2281 shims,
2282 for_module,
2283 ReallocSite::BeforeInstantiation,
2284 *options,
2285 realloc,
2286 );
2287 let options = options
2288 .into_iter(encoding, self.memory_index, realloc)?
2289 .collect::<Vec<_>>();
2290 self.component.lower_func(Some(name), func_index, options)
2291 }
2292
2293 Lowering::Indirect { .. } => {
2297 let encoding = metadata.import_encodings.get(resolve, key, name).unwrap();
2298 return Ok(self.materialize_shim_import(
2299 shims,
2300 &ShimKind::IndirectLowering {
2301 interface: interface_key,
2302 index,
2303 realloc: for_module,
2304 encoding,
2305 },
2306 ));
2307 }
2308
2309 Lowering::ResourceDrop(id) => {
2312 let resource_idx = self.lookup_resource_index(*id);
2313 self.component.resource_drop(resource_idx)
2314 }
2315 };
2316 Ok((ExportKind::Func, index))
2317 }
2318
2319 fn realloc_index(
2322 &mut self,
2323 shims: &Shims<'_>,
2324 module: CustomModule<'_>,
2325 site: ReallocSite,
2326 options: RequiredOptions,
2327 export: Option<&str>,
2328 ) -> Option<u32> {
2329 if !options.contains(RequiredOptions::REALLOC) {
2330 return None;
2331 }
2332 let (module, export) = resolve_realloc(self.info, module, export)?;
2333
2334 if !realloc_needs_shim(self.info, site) {
2335 let instance = self.instance_for(module);
2336 return Some(self.core_alias_export(Some(export), instance, export, ExportKind::Func));
2337 }
2338
2339 let kind = ShimKind::Realloc { module, export };
2340 let shim = shims.shims.get(&kind).unwrap_or_else(|| {
2341 panic!(
2342 "no shim was registered for the `realloc` \
2343 function `{export}` in `{}`",
2344 module.debug_name()
2345 )
2346 });
2347 let instance = self
2348 .shim_instance_index
2349 .expect("shim should be instantiated");
2350 Some(self.core_alias_export(
2351 Some(&shim.debug_name),
2352 instance,
2353 &shim.name,
2354 ExportKind::Func,
2355 ))
2356 }
2357
2358 fn hooked_core_alias_export(&mut self, module: CustomModule<'_>, core_name: &str) -> u32 {
2359 let key = (module.to_imported_instance(), core_name.to_string());
2360 if let Some(&wrapper_idx) = self.export_task_initialization_wrappers.get(&key) {
2361 wrapper_idx
2362 } else {
2363 let instance = self.instance_for(module);
2364 self.core_alias_export(Some(core_name), instance, core_name, ExportKind::Func)
2365 }
2366 }
2367
2368 fn instance_for(&self, module: CustomModule) -> u32 {
2371 match module {
2372 CustomModule::Main => self.instance_index.expect("instantiated by now"),
2373 CustomModule::Adapter(name) => self.adapter_instances[name],
2374 }
2375 }
2376
2377 fn module_for(&self, module: CustomModule) -> u32 {
2380 match module {
2381 CustomModule::Main => self.module_index.unwrap(),
2382 CustomModule::Adapter(name) => self.adapter_modules[name],
2383 }
2384 }
2385
2386 fn core_alias_export(
2389 &mut self,
2390 debug_name: Option<&str>,
2391 instance: u32,
2392 name: &str,
2393 kind: ExportKind,
2394 ) -> u32 {
2395 *self
2396 .aliased_core_items
2397 .entry((instance, name.to_string()))
2398 .or_insert_with(|| {
2399 self.component
2400 .core_alias_export(debug_name, instance, name, kind)
2401 })
2402 }
2403}
2404
2405#[derive(Default)]
2423struct Shims<'a> {
2424 shims: IndexMap<ShimKind<'a>, Shim<'a>>,
2426}
2427
2428struct Shim<'a> {
2429 options: RequiredOptions,
2432
2433 name: String,
2437
2438 debug_name: String,
2441
2442 kind: ShimKind<'a>,
2444
2445 sig: WasmSignature,
2447}
2448
2449#[derive(Debug, Clone, Hash, Eq, PartialEq, Copy)]
2452enum PayloadFuncKind {
2453 FutureWrite,
2454 FutureRead,
2455 StreamWrite,
2456 StreamRead,
2457}
2458
2459#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2460enum ShimKind<'a> {
2461 IndirectLowering {
2465 interface: Option<String>,
2467 index: usize,
2469 realloc: CustomModule<'a>,
2471 encoding: StringEncoding,
2473 },
2474 Adapter {
2477 adapter: &'a str,
2479 func: &'a str,
2481 },
2482 ResourceDtor {
2485 module: CustomModule<'a>,
2487 export: &'a str,
2489 },
2490 PayloadFunc {
2494 for_module: CustomModule<'a>,
2497 info: &'a PayloadInfo,
2502 kind: PayloadFuncKind,
2504 },
2505 WaitableSetWait,
2509 WaitableSetPoll,
2513 TaskReturn {
2515 interface: Option<InterfaceId>,
2518 func: &'a str,
2521 result: Option<Type>,
2523 for_module: CustomModule<'a>,
2525 encoding: StringEncoding,
2527 },
2528 ErrorContextNew {
2532 encoding: StringEncoding,
2534 },
2535 ErrorContextDebugMessage {
2539 for_module: CustomModule<'a>,
2541 encoding: StringEncoding,
2543 },
2544 ThreadNewIndirect {
2547 func_ty: FuncType,
2549 },
2550 Realloc {
2552 module: CustomModule<'a>,
2554 export: &'a str,
2556 },
2557}
2558
2559#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2560enum ReallocSite {
2561 BeforeInstantiation,
2563 AfterInstantiation,
2566}
2567
2568fn realloc_needs_shim(world: &ComponentWorld<'_>, site: ReallocSite) -> bool {
2569 match site {
2570 ReallocSite::BeforeInstantiation => true,
2573
2574 ReallocSite::AfterInstantiation => world.info.exports.wasm_task_hook().is_some(),
2578 }
2579}
2580
2581#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
2591enum CustomModule<'a> {
2592 Main,
2595 Adapter(&'a str),
2598}
2599
2600impl<'a> CustomModule<'a> {
2601 fn debug_name(&self) -> &'a str {
2602 match self {
2603 CustomModule::Main => "main",
2604 CustomModule::Adapter(s) => s,
2605 }
2606 }
2607
2608 fn to_imported_instance(&self) -> fixup::ImportedInstance {
2611 match self {
2612 CustomModule::Main => fixup::ImportedInstance::Main,
2613 CustomModule::Adapter(s) => fixup::ImportedInstance::Adapter(s.to_string()),
2614 }
2615 }
2616}
2617
2618impl<'a> Shims<'a> {
2619 fn append_indirect(
2624 &mut self,
2625 world: &'a ComponentWorld<'a>,
2626 for_module: CustomModule<'a>,
2627 ) -> Result<()> {
2628 let module_imports = world.imports_for(for_module);
2629 let module_exports = world.exports_for(for_module);
2630 let resolve = &world.encoder.metadata.resolve;
2631 let memory_available = world.info.imports.imported_memory().is_some();
2632
2633 for (module, field, import) in module_imports.imports() {
2634 match import {
2635 Import::ImportedResourceDrop(..)
2638 | Import::MainModuleMemory(_)
2639 | Import::MainModuleExport { .. }
2640 | Import::Item(_)
2641 | Import::ExportedResourceDrop(..)
2642 | Import::ExportedResourceRep(..)
2643 | Import::ExportedResourceNew(..)
2644 | Import::ExportedTaskCancel
2645 | Import::ErrorContextDrop
2646 | Import::BackpressureInc
2647 | Import::BackpressureDec
2648 | Import::SubtaskDrop
2649 | Import::SubtaskCancel { .. }
2650 | Import::FutureNew(..)
2651 | Import::StreamNew(..)
2652 | Import::FutureCancelRead { .. }
2653 | Import::FutureCancelWrite { .. }
2654 | Import::FutureDropWritable { .. }
2655 | Import::FutureDropReadable { .. }
2656 | Import::StreamCancelRead { .. }
2657 | Import::StreamCancelWrite { .. }
2658 | Import::StreamDropWritable { .. }
2659 | Import::StreamDropReadable { .. }
2660 | Import::WaitableSetNew
2661 | Import::WaitableSetDrop
2662 | Import::WaitableJoin
2663 | Import::ContextGet { .. }
2664 | Import::ContextSet { .. }
2665 | Import::TlsBaseGet { .. }
2666 | Import::TlsBaseSet { .. }
2667 | Import::ThreadIndex
2668 | Import::ThreadResumeLater
2669 | Import::ThreadSuspend { .. }
2670 | Import::ThreadYield { .. }
2671 | Import::ThreadSuspendThenResume { .. }
2672 | Import::ThreadYieldThenResume { .. }
2673 | Import::ThreadSuspendThenPromote { .. }
2674 | Import::ThreadYieldThenPromote { .. } => {}
2675
2676 Import::ExportedTaskReturn(key, interface, func) => {
2680 let (options, sig) = task_return_options_and_type(resolve, func);
2681 if options.is_empty() || memory_available {
2682 continue;
2683 }
2684 let name = self.shims.len().to_string();
2685 let encoding = world
2686 .module_metadata_for(for_module)
2687 .export_encodings
2688 .get(resolve, key, &func.name)
2689 .ok_or_else(|| {
2690 anyhow::anyhow!(
2691 "missing component metadata for export of \
2692 `{module}::{field}`"
2693 )
2694 })?;
2695 self.push(Shim {
2696 name,
2697 debug_name: format!("task-return-{}", func.name),
2698 options,
2699 kind: ShimKind::TaskReturn {
2700 interface: *interface,
2701 func: &func.name,
2702 result: func.result,
2703 for_module,
2704 encoding,
2705 },
2706 sig,
2707 });
2708 }
2709
2710 Import::FutureWrite { async_, info } => {
2711 self.append_indirect_payload_push(
2712 world,
2713 for_module,
2714 module,
2715 *async_,
2716 info,
2717 PayloadFuncKind::FutureWrite,
2718 vec![WasmType::I32; 2],
2719 vec![WasmType::I32],
2720 );
2721 }
2722 Import::FutureRead { async_, info } => {
2723 self.append_indirect_payload_push(
2724 world,
2725 for_module,
2726 module,
2727 *async_,
2728 info,
2729 PayloadFuncKind::FutureRead,
2730 vec![WasmType::I32; 2],
2731 vec![WasmType::I32],
2732 );
2733 }
2734 Import::StreamWrite { async_, info } => {
2735 self.append_indirect_payload_push(
2736 world,
2737 for_module,
2738 module,
2739 *async_,
2740 info,
2741 PayloadFuncKind::StreamWrite,
2742 vec![WasmType::I32; 3],
2743 vec![WasmType::I32],
2744 );
2745 }
2746 Import::StreamRead { async_, info } => {
2747 self.append_indirect_payload_push(
2748 world,
2749 for_module,
2750 module,
2751 *async_,
2752 info,
2753 PayloadFuncKind::StreamRead,
2754 vec![WasmType::I32; 3],
2755 vec![WasmType::I32],
2756 );
2757 }
2758
2759 Import::WaitableSetWait => {
2760 if memory_available {
2761 continue;
2762 }
2763 let name = self.shims.len().to_string();
2764 self.push(Shim {
2765 name,
2766 debug_name: "waitable-set.wait".to_string(),
2767 options: RequiredOptions::empty(),
2768 kind: ShimKind::WaitableSetWait,
2769 sig: WasmSignature {
2770 params: vec![WasmType::I32; 2],
2771 results: vec![WasmType::I32],
2772 indirect_params: false,
2773 retptr: false,
2774 },
2775 });
2776 }
2777
2778 Import::WaitableSetPoll => {
2779 if memory_available {
2780 continue;
2781 }
2782 let name = self.shims.len().to_string();
2783 self.push(Shim {
2784 name,
2785 debug_name: "waitable-set.poll".to_string(),
2786 options: RequiredOptions::empty(),
2787 kind: ShimKind::WaitableSetPoll,
2788 sig: WasmSignature {
2789 params: vec![WasmType::I32; 2],
2790 results: vec![WasmType::I32],
2791 indirect_params: false,
2792 retptr: false,
2793 },
2794 });
2795 }
2796
2797 Import::ErrorContextNew { encoding } => {
2798 if memory_available {
2799 continue;
2800 }
2801 let name = self.shims.len().to_string();
2802 self.push(Shim {
2803 name,
2804 debug_name: "error-new".to_string(),
2805 options: RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING,
2806 kind: ShimKind::ErrorContextNew {
2807 encoding: *encoding,
2808 },
2809 sig: WasmSignature {
2810 params: vec![WasmType::I32; 2],
2811 results: vec![WasmType::I32],
2812 indirect_params: false,
2813 retptr: false,
2814 },
2815 });
2816 }
2817
2818 Import::ErrorContextDebugMessage { encoding } => {
2819 let name = self.shims.len().to_string();
2820 let options = RequiredOptions::MEMORY
2821 | RequiredOptions::STRING_ENCODING
2822 | RequiredOptions::REALLOC;
2823 self.push(Shim {
2824 name,
2825 debug_name: "error-debug-message".to_string(),
2826 options,
2827 kind: ShimKind::ErrorContextDebugMessage {
2828 for_module,
2829 encoding: *encoding,
2830 },
2831 sig: WasmSignature {
2832 params: vec![WasmType::I32; 2],
2833 results: vec![],
2834 indirect_params: false,
2835 retptr: false,
2836 },
2837 });
2838 let realloc = module_exports.import_realloc_fallback();
2839 self.push_realloc(
2840 world,
2841 for_module,
2842 ReallocSite::AfterInstantiation,
2843 options,
2844 realloc,
2845 );
2846 }
2847
2848 Import::ThreadNewIndirect => {
2849 let name = self.shims.len().to_string();
2850 self.push(Shim {
2851 name,
2852 debug_name: "thread.new-indirect".to_string(),
2853 options: RequiredOptions::empty(),
2854 kind: ShimKind::ThreadNewIndirect {
2855 func_ty: FuncType::new([ValType::I32], vec![]),
2857 },
2858 sig: WasmSignature {
2859 params: vec![WasmType::I32; 2],
2860 results: vec![WasmType::I32],
2861 indirect_params: false,
2862 retptr: false,
2863 },
2864 });
2865 }
2866
2867 Import::AdapterExport { adapter, func, ty } => {
2870 let name = self.shims.len().to_string();
2871 log::debug!("shim {name} is adapter `{module}::{field}`");
2872 self.push(Shim {
2873 name,
2874 debug_name: format!("adapt-{module}-{field}"),
2875 options: RequiredOptions::MEMORY,
2879 kind: ShimKind::Adapter { adapter, func },
2880 sig: WasmSignature {
2881 params: ty.params().iter().map(to_wasm_type).collect(),
2882 results: ty.results().iter().map(to_wasm_type).collect(),
2883 indirect_params: false,
2884 retptr: false,
2885 },
2886 });
2887
2888 fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType {
2889 match ty {
2890 wasmparser::ValType::I32 => WasmType::I32,
2891 wasmparser::ValType::I64 => WasmType::I64,
2892 wasmparser::ValType::F32 => WasmType::F32,
2893 wasmparser::ValType::F64 => WasmType::F64,
2894 _ => unreachable!(),
2895 }
2896 }
2897 }
2898
2899 Import::InterfaceFunc(key, _, name, abi) => {
2903 self.append_indirect_wit_func(
2904 world,
2905 for_module,
2906 module,
2907 field,
2908 key,
2909 name,
2910 Some(resolve.name_world_key(key)),
2911 *abi,
2912 )?;
2913 }
2914 Import::WorldFunc(key, name, abi) => {
2915 self.append_indirect_wit_func(
2916 world, for_module, module, field, key, name, None, *abi,
2917 )?;
2918 }
2919 }
2920 }
2921
2922 for (export_name, export) in module_exports.iter() {
2928 let id = match export {
2929 Export::ResourceDtor(id) => id,
2930 _ => continue,
2931 };
2932 let resource = resolve.types[*id].name.as_ref().unwrap();
2933 let name = self.shims.len().to_string();
2934 self.push(Shim {
2935 name,
2936 debug_name: format!("dtor-{resource}"),
2937 options: RequiredOptions::empty(),
2938 kind: ShimKind::ResourceDtor {
2939 module: for_module,
2940 export: export_name,
2941 },
2942 sig: WasmSignature {
2943 params: vec![WasmType::I32],
2944 results: Vec::new(),
2945 indirect_params: false,
2946 retptr: false,
2947 },
2948 });
2949 }
2950
2951 Ok(())
2952 }
2953
2954 fn append_indirect_payload_push(
2957 &mut self,
2958 world: &'a ComponentWorld<'a>,
2959 for_module: CustomModule<'a>,
2960 module: &str,
2961 async_: bool,
2962 info: &'a PayloadInfo,
2963 kind: PayloadFuncKind,
2964 params: Vec<WasmType>,
2965 results: Vec<WasmType>,
2966 ) {
2967 let resolve = &world.encoder.metadata.resolve;
2968 let debug_name = format!("{module}-{}", info.name);
2969 let name = self.shims.len().to_string();
2970
2971 let options = RequiredOptions::for_payload(resolve, info, &kind, async_);
2972 if !options.contains(RequiredOptions::REALLOC)
2973 && world.info.imports.imported_memory().is_some()
2974 {
2975 return;
2976 }
2977 self.push(Shim {
2978 name,
2979 debug_name,
2980 options,
2981 kind: ShimKind::PayloadFunc {
2982 for_module,
2983 info,
2984 kind,
2985 },
2986 sig: WasmSignature {
2987 params,
2988 results,
2989 indirect_params: false,
2990 retptr: false,
2991 },
2992 });
2993 let realloc = payload_realloc_name(world, for_module, info);
2994 self.push_realloc(
2995 world,
2996 for_module,
2997 ReallocSite::AfterInstantiation,
2998 options,
2999 realloc,
3000 );
3001 }
3002
3003 fn append_indirect_wit_func(
3006 &mut self,
3007 world: &'a ComponentWorld<'a>,
3008 for_module: CustomModule<'a>,
3009 module: &str,
3010 field: &str,
3011 key: &WorldKey,
3012 name: &String,
3013 interface_key: Option<String>,
3014 abi: AbiVariant,
3015 ) -> Result<()> {
3016 let resolve = &world.encoder.metadata.resolve;
3017 let metadata = world.module_metadata_for(for_module);
3018 let interface = &world.import_map[&interface_key];
3019 let (index, _, lowering) = interface.lowerings.get_full(&(name.clone(), abi)).unwrap();
3020 let shim_name = self.shims.len().to_string();
3021 match lowering {
3022 Lowering::ResourceDrop(_) => {}
3023
3024 Lowering::Direct { options } => {
3025 let realloc = world
3026 .exports_for(for_module)
3027 .import_realloc_for(interface.interface, name);
3028 self.push_realloc(
3029 world,
3030 for_module,
3031 ReallocSite::BeforeInstantiation,
3032 *options,
3033 realloc,
3034 );
3035 }
3036
3037 Lowering::Indirect { sig, options } => {
3038 log::debug!(
3039 "shim {shim_name} is import `{module}::{field}` lowering {index} `{name}`",
3040 );
3041 let encoding = metadata
3042 .import_encodings
3043 .get(resolve, key, name)
3044 .ok_or_else(|| {
3045 anyhow::anyhow!(
3046 "missing component metadata for import of \
3047 `{module}::{field}`"
3048 )
3049 })?;
3050 self.push(Shim {
3051 name: shim_name,
3052 debug_name: format!("indirect-{module}-{field}"),
3053 options: *options,
3054 kind: ShimKind::IndirectLowering {
3055 interface: interface_key,
3056 index,
3057 realloc: for_module,
3058 encoding,
3059 },
3060 sig: sig.clone(),
3061 });
3062
3063 let realloc = world
3064 .exports_for(for_module)
3065 .import_realloc_for(interface.interface, name);
3066 self.push_realloc(
3067 world,
3068 for_module,
3069 ReallocSite::AfterInstantiation,
3070 *options,
3071 realloc,
3072 );
3073 }
3074 }
3075
3076 Ok(())
3077 }
3078
3079 fn push_realloc(
3083 &mut self,
3084 world: &'a ComponentWorld<'a>,
3085 for_module: CustomModule<'a>,
3086 site: ReallocSite,
3087 options: RequiredOptions,
3088 export: Option<&'a str>,
3089 ) {
3090 if !options.contains(RequiredOptions::REALLOC) {
3091 return;
3092 }
3093 let Some((for_module, export)) = resolve_realloc(world, for_module, export) else {
3094 return;
3095 };
3096 if !realloc_needs_shim(world, site) {
3097 return;
3098 }
3099 let name = self.shims.len().to_string();
3100 self.push(Shim {
3101 name,
3102 debug_name: format!("realloc-{}-{export}", for_module.debug_name()),
3103 options: RequiredOptions::empty(),
3104 kind: ShimKind::Realloc {
3105 module: for_module,
3106 export,
3107 },
3108 sig: WasmSignature {
3109 params: vec![WasmType::I32; 4],
3110 results: vec![WasmType::I32],
3111 indirect_params: false,
3112 retptr: false,
3113 },
3114 });
3115 }
3116
3117 fn push(&mut self, shim: Shim<'a>) {
3118 if !self.shims.contains_key(&shim.kind) {
3122 self.shims.insert(shim.kind.clone(), shim);
3123 }
3124 }
3125}
3126
3127fn resolve_realloc<'a>(
3134 world: &'a ComponentWorld<'a>,
3135 module: CustomModule<'a>,
3136 export: Option<&'a str>,
3137) -> Option<(CustomModule<'a>, &'a str)> {
3138 if let Some(export) = export {
3139 return Some((module, export));
3140 }
3141 match module {
3142 CustomModule::Main => None,
3145
3146 CustomModule::Adapter(name) => {
3148 let _info = world.adapters[name].library_info.as_ref()?;
3149 let main_realloc = world.info.exports.general_purpose_realloc()?;
3150 Some((CustomModule::Main, main_realloc))
3151 }
3152 }
3153}
3154
3155fn payload_realloc_name<'a>(
3156 world: &'a ComponentWorld<'_>,
3157 for_module: CustomModule<'_>,
3158 info: &PayloadInfo,
3159) -> Option<&'a str> {
3160 let exports = world.exports_for(for_module);
3161 match &info.ty {
3162 PayloadType::Type { function, .. } => {
3163 if info.imported {
3164 exports.import_realloc_for(info.interface, function)
3165 } else {
3166 exports.export_realloc_for(&info.key, function)
3167 }
3168 }
3169 PayloadType::UnitFuture | PayloadType::UnitStream => None,
3170 }
3171}
3172
3173fn task_return_options_and_type(
3174 resolve: &Resolve,
3175 func: &Function,
3176) -> (RequiredOptions, WasmSignature) {
3177 let func_tmp = Function {
3178 name: String::new(),
3179 kind: FunctionKind::Freestanding,
3180 params: match &func.result {
3181 Some(ty) => vec![Param {
3182 name: "a".to_string(),
3183 ty: *ty,
3184 span: Default::default(),
3185 }],
3186 None => Vec::new(),
3187 },
3188 result: None,
3189 docs: Default::default(),
3190 stability: Stability::Unknown,
3191 span: Default::default(),
3192 external_id: None,
3193 };
3194 let abi = AbiVariant::GuestImport;
3195 let mut options = RequiredOptions::for_import(resolve, func, abi);
3196 options.remove(RequiredOptions::REALLOC);
3198 let sig = resolve.wasm_signature(abi, &func_tmp);
3199 (options, sig)
3200}
3201
3202#[derive(Clone, Debug)]
3204pub struct Item {
3205 pub alias: String,
3206 pub kind: ExportKind,
3207 pub which: MainOrAdapter,
3208 pub name: String,
3209}
3210
3211#[derive(Debug, PartialEq, Clone)]
3213pub enum MainOrAdapter {
3214 Main,
3215 Adapter(String),
3216}
3217
3218impl MainOrAdapter {
3219 fn to_custom_module(&self) -> CustomModule<'_> {
3220 match self {
3221 MainOrAdapter::Main => CustomModule::Main,
3222 MainOrAdapter::Adapter(s) => CustomModule::Adapter(s),
3223 }
3224 }
3225}
3226
3227#[derive(Clone)]
3229pub enum Instance {
3230 MainOrAdapter(MainOrAdapter),
3232
3233 Items(Vec<Item>),
3235}
3236
3237#[derive(Clone)]
3240pub struct LibraryInfo {
3241 pub arguments: Vec<(String, Instance)>,
3243}
3244
3245pub(super) struct Adapter {
3247 wasm: Vec<u8>,
3249
3250 metadata: ModuleMetadata,
3252
3253 required_exports: IndexSet<WorldKey>,
3256
3257 library_info: Option<LibraryInfo>,
3262}
3263
3264#[derive(Default)]
3266pub struct ComponentEncoder {
3267 module: Vec<u8>,
3268 module_import_map: Option<ModuleImportMap>,
3269 pub(super) metadata: Bindgen,
3270 validate: bool,
3271 pub(super) main_module_exports: IndexSet<WorldKey>,
3272 pub(super) adapters: IndexMap<String, Adapter>,
3273 import_name_map: HashMap<String, String>,
3274 realloc_via_memory_grow: bool,
3275 merge_imports_based_on_semver: Option<bool>,
3276 pub(super) reject_legacy_names: bool,
3277 debug_names: bool,
3278 shim_return_call_ref: bool,
3279}
3280
3281impl ComponentEncoder {
3282 pub fn module(&mut self, module: &[u8]) -> Result<&mut Self> {
3288 let (wasm, metadata) = self.decode(module.as_ref())?;
3289 let (wasm, module_import_map) = ModuleImportMap::new(wasm)?;
3290 self.module = if let Some(producers) = &metadata.producers {
3291 producers.add_to_wasm(&wasm)?
3292 } else {
3293 wasm.to_vec()
3294 };
3295 let exports = self
3296 .merge_metadata(metadata)
3297 .context("failed merge WIT metadata for module with previous metadata")?;
3298 self.main_module_exports.extend(exports);
3299 self.module_import_map = module_import_map;
3300 Ok(self)
3301 }
3302
3303 fn decode<'a>(&self, wasm: &'a [u8]) -> Result<(Cow<'a, [u8]>, Bindgen)> {
3304 let (bytes, metadata) = metadata::decode(wasm)?;
3305 match bytes {
3306 Some(wasm) => Ok((Cow::Owned(wasm), metadata)),
3307 None => Ok((Cow::Borrowed(wasm), metadata)),
3308 }
3309 }
3310
3311 fn merge_metadata(&mut self, metadata: Bindgen) -> Result<IndexSet<WorldKey>> {
3312 self.metadata.merge(metadata)
3313 }
3314
3315 pub fn validate(&mut self, validate: bool) -> &mut Self {
3317 self.validate = validate;
3318 self
3319 }
3320
3321 pub fn debug_names(&mut self, debug_names: bool) -> &mut Self {
3323 self.debug_names = debug_names;
3324 self
3325 }
3326
3327 pub fn shim_return_call_ref(&mut self, enable: bool) -> &mut Self {
3330 self.shim_return_call_ref = enable;
3331 self
3332 }
3333
3334 pub fn merge_imports_based_on_semver(&mut self, merge: bool) -> &mut Self {
3342 self.merge_imports_based_on_semver = Some(merge);
3343 self
3344 }
3345
3346 pub fn reject_legacy_names(&mut self, reject: bool) -> &mut Self {
3355 self.reject_legacy_names = reject;
3356 self
3357 }
3358
3359 pub fn adapter(&mut self, name: &str, bytes: &[u8]) -> Result<&mut Self> {
3377 self.library_or_adapter(name, bytes, None)
3378 }
3379
3380 pub fn library(
3393 &mut self,
3394 name: &str,
3395 bytes: &[u8],
3396 library_info: LibraryInfo,
3397 ) -> Result<&mut Self> {
3398 self.library_or_adapter(name, bytes, Some(library_info))
3399 }
3400
3401 fn library_or_adapter(
3402 &mut self,
3403 name: &str,
3404 bytes: &[u8],
3405 library_info: Option<LibraryInfo>,
3406 ) -> Result<&mut Self> {
3407 let (wasm, mut metadata) = self.decode(bytes)?;
3408 let adapter_metadata = mem::take(&mut metadata.metadata);
3416 let exports = self.merge_metadata(metadata).with_context(|| {
3417 format!("failed to merge WIT packages of adapter `{name}` into main packages")
3418 })?;
3419 if let Some(library_info) = &library_info {
3420 for (_, instance) in &library_info.arguments {
3422 let resolve = |which: &_| match which {
3423 MainOrAdapter::Main => Ok(()),
3424 MainOrAdapter::Adapter(name) => {
3425 if self.adapters.contains_key(name.as_str()) {
3426 Ok(())
3427 } else {
3428 Err(anyhow!("instance refers to unknown adapter `{name}`"))
3429 }
3430 }
3431 };
3432
3433 match instance {
3434 Instance::MainOrAdapter(which) => resolve(which)?,
3435 Instance::Items(items) => {
3436 for item in items {
3437 resolve(&item.which)?;
3438 }
3439 }
3440 }
3441 }
3442 }
3443 self.adapters.insert(
3444 name.to_string(),
3445 Adapter {
3446 wasm: wasm.to_vec(),
3447 metadata: adapter_metadata,
3448 required_exports: exports,
3449 library_info,
3450 },
3451 );
3452 Ok(self)
3453 }
3454
3455 pub fn realloc_via_memory_grow(&mut self, value: bool) -> &mut Self {
3466 self.realloc_via_memory_grow = value;
3467 self
3468 }
3469
3470 pub fn import_name_map(&mut self, map: HashMap<String, String>) -> &mut Self {
3481 self.import_name_map = map;
3482 self
3483 }
3484
3485 pub fn encode(&mut self) -> Result<Vec<u8>> {
3487 self.encode_with_fixups(None)
3488 }
3489
3490 pub(crate) fn encode_with_fixups(
3491 &mut self,
3492 fixup_hook: Option<&mut dyn FnMut(&mut fixup::FixupModule) -> Result<()>>,
3493 ) -> Result<Vec<u8>> {
3494 if self.module.is_empty() {
3495 bail!("a module is required when encoding a component");
3496 }
3497
3498 if self.merge_imports_based_on_semver.unwrap_or(true) {
3499 self.metadata
3500 .resolve
3501 .merge_world_imports_based_on_semver(self.metadata.world)?;
3502 }
3503
3504 self.finalize_resolve_with_nominal_ids();
3505
3506 let world = ComponentWorld::new(self).context("failed to decode world from module")?;
3507 let mut state = EncodingState {
3508 component: ComponentBuilder::default(),
3509 module_index: None,
3510 instance_index: None,
3511 memory_index: None,
3512 shim_instance_index: None,
3513 adapter_modules: IndexMap::new(),
3514 adapter_instances: IndexMap::new(),
3515 type_encoding_maps: Default::default(),
3516 instances: Default::default(),
3517 imported_funcs: Default::default(),
3518 aliased_core_items: Default::default(),
3519 info: &world,
3520 export_task_initialization_wrappers: HashMap::new(),
3521 };
3522 state.encode_imports(&self.import_name_map)?;
3523 state.encode_core_modules();
3524 state.encode_core_instantiation(fixup_hook)?;
3525 state.encode_exports(CustomModule::Main)?;
3526 for name in self.adapters.keys() {
3527 state.encode_exports(CustomModule::Adapter(name))?;
3528 }
3529 state.component.append_names();
3530 state
3531 .component
3532 .raw_custom_section(&crate::base_producers().raw_custom_section());
3533 let bytes = state.component.finish();
3534
3535 if self.validate {
3536 Validator::new_with_features(WasmFeatures::all())
3537 .validate_all(&bytes)
3538 .context("failed to validate component output")?;
3539 }
3540
3541 Ok(bytes)
3542 }
3543
3544 fn finalize_resolve_with_nominal_ids(&mut self) {
3553 let world = &self.metadata.resolve.worlds[self.metadata.world];
3560 let main_module_exports = self
3561 .main_module_exports
3562 .iter()
3563 .map(|i| world.exports.get_index_of(i).unwrap())
3564 .collect::<Vec<_>>();
3565 let adapter_exports = self
3566 .adapters
3567 .values()
3568 .map(|adapter| {
3569 adapter
3570 .required_exports
3571 .iter()
3572 .map(|i| world.exports.get_index_of(i).unwrap())
3573 .collect::<Vec<_>>()
3574 })
3575 .collect::<Vec<_>>();
3576
3577 self.metadata
3581 .resolve
3582 .generate_nominal_type_ids(self.metadata.world);
3583
3584 self.main_module_exports.clear();
3587 let world = &self.metadata.resolve.worlds[self.metadata.world];
3588 for index in main_module_exports {
3589 let (key, _) = world.exports.get_index(index).unwrap();
3590 self.main_module_exports.insert(key.clone());
3591 }
3592 for (exports, adapter) in adapter_exports.into_iter().zip(self.adapters.values_mut()) {
3593 adapter.required_exports.clear();
3594 for index in exports {
3595 let (key, _) = world.exports.get_index(index).unwrap();
3596 adapter.required_exports.insert(key.clone());
3597 }
3598 }
3599 }
3600}
3601
3602impl ComponentWorld<'_> {
3603 fn imports_for(&self, module: CustomModule) -> &ImportMap {
3605 match module {
3606 CustomModule::Main => &self.info.imports,
3607 CustomModule::Adapter(name) => &self.adapters[name].info.imports,
3608 }
3609 }
3610
3611 fn exports_for(&self, module: CustomModule) -> &ExportMap {
3613 match module {
3614 CustomModule::Main => &self.info.exports,
3615 CustomModule::Adapter(name) => &self.adapters[name].info.exports,
3616 }
3617 }
3618
3619 fn module_metadata_for(&self, module: CustomModule) -> &ModuleMetadata {
3621 match module {
3622 CustomModule::Main => &self.encoder.metadata.metadata,
3623 CustomModule::Adapter(name) => &self.encoder.adapters[name].metadata,
3624 }
3625 }
3626}
3627
3628#[cfg(all(test, feature = "dummy-module"))]
3629mod test {
3630 use super::*;
3631 use crate::{dummy_module, embed_component_metadata};
3632 use wit_parser::ManglingAndAbi;
3633
3634 #[test]
3635 fn it_renames_imports() {
3636 let mut resolve = Resolve::new();
3637 let pkg = resolve
3638 .push_str(
3639 "test.wit",
3640 r#"
3641package test:wit;
3642
3643interface i {
3644 f: func();
3645}
3646
3647world test {
3648 import i;
3649 import foo: interface {
3650 f: func();
3651 }
3652}
3653"#,
3654 )
3655 .unwrap();
3656 let world = resolve.select_world(&[pkg], None).unwrap();
3657
3658 let mut module = dummy_module(&resolve, world, ManglingAndAbi::Standard32);
3659
3660 embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8).unwrap();
3661
3662 let encoded = ComponentEncoder::default()
3663 .import_name_map(HashMap::from([
3664 (
3665 "foo".to_string(),
3666 "unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>".to_string(),
3667 ),
3668 (
3669 "test:wit/i".to_string(),
3670 "locked-dep=<foo:bar/i@1.2.3>".to_string(),
3671 ),
3672 ]))
3673 .module(&module)
3674 .unwrap()
3675 .validate(true)
3676 .encode()
3677 .unwrap();
3678
3679 let wat = wasmprinter::print_bytes(encoded).unwrap();
3680 assert!(wat.contains("unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>"));
3681 assert!(wat.contains("locked-dep=<foo:bar/i@1.2.3>"));
3682 }
3683}