1use crate::StringEncoding;
75use crate::encoding::wit::{component_extern_name, interface_extern_name};
76use crate::metadata::{self, Bindgen, ModuleMetadata};
77use crate::validation::{
78 Export, ExportMap, Import, ImportInstance, ImportMap, PayloadInfo, PayloadType,
79};
80use anyhow::{Context, Result, anyhow, bail};
81use indexmap::{IndexMap, IndexSet};
82use std::borrow::Cow;
83use std::collections::HashMap;
84use std::hash::Hash;
85use std::mem;
86use wasm_encoder::reencode::{Reencode, RoundtripReencoder};
87use wasm_encoder::*;
88use wasmparser::{Validator, WasmFeatures};
89use wit_parser::{
90 Function, FunctionKind, InterfaceId, LiveTypes, Param, Resolve, Stability, Type, TypeDefKind,
91 TypeId, TypeOwner, WorldId, WorldItem, WorldKey,
92 abi::{AbiVariant, WasmSignature, WasmType},
93};
94
95const INDIRECT_TABLE_NAME: &str = "$imports";
96const SHIM_MEMORY_NAME: &str = "$memory";
97const TLS_BASE_GET: &str = "$get-tls-base";
98const TLS_BASE_SET: &str = "$set-tls-base";
99
100pub(crate) mod fixup;
101
102mod wit;
103pub use wit::{encode, encode_world};
104
105mod types;
106use types::{InstanceTypeEncoder, RootTypeEncoder, TypeEncodingMaps, ValtypeEncoder};
107mod world;
108use world::{ComponentWorld, ImportedInterface, Lowering};
109
110mod dedupe;
111pub(crate) use dedupe::ModuleImportMap;
112use wasm_metadata::AddMetadataField;
113
114fn to_val_type(ty: &WasmType) -> ValType {
115 match ty {
116 WasmType::I32 => ValType::I32,
117 WasmType::I64 => ValType::I64,
118 WasmType::F32 => ValType::F32,
119 WasmType::F64 => ValType::F64,
120 WasmType::Pointer => ValType::I32,
121 WasmType::PointerOrI64 => ValType::I64,
122 WasmType::Length => ValType::I32,
123 }
124}
125
126fn import_func_name(f: &Function) -> String {
127 match f.kind {
128 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {
129 format!("import-func-{}", f.item_name())
130 }
131
132 FunctionKind::Getter
140 | FunctionKind::Setter
141 | FunctionKind::Method(_)
142 | FunctionKind::MethodGetter(_)
143 | FunctionKind::MethodSetter(_)
144 | FunctionKind::AsyncMethod(_)
145 | FunctionKind::Static(_)
146 | FunctionKind::StaticGetter(_)
147 | FunctionKind::StaticSetter(_)
148 | FunctionKind::AsyncStatic(_)
149 | FunctionKind::Constructor(_) => {
150 format!(
151 "import-{}",
152 f.name.replace('[', "").replace([']', '.'], "-")
153 )
154 }
155 }
156}
157
158bitflags::bitflags! {
159 #[derive(Copy, Clone, Debug)]
162 pub struct RequiredOptions: u8 {
163 const MEMORY = 1 << 0;
166 const REALLOC = 1 << 1;
169 const STRING_ENCODING = 1 << 2;
172 const ASYNC = 1 << 3;
173 }
174}
175
176impl RequiredOptions {
177 fn for_import(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
178 let sig = resolve.wasm_signature(abi, func);
179 let mut ret = RequiredOptions::empty();
180 ret.add_lift(TypeContents::for_types(
182 resolve,
183 func.params.iter().map(|p| &p.ty),
184 ));
185 ret.add_lower(TypeContents::for_types(resolve, &func.result));
186
187 if sig.retptr || sig.indirect_params {
190 ret |= RequiredOptions::MEMORY;
191 }
192 if abi == AbiVariant::GuestImportAsync {
193 ret |= RequiredOptions::ASYNC;
194 }
195 ret
196 }
197
198 fn for_export(resolve: &Resolve, func: &Function, abi: AbiVariant) -> RequiredOptions {
199 let sig = resolve.wasm_signature(abi, func);
200 let mut ret = RequiredOptions::empty();
201 ret.add_lower(TypeContents::for_types(
203 resolve,
204 func.params.iter().map(|p| &p.ty),
205 ));
206 ret.add_lift(TypeContents::for_types(resolve, &func.result));
207
208 if sig.retptr || sig.indirect_params {
212 ret |= RequiredOptions::MEMORY;
213 if sig.indirect_params {
214 ret |= RequiredOptions::REALLOC;
215 }
216 }
217 if let AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful = abi {
218 ret |= RequiredOptions::ASYNC;
219 ret |= task_return_options_and_type(resolve, func).0;
220 }
221 ret
222 }
223
224 fn for_payload(
225 resolve: &Resolve,
226 info: &PayloadInfo,
227 kind: &PayloadFuncKind,
228 async_: bool,
229 ) -> RequiredOptions {
230 let payload = info.payload(resolve);
231 let (wit_param, wit_result) = match kind {
232 PayloadFuncKind::StreamRead | PayloadFuncKind::FutureRead => (None, payload),
233 PayloadFuncKind::StreamWrite | PayloadFuncKind::FutureWrite => (payload, None),
234 };
235 RequiredOptions::MEMORY
236 | RequiredOptions::for_import(
237 resolve,
238 &Function {
239 name: String::new(),
240 kind: FunctionKind::Freestanding,
241 params: match wit_param {
242 Some(ty) => vec![Param {
243 name: "a".to_string(),
244 ty,
245 span: Default::default(),
246 }],
247 None => Vec::new(),
248 },
249 result: wit_result,
250 docs: Default::default(),
251 stability: Stability::Unknown,
252 span: Default::default(),
253 external_id: None,
254 },
255 if async_ {
256 AbiVariant::GuestImportAsync
257 } else {
258 AbiVariant::GuestImport
259 },
260 )
261 }
262
263 fn add_lower(&mut self, types: TypeContents) {
264 if types.contains(TypeContents::NEEDS_MEMORY) {
268 *self |= RequiredOptions::MEMORY | RequiredOptions::REALLOC;
269 }
270 if types.contains(TypeContents::STRING) {
271 *self |= RequiredOptions::MEMORY
272 | RequiredOptions::STRING_ENCODING
273 | RequiredOptions::REALLOC;
274 }
275 }
276
277 fn add_lift(&mut self, types: TypeContents) {
278 if types.contains(TypeContents::NEEDS_MEMORY) {
282 *self |= RequiredOptions::MEMORY;
283 }
284 if types.contains(TypeContents::STRING) {
285 *self |= RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING;
286 }
287 }
288
289 fn into_iter(
290 self,
291 encoding: StringEncoding,
292 memory_index: Option<u32>,
293 realloc_index: Option<u32>,
294 ) -> Result<impl ExactSizeIterator<Item = CanonicalOption>> {
295 #[derive(Default)]
296 struct Iter {
297 options: [Option<CanonicalOption>; 5],
298 current: usize,
299 count: usize,
300 }
301
302 impl Iter {
303 fn push(&mut self, option: CanonicalOption) {
304 assert!(self.count < self.options.len());
305 self.options[self.count] = Some(option);
306 self.count += 1;
307 }
308 }
309
310 impl Iterator for Iter {
311 type Item = CanonicalOption;
312
313 fn next(&mut self) -> Option<Self::Item> {
314 if self.current == self.count {
315 return None;
316 }
317 let option = self.options[self.current];
318 self.current += 1;
319 option
320 }
321
322 fn size_hint(&self) -> (usize, Option<usize>) {
323 (self.count - self.current, Some(self.count - self.current))
324 }
325 }
326
327 impl ExactSizeIterator for Iter {}
328
329 let mut iter = Iter::default();
330
331 if self.contains(RequiredOptions::MEMORY) {
332 iter.push(CanonicalOption::Memory(memory_index.ok_or_else(|| {
333 anyhow!("module does not export a memory named `memory`")
334 })?));
335 }
336
337 if self.contains(RequiredOptions::REALLOC) {
338 iter.push(CanonicalOption::Realloc(realloc_index.ok_or_else(
339 || anyhow!("module does not export a function named `cabi_realloc`"),
340 )?));
341 }
342
343 if self.contains(RequiredOptions::STRING_ENCODING) {
344 iter.push(encoding.into());
345 }
346
347 if self.contains(RequiredOptions::ASYNC) {
348 iter.push(CanonicalOption::Async);
349 }
350
351 Ok(iter)
352 }
353}
354
355bitflags::bitflags! {
356 struct TypeContents: u8 {
359 const STRING = 1 << 0;
360 const NEEDS_MEMORY = 1 << 1;
361 }
362}
363
364impl TypeContents {
365 fn for_types<'a>(resolve: &Resolve, types: impl IntoIterator<Item = &'a Type>) -> Self {
366 let mut cur = TypeContents::empty();
367 for ty in types {
368 cur |= Self::for_type(resolve, ty);
369 }
370 cur
371 }
372
373 fn for_optional_types<'a>(
374 resolve: &Resolve,
375 types: impl Iterator<Item = Option<&'a Type>>,
376 ) -> Self {
377 Self::for_types(resolve, types.flatten())
378 }
379
380 fn for_optional_type(resolve: &Resolve, ty: Option<&Type>) -> Self {
381 match ty {
382 Some(ty) => Self::for_type(resolve, ty),
383 None => Self::empty(),
384 }
385 }
386
387 fn for_type(resolve: &Resolve, ty: &Type) -> Self {
388 match ty {
389 Type::Id(id) => match &resolve.types[*id].kind {
390 TypeDefKind::Handle(h) => match h {
391 wit_parser::Handle::Own(_) => Self::empty(),
392 wit_parser::Handle::Borrow(_) => Self::empty(),
393 },
394 TypeDefKind::Resource => Self::empty(),
395 TypeDefKind::Record(r) => Self::for_types(resolve, r.fields.iter().map(|f| &f.ty)),
396 TypeDefKind::Tuple(t) => Self::for_types(resolve, t.types.iter()),
397 TypeDefKind::Flags(_) => Self::empty(),
398 TypeDefKind::Option(t) => Self::for_type(resolve, t),
399 TypeDefKind::Result(r) => {
400 Self::for_optional_type(resolve, r.ok.as_ref())
401 | Self::for_optional_type(resolve, r.err.as_ref())
402 }
403 TypeDefKind::Variant(v) => {
404 Self::for_optional_types(resolve, v.cases.iter().map(|c| c.ty.as_ref()))
405 }
406 TypeDefKind::Enum(_) => Self::empty(),
407 TypeDefKind::List(t) => Self::for_type(resolve, t) | Self::NEEDS_MEMORY,
408 TypeDefKind::Map(k, v) => {
409 Self::for_type(resolve, k) | Self::for_type(resolve, v) | Self::NEEDS_MEMORY
410 }
411 TypeDefKind::FixedLengthList(t, _elements) => Self::for_type(resolve, t),
412 TypeDefKind::Type(t) => Self::for_type(resolve, t),
413 TypeDefKind::Future(_) => Self::empty(),
414 TypeDefKind::Stream(_) => Self::empty(),
415 TypeDefKind::Unknown => unreachable!(),
416 },
417 Type::String => Self::STRING,
418 _ => Self::empty(),
419 }
420 }
421}
422
423pub struct EncodingState<'a> {
425 component: ComponentBuilder,
427 module_index: Option<u32>,
431 instance_index: Option<u32>,
435 memory_index: Option<u32>,
439 shim_instance_index: Option<u32>,
443
444 adapter_modules: IndexMap<&'a str, u32>,
447 adapter_instances: IndexMap<&'a str, u32>,
449
450 instances: IndexMap<InterfaceId, u32>,
452 imported_funcs: IndexMap<String, u32>,
453
454 type_encoding_maps: TypeEncodingMaps<'a>,
459
460 aliased_core_items: HashMap<(u32, String), u32>,
466
467 info: &'a ComponentWorld<'a>,
469
470 export_task_initialization_wrappers: HashMap<(fixup::ImportedInstance, String), u32>,
477}
478
479impl<'a> EncodingState<'a> {
480 fn encode_core_modules(&mut self) {
481 assert!(self.module_index.is_none());
482 let idx = self
483 .component
484 .core_module_raw(Some("main"), &self.info.encoder.module);
485 self.module_index = Some(idx);
486
487 for (name, adapter) in self.info.adapters.iter() {
488 let debug_name = if adapter.library_info.is_some() {
489 name.to_string()
490 } else {
491 format!("wit-component:adapter:{name}")
492 };
493 let idx = if self.info.encoder.debug_names {
494 let mut add_meta = wasm_metadata::AddMetadata::default();
495 add_meta.name = AddMetadataField::Set(debug_name.clone());
496 let wasm = add_meta
497 .to_wasm(&adapter.wasm)
498 .expect("core wasm can get name added");
499 self.component.core_module_raw(Some(&debug_name), &wasm)
500 } else {
501 self.component
502 .core_module_raw(Some(&debug_name), &adapter.wasm)
503 };
504 let prev = self.adapter_modules.insert(name, idx);
505 assert!(prev.is_none());
506 }
507 }
508
509 fn root_import_type_encoder(
510 &mut self,
511 interface: Option<InterfaceId>,
512 ) -> RootTypeEncoder<'_, 'a> {
513 RootTypeEncoder {
514 state: self,
515 interface,
516 import_types: true,
517 }
518 }
519
520 fn root_export_type_encoder(
521 &mut self,
522 interface: Option<InterfaceId>,
523 ) -> RootTypeEncoder<'_, 'a> {
524 RootTypeEncoder {
525 state: self,
526 interface,
527 import_types: false,
528 }
529 }
530
531 fn instance_type_encoder(&mut self, interface: InterfaceId) -> InstanceTypeEncoder<'_, 'a> {
532 InstanceTypeEncoder {
533 state: self,
534 interface,
535 type_encoding_maps: Default::default(),
536 ty: Default::default(),
537 }
538 }
539
540 fn encode_imports(&mut self, name_map: &HashMap<String, String>) -> Result<()> {
541 let mut has_funcs = false;
542 for (name, info) in self.info.import_map.iter() {
543 match name {
544 Some(name) => {
545 self.encode_interface_import(name_map.get(name).unwrap_or(name), info)?
546 }
547 None => has_funcs = true,
548 }
549 }
550
551 let resolve = &self.info.encoder.metadata.resolve;
552 let world = &resolve.worlds[self.info.encoder.metadata.world];
553
554 for (_name, item) in world.imports.iter() {
557 if let WorldItem::Type { id, .. } = item {
558 self.root_import_type_encoder(None)
559 .encode_valtype(resolve, &Type::Id(*id))?;
560 }
561 }
562
563 if has_funcs {
564 let info = &self.info.import_map[&None];
565 self.encode_root_import_funcs(info)?;
566 }
567 Ok(())
568 }
569
570 fn encode_interface_import(&mut self, name: &str, info: &ImportedInterface) -> Result<()> {
571 let resolve = &self.info.encoder.metadata.resolve;
572 let interface_id = info.interface.as_ref().unwrap();
573 let interface_id = *interface_id;
574 let interface = &resolve.interfaces[interface_id];
575 log::trace!("encoding imports for `{name}` as {interface_id:?}");
576 let mut encoder = self.instance_type_encoder(interface_id);
577
578 if let Some(live) = encoder.state.info.live_type_imports.get(&interface_id) {
580 for ty in live {
581 log::trace!(
582 "encoding extra type {ty:?} name={:?}",
583 resolve.types[*ty].name
584 );
585 encoder.encode_valtype(resolve, &Type::Id(*ty))?;
586 }
587 }
588
589 for (_, func) in interface.functions.iter() {
592 if !(info
593 .lowerings
594 .contains_key(&(func.name.clone(), AbiVariant::GuestImport))
595 || info
596 .lowerings
597 .contains_key(&(func.name.clone(), AbiVariant::GuestImportAsync)))
598 {
599 continue;
600 }
601 log::trace!("encoding function type for `{}`", func.name);
602 let idx = encoder.encode_func_type(resolve, func)?;
603
604 encoder.ty.export(
605 crate::encoding::types::extern_name(&func.name, func.external_id.as_deref()),
606 ComponentTypeRef::Func(idx),
607 );
608 }
609
610 let ty = encoder.ty;
611 if ty.is_empty() {
614 return Ok(());
615 }
616 let instance_type_idx = self
617 .component
618 .type_instance(Some(&format!("ty-{name}")), &ty);
619
620 let is_interface_name = info.implements.is_none() && interface.name.is_some();
623 let extern_name = interface_extern_name(
624 resolve,
625 name,
626 is_interface_name.then_some(interface_id),
627 info.implements,
628 info.external_id.clone(),
629 self.info.encoder.emit_canonical_names,
630 );
631 let instance_idx = self
632 .component
633 .import(extern_name, ComponentTypeRef::Instance(instance_type_idx));
634 let prev = self.instances.insert(interface_id, instance_idx);
635 assert!(prev.is_none());
636 Ok(())
637 }
638
639 fn encode_root_import_funcs(&mut self, info: &ImportedInterface) -> Result<()> {
640 let resolve = &self.info.encoder.metadata.resolve;
641 let world = self.info.encoder.metadata.world;
642 for (name, item) in resolve.worlds[world].imports.iter() {
643 let func = match item {
644 WorldItem::Function(f) => f,
645 WorldItem::Interface { .. } | WorldItem::Type { .. } => continue,
646 };
647 let name = resolve.name_world_key(name);
648 if !(info
649 .lowerings
650 .contains_key(&(name.clone(), AbiVariant::GuestImport))
651 || info
652 .lowerings
653 .contains_key(&(name.clone(), AbiVariant::GuestImportAsync)))
654 {
655 continue;
656 }
657 log::trace!("encoding function type for `{}`", func.name);
658 let idx = self
659 .root_import_type_encoder(None)
660 .encode_func_type(resolve, func)?;
661 let func_idx = self.component.import(
662 crate::encoding::types::extern_name(name.as_str(), func.external_id.as_deref()),
663 ComponentTypeRef::Func(idx),
664 );
665 let prev = self.imported_funcs.insert(name, func_idx);
666 assert!(prev.is_none());
667 }
668 Ok(())
669 }
670
671 fn alias_instance_type_export(&mut self, interface: InterfaceId, id: TypeId) -> u32 {
672 let ty = &self.info.encoder.metadata.resolve.types[id];
673 let name = ty.name.as_ref().expect("type must have a name");
674 let instance = self.instances[&interface];
675 self.component
676 .alias_export(instance, name, ComponentExportKind::Type)
677 }
678
679 fn encode_core_instantiation(
680 &mut self,
681 fixup_hook: Option<&mut dyn FnMut(&mut fixup::FixupModule) -> Result<()>>,
682 ) -> Result<()> {
683 let (shims, mut fixups) = self.encode_shim_instantiation()?;
685
686 self.declare_types_for_imported_intrinsics(&shims)?;
690
691 self.instantiate_main_module(&shims)?;
695
696 for (name, _adapter) in self.info.adapters.iter() {
697 self.instantiate_adapter_module(&shims, name)?;
698 }
699
700 if let Some(initialize) = self.info.info.exports.initialize() {
701 fixups.add_initialize(initialize)?;
702 }
703
704 if let Some(hook) = fixup_hook {
705 hook(&mut fixups)?;
706 }
707
708 fixups.instantiate(&shims, self)?;
711
712 Ok(())
713 }
714
715 fn lookup_resource_index(&mut self, id: TypeId) -> u32 {
716 let resolve = &self.info.encoder.metadata.resolve;
717 let ty = &resolve.types[id];
718 match ty.owner {
719 TypeOwner::World(_) => self.type_encoding_maps.id_to_index[&id],
723 TypeOwner::Interface(i) => {
724 let instance = self.instances[&i];
725 let name = ty.name.as_ref().expect("resources must be named");
726 self.component
727 .alias_export(instance, name, ComponentExportKind::Type)
728 }
729 TypeOwner::None => panic!("resources must have an owner"),
730 }
731 }
732
733 fn encode_exports(&mut self, module: CustomModule) -> Result<()> {
734 let resolve = &self.info.encoder.metadata.resolve;
735 let exports = match module {
736 CustomModule::Main => &self.info.encoder.main_module_exports,
737 CustomModule::Adapter(name) => &self.info.encoder.adapters[name].required_exports,
738 };
739
740 if exports.is_empty() {
741 return Ok(());
742 }
743
744 let mut interface_func_core_names = IndexMap::new();
745 let mut world_func_core_names = IndexMap::new();
746 for (core_name, export) in self.info.exports_for(module).iter() {
747 match export {
748 Export::WorldFunc(_, name, _) => {
749 let prev = world_func_core_names.insert(name, core_name);
750 assert!(prev.is_none());
751 }
752 Export::InterfaceFunc(key, _, name, _) => {
753 let prev = interface_func_core_names
754 .entry(key)
755 .or_insert(IndexMap::new())
756 .insert(name.as_str(), core_name);
757 assert!(prev.is_none());
758 }
759 Export::WorldFuncCallback(..)
760 | Export::InterfaceFuncCallback(..)
761 | Export::WorldFuncPostReturn(..)
762 | Export::InterfaceFuncPostReturn(..)
763 | Export::ResourceDtor(..)
764 | Export::Memory(_)
765 | Export::GeneralPurposeRealloc
766 | Export::GeneralPurposeExportRealloc
767 | Export::GeneralPurposeImportRealloc
768 | Export::Initialize
769 | Export::ReallocForAdapter
770 | Export::IndirectFunctionTable
771 | Export::WasmTaskHook => continue,
772 }
773 }
774
775 let world = &resolve.worlds[self.info.encoder.metadata.world];
776
777 for export_name in exports {
778 let export_string = if self.info.encoder.emit_canonical_names {
779 resolve.name_canonicalized_world_key(export_name)
780 } else {
781 resolve.name_world_key(export_name)
782 };
783 match &world.exports[export_name] {
784 WorldItem::Function(func) => {
785 let ty = self
786 .root_import_type_encoder(None)
787 .encode_func_type(resolve, func)?;
788 let core_name = world_func_core_names[&func.name];
789 let idx = self.encode_lift(module, &core_name, export_name, func, ty)?;
790 self.component.export(
791 crate::encoding::types::extern_name(
792 &export_string,
793 func.external_id.as_deref(),
794 ),
795 ComponentExportKind::Func,
796 idx,
797 None,
798 );
799 }
800 item @ WorldItem::Interface { id, .. } => {
801 let core_names = interface_func_core_names.get(export_name);
802 self.encode_interface_export(
803 &export_string,
804 module,
805 export_name,
806 item,
807 *id,
808 core_names,
809 )?;
810 }
811 WorldItem::Type { .. } => unreachable!(),
812 }
813 }
814
815 Ok(())
816 }
817
818 fn encode_interface_export(
819 &mut self,
820 export_name: &str,
821 module: CustomModule<'_>,
822 key: &WorldKey,
823 item: &WorldItem,
824 export: InterfaceId,
825 interface_func_core_names: Option<&IndexMap<&str, &str>>,
826 ) -> Result<()> {
827 log::trace!("encode interface export `{export_name}`");
828 let resolve = &self.info.encoder.metadata.resolve;
829
830 let mut imports = Vec::new();
837 let mut root = self.root_export_type_encoder(Some(export));
838 for (_, func) in &resolve.interfaces[export].functions {
839 let core_name = interface_func_core_names.unwrap()[func.name.as_str()];
840 let ty = root.encode_func_type(resolve, func)?;
841 let func_index = root.state.encode_lift(module, &core_name, key, func, ty)?;
842 imports.push((
843 import_func_name(func),
844 ComponentExportKind::Func,
845 func_index,
846 ));
847 }
848
849 let mut nested = NestedComponentTypeEncoder {
853 component: ComponentBuilder::default(),
854 type_encoding_maps: Default::default(),
855 export_types: false,
856 interface: export,
857 state: self,
858 imports: IndexMap::new(),
859 };
860
861 let mut types_to_import = LiveTypes::default();
871 types_to_import.add_interface(resolve, export);
872 let exports_used = &nested.state.info.exports_used[&export];
873 for ty in types_to_import.iter() {
874 if let TypeOwner::Interface(owner) = resolve.types[ty].owner {
875 if owner == export {
876 continue;
879 }
880
881 let mut encoder = if exports_used.contains(&owner) {
884 nested.state.root_export_type_encoder(Some(export))
885 } else {
886 nested.state.root_import_type_encoder(Some(export))
887 };
888 encoder.encode_valtype(resolve, &Type::Id(ty))?;
889
890 nested.interface = owner;
894 nested.encode_valtype(resolve, &Type::Id(ty))?;
895 }
896 }
897 nested.interface = export;
898
899 let imported_type_maps = nested.type_encoding_maps.clone();
903
904 let mut resources = HashMap::new();
910 for (_name, ty) in resolve.interfaces[export].types.iter() {
911 if !matches!(resolve.types[*ty].kind, TypeDefKind::Resource) {
912 continue;
913 }
914 let idx = match nested.encode_valtype(resolve, &Type::Id(*ty))? {
915 ComponentValType::Type(idx) => idx,
916 _ => unreachable!(),
917 };
918 resources.insert(*ty, idx);
919 }
920
921 for (_, func) in resolve.interfaces[export].functions.iter() {
925 let ty = nested.encode_func_type(resolve, func)?;
926 nested
927 .component
928 .import(&import_func_name(func), ComponentTypeRef::Func(ty));
929 }
930
931 let reverse_map = nested
938 .type_encoding_maps
939 .id_to_index
940 .drain()
941 .map(|p| (p.1, p.0))
942 .collect::<HashMap<_, _>>();
943 nested.type_encoding_maps.def_to_index.clear();
944 for (name, idx) in nested.imports.drain(..) {
945 let id = reverse_map[&idx];
946 let idx = nested.state.type_encoding_maps.id_to_index[&id];
947 imports.push((name, ComponentExportKind::Type, idx))
948 }
949
950 nested.type_encoding_maps = imported_type_maps;
955
956 nested.export_types = true;
963 nested.type_encoding_maps.func_type_map.clear();
964
965 for (_, id) in resolve.interfaces[export].types.iter() {
971 let ty = &resolve.types[*id];
972 match ty.kind {
973 TypeDefKind::Resource => {
974 let idx = nested.component.export(
975 crate::encoding::types::extern_name(
976 ty.name.as_ref().expect("resources must be named"),
977 ty.external_id.as_deref(),
978 ),
979 ComponentExportKind::Type,
980 resources[id],
981 None,
982 );
983 nested.type_encoding_maps.id_to_index.insert(*id, idx);
984 }
985 _ => {
986 nested.encode_valtype(resolve, &Type::Id(*id))?;
987 }
988 }
989 }
990
991 for (i, (_, func)) in resolve.interfaces[export].functions.iter().enumerate() {
992 let ty = nested.encode_func_type(resolve, func)?;
993 nested.component.export(
994 crate::encoding::types::extern_name(&func.name, func.external_id.as_deref()),
995 ComponentExportKind::Func,
996 i as u32,
997 Some(ComponentTypeRef::Func(ty)),
998 );
999 }
1000
1001 let component = nested.component;
1005 let component_index = self
1006 .component
1007 .component(Some(&format!("{export_name}-shim-component")), component);
1008 let instance_index = self.component.instantiate(
1009 Some(&format!("{export_name}-shim-instance")),
1010 component_index,
1011 imports,
1012 );
1013 let extern_name =
1014 component_extern_name(resolve, key, item, self.info.encoder.emit_canonical_names);
1015 let idx = self.component.export(
1016 extern_name,
1017 ComponentExportKind::Instance,
1018 instance_index,
1019 None,
1020 );
1021 let prev = self.instances.insert(export, idx);
1022 assert!(prev.is_none());
1023
1024 for (_name, id) in resolve.interfaces[export].types.iter() {
1032 self.type_encoding_maps.id_to_index.remove(id);
1033 self.type_encoding_maps
1034 .def_to_index
1035 .remove(&resolve.types[*id].kind);
1036 }
1037
1038 return Ok(());
1039
1040 struct NestedComponentTypeEncoder<'state, 'a> {
1041 component: ComponentBuilder,
1042 type_encoding_maps: TypeEncodingMaps<'a>,
1043 export_types: bool,
1044 interface: InterfaceId,
1045 state: &'state mut EncodingState<'a>,
1046 imports: IndexMap<String, u32>,
1047 }
1048
1049 impl<'a> ValtypeEncoder<'a> for NestedComponentTypeEncoder<'_, 'a> {
1050 fn defined_type(&mut self) -> (u32, ComponentDefinedTypeEncoder<'_>) {
1051 self.component.type_defined(None)
1052 }
1053 fn define_function_type(&mut self) -> (u32, ComponentFuncTypeEncoder<'_>) {
1054 self.component.type_function(None)
1055 }
1056 fn export_type(
1057 &mut self,
1058 idx: u32,
1059 name: wasm_encoder::ComponentExternName<'a>,
1060 ) -> Option<u32> {
1061 if self.export_types {
1062 Some(
1063 self.component
1064 .export(name, ComponentExportKind::Type, idx, None),
1065 )
1066 } else {
1067 let name = self.unique_import_name(&name.name);
1068 let ret = self
1069 .component
1070 .import(&name, ComponentTypeRef::Type(TypeBounds::Eq(idx)));
1071 self.imports.insert(name, ret);
1072 Some(ret)
1073 }
1074 }
1075 fn export_resource(&mut self, name: wasm_encoder::ComponentExternName<'a>) -> u32 {
1076 if self.export_types {
1077 panic!("resources should already be exported")
1078 } else {
1079 let name = self.unique_import_name(&name.name);
1080 let ret = self
1081 .component
1082 .import(&name, ComponentTypeRef::Type(TypeBounds::SubResource));
1083 self.imports.insert(name, ret);
1084 ret
1085 }
1086 }
1087 fn import_type(&mut self, _: InterfaceId, _id: TypeId) -> u32 {
1088 unreachable!()
1089 }
1090 fn type_encoding_maps(&mut self) -> &mut TypeEncodingMaps<'a> {
1091 &mut self.type_encoding_maps
1092 }
1093 fn interface(&self) -> Option<InterfaceId> {
1094 Some(self.interface)
1095 }
1096 }
1097
1098 impl NestedComponentTypeEncoder<'_, '_> {
1099 fn unique_import_name(&mut self, name: &str) -> String {
1100 let mut name = format!("import-type-{name}");
1101 let mut n = 0;
1102 while self.imports.contains_key(&name) {
1103 name = format!("{name}{n}");
1104 n += 1;
1105 }
1106 name
1107 }
1108 }
1109 }
1110
1111 fn encode_lift(
1112 &mut self,
1113 module: CustomModule<'_>,
1114 core_name: &str,
1115 key: &WorldKey,
1116 func: &Function,
1117 ty: u32,
1118 ) -> Result<u32> {
1119 let resolve = &self.info.encoder.metadata.resolve;
1120 let metadata = self.info.module_metadata_for(module);
1121
1122 let core_alias_export =
1123 |me: &mut Self, core_name: &str| me.hooked_core_alias_export(module, core_name);
1124
1125 let core_func_index = core_alias_export(self, core_name);
1126 let exports = self.info.exports_for(module);
1127
1128 let options = RequiredOptions::for_export(
1129 resolve,
1130 func,
1131 exports
1132 .abi(key, func)
1133 .ok_or_else(|| anyhow!("no ABI found for {}", func.name))?,
1134 );
1135
1136 let encoding = metadata
1137 .export_encodings
1138 .get(resolve, key, &func.name)
1139 .unwrap();
1140 let exports = self.info.exports_for(module);
1141 let realloc_index = if options.contains(RequiredOptions::REALLOC) {
1142 let realloc = exports.export_realloc_for(key, &func.name);
1143 resolve_realloc(self.info, module, realloc)
1144 .map(|(module, name)| self.hooked_core_alias_export(module, name))
1145 } else {
1146 None
1147 };
1148 let mut options = options
1149 .into_iter(encoding, self.memory_index, realloc_index)?
1150 .collect::<Vec<_>>();
1151
1152 if let Some(post_return) = exports.post_return(key, func) {
1153 let post_return = core_alias_export(self, post_return);
1154 options.push(CanonicalOption::PostReturn(post_return));
1155 }
1156 if let Some(callback) = exports.callback(key, func) {
1157 let callback = core_alias_export(self, callback);
1158 options.push(CanonicalOption::Callback(callback));
1159 }
1160 let func_index = self
1161 .component
1162 .lift_func(Some(&func.name), core_func_index, ty, options);
1163 Ok(func_index)
1164 }
1165
1166 fn encode_shim_instantiation(&mut self) -> Result<(Shims<'a>, fixup::FixupModule)> {
1167 let mut ret = Shims::default();
1168 let mut fixups = fixup::FixupModule::default();
1169
1170 ret.append_indirect(self.info, CustomModule::Main)
1171 .context("failed to register indirect shims for main module")?;
1172
1173 for (adapter_name, _adapter) in self.info.adapters.iter() {
1177 ret.append_indirect(self.info, CustomModule::Adapter(adapter_name))
1178 .with_context(|| {
1179 format!("failed to register indirect shims for adapter {adapter_name}")
1180 })?;
1181 }
1182
1183 let tls_base_global_type = if self.info.can_use_context_slot_1() {
1186 None
1187 } else {
1188 let infos = [&self.info.info]
1189 .into_iter()
1190 .chain(self.info.adapters.values().map(|a| &a.info));
1191 let mut ret = None;
1192 for info in infos {
1193 for (_, _, import) in info.imports.imports() {
1194 let ty = match import {
1195 Import::TlsBaseGet { ty } | Import::TlsBaseSet { ty } => *ty,
1196 _ => continue,
1197 };
1198 let prev = *ret.get_or_insert(ty);
1199 if prev != ty {
1200 bail!("conflicting TLS base pointer types `{prev}` and `{ty}`");
1201 }
1202 }
1203 }
1204 match ret {
1205 Some(ret) => Some(ret.try_into()?),
1206 None => None,
1207 }
1208 };
1209
1210 if ret.shims.is_empty()
1211 && self.info.info.imports.imported_memory().is_none()
1212 && tls_base_global_type.is_none()
1213 {
1214 return Ok((ret, fixups));
1215 }
1216
1217 assert!(self.shim_instance_index.is_none());
1218
1219 let mut types = TypeSection::new();
1226 let mut shim_globals = GlobalSection::new();
1227 let mut shim_tables = TableSection::new();
1228 let mut shim_memories = MemorySection::new();
1229 let mut shim_functions = FunctionSection::new();
1230 let mut shim_exports = ExportSection::new();
1231 let mut shim_code = CodeSection::new();
1232 let mut sigs = IndexMap::new();
1233 let mut trapping_stubs = IndexMap::new();
1234 let mut func_indexes = Vec::new();
1235 let mut func_names = NameMap::new();
1236
1237 let mut intern_type =
1238 |types: &mut TypeSection, params: Vec<ValType>, results: Vec<ValType>| {
1239 *sigs
1240 .entry((params, results))
1241 .or_insert_with_key(|(params, results)| {
1242 let index = types.len();
1243 types
1244 .ty()
1245 .function(params.iter().copied(), results.iter().copied());
1246 index
1247 })
1248 };
1249
1250 for shim in ret.shims.values() {
1251 let type_index = intern_type(
1252 &mut types,
1253 shim.sig.params.iter().map(to_val_type).collect(),
1254 shim.sig.results.iter().map(to_val_type).collect(),
1255 );
1256
1257 let trapping_stub = if self.info.encoder.shim_return_call_ref {
1258 Some(*trapping_stubs.entry(type_index).or_insert_with(|| {
1261 let mut stub = wasm_encoder::Function::new(std::iter::empty());
1262 stub.instructions().unreachable().end();
1263 let index = shim_code.len();
1264 shim_functions.function(type_index);
1265 shim_code.function(&stub);
1266 func_names.append(index, "trap stub before initialization");
1267 index
1268 }))
1269 } else {
1270 None
1271 };
1272
1273 let func_index = shim_functions.len();
1274 shim_functions.function(type_index);
1275 let mut func = wasm_encoder::Function::new(std::iter::empty());
1276 for i in 0..shim.sig.params.len() {
1277 func.instructions().local_get(i as u32);
1278 }
1279 fixups.add_shim(&self.info.encoder, shim)?;
1280 if self.info.encoder.shim_return_call_ref {
1281 let global = shim_globals.len();
1284 let ty = GlobalType {
1285 val_type: RefType {
1286 nullable: false,
1287 heap_type: HeapType::Concrete(type_index),
1288 }
1289 .into(),
1290 mutable: true,
1291 shared: false,
1292 };
1293 let global_name = format!("g{}", shim.name);
1294 shim_globals.global(ty, &ConstExpr::ref_func(trapping_stub.unwrap()));
1295 shim_exports.export(&global_name, ExportKind::Global, global);
1296
1297 func.instructions().global_get(global);
1298 func.instructions().return_call_ref(type_index);
1299 } else {
1300 func.instructions().i32_const(func_index as i32);
1301 func.instructions().call_indirect(0, type_index);
1302 }
1303 func.instructions().end();
1304 shim_code.function(&func);
1305 shim_exports.export(&shim.name, ExportKind::Func, func_index);
1306
1307 func_indexes.push(func_index);
1308 func_names.append(func_index, &shim.debug_name);
1309 }
1310
1311 if !ret.shims.is_empty() && !self.info.encoder.shim_return_call_ref {
1312 let table_type = TableType {
1313 element_type: RefType::FUNCREF,
1314 minimum: ret.shims.len() as u64,
1315 maximum: Some(ret.shims.len() as u64),
1316 table64: false,
1317 shared: false,
1318 };
1319
1320 shim_tables.table(table_type);
1321 shim_exports.export(INDIRECT_TABLE_NAME, ExportKind::Table, 0);
1322 }
1323
1324 if let Some(ty) = self.info.info.imports.imported_memory() {
1327 shim_memories.memory(RoundtripReencoder.memory_type(ty)?);
1328 shim_exports.export(SHIM_MEMORY_NAME, ExportKind::Memory, 0);
1329 }
1330
1331 if let Some(ty) = tls_base_global_type {
1335 let get_ty = intern_type(&mut types, Vec::new(), vec![ty]);
1336 let set_ty = intern_type(&mut types, vec![ty], Vec::new());
1337
1338 let global = shim_globals.len();
1339 shim_globals.global(
1340 GlobalType {
1341 val_type: ty,
1342 mutable: true,
1343 shared: false,
1344 },
1345 &match ty {
1346 ValType::I64 => ConstExpr::i64_const(0),
1347 ValType::I32 => ConstExpr::i32_const(0),
1348 _ => unreachable!(),
1349 },
1350 );
1351
1352 let get = shim_functions.len();
1353 shim_functions.function(get_ty);
1354 let mut func = wasm_encoder::Function::new(std::iter::empty());
1355 func.instructions().global_get(global).end();
1356 shim_code.function(&func);
1357 shim_exports.export(TLS_BASE_GET, ExportKind::Func, get);
1358 func_names.append(get, TLS_BASE_GET);
1359
1360 let set = shim_functions.len();
1361 shim_functions.function(set_ty);
1362 let mut func = wasm_encoder::Function::new(std::iter::empty());
1363 func.instructions().local_get(0).global_set(global).end();
1364 shim_code.function(&func);
1365 shim_exports.export(TLS_BASE_SET, ExportKind::Func, set);
1366 func_names.append(set, TLS_BASE_SET);
1367 }
1368
1369 let mut shim_names = NameSection::new();
1370 shim_names.module("wit-component:shim");
1371 shim_names.functions(&func_names);
1372
1373 let mut shim = Module::new();
1374 shim.section(&types);
1375 if !shim_functions.is_empty() {
1376 shim.section(&shim_functions);
1377 }
1378 if !shim_tables.is_empty() {
1379 shim.section(&shim_tables);
1380 }
1381 if !shim_memories.is_empty() {
1382 shim.section(&shim_memories);
1383 }
1384 if !shim_globals.is_empty() {
1385 shim.section(&shim_globals);
1386 }
1387 if !shim_exports.is_empty() {
1388 shim.section(&shim_exports);
1389 }
1390 if !shim_code.is_empty() {
1391 shim.section(&shim_code);
1392 }
1393 shim.section(&RawCustomSection(
1394 &crate::base_producers().raw_custom_section(),
1395 ));
1396 if self.info.encoder.debug_names {
1397 shim.section(&shim_names);
1398 }
1399
1400 let shim_module_index = self
1401 .component
1402 .core_module(Some("wit-component-shim-module"), &shim);
1403
1404 let shim_instance = self.component.core_instantiate(
1405 Some("wit-component-shim-instance"),
1406 shim_module_index,
1407 [],
1408 );
1409 self.shim_instance_index = Some(shim_instance);
1410
1411 if self.info.info.imports.imported_memory().is_some() {
1414 assert!(self.memory_index.is_none());
1415 self.memory_index = Some(self.core_alias_export(
1416 Some("memory"),
1417 shim_instance,
1418 SHIM_MEMORY_NAME,
1419 ExportKind::Memory,
1420 ));
1421 }
1422
1423 Ok((ret, fixups))
1424 }
1425
1426 fn encode_shim(&mut self, shims: &Shims<'_>, shim: &Shim<'_>) -> Result<u32> {
1427 let resolve = &self.info.encoder.metadata.resolve;
1428 Ok(match &shim.kind {
1429 ShimKind::IndirectLowering {
1436 interface,
1437 index,
1438 realloc,
1439 encoding,
1440 } => {
1441 let interface = &self.info.import_map[interface];
1442 let ((name, _), _) = interface.lowerings.get_index(*index).unwrap();
1443 let func_index = match &interface.interface {
1444 Some(interface_id) => {
1445 let instance_index = self.instances[interface_id];
1446 self.component
1447 .alias_export(instance_index, name, ComponentExportKind::Func)
1448 }
1449 None => self.imported_funcs[name],
1450 };
1451
1452 let realloc_export = self
1453 .info
1454 .exports_for(*realloc)
1455 .import_realloc_for(interface.interface, name);
1456 let realloc = self.realloc_index(
1457 shims,
1458 *realloc,
1459 ReallocSite::AfterInstantiation,
1460 shim.options,
1461 realloc_export,
1462 );
1463
1464 self.component.lower_func(
1465 Some(&shim.debug_name),
1466 func_index,
1467 shim.options
1468 .into_iter(*encoding, self.memory_index, realloc)?,
1469 )
1470 }
1471
1472 ShimKind::Adapter { adapter, func } => self.core_alias_export(
1477 Some(func),
1478 self.adapter_instances[adapter],
1479 func,
1480 ExportKind::Func,
1481 ),
1482
1483 ShimKind::ResourceDtor { module, export } => self.core_alias_export(
1488 Some(export),
1489 self.instance_for(*module),
1490 export,
1491 ExportKind::Func,
1492 ),
1493
1494 ShimKind::PayloadFunc {
1495 for_module,
1496 info,
1497 kind,
1498 } => self.encode_payload_func(
1499 shims,
1500 for_module,
1501 info,
1502 kind,
1503 shim.options,
1504 ReallocSite::AfterInstantiation,
1505 )?,
1506
1507 ShimKind::WaitableSetWait => {
1508 self.component.waitable_set_wait(self.memory_index.unwrap())
1509 }
1510 ShimKind::WaitableSetPoll => {
1511 self.component.waitable_set_poll(self.memory_index.unwrap())
1512 }
1513 ShimKind::ErrorContextNew { encoding } => self
1514 .component
1515 .error_context_new(shim.options.into_iter(*encoding, self.memory_index, None)?),
1516 ShimKind::ErrorContextDebugMessage {
1517 for_module,
1518 encoding,
1519 } => {
1520 let realloc = self.info.exports_for(*for_module).import_realloc_fallback();
1521 let realloc_index = self.realloc_index(
1522 shims,
1523 *for_module,
1524 ReallocSite::AfterInstantiation,
1525 shim.options,
1526 realloc,
1527 );
1528
1529 self.component
1530 .error_context_debug_message(shim.options.into_iter(
1531 *encoding,
1532 self.memory_index,
1533 realloc_index,
1534 )?)
1535 }
1536 ShimKind::TaskReturn {
1537 interface,
1538 func,
1539 result,
1540 encoding,
1541 for_module,
1542 } => {
1543 let mut encoder = if interface.is_none() {
1546 self.root_import_type_encoder(*interface)
1547 } else {
1548 self.root_export_type_encoder(*interface)
1549 };
1550 let result = match result {
1551 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1552 None => None,
1553 };
1554
1555 let exports = self.info.exports_for(*for_module);
1556 let realloc = exports.import_realloc_for(*interface, func);
1557
1558 let instance_index = self.instance_for(*for_module);
1559 let realloc_index = realloc.map(|r| {
1560 self.core_alias_export(Some("realloc"), instance_index, r, ExportKind::Func)
1561 });
1562 let options =
1563 shim.options
1564 .into_iter(*encoding, self.memory_index, realloc_index)?;
1565 self.component.task_return(result, options)
1566 }
1567 ShimKind::ThreadNewIndirect { func_ty } => {
1568 let (func_ty_idx, f) = self.component.core_type(Some("thread-start"));
1570 f.core().func_type(func_ty);
1571
1572 let exports = self.info.exports_for(CustomModule::Main);
1575 let instance_index = self.instance_for(CustomModule::Main);
1576 let table_idx = exports.indirect_function_table().map(|table| {
1577 self.core_alias_export(
1578 Some("indirect-function-table"),
1579 instance_index,
1580 table,
1581 ExportKind::Table,
1582 )
1583 }).ok_or_else(|| {
1584 anyhow!(
1585 "table __indirect_function_table must be an exported funcref table for thread.new-indirect"
1586 )
1587 })?;
1588
1589 self.component.thread_new_indirect(func_ty_idx, table_idx)
1590 }
1591
1592 ShimKind::Realloc { module, export } => {
1593 let instance = self.instance_for(*module);
1594 self.core_alias_export(Some(export), instance, export, ExportKind::Func)
1595 }
1596 })
1597 }
1598
1599 fn encode_payload_func(
1600 &mut self,
1601 shims: &Shims<'_>,
1602 for_module: &CustomModule,
1603 info: &PayloadInfo,
1604 kind: &PayloadFuncKind,
1605 options: RequiredOptions,
1606 site: ReallocSite,
1607 ) -> Result<u32> {
1608 let resolve = &self.info.encoder.metadata.resolve;
1609 let metadata = self.info.module_metadata_for(*for_module);
1610 let encoding = match &info.ty {
1611 PayloadType::Type { function, .. } => {
1612 if info.imported {
1613 metadata.import_encodings.get(resolve, &info.key, function)
1614 } else {
1615 metadata.export_encodings.get(resolve, &info.key, function)
1616 }
1617 }
1618 PayloadType::UnitFuture | PayloadType::UnitStream => None,
1619 };
1620 let realloc = payload_realloc_name(self.info, *for_module, info);
1621 let encoding = encoding.unwrap_or(StringEncoding::UTF8);
1622 let realloc_index = self.realloc_index(shims, *for_module, site, options, realloc);
1623 let type_index = self.payload_type_index(info)?;
1624 let options = options.into_iter(encoding, self.memory_index, realloc_index)?;
1625
1626 Ok(match kind {
1627 PayloadFuncKind::FutureWrite => self.component.future_write(type_index, options),
1628 PayloadFuncKind::FutureRead => self.component.future_read(type_index, options),
1629 PayloadFuncKind::StreamWrite => self.component.stream_write(type_index, options),
1630 PayloadFuncKind::StreamRead => self.component.stream_read(type_index, options),
1631 })
1632 }
1633
1634 fn payload_type_index(&mut self, info: &PayloadInfo) -> Result<u32> {
1642 let resolve = &self.info.encoder.metadata.resolve;
1643 let mut encoder = if info.imported || info.interface.is_none() {
1659 self.root_import_type_encoder(None)
1660 } else {
1661 self.root_export_type_encoder(info.interface)
1662 };
1663 match info.ty {
1664 PayloadType::Type { id, .. } => match encoder.encode_valtype(resolve, &Type::Id(id))? {
1665 ComponentValType::Type(index) => Ok(index),
1666 ComponentValType::Primitive(_) => unreachable!(),
1667 },
1668 PayloadType::UnitFuture => Ok(encoder.encode_unit_future()),
1669 PayloadType::UnitStream => Ok(encoder.encode_unit_stream()),
1670 }
1671 }
1672
1673 fn declare_types_for_imported_intrinsics(&mut self, shims: &Shims<'_>) -> Result<()> {
1680 let resolve = &self.info.encoder.metadata.resolve;
1681 let world = &resolve.worlds[self.info.encoder.metadata.world];
1682
1683 let main_module_keys = self.info.encoder.main_module_exports.iter();
1686 let main_module_keys = main_module_keys.map(|key| (CustomModule::Main, key));
1687 let adapter_keys = self.info.encoder.adapters.iter().flat_map(|(name, info)| {
1688 info.required_exports
1689 .iter()
1690 .map(move |key| (CustomModule::Adapter(name), key))
1691 });
1692 for (for_module, key) in main_module_keys.chain(adapter_keys) {
1693 let id = match &world.exports[key] {
1694 WorldItem::Interface { id, .. } => *id,
1695 WorldItem::Type { .. } => unreachable!(),
1696 WorldItem::Function(_) => continue,
1697 };
1698
1699 for ty in resolve.interfaces[id].types.values() {
1700 let def = &resolve.types[*ty];
1701 match &def.kind {
1702 TypeDefKind::Resource => {
1706 let exports = self.info.exports_for(for_module);
1709 let dtor = exports.resource_dtor(*ty).map(|name| {
1710 let shim = &shims.shims[&ShimKind::ResourceDtor {
1711 module: for_module,
1712 export: name,
1713 }];
1714 let index = self.shim_instance_index.unwrap();
1715 self.core_alias_export(
1716 Some(&shim.debug_name),
1717 index,
1718 &shim.name,
1719 ExportKind::Func,
1720 )
1721 });
1722
1723 let resource_idx = self.component.type_resource(
1727 Some(def.name.as_ref().unwrap()),
1728 ValType::I32,
1729 dtor,
1730 );
1731 let prev = self
1732 .type_encoding_maps
1733 .id_to_index
1734 .insert(*ty, resource_idx);
1735 assert!(prev.is_none());
1736 }
1737 _other => {
1738 self.root_export_type_encoder(Some(id))
1739 .encode_valtype(resolve, &Type::Id(*ty))?;
1740 }
1741 }
1742 }
1743 }
1744 Ok(())
1745 }
1746
1747 fn instantiate_main_module(&mut self, shims: &Shims<'_>) -> Result<()> {
1750 assert!(self.instance_index.is_none());
1751
1752 let instance_index = self.instantiate_core_module(shims, CustomModule::Main)?;
1753
1754 if self.memory_index.is_none() {
1757 if let Some((memory, _)) = self.info.info.exports.memory() {
1758 self.memory_index = Some(self.core_alias_export(
1759 Some("memory"),
1760 instance_index,
1761 memory,
1762 ExportKind::Memory,
1763 ));
1764 }
1765 }
1766
1767 self.instance_index = Some(instance_index);
1768 Ok(())
1769 }
1770
1771 fn instantiate_adapter_module(&mut self, shims: &Shims<'_>, name: &'a str) -> Result<()> {
1774 let instance = self.instantiate_core_module(shims, CustomModule::Adapter(name))?;
1775 self.adapter_instances.insert(name, instance);
1776 Ok(())
1777 }
1778
1779 fn instantiate_core_module(
1786 &mut self,
1787 shims: &Shims,
1788 for_module: CustomModule<'_>,
1789 ) -> Result<u32> {
1790 let module = self.module_for(for_module);
1791
1792 let mut args = Vec::new();
1793 for (core_wasm_name, instance) in self.info.imports_for(for_module).modules() {
1794 match instance {
1795 ImportInstance::Names(names) => {
1801 let mut exports = Vec::new();
1802 for (name, import) in names {
1803 log::trace!(
1804 "attempting to materialize import of `{core_wasm_name}::{name}` for {for_module:?}"
1805 );
1806 let (kind, index) = self
1807 .materialize_import(&shims, for_module, import)
1808 .with_context(|| {
1809 format!("failed to satisfy import `{core_wasm_name}::{name}`")
1810 })?;
1811 exports.push((name.as_str(), kind, index));
1812 }
1813 let index = self
1814 .component
1815 .core_instantiate_exports(Some(core_wasm_name), exports);
1816 args.push((core_wasm_name.as_str(), ModuleArg::Instance(index)));
1817 }
1818
1819 ImportInstance::Whole(which) => {
1822 let instance = self.instance_for(which.to_custom_module());
1823 args.push((core_wasm_name.as_str(), ModuleArg::Instance(instance)));
1824 }
1825 }
1826 }
1827
1828 Ok(self
1830 .component
1831 .core_instantiate(Some(for_module.debug_name()), module, args))
1832 }
1833
1834 fn materialize_import(
1841 &mut self,
1842 shims: &Shims<'_>,
1843 for_module: CustomModule<'_>,
1844 import: &'a Import,
1845 ) -> Result<(ExportKind, u32)> {
1846 let resolve = &self.info.encoder.metadata.resolve;
1847 match import {
1848 Import::AdapterExport {
1851 adapter,
1852 func,
1853 ty: _,
1854 } => {
1855 assert!(self.info.encoder.adapters.contains_key(adapter));
1856 Ok(self.materialize_shim_import(shims, &ShimKind::Adapter { adapter, func }))
1857 }
1858
1859 Import::MainModuleMemory(_) => {
1862 let index = self
1863 .memory_index
1864 .ok_or_else(|| anyhow!("main module cannot import memory"))?;
1865 Ok((ExportKind::Memory, index))
1866 }
1867
1868 Import::MainModuleExport { name, kind } => {
1870 let instance = self.instance_index.unwrap();
1871 let index = self.core_alias_export(Some(name), instance, name, *kind);
1872 Ok((*kind, index))
1873 }
1874
1875 Import::Item(item) => {
1879 let instance = self.instance_for(item.which.to_custom_module());
1880 let index =
1881 self.core_alias_export(Some(&item.name), instance, &item.name, item.kind);
1882 Ok((item.kind, index))
1883 }
1884
1885 Import::ExportedResourceDrop(_key, id) => {
1891 let index = self
1892 .component
1893 .resource_drop(self.type_encoding_maps.id_to_index[id]);
1894 Ok((ExportKind::Func, index))
1895 }
1896 Import::ExportedResourceRep(_key, id) => {
1897 let index = self
1898 .component
1899 .resource_rep(self.type_encoding_maps.id_to_index[id]);
1900 Ok((ExportKind::Func, index))
1901 }
1902 Import::ExportedResourceNew(_key, id) => {
1903 let index = self
1904 .component
1905 .resource_new(self.type_encoding_maps.id_to_index[id]);
1906 Ok((ExportKind::Func, index))
1907 }
1908
1909 Import::ImportedResourceDrop(key, iface, id) => {
1914 let ty = &resolve.types[*id];
1915 let name = ty.name.as_ref().unwrap();
1916 self.materialize_wit_import(
1917 shims,
1918 for_module,
1919 iface.map(|_| resolve.name_world_key(key)),
1920 &format!("{name}_drop"),
1921 key,
1922 AbiVariant::GuestImport,
1923 )
1924 }
1925 Import::ExportedTaskReturn(key, interface, func) => {
1926 let (options, _sig) = task_return_options_and_type(resolve, func);
1927 let result_ty = func.result;
1928 if options.is_empty() || self.memory_index.is_some() {
1929 let mut encoder = if interface.is_none() {
1935 self.root_import_type_encoder(*interface)
1936 } else {
1937 self.root_export_type_encoder(*interface)
1938 };
1939
1940 let result = match result_ty.as_ref() {
1941 Some(ty) => Some(encoder.encode_valtype(resolve, ty)?),
1942 None => None,
1943 };
1944 let metadata = &self.info.module_metadata_for(for_module);
1945 let encoding = metadata
1946 .export_encodings
1947 .get(resolve, key, &func.name)
1948 .ok_or_else(|| {
1949 anyhow!("missing component metadata for export of `{}`", func.name)
1950 })?;
1951 let options = options
1952 .into_iter(encoding, self.memory_index, None)?
1953 .collect::<Vec<_>>();
1954 let index = self.component.task_return(result, options);
1955 Ok((ExportKind::Func, index))
1956 } else {
1957 let metadata = &self.info.module_metadata_for(for_module);
1958 let encoding = metadata
1959 .export_encodings
1960 .get(resolve, key, &func.name)
1961 .unwrap();
1962 Ok(self.materialize_shim_import(
1963 shims,
1964 &ShimKind::TaskReturn {
1965 for_module,
1966 interface: *interface,
1967 func: &func.name,
1968 result: result_ty,
1969 encoding,
1970 },
1971 ))
1972 }
1973 }
1974 Import::BackpressureInc => {
1975 let index = self.component.backpressure_inc();
1976 Ok((ExportKind::Func, index))
1977 }
1978 Import::BackpressureDec => {
1979 let index = self.component.backpressure_dec();
1980 Ok((ExportKind::Func, index))
1981 }
1982 Import::WaitableSetWait => {
1983 if let Some(memory) = self.memory_index {
1984 let index = self.component.waitable_set_wait(memory);
1985 return Ok((ExportKind::Func, index));
1986 }
1987 Ok(self.materialize_shim_import(shims, &ShimKind::WaitableSetWait))
1988 }
1989 Import::WaitableSetPoll => {
1990 if let Some(memory) = self.memory_index {
1991 let index = self.component.waitable_set_poll(memory);
1992 return Ok((ExportKind::Func, index));
1993 }
1994 Ok(self.materialize_shim_import(shims, &ShimKind::WaitableSetPoll))
1995 }
1996 Import::SubtaskDrop => {
1997 let index = self.component.subtask_drop();
1998 Ok((ExportKind::Func, index))
1999 }
2000 Import::SubtaskCancel { async_ } => {
2001 let index = self.component.subtask_cancel(*async_);
2002 Ok((ExportKind::Func, index))
2003 }
2004 Import::StreamNew(info) => {
2005 let ty = self.payload_type_index(info)?;
2006 let index = self.component.stream_new(ty);
2007 Ok((ExportKind::Func, index))
2008 }
2009 Import::StreamRead { info, async_ } => self.materialize_payload_import(
2010 shims,
2011 for_module,
2012 info,
2013 PayloadFuncKind::StreamRead,
2014 *async_,
2015 ),
2016 Import::StreamWrite { info, async_ } => self.materialize_payload_import(
2017 shims,
2018 for_module,
2019 info,
2020 PayloadFuncKind::StreamWrite,
2021 *async_,
2022 ),
2023 Import::StreamForward(info) => {
2024 let ty = self.payload_type_index(info)?;
2025 let index = self.component.stream_forward(ty);
2026 Ok((ExportKind::Func, index))
2027 }
2028 Import::StreamCancelRead { info, async_ } => {
2029 let ty = self.payload_type_index(info)?;
2030 let index = self.component.stream_cancel_read(ty, *async_);
2031 Ok((ExportKind::Func, index))
2032 }
2033 Import::StreamCancelWrite { info, async_ } => {
2034 let ty = self.payload_type_index(info)?;
2035 let index = self.component.stream_cancel_write(ty, *async_);
2036 Ok((ExportKind::Func, index))
2037 }
2038 Import::StreamDropReadable(info) => {
2039 let type_index = self.payload_type_index(info)?;
2040 let index = self.component.stream_drop_readable(type_index);
2041 Ok((ExportKind::Func, index))
2042 }
2043 Import::StreamDropWritable(info) => {
2044 let type_index = self.payload_type_index(info)?;
2045 let index = self.component.stream_drop_writable(type_index);
2046 Ok((ExportKind::Func, index))
2047 }
2048 Import::FutureNew(info) => {
2049 let ty = self.payload_type_index(info)?;
2050 let index = self.component.future_new(ty);
2051 Ok((ExportKind::Func, index))
2052 }
2053 Import::FutureRead { info, async_ } => self.materialize_payload_import(
2054 shims,
2055 for_module,
2056 info,
2057 PayloadFuncKind::FutureRead,
2058 *async_,
2059 ),
2060 Import::FutureWrite { info, async_ } => self.materialize_payload_import(
2061 shims,
2062 for_module,
2063 info,
2064 PayloadFuncKind::FutureWrite,
2065 *async_,
2066 ),
2067 Import::FutureForward(info) => {
2068 let ty = self.payload_type_index(info)?;
2069 let index = self.component.future_forward(ty);
2070 Ok((ExportKind::Func, index))
2071 }
2072 Import::FutureCancelRead { info, async_ } => {
2073 let ty = self.payload_type_index(info)?;
2074 let index = self.component.future_cancel_read(ty, *async_);
2075 Ok((ExportKind::Func, index))
2076 }
2077 Import::FutureCancelWrite { info, async_ } => {
2078 let ty = self.payload_type_index(info)?;
2079 let index = self.component.future_cancel_write(ty, *async_);
2080 Ok((ExportKind::Func, index))
2081 }
2082 Import::FutureDropReadable(info) => {
2083 let type_index = self.payload_type_index(info)?;
2084 let index = self.component.future_drop_readable(type_index);
2085 Ok((ExportKind::Func, index))
2086 }
2087 Import::FutureDropWritable(info) => {
2088 let type_index = self.payload_type_index(info)?;
2089 let index = self.component.future_drop_writable(type_index);
2090 Ok((ExportKind::Func, index))
2091 }
2092 Import::ErrorContextNew { encoding } => {
2093 if self.memory_index.is_some() {
2094 let options = (RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING)
2095 .into_iter(*encoding, self.memory_index, None)?;
2096 let index = self.component.error_context_new(options);
2097 return Ok((ExportKind::Func, index));
2098 }
2099 Ok(self.materialize_shim_import(
2100 shims,
2101 &ShimKind::ErrorContextNew {
2102 encoding: *encoding,
2103 },
2104 ))
2105 }
2106 Import::ErrorContextDebugMessage { encoding } => Ok(self.materialize_shim_import(
2107 shims,
2108 &ShimKind::ErrorContextDebugMessage {
2109 for_module,
2110 encoding: *encoding,
2111 },
2112 )),
2113 Import::ErrorContextDrop => {
2114 let index = self.component.error_context_drop();
2115 Ok((ExportKind::Func, index))
2116 }
2117 Import::WorldFunc(key, name, abi) => {
2118 self.materialize_wit_import(shims, for_module, None, name, key, *abi)
2119 }
2120 Import::InterfaceFunc(key, _, name, abi) => self.materialize_wit_import(
2121 shims,
2122 for_module,
2123 Some(resolve.name_world_key(key)),
2124 name,
2125 key,
2126 *abi,
2127 ),
2128
2129 Import::WaitableSetNew => {
2130 let index = self.component.waitable_set_new();
2131 Ok((ExportKind::Func, index))
2132 }
2133 Import::WaitableSetDrop => {
2134 let index = self.component.waitable_set_drop();
2135 Ok((ExportKind::Func, index))
2136 }
2137 Import::WaitableJoin => {
2138 let index = self.component.waitable_join();
2139 Ok((ExportKind::Func, index))
2140 }
2141 Import::ContextGet { ty, slot } => {
2142 let index = self.component.context_get((*ty).try_into()?, *slot);
2143 Ok((ExportKind::Func, index))
2144 }
2145 Import::ContextSet { ty, slot } => {
2146 let index = self.component.context_set((*ty).try_into()?, *slot);
2147 Ok((ExportKind::Func, index))
2148 }
2149 Import::TlsBaseGet { ty } => Ok((
2150 ExportKind::Func,
2151 self.materialize_tls_base_import(false, (*ty).try_into()?),
2152 )),
2153 Import::TlsBaseSet { ty } => Ok((
2154 ExportKind::Func,
2155 self.materialize_tls_base_import(true, (*ty).try_into()?),
2156 )),
2157 Import::ExportedTaskCancel => {
2158 let index = self.component.task_cancel();
2159 Ok((ExportKind::Func, index))
2160 }
2161 Import::ThreadIndex => {
2162 let index = self.component.thread_index();
2163 Ok((ExportKind::Func, index))
2164 }
2165 Import::ThreadNewIndirect => Ok(self.materialize_shim_import(
2166 shims,
2167 &ShimKind::ThreadNewIndirect {
2168 func_ty: FuncType::new([ValType::I32], []),
2170 },
2171 )),
2172 Import::ThreadResumeLater => {
2173 let index = self.component.thread_resume_later();
2174 Ok((ExportKind::Func, index))
2175 }
2176 Import::ThreadSuspend => {
2177 let index = self.component.thread_suspend();
2178 Ok((ExportKind::Func, index))
2179 }
2180 Import::ThreadYield => {
2181 let index = self.component.thread_yield();
2182 Ok((ExportKind::Func, index))
2183 }
2184 Import::ThreadSuspendThenResume => {
2185 let index = self.component.thread_suspend_then_resume();
2186 Ok((ExportKind::Func, index))
2187 }
2188 Import::ThreadYieldThenResume => {
2189 let index = self.component.thread_yield_then_resume();
2190 Ok((ExportKind::Func, index))
2191 }
2192 Import::ThreadSuspendThenPromote => {
2193 let index = self.component.thread_suspend_then_promote();
2194 Ok((ExportKind::Func, index))
2195 }
2196 Import::ThreadYieldThenPromote => {
2197 let index = self.component.thread_yield_then_promote();
2198 Ok((ExportKind::Func, index))
2199 }
2200 }
2201 }
2202
2203 fn materialize_tls_base_import(&mut self, set: bool, ty: ValType) -> u32 {
2207 if self.info.can_use_context_slot_1() {
2208 if set {
2209 self.component.context_set(ty, 1)
2210 } else {
2211 self.component.context_get(ty, 1)
2212 }
2213 } else {
2214 let name = if set { TLS_BASE_SET } else { TLS_BASE_GET };
2215 self.core_alias_export(
2216 Some(name),
2217 self.shim_instance_index.unwrap(),
2218 name,
2219 ExportKind::Func,
2220 )
2221 }
2222 }
2223
2224 fn materialize_shim_import(&mut self, shims: &Shims<'_>, kind: &ShimKind) -> (ExportKind, u32) {
2227 let index = self.core_alias_export(
2228 Some(&shims.shims[kind].debug_name),
2229 self.shim_instance_index
2230 .expect("shim should be instantiated"),
2231 &shims.shims[kind].name,
2232 ExportKind::Func,
2233 );
2234 (ExportKind::Func, index)
2235 }
2236
2237 fn materialize_payload_import(
2240 &mut self,
2241 shims: &Shims<'_>,
2242 for_module: CustomModule<'_>,
2243 info: &PayloadInfo,
2244 kind: PayloadFuncKind,
2245 async_: bool,
2246 ) -> Result<(ExportKind, u32)> {
2247 let shim_kind = ShimKind::PayloadFunc {
2248 for_module,
2249 info,
2250 kind,
2251 };
2252 if shims.shims.get(&shim_kind).is_some() {
2253 return Ok(self.materialize_shim_import(shims, &shim_kind));
2254 }
2255 let resolve = &self.info.encoder.metadata.resolve;
2256 let options = RequiredOptions::for_payload(resolve, info, &kind, async_);
2257 let func = self.encode_payload_func(
2258 shims,
2259 &for_module,
2260 info,
2261 &kind,
2262 options,
2263 ReallocSite::BeforeInstantiation,
2264 )?;
2265 Ok((ExportKind::Func, func))
2266 }
2267
2268 fn materialize_wit_import(
2271 &mut self,
2272 shims: &Shims<'_>,
2273 for_module: CustomModule<'_>,
2274 interface_key: Option<String>,
2275 name: &String,
2276 key: &WorldKey,
2277 abi: AbiVariant,
2278 ) -> Result<(ExportKind, u32)> {
2279 let resolve = &self.info.encoder.metadata.resolve;
2280 let import = &self.info.import_map[&interface_key];
2281 let (index, _, lowering) = import.lowerings.get_full(&(name.clone(), abi)).unwrap();
2282 let metadata = self.info.module_metadata_for(for_module);
2283
2284 let index = match lowering {
2285 Lowering::Direct { options } => {
2288 let func_index = match &import.interface {
2289 Some(interface) => {
2290 let instance_index = self.instances[interface];
2291 self.component
2292 .alias_export(instance_index, name, ComponentExportKind::Func)
2293 }
2294 None => self.imported_funcs[name],
2295 };
2296 let encoding = metadata
2297 .import_encodings
2298 .get(resolve, key, name)
2299 .ok_or_else(|| anyhow!("missing component metadata for import of `{name}`"))?;
2300 let realloc = self
2301 .info
2302 .exports_for(for_module)
2303 .import_realloc_for(import.interface, name);
2304 let realloc = self.realloc_index(
2305 shims,
2306 for_module,
2307 ReallocSite::BeforeInstantiation,
2308 *options,
2309 realloc,
2310 );
2311 let options = options
2312 .into_iter(encoding, self.memory_index, realloc)?
2313 .collect::<Vec<_>>();
2314 self.component.lower_func(Some(name), func_index, options)
2315 }
2316
2317 Lowering::Indirect { .. } => {
2321 let encoding = metadata.import_encodings.get(resolve, key, name).unwrap();
2322 return Ok(self.materialize_shim_import(
2323 shims,
2324 &ShimKind::IndirectLowering {
2325 interface: interface_key,
2326 index,
2327 realloc: for_module,
2328 encoding,
2329 },
2330 ));
2331 }
2332
2333 Lowering::ResourceDrop(id) => {
2336 let resource_idx = self.lookup_resource_index(*id);
2337 self.component.resource_drop(resource_idx)
2338 }
2339 };
2340 Ok((ExportKind::Func, index))
2341 }
2342
2343 fn realloc_index(
2346 &mut self,
2347 shims: &Shims<'_>,
2348 module: CustomModule<'_>,
2349 site: ReallocSite,
2350 options: RequiredOptions,
2351 export: Option<&str>,
2352 ) -> Option<u32> {
2353 if !options.contains(RequiredOptions::REALLOC) {
2354 return None;
2355 }
2356 let (module, export) = resolve_realloc(self.info, module, export)?;
2357
2358 if !realloc_needs_shim(self.info, site) {
2359 let instance = self.instance_for(module);
2360 return Some(self.core_alias_export(Some(export), instance, export, ExportKind::Func));
2361 }
2362
2363 let kind = ShimKind::Realloc { module, export };
2364 let shim = shims.shims.get(&kind).unwrap_or_else(|| {
2365 panic!(
2366 "no shim was registered for the `realloc` \
2367 function `{export}` in `{}`",
2368 module.debug_name()
2369 )
2370 });
2371 let instance = self
2372 .shim_instance_index
2373 .expect("shim should be instantiated");
2374 Some(self.core_alias_export(
2375 Some(&shim.debug_name),
2376 instance,
2377 &shim.name,
2378 ExportKind::Func,
2379 ))
2380 }
2381
2382 fn hooked_core_alias_export(&mut self, module: CustomModule<'_>, core_name: &str) -> u32 {
2383 let key = (module.to_imported_instance(), core_name.to_string());
2384 if let Some(&wrapper_idx) = self.export_task_initialization_wrappers.get(&key) {
2385 wrapper_idx
2386 } else {
2387 let instance = self.instance_for(module);
2388 self.core_alias_export(Some(core_name), instance, core_name, ExportKind::Func)
2389 }
2390 }
2391
2392 fn instance_for(&self, module: CustomModule) -> u32 {
2395 match module {
2396 CustomModule::Main => self.instance_index.expect("instantiated by now"),
2397 CustomModule::Adapter(name) => self.adapter_instances[name],
2398 }
2399 }
2400
2401 fn module_for(&self, module: CustomModule) -> u32 {
2404 match module {
2405 CustomModule::Main => self.module_index.unwrap(),
2406 CustomModule::Adapter(name) => self.adapter_modules[name],
2407 }
2408 }
2409
2410 fn core_alias_export(
2413 &mut self,
2414 debug_name: Option<&str>,
2415 instance: u32,
2416 name: &str,
2417 kind: ExportKind,
2418 ) -> u32 {
2419 *self
2420 .aliased_core_items
2421 .entry((instance, name.to_string()))
2422 .or_insert_with(|| {
2423 self.component
2424 .core_alias_export(debug_name, instance, name, kind)
2425 })
2426 }
2427}
2428
2429#[derive(Default)]
2447struct Shims<'a> {
2448 shims: IndexMap<ShimKind<'a>, Shim<'a>>,
2450}
2451
2452struct Shim<'a> {
2453 options: RequiredOptions,
2456
2457 name: String,
2461
2462 debug_name: String,
2465
2466 kind: ShimKind<'a>,
2468
2469 sig: WasmSignature,
2471}
2472
2473#[derive(Debug, Clone, Hash, Eq, PartialEq, Copy)]
2476enum PayloadFuncKind {
2477 FutureWrite,
2478 FutureRead,
2479 StreamWrite,
2480 StreamRead,
2481}
2482
2483#[derive(Debug, Clone, Hash, Eq, PartialEq)]
2484enum ShimKind<'a> {
2485 IndirectLowering {
2489 interface: Option<String>,
2491 index: usize,
2493 realloc: CustomModule<'a>,
2495 encoding: StringEncoding,
2497 },
2498 Adapter {
2501 adapter: &'a str,
2503 func: &'a str,
2505 },
2506 ResourceDtor {
2509 module: CustomModule<'a>,
2511 export: &'a str,
2513 },
2514 PayloadFunc {
2518 for_module: CustomModule<'a>,
2521 info: &'a PayloadInfo,
2526 kind: PayloadFuncKind,
2528 },
2529 WaitableSetWait,
2533 WaitableSetPoll,
2537 TaskReturn {
2539 interface: Option<InterfaceId>,
2542 func: &'a str,
2545 result: Option<Type>,
2547 for_module: CustomModule<'a>,
2549 encoding: StringEncoding,
2551 },
2552 ErrorContextNew {
2556 encoding: StringEncoding,
2558 },
2559 ErrorContextDebugMessage {
2563 for_module: CustomModule<'a>,
2565 encoding: StringEncoding,
2567 },
2568 ThreadNewIndirect {
2571 func_ty: FuncType,
2573 },
2574 Realloc {
2576 module: CustomModule<'a>,
2578 export: &'a str,
2580 },
2581}
2582
2583#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2584enum ReallocSite {
2585 BeforeInstantiation,
2587 AfterInstantiation,
2590}
2591
2592fn realloc_needs_shim(world: &ComponentWorld<'_>, site: ReallocSite) -> bool {
2593 match site {
2594 ReallocSite::BeforeInstantiation => true,
2597
2598 ReallocSite::AfterInstantiation => world.info.exports.wasm_task_hook().is_some(),
2602 }
2603}
2604
2605#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
2615enum CustomModule<'a> {
2616 Main,
2619 Adapter(&'a str),
2622}
2623
2624impl<'a> CustomModule<'a> {
2625 fn debug_name(&self) -> &'a str {
2626 match self {
2627 CustomModule::Main => "main",
2628 CustomModule::Adapter(s) => s,
2629 }
2630 }
2631
2632 fn to_imported_instance(&self) -> fixup::ImportedInstance {
2635 match self {
2636 CustomModule::Main => fixup::ImportedInstance::Main,
2637 CustomModule::Adapter(s) => fixup::ImportedInstance::Adapter(s.to_string()),
2638 }
2639 }
2640}
2641
2642impl<'a> Shims<'a> {
2643 fn append_indirect(
2648 &mut self,
2649 world: &'a ComponentWorld<'a>,
2650 for_module: CustomModule<'a>,
2651 ) -> Result<()> {
2652 let module_imports = world.imports_for(for_module);
2653 let module_exports = world.exports_for(for_module);
2654 let resolve = &world.encoder.metadata.resolve;
2655 let memory_available = world.info.imports.imported_memory().is_some();
2656
2657 for (module, field, import) in module_imports.imports() {
2658 match import {
2659 Import::ImportedResourceDrop(..)
2662 | Import::MainModuleMemory(_)
2663 | Import::MainModuleExport { .. }
2664 | Import::Item(_)
2665 | Import::ExportedResourceDrop(..)
2666 | Import::ExportedResourceRep(..)
2667 | Import::ExportedResourceNew(..)
2668 | Import::ExportedTaskCancel
2669 | Import::ErrorContextDrop
2670 | Import::BackpressureInc
2671 | Import::BackpressureDec
2672 | Import::SubtaskDrop
2673 | Import::SubtaskCancel { .. }
2674 | Import::FutureNew(..)
2675 | Import::StreamNew(..)
2676 | Import::FutureForward { .. }
2677 | Import::FutureCancelRead { .. }
2678 | Import::FutureCancelWrite { .. }
2679 | Import::FutureDropWritable { .. }
2680 | Import::FutureDropReadable { .. }
2681 | Import::StreamForward { .. }
2682 | Import::StreamCancelRead { .. }
2683 | Import::StreamCancelWrite { .. }
2684 | Import::StreamDropWritable { .. }
2685 | Import::StreamDropReadable { .. }
2686 | Import::WaitableSetNew
2687 | Import::WaitableSetDrop
2688 | Import::WaitableJoin
2689 | Import::ContextGet { .. }
2690 | Import::ContextSet { .. }
2691 | Import::TlsBaseGet { .. }
2692 | Import::TlsBaseSet { .. }
2693 | Import::ThreadIndex
2694 | Import::ThreadResumeLater
2695 | Import::ThreadSuspend { .. }
2696 | Import::ThreadYield { .. }
2697 | Import::ThreadSuspendThenResume { .. }
2698 | Import::ThreadYieldThenResume { .. }
2699 | Import::ThreadSuspendThenPromote { .. }
2700 | Import::ThreadYieldThenPromote { .. } => {}
2701
2702 Import::ExportedTaskReturn(key, interface, func) => {
2706 let (options, sig) = task_return_options_and_type(resolve, func);
2707 if options.is_empty() || memory_available {
2708 continue;
2709 }
2710 let name = self.shims.len().to_string();
2711 let encoding = world
2712 .module_metadata_for(for_module)
2713 .export_encodings
2714 .get(resolve, key, &func.name)
2715 .ok_or_else(|| {
2716 anyhow::anyhow!(
2717 "missing component metadata for export of \
2718 `{module}::{field}`"
2719 )
2720 })?;
2721 self.push(Shim {
2722 name,
2723 debug_name: format!("task-return-{}", func.name),
2724 options,
2725 kind: ShimKind::TaskReturn {
2726 interface: *interface,
2727 func: &func.name,
2728 result: func.result,
2729 for_module,
2730 encoding,
2731 },
2732 sig,
2733 });
2734 }
2735
2736 Import::FutureWrite { async_, info } => {
2737 self.append_indirect_payload_push(
2738 world,
2739 for_module,
2740 module,
2741 *async_,
2742 info,
2743 PayloadFuncKind::FutureWrite,
2744 vec![WasmType::I32; 2],
2745 vec![WasmType::I32],
2746 );
2747 }
2748 Import::FutureRead { async_, info } => {
2749 self.append_indirect_payload_push(
2750 world,
2751 for_module,
2752 module,
2753 *async_,
2754 info,
2755 PayloadFuncKind::FutureRead,
2756 vec![WasmType::I32; 2],
2757 vec![WasmType::I32],
2758 );
2759 }
2760 Import::StreamWrite { async_, info } => {
2761 self.append_indirect_payload_push(
2762 world,
2763 for_module,
2764 module,
2765 *async_,
2766 info,
2767 PayloadFuncKind::StreamWrite,
2768 vec![WasmType::I32; 3],
2769 vec![WasmType::I32],
2770 );
2771 }
2772 Import::StreamRead { async_, info } => {
2773 self.append_indirect_payload_push(
2774 world,
2775 for_module,
2776 module,
2777 *async_,
2778 info,
2779 PayloadFuncKind::StreamRead,
2780 vec![WasmType::I32; 3],
2781 vec![WasmType::I32],
2782 );
2783 }
2784
2785 Import::WaitableSetWait => {
2786 if memory_available {
2787 continue;
2788 }
2789 let name = self.shims.len().to_string();
2790 self.push(Shim {
2791 name,
2792 debug_name: "waitable-set.wait".to_string(),
2793 options: RequiredOptions::empty(),
2794 kind: ShimKind::WaitableSetWait,
2795 sig: WasmSignature {
2796 params: vec![WasmType::I32; 2],
2797 results: vec![WasmType::I32],
2798 indirect_params: false,
2799 retptr: false,
2800 },
2801 });
2802 }
2803
2804 Import::WaitableSetPoll => {
2805 if memory_available {
2806 continue;
2807 }
2808 let name = self.shims.len().to_string();
2809 self.push(Shim {
2810 name,
2811 debug_name: "waitable-set.poll".to_string(),
2812 options: RequiredOptions::empty(),
2813 kind: ShimKind::WaitableSetPoll,
2814 sig: WasmSignature {
2815 params: vec![WasmType::I32; 2],
2816 results: vec![WasmType::I32],
2817 indirect_params: false,
2818 retptr: false,
2819 },
2820 });
2821 }
2822
2823 Import::ErrorContextNew { encoding } => {
2824 if memory_available {
2825 continue;
2826 }
2827 let name = self.shims.len().to_string();
2828 self.push(Shim {
2829 name,
2830 debug_name: "error-new".to_string(),
2831 options: RequiredOptions::MEMORY | RequiredOptions::STRING_ENCODING,
2832 kind: ShimKind::ErrorContextNew {
2833 encoding: *encoding,
2834 },
2835 sig: WasmSignature {
2836 params: vec![WasmType::I32; 2],
2837 results: vec![WasmType::I32],
2838 indirect_params: false,
2839 retptr: false,
2840 },
2841 });
2842 }
2843
2844 Import::ErrorContextDebugMessage { encoding } => {
2845 let name = self.shims.len().to_string();
2846 let options = RequiredOptions::MEMORY
2847 | RequiredOptions::STRING_ENCODING
2848 | RequiredOptions::REALLOC;
2849 self.push(Shim {
2850 name,
2851 debug_name: "error-debug-message".to_string(),
2852 options,
2853 kind: ShimKind::ErrorContextDebugMessage {
2854 for_module,
2855 encoding: *encoding,
2856 },
2857 sig: WasmSignature {
2858 params: vec![WasmType::I32; 2],
2859 results: vec![],
2860 indirect_params: false,
2861 retptr: false,
2862 },
2863 });
2864 let realloc = module_exports.import_realloc_fallback();
2865 self.push_realloc(
2866 world,
2867 for_module,
2868 ReallocSite::AfterInstantiation,
2869 options,
2870 realloc,
2871 );
2872 }
2873
2874 Import::ThreadNewIndirect => {
2875 let name = self.shims.len().to_string();
2876 self.push(Shim {
2877 name,
2878 debug_name: "thread.new-indirect".to_string(),
2879 options: RequiredOptions::empty(),
2880 kind: ShimKind::ThreadNewIndirect {
2881 func_ty: FuncType::new([ValType::I32], vec![]),
2883 },
2884 sig: WasmSignature {
2885 params: vec![WasmType::I32; 2],
2886 results: vec![WasmType::I32],
2887 indirect_params: false,
2888 retptr: false,
2889 },
2890 });
2891 }
2892
2893 Import::AdapterExport { adapter, func, ty } => {
2896 let name = self.shims.len().to_string();
2897 log::debug!("shim {name} is adapter `{module}::{field}`");
2898 self.push(Shim {
2899 name,
2900 debug_name: format!("adapt-{module}-{field}"),
2901 options: RequiredOptions::MEMORY,
2905 kind: ShimKind::Adapter { adapter, func },
2906 sig: WasmSignature {
2907 params: ty.params().iter().map(to_wasm_type).collect(),
2908 results: ty.results().iter().map(to_wasm_type).collect(),
2909 indirect_params: false,
2910 retptr: false,
2911 },
2912 });
2913
2914 fn to_wasm_type(ty: &wasmparser::ValType) -> WasmType {
2915 match ty {
2916 wasmparser::ValType::I32 => WasmType::I32,
2917 wasmparser::ValType::I64 => WasmType::I64,
2918 wasmparser::ValType::F32 => WasmType::F32,
2919 wasmparser::ValType::F64 => WasmType::F64,
2920 _ => unreachable!(),
2921 }
2922 }
2923 }
2924
2925 Import::InterfaceFunc(key, _, name, abi) => {
2929 self.append_indirect_wit_func(
2930 world,
2931 for_module,
2932 module,
2933 field,
2934 key,
2935 name,
2936 Some(resolve.name_world_key(key)),
2937 *abi,
2938 )?;
2939 }
2940 Import::WorldFunc(key, name, abi) => {
2941 self.append_indirect_wit_func(
2942 world, for_module, module, field, key, name, None, *abi,
2943 )?;
2944 }
2945 }
2946 }
2947
2948 for (export_name, export) in module_exports.iter() {
2954 let id = match export {
2955 Export::ResourceDtor(id) => id,
2956 _ => continue,
2957 };
2958 let resource = resolve.types[*id].name.as_ref().unwrap();
2959 let name = self.shims.len().to_string();
2960 self.push(Shim {
2961 name,
2962 debug_name: format!("dtor-{resource}"),
2963 options: RequiredOptions::empty(),
2964 kind: ShimKind::ResourceDtor {
2965 module: for_module,
2966 export: export_name,
2967 },
2968 sig: WasmSignature {
2969 params: vec![WasmType::I32],
2970 results: Vec::new(),
2971 indirect_params: false,
2972 retptr: false,
2973 },
2974 });
2975 }
2976
2977 Ok(())
2978 }
2979
2980 fn append_indirect_payload_push(
2983 &mut self,
2984 world: &'a ComponentWorld<'a>,
2985 for_module: CustomModule<'a>,
2986 module: &str,
2987 async_: bool,
2988 info: &'a PayloadInfo,
2989 kind: PayloadFuncKind,
2990 params: Vec<WasmType>,
2991 results: Vec<WasmType>,
2992 ) {
2993 let resolve = &world.encoder.metadata.resolve;
2994 let debug_name = format!("{module}-{}", info.name);
2995 let name = self.shims.len().to_string();
2996
2997 let options = RequiredOptions::for_payload(resolve, info, &kind, async_);
2998 if !options.contains(RequiredOptions::REALLOC)
2999 && world.info.imports.imported_memory().is_some()
3000 {
3001 return;
3002 }
3003 self.push(Shim {
3004 name,
3005 debug_name,
3006 options,
3007 kind: ShimKind::PayloadFunc {
3008 for_module,
3009 info,
3010 kind,
3011 },
3012 sig: WasmSignature {
3013 params,
3014 results,
3015 indirect_params: false,
3016 retptr: false,
3017 },
3018 });
3019 let realloc = payload_realloc_name(world, for_module, info);
3020 self.push_realloc(
3021 world,
3022 for_module,
3023 ReallocSite::AfterInstantiation,
3024 options,
3025 realloc,
3026 );
3027 }
3028
3029 fn append_indirect_wit_func(
3032 &mut self,
3033 world: &'a ComponentWorld<'a>,
3034 for_module: CustomModule<'a>,
3035 module: &str,
3036 field: &str,
3037 key: &WorldKey,
3038 name: &String,
3039 interface_key: Option<String>,
3040 abi: AbiVariant,
3041 ) -> Result<()> {
3042 let resolve = &world.encoder.metadata.resolve;
3043 let metadata = world.module_metadata_for(for_module);
3044 let interface = &world.import_map[&interface_key];
3045 let (index, _, lowering) = interface.lowerings.get_full(&(name.clone(), abi)).unwrap();
3046 let shim_name = self.shims.len().to_string();
3047 match lowering {
3048 Lowering::ResourceDrop(_) => {}
3049
3050 Lowering::Direct { options } => {
3051 let realloc = world
3052 .exports_for(for_module)
3053 .import_realloc_for(interface.interface, name);
3054 self.push_realloc(
3055 world,
3056 for_module,
3057 ReallocSite::BeforeInstantiation,
3058 *options,
3059 realloc,
3060 );
3061 }
3062
3063 Lowering::Indirect { sig, options } => {
3064 log::debug!(
3065 "shim {shim_name} is import `{module}::{field}` lowering {index} `{name}`",
3066 );
3067 let encoding = metadata
3068 .import_encodings
3069 .get(resolve, key, name)
3070 .ok_or_else(|| {
3071 anyhow::anyhow!(
3072 "missing component metadata for import of \
3073 `{module}::{field}`"
3074 )
3075 })?;
3076 self.push(Shim {
3077 name: shim_name,
3078 debug_name: format!("indirect-{module}-{field}"),
3079 options: *options,
3080 kind: ShimKind::IndirectLowering {
3081 interface: interface_key,
3082 index,
3083 realloc: for_module,
3084 encoding,
3085 },
3086 sig: sig.clone(),
3087 });
3088
3089 let realloc = world
3090 .exports_for(for_module)
3091 .import_realloc_for(interface.interface, name);
3092 self.push_realloc(
3093 world,
3094 for_module,
3095 ReallocSite::AfterInstantiation,
3096 *options,
3097 realloc,
3098 );
3099 }
3100 }
3101
3102 Ok(())
3103 }
3104
3105 fn push_realloc(
3109 &mut self,
3110 world: &'a ComponentWorld<'a>,
3111 for_module: CustomModule<'a>,
3112 site: ReallocSite,
3113 options: RequiredOptions,
3114 export: Option<&'a str>,
3115 ) {
3116 if !options.contains(RequiredOptions::REALLOC) {
3117 return;
3118 }
3119 let Some((for_module, export)) = resolve_realloc(world, for_module, export) else {
3120 return;
3121 };
3122 if !realloc_needs_shim(world, site) {
3123 return;
3124 }
3125 let name = self.shims.len().to_string();
3126 self.push(Shim {
3127 name,
3128 debug_name: format!("realloc-{}-{export}", for_module.debug_name()),
3129 options: RequiredOptions::empty(),
3130 kind: ShimKind::Realloc {
3131 module: for_module,
3132 export,
3133 },
3134 sig: WasmSignature {
3135 params: vec![WasmType::I32; 4],
3136 results: vec![WasmType::I32],
3137 indirect_params: false,
3138 retptr: false,
3139 },
3140 });
3141 }
3142
3143 fn push(&mut self, shim: Shim<'a>) {
3144 if !self.shims.contains_key(&shim.kind) {
3148 self.shims.insert(shim.kind.clone(), shim);
3149 }
3150 }
3151}
3152
3153fn resolve_realloc<'a>(
3160 world: &'a ComponentWorld<'a>,
3161 module: CustomModule<'a>,
3162 export: Option<&'a str>,
3163) -> Option<(CustomModule<'a>, &'a str)> {
3164 if let Some(export) = export {
3165 return Some((module, export));
3166 }
3167 match module {
3168 CustomModule::Main => None,
3171
3172 CustomModule::Adapter(name) => {
3174 let _info = world.adapters[name].library_info.as_ref()?;
3175 let main_realloc = world.info.exports.general_purpose_realloc()?;
3176 Some((CustomModule::Main, main_realloc))
3177 }
3178 }
3179}
3180
3181fn payload_realloc_name<'a>(
3182 world: &'a ComponentWorld<'_>,
3183 for_module: CustomModule<'_>,
3184 info: &PayloadInfo,
3185) -> Option<&'a str> {
3186 let exports = world.exports_for(for_module);
3187 match &info.ty {
3188 PayloadType::Type { function, .. } => {
3189 if info.imported {
3190 exports.import_realloc_for(info.interface, function)
3191 } else {
3192 exports.export_realloc_for(&info.key, function)
3193 }
3194 }
3195 PayloadType::UnitFuture | PayloadType::UnitStream => None,
3196 }
3197}
3198
3199fn task_return_options_and_type(
3200 resolve: &Resolve,
3201 func: &Function,
3202) -> (RequiredOptions, WasmSignature) {
3203 let func_tmp = Function {
3204 name: String::new(),
3205 kind: FunctionKind::Freestanding,
3206 params: match &func.result {
3207 Some(ty) => vec![Param {
3208 name: "a".to_string(),
3209 ty: *ty,
3210 span: Default::default(),
3211 }],
3212 None => Vec::new(),
3213 },
3214 result: None,
3215 docs: Default::default(),
3216 stability: Stability::Unknown,
3217 span: Default::default(),
3218 external_id: None,
3219 };
3220 let abi = AbiVariant::GuestImport;
3221 let mut options = RequiredOptions::for_import(resolve, func, abi);
3222 options.remove(RequiredOptions::REALLOC);
3224 let sig = resolve.wasm_signature(abi, &func_tmp);
3225 (options, sig)
3226}
3227
3228#[derive(Clone, Debug)]
3230pub struct Item {
3231 pub alias: String,
3232 pub kind: ExportKind,
3233 pub which: MainOrAdapter,
3234 pub name: String,
3235}
3236
3237#[derive(Debug, PartialEq, Clone)]
3239pub enum MainOrAdapter {
3240 Main,
3241 Adapter(String),
3242}
3243
3244impl MainOrAdapter {
3245 fn to_custom_module(&self) -> CustomModule<'_> {
3246 match self {
3247 MainOrAdapter::Main => CustomModule::Main,
3248 MainOrAdapter::Adapter(s) => CustomModule::Adapter(s),
3249 }
3250 }
3251}
3252
3253#[derive(Clone)]
3255pub enum Instance {
3256 MainOrAdapter(MainOrAdapter),
3258
3259 Items(Vec<Item>),
3261}
3262
3263#[derive(Clone)]
3266pub struct LibraryInfo {
3267 pub arguments: Vec<(String, Instance)>,
3269}
3270
3271pub(super) struct Adapter {
3273 wasm: Vec<u8>,
3275
3276 metadata: ModuleMetadata,
3278
3279 required_exports: IndexSet<WorldKey>,
3282
3283 library_info: Option<LibraryInfo>,
3288}
3289
3290#[derive(Default)]
3292pub struct ComponentEncoder {
3293 module: Vec<u8>,
3294 module_import_map: Option<ModuleImportMap>,
3295 pub(super) metadata: Bindgen,
3296 validate: bool,
3297 pub(super) main_module_exports: IndexSet<WorldKey>,
3298 pub(super) adapters: IndexMap<String, Adapter>,
3299 import_name_map: HashMap<String, String>,
3300 realloc_via_memory_grow: bool,
3301 merge_imports_based_on_semver: Option<bool>,
3302 pub(super) reject_legacy_names: bool,
3303 debug_names: bool,
3304 shim_return_call_ref: bool,
3305 emit_canonical_names: bool,
3306}
3307
3308impl ComponentEncoder {
3309 pub fn module(&mut self, module: &[u8]) -> Result<&mut Self> {
3315 let (wasm, metadata) = self.decode(module.as_ref())?;
3316 let (wasm, module_import_map) = ModuleImportMap::new(wasm)?;
3317 self.module = if let Some(producers) = &metadata.producers {
3318 producers.add_to_wasm(&wasm)?
3319 } else {
3320 wasm.to_vec()
3321 };
3322 let exports = self
3323 .merge_metadata(metadata)
3324 .context("failed merge WIT metadata for module with previous metadata")?;
3325 self.main_module_exports.extend(exports);
3326 self.module_import_map = module_import_map;
3327 Ok(self)
3328 }
3329
3330 fn decode<'a>(&self, wasm: &'a [u8]) -> Result<(Cow<'a, [u8]>, Bindgen)> {
3331 let (bytes, metadata) = metadata::decode(wasm)?;
3332 match bytes {
3333 Some(wasm) => Ok((Cow::Owned(wasm), metadata)),
3334 None => Ok((Cow::Borrowed(wasm), metadata)),
3335 }
3336 }
3337
3338 fn merge_metadata(&mut self, metadata: Bindgen) -> Result<IndexSet<WorldKey>> {
3339 self.metadata.merge(metadata)
3340 }
3341
3342 pub fn validate(&mut self, validate: bool) -> &mut Self {
3344 self.validate = validate;
3345 self
3346 }
3347
3348 pub fn debug_names(&mut self, debug_names: bool) -> &mut Self {
3350 self.debug_names = debug_names;
3351 self
3352 }
3353
3354 pub fn shim_return_call_ref(&mut self, enable: bool) -> &mut Self {
3357 self.shim_return_call_ref = enable;
3358 self
3359 }
3360
3361 pub fn merge_imports_based_on_semver(&mut self, merge: bool) -> &mut Self {
3369 self.merge_imports_based_on_semver = Some(merge);
3370 self
3371 }
3372
3373 pub fn emit_canonical_names(&mut self, emit: bool) -> &mut Self {
3381 self.emit_canonical_names = emit;
3382 self
3383 }
3384
3385 pub fn reject_legacy_names(&mut self, reject: bool) -> &mut Self {
3394 self.reject_legacy_names = reject;
3395 self
3396 }
3397
3398 pub fn adapter(&mut self, name: &str, bytes: &[u8]) -> Result<&mut Self> {
3416 self.library_or_adapter(name, bytes, None)
3417 }
3418
3419 pub fn library(
3432 &mut self,
3433 name: &str,
3434 bytes: &[u8],
3435 library_info: LibraryInfo,
3436 ) -> Result<&mut Self> {
3437 self.library_or_adapter(name, bytes, Some(library_info))
3438 }
3439
3440 fn library_or_adapter(
3441 &mut self,
3442 name: &str,
3443 bytes: &[u8],
3444 library_info: Option<LibraryInfo>,
3445 ) -> Result<&mut Self> {
3446 let (wasm, mut metadata) = self.decode(bytes)?;
3447 let adapter_metadata = mem::take(&mut metadata.metadata);
3455 let exports = self.merge_metadata(metadata).with_context(|| {
3456 format!("failed to merge WIT packages of adapter `{name}` into main packages")
3457 })?;
3458 if let Some(library_info) = &library_info {
3459 for (_, instance) in &library_info.arguments {
3461 let resolve = |which: &_| match which {
3462 MainOrAdapter::Main => Ok(()),
3463 MainOrAdapter::Adapter(name) => {
3464 if self.adapters.contains_key(name.as_str()) {
3465 Ok(())
3466 } else {
3467 Err(anyhow!("instance refers to unknown adapter `{name}`"))
3468 }
3469 }
3470 };
3471
3472 match instance {
3473 Instance::MainOrAdapter(which) => resolve(which)?,
3474 Instance::Items(items) => {
3475 for item in items {
3476 resolve(&item.which)?;
3477 }
3478 }
3479 }
3480 }
3481 }
3482 self.adapters.insert(
3483 name.to_string(),
3484 Adapter {
3485 wasm: wasm.to_vec(),
3486 metadata: adapter_metadata,
3487 required_exports: exports,
3488 library_info,
3489 },
3490 );
3491 Ok(self)
3492 }
3493
3494 pub fn realloc_via_memory_grow(&mut self, value: bool) -> &mut Self {
3505 self.realloc_via_memory_grow = value;
3506 self
3507 }
3508
3509 pub fn import_name_map(&mut self, map: HashMap<String, String>) -> &mut Self {
3520 self.import_name_map = map;
3521 self
3522 }
3523
3524 pub fn encode(&mut self) -> Result<Vec<u8>> {
3526 self.encode_with_fixups(None)
3527 }
3528
3529 pub(crate) fn encode_with_fixups(
3530 &mut self,
3531 fixup_hook: Option<&mut dyn FnMut(&mut fixup::FixupModule) -> Result<()>>,
3532 ) -> Result<Vec<u8>> {
3533 if self.module.is_empty() {
3534 bail!("a module is required when encoding a component");
3535 }
3536
3537 if self.merge_imports_based_on_semver.unwrap_or(true) {
3538 self.metadata
3539 .resolve
3540 .merge_world_imports_based_on_semver(self.metadata.world)?;
3541 }
3542
3543 if self.emit_canonical_names {
3544 check_duplicate_canonical_names(&self.metadata.resolve, self.metadata.world)?;
3545 }
3546
3547 self.finalize_resolve_with_nominal_ids();
3548
3549 let world = ComponentWorld::new(self).context("failed to decode world from module")?;
3550 let mut state = EncodingState {
3551 component: ComponentBuilder::default(),
3552 module_index: None,
3553 instance_index: None,
3554 memory_index: None,
3555 shim_instance_index: None,
3556 adapter_modules: IndexMap::new(),
3557 adapter_instances: IndexMap::new(),
3558 type_encoding_maps: Default::default(),
3559 instances: Default::default(),
3560 imported_funcs: Default::default(),
3561 aliased_core_items: Default::default(),
3562 info: &world,
3563 export_task_initialization_wrappers: HashMap::new(),
3564 };
3565 state.encode_imports(&self.import_name_map)?;
3566 state.encode_core_modules();
3567 state.encode_core_instantiation(fixup_hook)?;
3568 state.encode_exports(CustomModule::Main)?;
3569 for name in self.adapters.keys() {
3570 state.encode_exports(CustomModule::Adapter(name))?;
3571 }
3572 state.component.append_names();
3573 state
3574 .component
3575 .raw_custom_section(&crate::base_producers().raw_custom_section());
3576 let bytes = state.component.finish();
3577
3578 if self.validate {
3579 Validator::new_with_features(WasmFeatures::all())
3580 .validate_all(&bytes)
3581 .context("failed to validate component output")?;
3582 }
3583
3584 Ok(bytes)
3585 }
3586
3587 fn finalize_resolve_with_nominal_ids(&mut self) {
3596 let world = &self.metadata.resolve.worlds[self.metadata.world];
3603 let main_module_exports = self
3604 .main_module_exports
3605 .iter()
3606 .map(|i| world.exports.get_index_of(i).unwrap())
3607 .collect::<Vec<_>>();
3608 let adapter_exports = self
3609 .adapters
3610 .values()
3611 .map(|adapter| {
3612 adapter
3613 .required_exports
3614 .iter()
3615 .map(|i| world.exports.get_index_of(i).unwrap())
3616 .collect::<Vec<_>>()
3617 })
3618 .collect::<Vec<_>>();
3619
3620 self.metadata
3624 .resolve
3625 .generate_nominal_type_ids(self.metadata.world);
3626
3627 self.main_module_exports.clear();
3630 let world = &self.metadata.resolve.worlds[self.metadata.world];
3631 for index in main_module_exports {
3632 let (key, _) = world.exports.get_index(index).unwrap();
3633 self.main_module_exports.insert(key.clone());
3634 }
3635 for (exports, adapter) in adapter_exports.into_iter().zip(self.adapters.values_mut()) {
3636 adapter.required_exports.clear();
3637 for index in exports {
3638 let (key, _) = world.exports.get_index(index).unwrap();
3639 adapter.required_exports.insert(key.clone());
3640 }
3641 }
3642 }
3643}
3644
3645impl ComponentWorld<'_> {
3646 fn imports_for(&self, module: CustomModule) -> &ImportMap {
3648 match module {
3649 CustomModule::Main => &self.info.imports,
3650 CustomModule::Adapter(name) => &self.adapters[name].info.imports,
3651 }
3652 }
3653
3654 fn exports_for(&self, module: CustomModule) -> &ExportMap {
3656 match module {
3657 CustomModule::Main => &self.info.exports,
3658 CustomModule::Adapter(name) => &self.adapters[name].info.exports,
3659 }
3660 }
3661
3662 fn module_metadata_for(&self, module: CustomModule) -> &ModuleMetadata {
3664 match module {
3665 CustomModule::Main => &self.encoder.metadata.metadata,
3666 CustomModule::Adapter(name) => &self.encoder.adapters[name].metadata,
3667 }
3668 }
3669}
3670
3671pub(crate) fn check_duplicate_canonical_names(resolve: &Resolve, world: WorldId) -> Result<()> {
3674 let world = &resolve.worlds[world];
3675 let mut names = HashMap::new();
3676 for key in world.imports.keys() {
3677 let WorldKey::Interface(id) = key else {
3678 continue;
3679 };
3680 let canonical = resolve.canonicalized_id_of(*id).unwrap();
3681 if let Some(prev) = names.insert(canonical.clone(), *id) {
3682 bail!(
3683 "import `{}` and import `{}` both have the canonical name \
3684 `{canonical}`; semver-compatible imports must be merged \
3685 before emitting canonical names",
3686 resolve.id_of(prev).unwrap(),
3687 resolve.id_of(*id).unwrap(),
3688 );
3689 }
3690 }
3691 names.clear();
3692 for key in world.exports.keys() {
3693 let WorldKey::Interface(id) = key else {
3694 continue;
3695 };
3696 let canonical = resolve.canonicalized_id_of(*id).unwrap();
3697 if let Some(prev) = names.insert(canonical.clone(), *id) {
3698 bail!(
3699 "export `{}` and export `{}` both have the canonical name \
3700 `{canonical}`; semver-compatible versions of the same \
3701 interface cannot both be exported when emitting canonical \
3702 names",
3703 resolve.id_of(prev).unwrap(),
3704 resolve.id_of(*id).unwrap(),
3705 );
3706 }
3707 }
3708 Ok(())
3709}
3710
3711#[cfg(all(test, feature = "dummy-module"))]
3712mod test {
3713 use super::*;
3714 use crate::{dummy_module, embed_component_metadata};
3715 use wit_parser::ManglingAndAbi;
3716
3717 #[test]
3718 fn it_renames_imports() {
3719 let mut resolve = Resolve::new();
3720 let pkg = resolve
3721 .push_str(
3722 "test.wit",
3723 r#"
3724package test:wit;
3725
3726interface i {
3727 f: func();
3728}
3729
3730world test {
3731 import i;
3732 import foo: interface {
3733 f: func();
3734 }
3735}
3736"#,
3737 )
3738 .unwrap();
3739 let world = resolve.select_world(&[pkg], None).unwrap();
3740
3741 let mut module = dummy_module(&resolve, world, ManglingAndAbi::Standard32);
3742
3743 embed_component_metadata(&mut module, &resolve, world, StringEncoding::UTF8, true).unwrap();
3744
3745 let encoded = ComponentEncoder::default()
3746 .import_name_map(HashMap::from([
3747 ("foo".to_string(), "foo:bar/foo@1.0.0".to_string()),
3748 ("test:wit/i".to_string(), "foo:bar/i@1.2.3".to_string()),
3749 ]))
3750 .module(&module)
3751 .unwrap()
3752 .validate(true)
3753 .encode()
3754 .unwrap();
3755
3756 let wat = wasmprinter::print_bytes(encoded).unwrap();
3757 assert!(wat.contains("(import \"foo:bar/foo@1.0.0\""));
3758 assert!(wat.contains("(import \"foo:bar/i@1.2.3\""));
3759 assert!(!wat.contains("(import \"foo\""));
3760 assert!(!wat.contains("(import \"test:wit/i\""));
3761 }
3762}