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 { cancellable } => self
1494 .component
1495 .waitable_set_wait(*cancellable, self.memory_index.unwrap()),
1496 ShimKind::WaitableSetPoll { cancellable } => self
1497 .component
1498 .waitable_set_poll(*cancellable, self.memory_index.unwrap()),
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 { cancellable } => {
1969 if let Some(memory) = self.memory_index {
1970 let index = self.component.waitable_set_wait(*cancellable, memory);
1971 return Ok((ExportKind::Func, index));
1972 }
1973 Ok(self.materialize_shim_import(
1974 shims,
1975 &ShimKind::WaitableSetWait {
1976 cancellable: *cancellable,
1977 },
1978 ))
1979 }
1980 Import::WaitableSetPoll { cancellable } => {
1981 if let Some(memory) = self.memory_index {
1982 let index = self.component.waitable_set_poll(*cancellable, memory);
1983 return Ok((ExportKind::Func, index));
1984 }
1985 Ok(self.materialize_shim_import(
1986 shims,
1987 &ShimKind::WaitableSetPoll {
1988 cancellable: *cancellable,
1989 },
1990 ))
1991 }
1992 Import::SubtaskDrop => {
1993 let index = self.component.subtask_drop();
1994 Ok((ExportKind::Func, index))
1995 }
1996 Import::SubtaskCancel { async_ } => {
1997 let index = self.component.subtask_cancel(*async_);
1998 Ok((ExportKind::Func, index))
1999 }
2000 Import::StreamNew(info) => {
2001 let ty = self.payload_type_index(info)?;
2002 let index = self.component.stream_new(ty);
2003 Ok((ExportKind::Func, index))
2004 }
2005 Import::StreamRead { info, async_ } => self.materialize_payload_import(
2006 shims,
2007 for_module,
2008 info,
2009 PayloadFuncKind::StreamRead,
2010 *async_,
2011 ),
2012 Import::StreamWrite { info, async_ } => self.materialize_payload_import(
2013 shims,
2014 for_module,
2015 info,
2016 PayloadFuncKind::StreamWrite,
2017 *async_,
2018 ),
2019 Import::StreamCancelRead { info, async_ } => {
2020 let ty = self.payload_type_index(info)?;
2021 let index = self.component.stream_cancel_read(ty, *async_);
2022 Ok((ExportKind::Func, index))
2023 }
2024 Import::StreamCancelWrite { info, async_ } => {
2025 let ty = self.payload_type_index(info)?;
2026 let index = self.component.stream_cancel_write(ty, *async_);
2027 Ok((ExportKind::Func, index))
2028 }
2029 Import::StreamDropReadable(info) => {
2030 let type_index = self.payload_type_index(info)?;
2031 let index = self.component.stream_drop_readable(type_index);
2032 Ok((ExportKind::Func, index))
2033 }
2034 Import::StreamDropWritable(info) => {
2035 let type_index = self.payload_type_index(info)?;
2036 let index = self.component.stream_drop_writable(type_index);
2037 Ok((ExportKind::Func, index))
2038 }
2039 Import::FutureNew(info) => {
2040 let ty = self.payload_type_index(info)?;
2041 let index = self.component.future_new(ty);
2042 Ok((ExportKind::Func, index))
2043 }
2044 Import::FutureRead { info, async_ } => self.materialize_payload_import(
2045 shims,
2046 for_module,
2047 info,
2048 PayloadFuncKind::FutureRead,
2049 *async_,
2050 ),
2051 Import::FutureWrite { info, async_ } => self.materialize_payload_import(
2052 shims,
2053 for_module,
2054 info,
2055 PayloadFuncKind::FutureWrite,
2056 *async_,
2057 ),
2058 Import::FutureCancelRead { info, async_ } => {
2059 let ty = self.payload_type_index(info)?;
2060 let index = self.component.future_cancel_read(ty, *async_);
2061 Ok((ExportKind::Func, index))
2062 }
2063 Import::FutureCancelWrite { info, async_ } => {
2064 let ty = self.payload_type_index(info)?;
2065 let index = self.component.future_cancel_write(ty, *async_);
2066 Ok((ExportKind::Func, index))
2067 }
2068 Import::FutureDropReadable(info) => {
2069 let type_index = self.payload_type_index(info)?;
2070 let index = self.component.future_drop_readable(type_index);
2071 Ok((ExportKind::Func, index))
2072 }
2073 Import::FutureDropWritable(info) => {
2074 let type_index = self.payload_type_index(info)?;
2075 let index = self.component.future_drop_writable(type_index);
2076 Ok((ExportKind::Func, index))
2077 }
2078 Import::ErrorContextNew { encoding } => {
2079 if self.memory_index.is_some() {
2080 let options = (RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING)
2081 .into_iter(*encoding, self.memory_index, None)?;
2082 let index = self.component.error_context_new(options);
2083 return Ok((ExportKind::Func, index));
2084 }
2085 Ok(self.materialize_shim_import(
2086 shims,
2087 &ShimKind::ErrorContextNew {
2088 encoding: *encoding,
2089 },
2090 ))
2091 }
2092 Import::ErrorContextDebugMessage { encoding } => Ok(self.materialize_shim_import(
2093 shims,
2094 &ShimKind::ErrorContextDebugMessage {
2095 for_module,
2096 encoding: *encoding,
2097 },
2098 )),
2099 Import::ErrorContextDrop => {
2100 let index = self.component.error_context_drop();
2101 Ok((ExportKind::Func, index))
2102 }
2103 Import::WorldFunc(key, name, abi) => {
2104 self.materialize_wit_import(shims, for_module, None, name, key, *abi)
2105 }
2106 Import::InterfaceFunc(key, _, name, abi) => self.materialize_wit_import(
2107 shims,
2108 for_module,
2109 Some(resolve.name_world_key(key)),
2110 name,
2111 key,
2112 *abi,
2113 ),
2114
2115 Import::WaitableSetNew => {
2116 let index = self.component.waitable_set_new();
2117 Ok((ExportKind::Func, index))
2118 }
2119 Import::WaitableSetDrop => {
2120 let index = self.component.waitable_set_drop();
2121 Ok((ExportKind::Func, index))
2122 }
2123 Import::WaitableJoin => {
2124 let index = self.component.waitable_join();
2125 Ok((ExportKind::Func, index))
2126 }
2127 Import::ContextGet { ty, slot } => {
2128 let index = self.component.context_get((*ty).try_into()?, *slot);
2129 Ok((ExportKind::Func, index))
2130 }
2131 Import::ContextSet { ty, slot } => {
2132 let index = self.component.context_set((*ty).try_into()?, *slot);
2133 Ok((ExportKind::Func, index))
2134 }
2135 Import::TlsBaseGet { ty } => Ok((
2136 ExportKind::Func,
2137 self.materialize_tls_base_import(false, (*ty).try_into()?),
2138 )),
2139 Import::TlsBaseSet { ty } => Ok((
2140 ExportKind::Func,
2141 self.materialize_tls_base_import(true, (*ty).try_into()?),
2142 )),
2143 Import::ExportedTaskCancel => {
2144 let index = self.component.task_cancel();
2145 Ok((ExportKind::Func, index))
2146 }
2147 Import::ThreadIndex => {
2148 let index = self.component.thread_index();
2149 Ok((ExportKind::Func, index))
2150 }
2151 Import::ThreadNewIndirect => Ok(self.materialize_shim_import(
2152 shims,
2153 &ShimKind::ThreadNewIndirect {
2154 func_ty: FuncType::new([ValType::I32], []),
2156 },
2157 )),
2158 Import::ThreadResumeLater => {
2159 let index = self.component.thread_resume_later();
2160 Ok((ExportKind::Func, index))
2161 }
2162 Import::ThreadSuspend { cancellable } => {
2163 let index = self.component.thread_suspend(*cancellable);
2164 Ok((ExportKind::Func, index))
2165 }
2166 Import::ThreadYield { cancellable } => {
2167 let index = self.component.thread_yield(*cancellable);
2168 Ok((ExportKind::Func, index))
2169 }
2170 Import::ThreadSuspendThenResume { cancellable } => {
2171 let index = self.component.thread_suspend_then_resume(*cancellable);
2172 Ok((ExportKind::Func, index))
2173 }
2174 Import::ThreadYieldThenResume { cancellable } => {
2175 let index = self.component.thread_yield_then_resume(*cancellable);
2176 Ok((ExportKind::Func, index))
2177 }
2178 Import::ThreadSuspendThenPromote { cancellable } => {
2179 let index = self.component.thread_suspend_then_promote(*cancellable);
2180 Ok((ExportKind::Func, index))
2181 }
2182 Import::ThreadYieldThenPromote { cancellable } => {
2183 let index = self.component.thread_yield_then_promote(*cancellable);
2184 Ok((ExportKind::Func, index))
2185 }
2186 }
2187 }
2188
2189 fn materialize_tls_base_import(&mut self, set: bool, ty: ValType) -> u32 {
2193 if self.info.can_use_context_slot_1() {
2194 if set {
2195 self.component.context_set(ty, 1)
2196 } else {
2197 self.component.context_get(ty, 1)
2198 }
2199 } else {
2200 let name = if set { TLS_BASE_SET } else { TLS_BASE_GET };
2201 self.core_alias_export(
2202 Some(name),
2203 self.shim_instance_index.unwrap(),
2204 name,
2205 ExportKind::Func,
2206 )
2207 }
2208 }
2209
2210 fn materialize_shim_import(&mut self, shims: &Shims<'_>, kind: &ShimKind) -> (ExportKind, u32) {
2213 let index = self.core_alias_export(
2214 Some(&shims.shims[kind].debug_name),
2215 self.shim_instance_index
2216 .expect("shim should be instantiated"),
2217 &shims.shims[kind].name,
2218 ExportKind::Func,
2219 );
2220 (ExportKind::Func, index)
2221 }
2222
2223 fn materialize_payload_import(
2226 &mut self,
2227 shims: &Shims<'_>,
2228 for_module: CustomModule<'_>,
2229 info: &PayloadInfo,
2230 kind: PayloadFuncKind,
2231 async_: bool,
2232 ) -> Result<(ExportKind, u32)> {
2233 let shim_kind = ShimKind::PayloadFunc {
2234 for_module,
2235 info,
2236 kind,
2237 };
2238 if shims.shims.get(&shim_kind).is_some() {
2239 return Ok(self.materialize_shim_import(shims, &shim_kind));
2240 }
2241 let resolve = &self.info.encoder.metadata.resolve;
2242 let options = RequiredOptions::for_payload(resolve, info, &kind, async_);
2243 let func = self.encode_payload_func(
2244 shims,
2245 &for_module,
2246 info,
2247 &kind,
2248 options,
2249 ReallocSite::BeforeInstantiation,
2250 )?;
2251 Ok((ExportKind::Func, func))
2252 }
2253
2254 fn materialize_wit_import(
2257 &mut self,
2258 shims: &Shims<'_>,
2259 for_module: CustomModule<'_>,
2260 interface_key: Option<String>,
2261 name: &String,
2262 key: &WorldKey,
2263 abi: AbiVariant,
2264 ) -> Result<(ExportKind, u32)> {
2265 let resolve = &self.info.encoder.metadata.resolve;
2266 let import = &self.info.import_map[&interface_key];
2267 let (index, _, lowering) = import.lowerings.get_full(&(name.clone(), abi)).unwrap();
2268 let metadata = self.info.module_metadata_for(for_module);
2269
2270 let index = match lowering {
2271 Lowering::Direct { options } => {
2274 let func_index = match &import.interface {
2275 Some(interface) => {
2276 let instance_index = self.instances[interface];
2277 self.component
2278 .alias_export(instance_index, name, ComponentExportKind::Func)
2279 }
2280 None => self.imported_funcs[name],
2281 };
2282 let encoding = metadata
2283 .import_encodings
2284 .get(resolve, key, name)
2285 .ok_or_else(|| anyhow!("missing component metadata for import of `{name}`"))?;
2286 let realloc = self
2287 .info
2288 .exports_for(for_module)
2289 .import_realloc_for(import.interface, name);
2290 let realloc = self.realloc_index(
2291 shims,
2292 for_module,
2293 ReallocSite::BeforeInstantiation,
2294 *options,
2295 realloc,
2296 );
2297 let options = options
2298 .into_iter(encoding, self.memory_index, realloc)?
2299 .collect::<Vec<_>>();
2300 self.component.lower_func(Some(name), func_index, options)
2301 }
2302
2303 Lowering::Indirect { .. } => {
2307 let encoding = metadata.import_encodings.get(resolve, key, name).unwrap();
2308 return Ok(self.materialize_shim_import(
2309 shims,
2310 &ShimKind::IndirectLowering {
2311 interface: interface_key,
2312 index,
2313 realloc: for_module,
2314 encoding,
2315 },
2316 ));
2317 }
2318
2319 Lowering::ResourceDrop(id) => {
2322 let resource_idx = self.lookup_resource_index(*id);
2323 self.component.resource_drop(resource_idx)
2324 }
2325 };
2326 Ok((ExportKind::Func, index))
2327 }
2328
2329 fn realloc_index(
2332 &mut self,
2333 shims: &Shims<'_>,
2334 module: CustomModule<'_>,
2335 site: ReallocSite,
2336 options: RequiredOptions,
2337 export: Option<&str>,
2338 ) -> Option<u32> {
2339 if !options.contains(RequiredOptions::REALLOC) {
2340 return None;
2341 }
2342 let (module, export) = resolve_realloc(self.info, module, export)?;
2343
2344 if !realloc_needs_shim(self.info, site) {
2345 let instance = self.instance_for(module);
2346 return Some(self.core_alias_export(Some(export), instance, export, ExportKind::Func));
2347 }
2348
2349 let kind = ShimKind::Realloc { module, export };
2350 let shim = shims.shims.get(&kind).unwrap_or_else(|| {
2351 panic!(
2352 "no shim was registered for the `realloc` \
2353 function `{export}` in `{}`",
2354 module.debug_name()
2355 )
2356 });
2357 let instance = self
2358 .shim_instance_index
2359 .expect("shim should be instantiated");
2360 Some(self.core_alias_export(
2361 Some(&shim.debug_name),
2362 instance,
2363 &shim.name,
2364 ExportKind::Func,
2365 ))
2366 }
2367
2368 fn hooked_core_alias_export(&mut self, module: CustomModule<'_>, core_name: &str) -> u32 {
2369 let key = (module.to_imported_instance(), core_name.to_string());
2370 if let Some(&wrapper_idx) = self.export_task_initialization_wrappers.get(&key) {
2371 wrapper_idx
2372 } else {
2373 let instance = self.instance_for(module);
2374 self.core_alias_export(Some(core_name), instance, core_name, ExportKind::Func)
2375 }
2376 }
2377
2378 fn instance_for(&self, module: CustomModule) -> u32 {
2381 match module {
2382 CustomModule::Main => self.instance_index.expect("instantiated by now"),
2383 CustomModule::Adapter(name) => self.adapter_instances[name],
2384 }
2385 }
2386
2387 fn module_for(&self, module: CustomModule) -> u32 {
2390 match module {
2391 CustomModule::Main => self.module_index.unwrap(),
2392 CustomModule::Adapter(name) => self.adapter_modules[name],
2393 }
2394 }
2395
2396 fn core_alias_export(
2399 &mut self,
2400 debug_name: Option<&str>,
2401 instance: u32,
2402 name: &str,
2403 kind: ExportKind,
2404 ) -> u32 {
2405 *self
2406 .aliased_core_items
2407 .entry((instance, name.to_string()))
2408 .or_insert_with(|| {
2409 self.component
2410 .core_alias_export(debug_name, instance, name, kind)
2411 })
2412 }
2413}
2414
2415#[derive(Default)]
2433struct Shims<'a> {
2434 shims: IndexMap<ShimKind<'a>, Shim<'a>>,
2436}
2437
2438struct Shim<'a> {
2439 options: RequiredOptions,
2442
2443 name: String,
2447
2448 debug_name: String,
2451
2452 kind: ShimKind<'a>,
2454
2455 sig: WasmSignature,
2457}
2458
2459#[derive(Debug, Clone, Hash, Eq, PartialEq, Copy)]
2462enum PayloadFuncKind {
2463 FutureWrite,
2464 FutureRead,
2465 StreamWrite,
2466 StreamRead,
2467}
2468
2469#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2470enum ShimKind<'a> {
2471 IndirectLowering {
2475 interface: Option<String>,
2477 index: usize,
2479 realloc: CustomModule<'a>,
2481 encoding: StringEncoding,
2483 },
2484 Adapter {
2487 adapter: &'a str,
2489 func: &'a str,
2491 },
2492 ResourceDtor {
2495 module: CustomModule<'a>,
2497 export: &'a str,
2499 },
2500 PayloadFunc {
2504 for_module: CustomModule<'a>,
2507 info: &'a PayloadInfo,
2512 kind: PayloadFuncKind,
2514 },
2515 WaitableSetWait { cancellable: bool },
2519 WaitableSetPoll { cancellable: bool },
2523 TaskReturn {
2525 interface: Option<InterfaceId>,
2528 func: &'a str,
2531 result: Option<Type>,
2533 for_module: CustomModule<'a>,
2535 encoding: StringEncoding,
2537 },
2538 ErrorContextNew {
2542 encoding: StringEncoding,
2544 },
2545 ErrorContextDebugMessage {
2549 for_module: CustomModule<'a>,
2551 encoding: StringEncoding,
2553 },
2554 ThreadNewIndirect {
2557 func_ty: FuncType,
2559 },
2560 Realloc {
2562 module: CustomModule<'a>,
2564 export: &'a str,
2566 },
2567}
2568
2569#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2570enum ReallocSite {
2571 BeforeInstantiation,
2573 AfterInstantiation,
2576}
2577
2578fn realloc_needs_shim(world: &ComponentWorld<'_>, site: ReallocSite) -> bool {
2579 match site {
2580 ReallocSite::BeforeInstantiation => true,
2583
2584 ReallocSite::AfterInstantiation => world.info.exports.wasm_task_hook().is_some(),
2588 }
2589}
2590
2591#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
2601enum CustomModule<'a> {
2602 Main,
2605 Adapter(&'a str),
2608}
2609
2610impl<'a> CustomModule<'a> {
2611 fn debug_name(&self) -> &'a str {
2612 match self {
2613 CustomModule::Main => "main",
2614 CustomModule::Adapter(s) => s,
2615 }
2616 }
2617
2618 fn to_imported_instance(&self) -> fixup::ImportedInstance {
2621 match self {
2622 CustomModule::Main => fixup::ImportedInstance::Main,
2623 CustomModule::Adapter(s) => fixup::ImportedInstance::Adapter(s.to_string()),
2624 }
2625 }
2626}
2627
2628impl<'a> Shims<'a> {
2629 fn append_indirect(
2634 &mut self,
2635 world: &'a ComponentWorld<'a>,
2636 for_module: CustomModule<'a>,
2637 ) -> Result<()> {
2638 let module_imports = world.imports_for(for_module);
2639 let module_exports = world.exports_for(for_module);
2640 let resolve = &world.encoder.metadata.resolve;
2641 let memory_available = world.info.imports.imported_memory().is_some();
2642
2643 for (module, field, import) in module_imports.imports() {
2644 match import {
2645 Import::ImportedResourceDrop(..)
2648 | Import::MainModuleMemory(_)
2649 | Import::MainModuleExport { .. }
2650 | Import::Item(_)
2651 | Import::ExportedResourceDrop(..)
2652 | Import::ExportedResourceRep(..)
2653 | Import::ExportedResourceNew(..)
2654 | Import::ExportedTaskCancel
2655 | Import::ErrorContextDrop
2656 | Import::BackpressureInc
2657 | Import::BackpressureDec
2658 | Import::SubtaskDrop
2659 | Import::SubtaskCancel { .. }
2660 | Import::FutureNew(..)
2661 | Import::StreamNew(..)
2662 | Import::FutureCancelRead { .. }
2663 | Import::FutureCancelWrite { .. }
2664 | Import::FutureDropWritable { .. }
2665 | Import::FutureDropReadable { .. }
2666 | Import::StreamCancelRead { .. }
2667 | Import::StreamCancelWrite { .. }
2668 | Import::StreamDropWritable { .. }
2669 | Import::StreamDropReadable { .. }
2670 | Import::WaitableSetNew
2671 | Import::WaitableSetDrop
2672 | Import::WaitableJoin
2673 | Import::ContextGet { .. }
2674 | Import::ContextSet { .. }
2675 | Import::TlsBaseGet { .. }
2676 | Import::TlsBaseSet { .. }
2677 | Import::ThreadIndex
2678 | Import::ThreadResumeLater
2679 | Import::ThreadSuspend { .. }
2680 | Import::ThreadYield { .. }
2681 | Import::ThreadSuspendThenResume { .. }
2682 | Import::ThreadYieldThenResume { .. }
2683 | Import::ThreadSuspendThenPromote { .. }
2684 | Import::ThreadYieldThenPromote { .. } => {}
2685
2686 Import::ExportedTaskReturn(key, interface, func) => {
2690 let (options, sig) = task_return_options_and_type(resolve, func);
2691 if options.is_empty() || memory_available {
2692 continue;
2693 }
2694 let name = self.shims.len().to_string();
2695 let encoding = world
2696 .module_metadata_for(for_module)
2697 .export_encodings
2698 .get(resolve, key, &func.name)
2699 .ok_or_else(|| {
2700 anyhow::anyhow!(
2701 "missing component metadata for export of \
2702 `{module}::{field}`"
2703 )
2704 })?;
2705 self.push(Shim {
2706 name,
2707 debug_name: format!("task-return-{}", func.name),
2708 options,
2709 kind: ShimKind::TaskReturn {
2710 interface: *interface,
2711 func: &func.name,
2712 result: func.result,
2713 for_module,
2714 encoding,
2715 },
2716 sig,
2717 });
2718 }
2719
2720 Import::FutureWrite { async_, info } => {
2721 self.append_indirect_payload_push(
2722 world,
2723 for_module,
2724 module,
2725 *async_,
2726 info,
2727 PayloadFuncKind::FutureWrite,
2728 vec![WasmType::I32; 2],
2729 vec![WasmType::I32],
2730 );
2731 }
2732 Import::FutureRead { async_, info } => {
2733 self.append_indirect_payload_push(
2734 world,
2735 for_module,
2736 module,
2737 *async_,
2738 info,
2739 PayloadFuncKind::FutureRead,
2740 vec![WasmType::I32; 2],
2741 vec![WasmType::I32],
2742 );
2743 }
2744 Import::StreamWrite { async_, info } => {
2745 self.append_indirect_payload_push(
2746 world,
2747 for_module,
2748 module,
2749 *async_,
2750 info,
2751 PayloadFuncKind::StreamWrite,
2752 vec![WasmType::I32; 3],
2753 vec![WasmType::I32],
2754 );
2755 }
2756 Import::StreamRead { async_, info } => {
2757 self.append_indirect_payload_push(
2758 world,
2759 for_module,
2760 module,
2761 *async_,
2762 info,
2763 PayloadFuncKind::StreamRead,
2764 vec![WasmType::I32; 3],
2765 vec![WasmType::I32],
2766 );
2767 }
2768
2769 Import::WaitableSetWait { cancellable } => {
2770 if memory_available {
2771 continue;
2772 }
2773 let name = self.shims.len().to_string();
2774 self.push(Shim {
2775 name,
2776 debug_name: "waitable-set.wait".to_string(),
2777 options: RequiredOptions::empty(),
2778 kind: ShimKind::WaitableSetWait {
2779 cancellable: *cancellable,
2780 },
2781 sig: WasmSignature {
2782 params: vec![WasmType::I32; 2],
2783 results: vec![WasmType::I32],
2784 indirect_params: false,
2785 retptr: false,
2786 },
2787 });
2788 }
2789
2790 Import::WaitableSetPoll { cancellable } => {
2791 if memory_available {
2792 continue;
2793 }
2794 let name = self.shims.len().to_string();
2795 self.push(Shim {
2796 name,
2797 debug_name: "waitable-set.poll".to_string(),
2798 options: RequiredOptions::empty(),
2799 kind: ShimKind::WaitableSetPoll {
2800 cancellable: *cancellable,
2801 },
2802 sig: WasmSignature {
2803 params: vec![WasmType::I32; 2],
2804 results: vec![WasmType::I32],
2805 indirect_params: false,
2806 retptr: false,
2807 },
2808 });
2809 }
2810
2811 Import::ErrorContextNew { encoding } => {
2812 if memory_available {
2813 continue;
2814 }
2815 let name = self.shims.len().to_string();
2816 self.push(Shim {
2817 name,
2818 debug_name: "error-new".to_string(),
2819 options: RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING,
2820 kind: ShimKind::ErrorContextNew {
2821 encoding: *encoding,
2822 },
2823 sig: WasmSignature {
2824 params: vec![WasmType::I32; 2],
2825 results: vec![WasmType::I32],
2826 indirect_params: false,
2827 retptr: false,
2828 },
2829 });
2830 }
2831
2832 Import::ErrorContextDebugMessage { encoding } => {
2833 let name = self.shims.len().to_string();
2834 let options = RequiredOptions::MEMORY
2835 | RequiredOptions::STRING_ENCODING
2836 | RequiredOptions::REALLOC;
2837 self.push(Shim {
2838 name,
2839 debug_name: "error-debug-message".to_string(),
2840 options,
2841 kind: ShimKind::ErrorContextDebugMessage {
2842 for_module,
2843 encoding: *encoding,
2844 },
2845 sig: WasmSignature {
2846 params: vec![WasmType::I32; 2],
2847 results: vec![],
2848 indirect_params: false,
2849 retptr: false,
2850 },
2851 });
2852 let realloc = module_exports.import_realloc_fallback();
2853 self.push_realloc(
2854 world,
2855 for_module,
2856 ReallocSite::AfterInstantiation,
2857 options,
2858 realloc,
2859 );
2860 }
2861
2862 Import::ThreadNewIndirect => {
2863 let name = self.shims.len().to_string();
2864 self.push(Shim {
2865 name,
2866 debug_name: "thread.new-indirect".to_string(),
2867 options: RequiredOptions::empty(),
2868 kind: ShimKind::ThreadNewIndirect {
2869 func_ty: FuncType::new([ValType::I32], vec![]),
2871 },
2872 sig: WasmSignature {
2873 params: vec![WasmType::I32; 2],
2874 results: vec![WasmType::I32],
2875 indirect_params: false,
2876 retptr: false,
2877 },
2878 });
2879 }
2880
2881 Import::AdapterExport { adapter, func, ty } => {
2884 let name = self.shims.len().to_string();
2885 log::debug!("shim {name} is adapter `{module}::{field}`");
2886 self.push(Shim {
2887 name,
2888 debug_name: format!("adapt-{module}-{field}"),
2889 options: RequiredOptions::MEMORY,
2893 kind: ShimKind::Adapter { adapter, func },
2894 sig: WasmSignature {
2895 params: ty.params().iter().map(to_wasm_type).collect(),
2896 results: ty.results().iter().map(to_wasm_type).collect(),
2897 indirect_params: false,
2898 retptr: false,
2899 },
2900 });
2901
2902 fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType {
2903 match ty {
2904 wasmparser::ValType::I32 => WasmType::I32,
2905 wasmparser::ValType::I64 => WasmType::I64,
2906 wasmparser::ValType::F32 => WasmType::F32,
2907 wasmparser::ValType::F64 => WasmType::F64,
2908 _ => unreachable!(),
2909 }
2910 }
2911 }
2912
2913 Import::InterfaceFunc(key, _, name, abi) => {
2917 self.append_indirect_wit_func(
2918 world,
2919 for_module,
2920 module,
2921 field,
2922 key,
2923 name,
2924 Some(resolve.name_world_key(key)),
2925 *abi,
2926 )?;
2927 }
2928 Import::WorldFunc(key, name, abi) => {
2929 self.append_indirect_wit_func(
2930 world, for_module, module, field, key, name, None, *abi,
2931 )?;
2932 }
2933 }
2934 }
2935
2936 for (export_name, export) in module_exports.iter() {
2942 let id = match export {
2943 Export::ResourceDtor(id) => id,
2944 _ => continue,
2945 };
2946 let resource = resolve.types[*id].name.as_ref().unwrap();
2947 let name = self.shims.len().to_string();
2948 self.push(Shim {
2949 name,
2950 debug_name: format!("dtor-{resource}"),
2951 options: RequiredOptions::empty(),
2952 kind: ShimKind::ResourceDtor {
2953 module: for_module,
2954 export: export_name,
2955 },
2956 sig: WasmSignature {
2957 params: vec![WasmType::I32],
2958 results: Vec::new(),
2959 indirect_params: false,
2960 retptr: false,
2961 },
2962 });
2963 }
2964
2965 Ok(())
2966 }
2967
2968 fn append_indirect_payload_push(
2971 &mut self,
2972 world: &'a ComponentWorld<'a>,
2973 for_module: CustomModule<'a>,
2974 module: &str,
2975 async_: bool,
2976 info: &'a PayloadInfo,
2977 kind: PayloadFuncKind,
2978 params: Vec<WasmType>,
2979 results: Vec<WasmType>,
2980 ) {
2981 let resolve = &world.encoder.metadata.resolve;
2982 let debug_name = format!("{module}-{}", info.name);
2983 let name = self.shims.len().to_string();
2984
2985 let options = RequiredOptions::for_payload(resolve, info, &kind, async_);
2986 if !options.contains(RequiredOptions::REALLOC)
2987 && world.info.imports.imported_memory().is_some()
2988 {
2989 return;
2990 }
2991 self.push(Shim {
2992 name,
2993 debug_name,
2994 options,
2995 kind: ShimKind::PayloadFunc {
2996 for_module,
2997 info,
2998 kind,
2999 },
3000 sig: WasmSignature {
3001 params,
3002 results,
3003 indirect_params: false,
3004 retptr: false,
3005 },
3006 });
3007 let realloc = payload_realloc_name(world, for_module, info);
3008 self.push_realloc(
3009 world,
3010 for_module,
3011 ReallocSite::AfterInstantiation,
3012 options,
3013 realloc,
3014 );
3015 }
3016
3017 fn append_indirect_wit_func(
3020 &mut self,
3021 world: &'a ComponentWorld<'a>,
3022 for_module: CustomModule<'a>,
3023 module: &str,
3024 field: &str,
3025 key: &WorldKey,
3026 name: &String,
3027 interface_key: Option<String>,
3028 abi: AbiVariant,
3029 ) -> Result<()> {
3030 let resolve = &world.encoder.metadata.resolve;
3031 let metadata = world.module_metadata_for(for_module);
3032 let interface = &world.import_map[&interface_key];
3033 let (index, _, lowering) = interface.lowerings.get_full(&(name.clone(), abi)).unwrap();
3034 let shim_name = self.shims.len().to_string();
3035 match lowering {
3036 Lowering::ResourceDrop(_) => {}
3037
3038 Lowering::Direct { options } => {
3039 let realloc = world
3040 .exports_for(for_module)
3041 .import_realloc_for(interface.interface, name);
3042 self.push_realloc(
3043 world,
3044 for_module,
3045 ReallocSite::BeforeInstantiation,
3046 *options,
3047 realloc,
3048 );
3049 }
3050
3051 Lowering::Indirect { sig, options } => {
3052 log::debug!(
3053 "shim {shim_name} is import `{module}::{field}` lowering {index} `{name}`",
3054 );
3055 let encoding = metadata
3056 .import_encodings
3057 .get(resolve, key, name)
3058 .ok_or_else(|| {
3059 anyhow::anyhow!(
3060 "missing component metadata for import of \
3061 `{module}::{field}`"
3062 )
3063 })?;
3064 self.push(Shim {
3065 name: shim_name,
3066 debug_name: format!("indirect-{module}-{field}"),
3067 options: *options,
3068 kind: ShimKind::IndirectLowering {
3069 interface: interface_key,
3070 index,
3071 realloc: for_module,
3072 encoding,
3073 },
3074 sig: sig.clone(),
3075 });
3076
3077 let realloc = world
3078 .exports_for(for_module)
3079 .import_realloc_for(interface.interface, name);
3080 self.push_realloc(
3081 world,
3082 for_module,
3083 ReallocSite::AfterInstantiation,
3084 *options,
3085 realloc,
3086 );
3087 }
3088 }
3089
3090 Ok(())
3091 }
3092
3093 fn push_realloc(
3097 &mut self,
3098 world: &'a ComponentWorld<'a>,
3099 for_module: CustomModule<'a>,
3100 site: ReallocSite,
3101 options: RequiredOptions,
3102 export: Option<&'a str>,
3103 ) {
3104 if !options.contains(RequiredOptions::REALLOC) {
3105 return;
3106 }
3107 let Some((for_module, export)) = resolve_realloc(world, for_module, export) else {
3108 return;
3109 };
3110 if !realloc_needs_shim(world, site) {
3111 return;
3112 }
3113 let name = self.shims.len().to_string();
3114 self.push(Shim {
3115 name,
3116 debug_name: format!("realloc-{}-{export}", for_module.debug_name()),
3117 options: RequiredOptions::empty(),
3118 kind: ShimKind::Realloc {
3119 module: for_module,
3120 export,
3121 },
3122 sig: WasmSignature {
3123 params: vec![WasmType::I32; 4],
3124 results: vec![WasmType::I32],
3125 indirect_params: false,
3126 retptr: false,
3127 },
3128 });
3129 }
3130
3131 fn push(&mut self, shim: Shim<'a>) {
3132 if !self.shims.contains_key(&shim.kind) {
3136 self.shims.insert(shim.kind.clone(), shim);
3137 }
3138 }
3139}
3140
3141fn resolve_realloc<'a>(
3148 world: &'a ComponentWorld<'a>,
3149 module: CustomModule<'a>,
3150 export: Option<&'a str>,
3151) -> Option<(CustomModule<'a>, &'a str)> {
3152 if let Some(export) = export {
3153 return Some((module, export));
3154 }
3155 match module {
3156 CustomModule::Main => None,
3159
3160 CustomModule::Adapter(name) => {
3162 let _info = world.adapters[name].library_info.as_ref()?;
3163 let main_realloc = world.info.exports.general_purpose_realloc()?;
3164 Some((CustomModule::Main, main_realloc))
3165 }
3166 }
3167}
3168
3169fn payload_realloc_name<'a>(
3170 world: &'a ComponentWorld<'_>,
3171 for_module: CustomModule<'_>,
3172 info: &PayloadInfo,
3173) -> Option<&'a str> {
3174 let exports = world.exports_for(for_module);
3175 match &info.ty {
3176 PayloadType::Type { function, .. } => {
3177 if info.imported {
3178 exports.import_realloc_for(info.interface, function)
3179 } else {
3180 exports.export_realloc_for(&info.key, function)
3181 }
3182 }
3183 PayloadType::UnitFuture | PayloadType::UnitStream => None,
3184 }
3185}
3186
3187fn task_return_options_and_type(
3188 resolve: &Resolve,
3189 func: &Function,
3190) -> (RequiredOptions, WasmSignature) {
3191 let func_tmp = Function {
3192 name: String::new(),
3193 kind: FunctionKind::Freestanding,
3194 params: match &func.result {
3195 Some(ty) => vec![Param {
3196 name: "a".to_string(),
3197 ty: *ty,
3198 span: Default::default(),
3199 }],
3200 None => Vec::new(),
3201 },
3202 result: None,
3203 docs: Default::default(),
3204 stability: Stability::Unknown,
3205 span: Default::default(),
3206 external_id: None,
3207 };
3208 let abi = AbiVariant::GuestImport;
3209 let mut options = RequiredOptions::for_import(resolve, func, abi);
3210 options.remove(RequiredOptions::REALLOC);
3212 let sig = resolve.wasm_signature(abi, &func_tmp);
3213 (options, sig)
3214}
3215
3216#[derive(Clone, Debug)]
3218pub struct Item {
3219 pub alias: String,
3220 pub kind: ExportKind,
3221 pub which: MainOrAdapter,
3222 pub name: String,
3223}
3224
3225#[derive(Debug, PartialEq, Clone)]
3227pub enum MainOrAdapter {
3228 Main,
3229 Adapter(String),
3230}
3231
3232impl MainOrAdapter {
3233 fn to_custom_module(&self) -> CustomModule<'_> {
3234 match self {
3235 MainOrAdapter::Main => CustomModule::Main,
3236 MainOrAdapter::Adapter(s) => CustomModule::Adapter(s),
3237 }
3238 }
3239}
3240
3241#[derive(Clone)]
3243pub enum Instance {
3244 MainOrAdapter(MainOrAdapter),
3246
3247 Items(Vec<Item>),
3249}
3250
3251#[derive(Clone)]
3254pub struct LibraryInfo {
3255 pub arguments: Vec<(String, Instance)>,
3257}
3258
3259pub(super) struct Adapter {
3261 wasm: Vec<u8>,
3263
3264 metadata: ModuleMetadata,
3266
3267 required_exports: IndexSet<WorldKey>,
3270
3271 library_info: Option<LibraryInfo>,
3276}
3277
3278#[derive(Default)]
3280pub struct ComponentEncoder {
3281 module: Vec<u8>,
3282 module_import_map: Option<ModuleImportMap>,
3283 pub(super) metadata: Bindgen,
3284 validate: bool,
3285 pub(super) main_module_exports: IndexSet<WorldKey>,
3286 pub(super) adapters: IndexMap<String, Adapter>,
3287 import_name_map: HashMap<String, String>,
3288 realloc_via_memory_grow: bool,
3289 merge_imports_based_on_semver: Option<bool>,
3290 pub(super) reject_legacy_names: bool,
3291 debug_names: bool,
3292 shim_return_call_ref: bool,
3293}
3294
3295impl ComponentEncoder {
3296 pub fn module(&mut self, module: &[u8]) -> Result<&mut Self> {
3302 let (wasm, metadata) = self.decode(module.as_ref())?;
3303 let (wasm, module_import_map) = ModuleImportMap::new(wasm)?;
3304 self.module = if let Some(producers) = &metadata.producers {
3305 producers.add_to_wasm(&wasm)?
3306 } else {
3307 wasm.to_vec()
3308 };
3309 let exports = self
3310 .merge_metadata(metadata)
3311 .context("failed merge WIT metadata for module with previous metadata")?;
3312 self.main_module_exports.extend(exports);
3313 self.module_import_map = module_import_map;
3314 Ok(self)
3315 }
3316
3317 fn decode<'a>(&self, wasm: &'a [u8]) -> Result<(Cow<'a, [u8]>, Bindgen)> {
3318 let (bytes, metadata) = metadata::decode(wasm)?;
3319 match bytes {
3320 Some(wasm) => Ok((Cow::Owned(wasm), metadata)),
3321 None => Ok((Cow::Borrowed(wasm), metadata)),
3322 }
3323 }
3324
3325 fn merge_metadata(&mut self, metadata: Bindgen) -> Result<IndexSet<WorldKey>> {
3326 self.metadata.merge(metadata)
3327 }
3328
3329 pub fn validate(&mut self, validate: bool) -> &mut Self {
3331 self.validate = validate;
3332 self
3333 }
3334
3335 pub fn debug_names(&mut self, debug_names: bool) -> &mut Self {
3337 self.debug_names = debug_names;
3338 self
3339 }
3340
3341 pub fn shim_return_call_ref(&mut self, enable: bool) -> &mut Self {
3344 self.shim_return_call_ref = enable;
3345 self
3346 }
3347
3348 pub fn merge_imports_based_on_semver(&mut self, merge: bool) -> &mut Self {
3356 self.merge_imports_based_on_semver = Some(merge);
3357 self
3358 }
3359
3360 pub fn reject_legacy_names(&mut self, reject: bool) -> &mut Self {
3369 self.reject_legacy_names = reject;
3370 self
3371 }
3372
3373 pub fn adapter(&mut self, name: &str, bytes: &[u8]) -> Result<&mut Self> {
3391 self.library_or_adapter(name, bytes, None)
3392 }
3393
3394 pub fn library(
3407 &mut self,
3408 name: &str,
3409 bytes: &[u8],
3410 library_info: LibraryInfo,
3411 ) -> Result<&mut Self> {
3412 self.library_or_adapter(name, bytes, Some(library_info))
3413 }
3414
3415 fn library_or_adapter(
3416 &mut self,
3417 name: &str,
3418 bytes: &[u8],
3419 library_info: Option<LibraryInfo>,
3420 ) -> Result<&mut Self> {
3421 let (wasm, mut metadata) = self.decode(bytes)?;
3422 let adapter_metadata = mem::take(&mut metadata.metadata);
3430 let exports = self.merge_metadata(metadata).with_context(|| {
3431 format!("failed to merge WIT packages of adapter `{name}` into main packages")
3432 })?;
3433 if let Some(library_info) = &library_info {
3434 for (_, instance) in &library_info.arguments {
3436 let resolve = |which: &_| match which {
3437 MainOrAdapter::Main => Ok(()),
3438 MainOrAdapter::Adapter(name) => {
3439 if self.adapters.contains_key(name.as_str()) {
3440 Ok(())
3441 } else {
3442 Err(anyhow!("instance refers to unknown adapter `{name}`"))
3443 }
3444 }
3445 };
3446
3447 match instance {
3448 Instance::MainOrAdapter(which) => resolve(which)?,
3449 Instance::Items(items) => {
3450 for item in items {
3451 resolve(&item.which)?;
3452 }
3453 }
3454 }
3455 }
3456 }
3457 self.adapters.insert(
3458 name.to_string(),
3459 Adapter {
3460 wasm: wasm.to_vec(),
3461 metadata: adapter_metadata,
3462 required_exports: exports,
3463 library_info,
3464 },
3465 );
3466 Ok(self)
3467 }
3468
3469 pub fn realloc_via_memory_grow(&mut self, value: bool) -> &mut Self {
3474 self.realloc_via_memory_grow = value;
3475 self
3476 }
3477
3478 pub fn import_name_map(&mut self, map: HashMap<String, String>) -> &mut Self {
3489 self.import_name_map = map;
3490 self
3491 }
3492
3493 pub fn encode(&mut self) -> Result<Vec<u8>> {
3495 self.encode_with_fixups(None)
3496 }
3497
3498 pub(crate) fn encode_with_fixups(
3499 &mut self,
3500 fixup_hook: Option<&mut dyn FnMut(&mut fixup::FixupModule) -> Result<()>>,
3501 ) -> Result<Vec<u8>> {
3502 if self.module.is_empty() {
3503 bail!("a module is required when encoding a component");
3504 }
3505
3506 if self.merge_imports_based_on_semver.unwrap_or(true) {
3507 self.metadata
3508 .resolve
3509 .merge_world_imports_based_on_semver(self.metadata.world)?;
3510 }
3511
3512 self.finalize_resolve_with_nominal_ids();
3513
3514 let world = ComponentWorld::new(self).context("failed to decode world from module")?;
3515 let mut state = EncodingState {
3516 component: ComponentBuilder::default(),
3517 module_index: None,
3518 instance_index: None,
3519 memory_index: None,
3520 shim_instance_index: None,
3521 adapter_modules: IndexMap::new(),
3522 adapter_instances: IndexMap::new(),
3523 type_encoding_maps: Default::default(),
3524 instances: Default::default(),
3525 imported_funcs: Default::default(),
3526 aliased_core_items: Default::default(),
3527 info: &world,
3528 export_task_initialization_wrappers: HashMap::new(),
3529 };
3530 state.encode_imports(&self.import_name_map)?;
3531 state.encode_core_modules();
3532 state.encode_core_instantiation(fixup_hook)?;
3533 state.encode_exports(CustomModule::Main)?;
3534 for name in self.adapters.keys() {
3535 state.encode_exports(CustomModule::Adapter(name))?;
3536 }
3537 state.component.append_names();
3538 state
3539 .component
3540 .raw_custom_section(&crate::base_producers().raw_custom_section());
3541 let bytes = state.component.finish();
3542
3543 if self.validate {
3544 Validator::new_with_features(WasmFeatures::all())
3545 .validate_all(&bytes)
3546 .context("failed to validate component output")?;
3547 }
3548
3549 Ok(bytes)
3550 }
3551
3552 fn finalize_resolve_with_nominal_ids(&mut self) {
3561 let world = &self.metadata.resolve.worlds[self.metadata.world];
3568 let main_module_exports = self
3569 .main_module_exports
3570 .iter()
3571 .map(|i| world.exports.get_index_of(i).unwrap())
3572 .collect::<Vec<_>>();
3573 let adapter_exports = self
3574 .adapters
3575 .values()
3576 .map(|adapter| {
3577 adapter
3578 .required_exports
3579 .iter()
3580 .map(|i| world.exports.get_index_of(i).unwrap())
3581 .collect::<Vec<_>>()
3582 })
3583 .collect::<Vec<_>>();
3584
3585 self.metadata
3589 .resolve
3590 .generate_nominal_type_ids(self.metadata.world);
3591
3592 self.main_module_exports.clear();
3595 let world = &self.metadata.resolve.worlds[self.metadata.world];
3596 for index in main_module_exports {
3597 let (key, _) = world.exports.get_index(index).unwrap();
3598 self.main_module_exports.insert(key.clone());
3599 }
3600 for (exports, adapter) in adapter_exports.into_iter().zip(self.adapters.values_mut()) {
3601 adapter.required_exports.clear();
3602 for index in exports {
3603 let (key, _) = world.exports.get_index(index).unwrap();
3604 adapter.required_exports.insert(key.clone());
3605 }
3606 }
3607 }
3608}
3609
3610impl ComponentWorld<'_> {
3611 fn imports_for(&self, module: CustomModule) -> &ImportMap {
3613 match module {
3614 CustomModule::Main => &self.info.imports,
3615 CustomModule::Adapter(name) => &self.adapters[name].info.imports,
3616 }
3617 }
3618
3619 fn exports_for(&self, module: CustomModule) -> &ExportMap {
3621 match module {
3622 CustomModule::Main => &self.info.exports,
3623 CustomModule::Adapter(name) => &self.adapters[name].info.exports,
3624 }
3625 }
3626
3627 fn module_metadata_for(&self, module: CustomModule) -> &ModuleMetadata {
3629 match module {
3630 CustomModule::Main => &self.encoder.metadata.metadata,
3631 CustomModule::Adapter(name) => &self.encoder.adapters[name].metadata,
3632 }
3633 }
3634}
3635
3636#[cfg(all(test, feature = "dummy-module"))]
3637mod test {
3638 use super::*;
3639 use crate::{dummy_module, embed_component_metadata};
3640 use wit_parser::ManglingAndAbi;
3641
3642 #[test]
3643 fn it_renames_imports() {
3644 let mut resolve = Resolve::new();
3645 let pkg = resolve
3646 .push_str(
3647 "test.wit",
3648 r#"
3649package test:wit;
3650
3651interface i {
3652 f: func();
3653}
3654
3655world test {
3656 import i;
3657 import foo: interface {
3658 f: func();
3659 }
3660}
3661"#,
3662 )
3663 .unwrap();
3664 let world = resolve.select_world(&[pkg], None).unwrap();
3665
3666 let mut module = dummy_module(&resolve, world, ManglingAndAbi::Standard32);
3667
3668 embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8).unwrap();
3669
3670 let encoded = ComponentEncoder::default()
3671 .import_name_map(HashMap::from([
3672 (
3673 "foo".to_string(),
3674 "unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>".to_string(),
3675 ),
3676 (
3677 "test:wit/i".to_string(),
3678 "locked-dep=<foo:bar/i@1.2.3>".to_string(),
3679 ),
3680 ]))
3681 .module(&module)
3682 .unwrap()
3683 .validate(true)
3684 .encode()
3685 .unwrap();
3686
3687 let wat = wasmprinter::print_bytes(encoded).unwrap();
3688 assert!(wat.contains("unlocked-dep=<foo:bar/foo@{>=1.0.0 <1.1.0}>"));
3689 assert!(wat.contains("locked-dep=<foo:bar/i@1.2.3>"));
3690 }
3691}