1use crate::encoding::{Instance, Item, LibraryInfo, MainOrAdapter, ModuleImportMap};
2use crate::{ComponentEncoder, StringEncoding};
3use anyhow::{Context, Result, anyhow, bail};
4use indexmap::{IndexMap, IndexSet, map::Entry};
5use std::fmt;
6use std::hash::Hash;
7use std::mem;
8use wasm_encoder::ExportKind;
9use wasmparser::names::{ComponentName, ComponentNameKind};
10use wasmparser::{
11 Encoding, ExternalKind, FuncType, MemoryType, Parser, Payload, TypeRef, ValType, ValidPayload,
12 Validator, WasmFeatures, types::TypesRef,
13};
14use wit_parser::{
15 Function, InterfaceId, PackageName, Resolve, Type, TypeDefKind, TypeId, World, WorldId,
16 WorldItem, WorldKey,
17 abi::{AbiVariant, WasmSignature, WasmType},
18};
19
20fn wasm_sig_to_func_type(signature: WasmSignature) -> FuncType {
21 fn from_wasm_type(ty: &WasmType) -> ValType {
22 match ty {
23 WasmType::I32 => ValType::I32,
24 WasmType::I64 => ValType::I64,
25 WasmType::F32 => ValType::F32,
26 WasmType::F64 => ValType::F64,
27 WasmType::Pointer => ValType::I32,
28 WasmType::PointerOrI64 => ValType::I64,
29 WasmType::Length => ValType::I32,
30 }
31 }
32
33 FuncType::new(
34 signature.params.iter().map(from_wasm_type),
35 signature.results.iter().map(from_wasm_type),
36 )
37}
38
39#[derive(Default)]
47pub struct ValidatedModule {
48 pub imports: ImportMap,
50
51 pub exports: ExportMap,
53}
54
55impl ValidatedModule {
56 fn new(
57 encoder: &ComponentEncoder,
58 bytes: &[u8],
59 exports: &IndexSet<WorldKey>,
60 import_map: Option<&ModuleImportMap>,
61 info: Option<&LibraryInfo>,
62 ) -> Result<ValidatedModule> {
63 let mut validator = Validator::new_with_features(WasmFeatures::all());
64 let mut ret = ValidatedModule::default();
65
66 for payload in Parser::new(0).parse_all(bytes) {
67 let payload = payload?;
68 if let ValidPayload::End(_) = validator.payload(&payload)? {
69 break;
70 }
71
72 let types = validator.types(0).unwrap();
73
74 match payload {
75 Payload::Version { encoding, .. } if encoding != Encoding::Module => {
76 bail!("data is not a WebAssembly module");
77 }
78 Payload::ImportSection(s) => {
79 for import in s.into_imports() {
80 let import = import?;
81 ret.imports.add(import, encoder, import_map, info, types)?;
82 }
83 }
84 Payload::ExportSection(s) => {
85 for export in s {
86 let export = export?;
87 ret.exports.add(export, encoder, &exports, types)?;
88 }
89 }
90 _ => continue,
91 }
92 }
93
94 ret.exports.validate(encoder, exports)?;
95
96 Ok(ret)
97 }
98}
99
100#[derive(Default)]
106pub struct ImportMap {
107 names: IndexMap<String, ImportInstance>,
111
112 imported_memory: Option<MemoryType>,
114}
115
116pub enum ImportInstance {
117 Whole(MainOrAdapter),
120
121 Names(IndexMap<String, Import>),
123}
124
125#[derive(Debug, Eq, PartialEq, Clone, Hash)]
142pub struct PayloadInfo {
143 pub name: String,
146 pub ty: PayloadType,
151 pub key: WorldKey,
153 pub interface: Option<InterfaceId>,
155 pub imported: bool,
160}
161
162#[derive(Debug, Eq, PartialEq, Clone, Hash)]
164pub enum PayloadType {
165 Type {
168 id: TypeId,
169 function: String,
172 },
173 UnitFuture,
175 UnitStream,
177}
178
179impl PayloadInfo {
180 pub fn payload(&self, resolve: &Resolve) -> Option<Type> {
182 let id = match self.ty {
183 PayloadType::Type { id, .. } => id,
184 PayloadType::UnitFuture | PayloadType::UnitStream => return None,
185 };
186 match resolve.types[id].kind {
187 TypeDefKind::Future(payload) | TypeDefKind::Stream(payload) => payload,
188 _ => unreachable!(),
189 }
190 }
191}
192
193#[derive(Debug, Clone)]
200pub enum Import {
201 WorldFunc(WorldKey, String, AbiVariant),
204
205 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
211
212 ImportedResourceDrop(WorldKey, Option<InterfaceId>, TypeId),
218
219 ExportedResourceDrop(WorldKey, TypeId),
225
226 ExportedResourceNew(WorldKey, TypeId),
232
233 ExportedResourceRep(WorldKey, TypeId),
239
240 AdapterExport {
246 adapter: String,
247 func: String,
248 ty: FuncType,
249 },
250
251 MainModuleMemory(MemoryType),
255
256 MainModuleExport { name: String, kind: ExportKind },
258
259 Item(Item),
265
266 ExportedTaskReturn(WorldKey, Option<InterfaceId>, Function),
275
276 ExportedTaskCancel,
280
281 ContextGet {
283 ty: ValType,
285 slot: u32,
287 },
288 ContextSet {
290 ty: ValType,
292 slot: u32,
294 },
295
296 TlsBaseGet {
304 ty: ValType,
306 },
307
308 TlsBaseSet {
310 ty: ValType,
312 },
313
314 BackpressureInc,
316
317 BackpressureDec,
319
320 WaitableSetNew,
322
323 WaitableSetWait,
329
330 WaitableSetPoll,
336
337 WaitableSetDrop,
339
340 WaitableJoin,
342
343 SubtaskDrop,
347
348 SubtaskCancel { async_: bool },
352
353 StreamNew(PayloadInfo),
357
358 StreamRead { async_: bool, info: PayloadInfo },
363
364 StreamWrite { async_: bool, info: PayloadInfo },
369
370 StreamCancelRead { info: PayloadInfo, async_: bool },
375
376 StreamCancelWrite { info: PayloadInfo, async_: bool },
381
382 StreamDropReadable(PayloadInfo),
386
387 StreamDropWritable(PayloadInfo),
391
392 FutureNew(PayloadInfo),
396
397 FutureRead { async_: bool, info: PayloadInfo },
402
403 FutureWrite { async_: bool, info: PayloadInfo },
407
408 FutureCancelRead { info: PayloadInfo, async_: bool },
413
414 FutureCancelWrite { info: PayloadInfo, async_: bool },
419
420 FutureDropReadable(PayloadInfo),
424
425 FutureDropWritable(PayloadInfo),
429
430 ErrorContextNew { encoding: StringEncoding },
435
436 ErrorContextDebugMessage { encoding: StringEncoding },
442
443 ErrorContextDrop,
448
449 ThreadIndex,
453
454 ThreadNewIndirect,
458
459 ThreadResumeLater,
461
462 ThreadSuspend,
464
465 ThreadYield,
467
468 ThreadSuspendThenResume,
470
471 ThreadYieldThenResume,
473
474 ThreadSuspendThenPromote,
476
477 ThreadYieldThenPromote,
479}
480
481impl ImportMap {
482 pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
484 let names = match self.names.get(name) {
485 Some(ImportInstance::Names(names)) => names,
486 _ => return IndexMap::new(),
487 };
488 names
489 .iter()
490 .map(|(_, import)| match import {
491 Import::AdapterExport { ty, func, adapter } => {
492 assert_eq!(adapter, name);
493 (func.clone(), ty.clone())
494 }
495 _ => unreachable!(),
496 })
497 .collect()
498 }
499
500 pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
504 self.names
505 .iter()
506 .filter_map(|(module, m)| match m {
507 ImportInstance::Names(names) => Some((module, names)),
508 ImportInstance::Whole(_) => None,
509 })
510 .flat_map(|(module, m)| {
511 m.iter()
512 .map(move |(field, import)| (module.as_str(), field.as_str(), import))
513 })
514 }
515
516 pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
518 &self.names
519 }
520
521 pub fn imported_memory(&self) -> Option<MemoryType> {
523 self.imported_memory
524 }
525
526 fn add(
529 &mut self,
530 import: wasmparser::Import<'_>,
531 encoder: &ComponentEncoder,
532 import_map: Option<&ModuleImportMap>,
533 library_info: Option<&LibraryInfo>,
534 types: TypesRef<'_>,
535 ) -> Result<()> {
536 if self.classify_import_with_library(import, library_info)? {
537 return Ok(());
538 }
539 let mut import_to_classify = import;
540 if let Some(map) = import_map {
541 if let Some(original_name) = map.original_name(&import) {
542 import_to_classify.name = original_name;
543 }
544 }
545 let item = self
546 .classify(import_to_classify, encoder, types)
547 .with_context(|| {
548 format!(
549 "failed to resolve import `{}::{}`",
550 import.module, import.name,
551 )
552 })?;
553 self.insert_import(import, item)
554 }
555
556 fn classify(
562 &self,
563 import: wasmparser::Import<'_>,
564 encoder: &ComponentEncoder,
565 types: TypesRef<'_>,
566 ) -> Result<Import> {
567 if import.module == "env" && import.name == "memory" {
570 if let TypeRef::Memory(ty) = import.ty {
571 return Ok(Import::MainModuleMemory(ty));
572 }
573 }
574
575 if import.module == "__main_module__" {
577 return Ok(Import::MainModuleExport {
578 name: import.name.to_string(),
579 kind: match import.ty {
580 TypeRef::Func(_) => ExportKind::Func,
581 TypeRef::Table(_) => ExportKind::Table,
582 TypeRef::Memory(_) => ExportKind::Memory,
583 TypeRef::Global(_) => ExportKind::Global,
584 TypeRef::Tag(_) => ExportKind::Tag,
585 TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
586 },
587 });
588 }
589
590 let ty_index = match import.ty {
591 TypeRef::Func(ty) => ty,
592 _ => bail!("module is only allowed to import functions"),
593 };
594 let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
595
596 if encoder.adapters.contains_key(import.module) {
599 return Ok(Import::AdapterExport {
600 adapter: import.module.to_string(),
601 func: import.name.to_string(),
602 ty: ty.clone(),
603 });
604 }
605
606 let (module, names) = match import.module.strip_prefix("cm32p2") {
607 Some(suffix) => (suffix, STANDARD),
608 None if encoder.reject_legacy_names => (import.module, STANDARD),
609 None => (import.module, LEGACY),
610 };
611 self.classify_component_model_import(module, import.name, encoder, ty, names)
612 }
613
614 fn classify_component_model_import(
617 &self,
618 module: &str,
619 name: &str,
620 encoder: &ComponentEncoder,
621 ty: &FuncType,
622 names: &dyn NameMangling,
623 ) -> Result<Import> {
624 let resolve = &encoder.metadata.resolve;
625 let world_id = encoder.metadata.world;
626 let world = &resolve.worlds[world_id];
627
628 if module == names.import_root() {
629 if names.error_context_drop(name) {
630 let expected = FuncType::new([ValType::I32], []);
631 validate_func_sig(name, &expected, ty)?;
632 return Ok(Import::ErrorContextDrop);
633 }
634
635 if names.backpressure_inc(name) {
636 let expected = FuncType::new([], []);
637 validate_func_sig(name, &expected, ty)?;
638 return Ok(Import::BackpressureInc);
639 }
640
641 if names.backpressure_dec(name) {
642 let expected = FuncType::new([], []);
643 validate_func_sig(name, &expected, ty)?;
644 return Ok(Import::BackpressureDec);
645 }
646
647 if names.waitable_set_new(name) {
648 let expected = FuncType::new([], [ValType::I32]);
649 validate_func_sig(name, &expected, ty)?;
650 return Ok(Import::WaitableSetNew);
651 }
652
653 if let Some(result_ty) = names.waitable_set_wait(name) {
654 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
655 validate_func_sig(name, &expected, ty)?;
656 return Ok(Import::WaitableSetWait);
657 }
658
659 if let Some(result_ty) = names.waitable_set_poll(name) {
660 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
661 validate_func_sig(name, &expected, ty)?;
662 return Ok(Import::WaitableSetPoll);
663 }
664
665 if names.waitable_set_drop(name) {
666 let expected = FuncType::new([ValType::I32], []);
667 validate_func_sig(name, &expected, ty)?;
668 return Ok(Import::WaitableSetDrop);
669 }
670
671 if names.waitable_join(name) {
672 let expected = FuncType::new([ValType::I32; 2], []);
673 validate_func_sig(name, &expected, ty)?;
674 return Ok(Import::WaitableJoin);
675 }
676
677 if names.subtask_drop(name) {
678 let expected = FuncType::new([ValType::I32], []);
679 validate_func_sig(name, &expected, ty)?;
680 return Ok(Import::SubtaskDrop);
681 }
682
683 if let Some(info) = names.subtask_cancel(name) {
684 let expected = FuncType::new([ValType::I32], [ValType::I32]);
685 validate_func_sig(name, &expected, ty)?;
686 return Ok(Import::SubtaskCancel {
687 async_: info.async_lowered,
688 });
689 }
690
691 if let Some(encoding) = names.error_context_new(name) {
692 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
693 validate_func_sig(name, &expected, ty)?;
694 return Ok(Import::ErrorContextNew { encoding });
695 }
696
697 if let Some(encoding) = names.error_context_debug_message(name) {
698 let expected = FuncType::new([ValType::I32; 2], []);
699 validate_func_sig(name, &expected, ty)?;
700 return Ok(Import::ErrorContextDebugMessage { encoding });
701 }
702
703 if let Some((slot_ty, slot)) = names.context_get(name) {
704 let expected = FuncType::new([], [slot_ty]);
705 validate_func_sig(name, &expected, ty)?;
706 return Ok(Import::ContextGet { ty: slot_ty, slot });
707 }
708 if let Some((slot_ty, slot)) = names.context_set(name) {
709 let expected = FuncType::new([slot_ty], []);
710 validate_func_sig(name, &expected, ty)?;
711 return Ok(Import::ContextSet { ty: slot_ty, slot });
712 }
713 if names.thread_index(name) {
714 let expected = FuncType::new([], [ValType::I32]);
715 validate_func_sig(name, &expected, ty)?;
716 return Ok(Import::ThreadIndex);
717 }
718 if names.thread_new_indirect(name) {
719 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
720 validate_func_sig(name, &expected, ty)?;
721 return Ok(Import::ThreadNewIndirect);
722 }
723 if names.thread_resume_later(name) {
724 let expected = FuncType::new([ValType::I32], []);
725 validate_func_sig(name, &expected, ty)?;
726 return Ok(Import::ThreadResumeLater);
727 }
728 if names.thread_suspend(name) {
729 let expected = FuncType::new([], [ValType::I32]);
730 validate_func_sig(name, &expected, ty)?;
731 return Ok(Import::ThreadSuspend);
732 }
733 if names.thread_yield(name) {
734 let expected = FuncType::new([], [ValType::I32]);
735 validate_func_sig(name, &expected, ty)?;
736 return Ok(Import::ThreadYield);
737 }
738 if names.thread_suspend_then_resume(name) {
739 let expected = FuncType::new([ValType::I32], [ValType::I32]);
740 validate_func_sig(name, &expected, ty)?;
741 return Ok(Import::ThreadSuspendThenResume);
742 }
743 if names.thread_yield_then_resume(name) {
744 let expected = FuncType::new([ValType::I32], [ValType::I32]);
745 validate_func_sig(name, &expected, ty)?;
746 return Ok(Import::ThreadYieldThenResume);
747 }
748 if names.thread_suspend_then_promote(name) {
749 let expected = FuncType::new([ValType::I32], [ValType::I32]);
750 validate_func_sig(name, &expected, ty)?;
751 return Ok(Import::ThreadSuspendThenPromote);
752 }
753 if names.thread_yield_then_promote(name) {
754 let expected = FuncType::new([ValType::I32], [ValType::I32]);
755 validate_func_sig(name, &expected, ty)?;
756 return Ok(Import::ThreadYieldThenPromote);
757 }
758
759 let (key_name, abi) = names.world_key_name_and_abi(name);
760 let key = WorldKey::Name(key_name.to_string());
761 if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
762 validate_func(resolve, ty, func, abi)?;
763 return Ok(Import::WorldFunc(key, func.name.clone(), abi));
764 }
765
766 if let Some(import) =
767 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
768 {
769 return Ok(import);
770 }
771
772 match world.imports.get(&key) {
773 Some(_) => bail!("expected world top-level import `{name}` to be a function"),
774 None => bail!("no top-level imported function `{name}` specified"),
775 }
776 }
777
778 if module == "env" {
779 if let Some(import) = names.env_import(name, ty) {
780 return Ok(import);
781 }
782 }
783
784 if matches!(
786 module.strip_prefix(names.import_exported_intrinsic_prefix()),
787 Some(module) if module == names.import_root()
788 ) {
789 if let Some(import) =
790 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
791 {
792 return Ok(import);
793 }
794 }
795
796 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
797 Some(name) => name,
798 None => bail!("unknown or invalid component model import syntax"),
799 };
800
801 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
802 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
803
804 if let Some(import) =
805 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
806 {
807 return Ok(import);
808 }
809 bail!("unknown function `{name}`")
810 }
811
812 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
813 let interface = &resolve.interfaces[id];
814 let (function_name, abi) = names.interface_function_name_and_abi(name);
815 if let Some(f) = interface.functions.get(function_name) {
816 validate_func(resolve, ty, f, abi).with_context(|| {
817 let name = resolve.name_world_key(&key);
818 format!("failed to validate import interface `{name}`")
819 })?;
820 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
821 }
822
823 if let Some(import) =
824 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
825 {
826 return Ok(import);
827 }
828 bail!(
829 "import interface `{module}` is missing function \
830 `{name}` that is required by the module",
831 )
832 }
833
834 fn maybe_classify_wit_intrinsic(
862 &self,
863 name: &str,
864 key_and_id: Option<(WorldKey, InterfaceId)>,
865 encoder: &ComponentEncoder,
866 ty: &FuncType,
867 import: bool,
868 names: &dyn NameMangling,
869 ) -> Result<Option<Import>> {
870 let resolve = &encoder.metadata.resolve;
871 let world_id = encoder.metadata.world;
872 let world = &resolve.worlds[world_id];
873
874 let (key, id) = match key_and_id {
879 Some((key, id)) => (Some(key), Some(id)),
880 None => (None, None),
881 };
882
883 let resource_test = |name: &str| match id {
885 Some(id) => resource_test_for_interface(resolve, id)(name),
886 None => resource_test_for_world(resolve, world_id)(name),
887 };
888
889 if let Some(resource) = names.resource_drop_name(name) {
891 if let Some(resource_id) = resource_test(resource) {
892 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
893 let expected = FuncType::new([ValType::I32], []);
894 validate_func_sig(name, &expected, ty)?;
895 return Ok(Some(if import {
896 Import::ImportedResourceDrop(key, id, resource_id)
897 } else {
898 Import::ExportedResourceDrop(key, resource_id)
899 }));
900 }
901 }
902
903 if !import {
906 if let Some(name) = names.resource_new_name(name) {
907 if let Some(id) = resource_test(name) {
908 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
909 let expected = FuncType::new([ValType::I32], [ValType::I32]);
910 validate_func_sig(name, &expected, ty)?;
911 return Ok(Some(Import::ExportedResourceNew(key, id)));
912 }
913 }
914 if let Some(name) = names.resource_rep_name(name) {
915 if let Some(id) = resource_test(name) {
916 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
917 let expected = FuncType::new([ValType::I32], [ValType::I32]);
918 validate_func_sig(name, &expected, ty)?;
919 return Ok(Some(Import::ExportedResourceRep(key, id)));
920 }
921 }
922 if let Some(name) = names.task_return_name(name) {
923 let func = get_function(resolve, world, name, id, import)?;
924 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
925 return Ok(Some(Import::ExportedTaskReturn(key, id, func.clone())));
928 }
929 if names.task_cancel(name) {
930 let expected = FuncType::new([], []);
931 validate_func_sig(name, &expected, ty)?;
932 return Ok(Some(Import::ExportedTaskCancel));
933 }
934 }
935
936 let lookup_context = PayloadLookupContext {
937 resolve,
938 world,
939 key,
940 id,
941 import,
942 };
943
944 let import = if let Some(info) = names.future_new(&lookup_context, name) {
948 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
949 Import::FutureNew(info)
950 } else if let Some(info) = names.future_write(&lookup_context, name) {
951 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
952 Import::FutureWrite {
953 async_: info.async_lowered,
954 info: info.inner,
955 }
956 } else if let Some(info) = names.future_read(&lookup_context, name) {
957 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
958 Import::FutureRead {
959 async_: info.async_lowered,
960 info: info.inner,
961 }
962 } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
963 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
964 Import::FutureCancelWrite {
965 async_: info.async_lowered,
966 info: info.inner,
967 }
968 } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
969 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
970 Import::FutureCancelRead {
971 async_: info.async_lowered,
972 info: info.inner,
973 }
974 } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
975 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
976 Import::FutureDropWritable(info)
977 } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
978 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
979 Import::FutureDropReadable(info)
980 } else if let Some(info) = names.stream_new(&lookup_context, name) {
981 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
982 Import::StreamNew(info)
983 } else if let Some(info) = names.stream_write(&lookup_context, name) {
984 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
985 Import::StreamWrite {
986 async_: info.async_lowered,
987 info: info.inner,
988 }
989 } else if let Some(info) = names.stream_read(&lookup_context, name) {
990 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
991 Import::StreamRead {
992 async_: info.async_lowered,
993 info: info.inner,
994 }
995 } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
996 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
997 Import::StreamCancelWrite {
998 async_: info.async_lowered,
999 info: info.inner,
1000 }
1001 } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
1002 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
1003 Import::StreamCancelRead {
1004 async_: info.async_lowered,
1005 info: info.inner,
1006 }
1007 } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
1008 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1009 Import::StreamDropWritable(info)
1010 } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
1011 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1012 Import::StreamDropReadable(info)
1013 } else {
1014 return Ok(None);
1015 };
1016 Ok(Some(import))
1017 }
1018
1019 fn classify_import_with_library(
1020 &mut self,
1021 import: wasmparser::Import<'_>,
1022 library_info: Option<&LibraryInfo>,
1023 ) -> Result<bool> {
1024 let info = match library_info {
1025 Some(info) => info,
1026 None => return Ok(false),
1027 };
1028 let Some((_, instance)) = info
1029 .arguments
1030 .iter()
1031 .find(|(name, _items)| *name == import.module)
1032 else {
1033 return Ok(false);
1034 };
1035 match instance {
1036 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1037 Some(ImportInstance::Whole(which)) => {
1038 if which != module {
1039 bail!("different whole modules imported under the same name");
1040 }
1041 }
1042 Some(ImportInstance::Names(_)) => {
1043 bail!("cannot mix individual imports and whole module imports")
1044 }
1045 None => {
1046 let instance = ImportInstance::Whole(module.clone());
1047 self.names.insert(import.module.to_string(), instance);
1048 }
1049 },
1050 Instance::Items(items) => {
1051 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1052 return Ok(false);
1053 };
1054 self.insert_import(import, Import::Item(item.clone()))?;
1055 }
1056 }
1057 Ok(true)
1058 }
1059
1060 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1064 if let Import::MainModuleMemory(ty) = item {
1065 if self.imported_memory.is_some() {
1066 bail!("module has multiple imports for memory");
1067 }
1068 self.imported_memory = Some(ty);
1069 }
1070 let entry = self
1071 .names
1072 .entry(import.module.to_string())
1073 .or_insert(ImportInstance::Names(IndexMap::default()));
1074 let names = match entry {
1075 ImportInstance::Names(names) => names,
1076 _ => bail!("cannot mix individual imports with module imports"),
1077 };
1078 let entry = match names.entry(import.name.to_string()) {
1079 Entry::Occupied(_) => {
1080 bail!(
1081 "module has duplicate import for `{}::{}`",
1082 import.module,
1083 import.name
1084 );
1085 }
1086 Entry::Vacant(v) => v,
1087 };
1088 log::trace!(
1089 "classifying import `{}::{} as {item:?}",
1090 import.module,
1091 import.name
1092 );
1093 entry.insert(item);
1094 Ok(())
1095 }
1096}
1097
1098#[derive(Default)]
1101pub struct ExportMap {
1102 names: IndexMap<String, Export>,
1103 raw_exports: IndexMap<String, FuncType>,
1104}
1105
1106#[derive(Debug)]
1109pub enum Export {
1110 WorldFunc(WorldKey, String, AbiVariant),
1113
1114 WorldFuncPostReturn(WorldKey),
1116
1117 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1119
1120 InterfaceFuncPostReturn(WorldKey, String),
1122
1123 ResourceDtor(TypeId),
1125
1126 Memory,
1128
1129 GeneralPurposeRealloc,
1131
1132 GeneralPurposeExportRealloc,
1134
1135 GeneralPurposeImportRealloc,
1137
1138 Initialize,
1140
1141 ReallocForAdapter,
1143
1144 WorldFuncCallback(WorldKey),
1145
1146 InterfaceFuncCallback(WorldKey, String),
1147
1148 IndirectFunctionTable,
1150
1151 WasmTaskHook,
1153}
1154
1155impl ExportMap {
1156 fn add(
1157 &mut self,
1158 export: wasmparser::Export<'_>,
1159 encoder: &ComponentEncoder,
1160 exports: &IndexSet<WorldKey>,
1161 types: TypesRef<'_>,
1162 ) -> Result<()> {
1163 if let Some(item) = self.classify(export, encoder, exports, types)? {
1164 log::debug!("classifying export `{}` as {item:?}", export.name);
1165 let prev = self.names.insert(export.name.to_string(), item);
1166 assert!(prev.is_none());
1167 }
1168 Ok(())
1169 }
1170
1171 fn classify(
1172 &mut self,
1173 export: wasmparser::Export<'_>,
1174 encoder: &ComponentEncoder,
1175 exports: &IndexSet<WorldKey>,
1176 types: TypesRef<'_>,
1177 ) -> Result<Option<Export>> {
1178 match export.kind {
1179 ExternalKind::Func => {
1180 let ty = types[types.core_function_at(export.index)].unwrap_func();
1181 self.raw_exports.insert(export.name.to_string(), ty.clone());
1182 }
1183 _ => {}
1184 }
1185
1186 if export.name == "canonical_abi_realloc" {
1188 return Ok(Some(Export::GeneralPurposeRealloc));
1189 } else if export.name == "cabi_import_realloc" {
1190 return Ok(Some(Export::GeneralPurposeImportRealloc));
1191 } else if export.name == "cabi_export_realloc" {
1192 return Ok(Some(Export::GeneralPurposeExportRealloc));
1193 } else if export.name == "cabi_realloc_adapter" {
1194 return Ok(Some(Export::ReallocForAdapter));
1195 }
1196
1197 let (name, names) = match export.name.strip_prefix("cm32p2") {
1198 Some(name) => (name, STANDARD),
1199 None if encoder.reject_legacy_names => return Ok(None),
1200 None => (export.name, LEGACY),
1201 };
1202
1203 if let Some(export) = self
1204 .classify_component_export(names, name, &export, encoder, exports, types)
1205 .with_context(|| format!("failed to classify export `{}`", export.name))?
1206 {
1207 return Ok(Some(export));
1208 }
1209 log::debug!("unknown export `{}`", export.name);
1210 Ok(None)
1211 }
1212
1213 fn classify_component_export(
1214 &mut self,
1215 names: &dyn NameMangling,
1216 name: &str,
1217 export: &wasmparser::Export<'_>,
1218 encoder: &ComponentEncoder,
1219 exports: &IndexSet<WorldKey>,
1220 types: TypesRef<'_>,
1221 ) -> Result<Option<Export>> {
1222 let resolve = &encoder.metadata.resolve;
1223 let world = encoder.metadata.world;
1224 match export.kind {
1225 ExternalKind::Func => {}
1226 ExternalKind::Memory => {
1227 if name == names.export_memory() {
1228 return Ok(Some(Export::Memory));
1229 }
1230 return Ok(None);
1231 }
1232 ExternalKind::Table => {
1233 if Some(name) == names.export_indirect_function_table() {
1234 return Ok(Some(Export::IndirectFunctionTable));
1235 }
1236 return Ok(None);
1237 }
1238 _ => return Ok(None),
1239 }
1240 let ty = types[types.core_function_at(export.index)].unwrap_func();
1241
1242 if name == names.export_realloc() {
1244 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1245 validate_func_sig(name, &expected, ty)?;
1246 return Ok(Some(Export::GeneralPurposeRealloc));
1247 } else if name == names.export_initialize() {
1248 let expected = FuncType::new([], []);
1249 validate_func_sig(name, &expected, ty)?;
1250 return Ok(Some(Export::Initialize));
1251 } else if Some(name) == names.export_wasm_task_hook() {
1252 let expected = FuncType::new([ValType::I32], []);
1253 validate_func_sig(name, &expected, ty)?;
1254 return Ok(Some(Export::WasmTaskHook));
1255 }
1256
1257 let full_name = name;
1258 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1259 (AbiVariant::GuestExportAsync, name)
1260 } else if let Some(name) = names.async_lift_stackful_name(name) {
1261 (AbiVariant::GuestExportAsyncStackful, name)
1262 } else {
1263 (AbiVariant::GuestExport, name)
1264 };
1265
1266 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1268 validate_func(resolve, ty, f, abi).with_context(|| {
1269 let key = resolve.name_world_key(key);
1270 format!("failed to validate export for `{key}`")
1271 })?;
1272 match id {
1273 Some(id) => {
1274 return Ok(Some(Export::InterfaceFunc(
1275 key.clone(),
1276 id,
1277 f.name.clone(),
1278 abi,
1279 )));
1280 }
1281 None => {
1282 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1283 }
1284 }
1285 }
1286
1287 if let Some(remaining) = names.strip_post_return(name) {
1289 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1290 validate_post_return(resolve, ty, f).with_context(|| {
1291 let key = resolve.name_world_key(key);
1292 format!("failed to validate export for `{key}`")
1293 })?;
1294 match id {
1295 Some(_id) => {
1296 return Ok(Some(Export::InterfaceFuncPostReturn(
1297 key.clone(),
1298 f.name.clone(),
1299 )));
1300 }
1301 None => {
1302 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1303 }
1304 }
1305 }
1306 }
1307
1308 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1309 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1310 validate_func_sig(
1311 full_name,
1312 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1313 ty,
1314 )?;
1315 return Ok(Some(if id.is_some() {
1316 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1317 } else {
1318 Export::WorldFuncCallback(key.clone())
1319 }));
1320 }
1321 }
1322
1323 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1325 let expected = FuncType::new([ValType::I32], []);
1326 validate_func_sig(full_name, &expected, ty)?;
1327 return Ok(Some(Export::ResourceDtor(dtor)));
1328 }
1329
1330 Ok(None)
1331 }
1332
1333 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1336 self.find(|m| match m {
1337 Export::WorldFuncPostReturn(k) => k == key,
1338 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1339 _ => false,
1340 })
1341 }
1342
1343 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1346 self.find(|m| match m {
1347 Export::WorldFuncCallback(k) => k == key,
1348 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1349 _ => false,
1350 })
1351 }
1352
1353 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1354 self.names.values().find_map(|m| match m {
1355 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1356 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1357 _ => None,
1358 })
1359 }
1360
1361 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1364 let _ = (key, func);
1368
1369 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1370 return Some(name);
1371 }
1372 self.general_purpose_realloc()
1373 }
1374
1375 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1378 let _ = (interface, func);
1382
1383 self.import_realloc_fallback()
1384 }
1385
1386 pub fn import_realloc_fallback(&self) -> Option<&str> {
1390 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1391 return Some(name);
1392 }
1393 self.general_purpose_realloc()
1394 }
1395
1396 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1398 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1399 return Some(name);
1400 }
1401 self.general_purpose_realloc()
1402 }
1403
1404 pub fn general_purpose_realloc(&self) -> Option<&str> {
1405 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1406 }
1407
1408 pub fn reallocs(&self) -> impl Iterator<Item = &str> + '_ {
1415 self.names.iter().filter_map(|(name, export)| match export {
1416 Export::GeneralPurposeRealloc
1417 | Export::GeneralPurposeExportRealloc
1418 | Export::GeneralPurposeImportRealloc => Some(name.as_str()),
1419 _ => None,
1420 })
1421 }
1422
1423 pub fn memory(&self) -> Option<&str> {
1425 self.find(|m| matches!(m, Export::Memory))
1426 }
1427
1428 pub fn indirect_function_table(&self) -> Option<&str> {
1430 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1431 }
1432
1433 pub fn wasm_task_hook(&self) -> Option<&str> {
1435 self.find(|t| matches!(t, Export::WasmTaskHook))
1436 }
1437
1438 pub fn initialize(&self) -> Option<&str> {
1440 self.find(|m| matches!(m, Export::Initialize))
1441 }
1442
1443 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1445 self.find(|m| match m {
1446 Export::ResourceDtor(t) => *t == ty,
1447 _ => false,
1448 })
1449 }
1450
1451 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1454 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1455 Some(name)
1456 }
1457
1458 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1460 self.names.iter().map(|(n, e)| (n.as_str(), e))
1461 }
1462
1463 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1464 let resolve = &encoder.metadata.resolve;
1465 let world = encoder.metadata.world;
1466 if self
1469 .names
1470 .values()
1471 .filter(|m| matches!(m, Export::Memory))
1472 .count()
1473 > 1
1474 {
1475 bail!("cannot componentize module that exports multiple memories")
1476 }
1477
1478 for (name, export) in &self.names {
1480 match export {
1481 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1482 if !matches!(
1483 self.names.get(&format!("[callback]{name}")),
1484 Some(Export::WorldFuncCallback(_))
1485 ) {
1486 bail!("missing callback for `{name}`");
1487 }
1488 }
1489 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1490 if !matches!(
1491 self.names.get(&format!("[callback]{name}")),
1492 Some(Export::InterfaceFuncCallback(_, _))
1493 ) {
1494 bail!("missing callback for `{name}`");
1495 }
1496 }
1497 _ => {}
1498 }
1499 }
1500
1501 for export in exports {
1503 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1504 let result = self.find(|e| match e {
1505 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1506 _ => false,
1507 });
1508 if result.is_some() {
1509 Ok(())
1510 } else {
1511 let export = resolve.name_world_key(export);
1512 bail!("failed to find export of interface `{export}` function `{name}`")
1513 }
1514 };
1515 let require_world_func = |name: &str| -> Result<()> {
1516 let result = self.find(|e| match e {
1517 Export::WorldFunc(_, s, _) => name == s,
1518 _ => false,
1519 });
1520 if result.is_some() {
1521 Ok(())
1522 } else {
1523 bail!("failed to find export of function `{name}`")
1524 }
1525 };
1526 match &resolve.worlds[world].exports[export] {
1527 WorldItem::Interface { id, .. } => {
1528 for (name, _) in resolve.interfaces[*id].functions.iter() {
1529 require_interface_func(*id, name)?;
1530 }
1531 }
1532 WorldItem::Function(f) => {
1533 require_world_func(&f.name)?;
1534 }
1535 WorldItem::Type { .. } => unreachable!(),
1536 }
1537 }
1538
1539 Ok(())
1540 }
1541}
1542
1543struct MaybeAsyncLowered<T> {
1545 inner: T,
1546 async_lowered: bool,
1547}
1548
1549struct PayloadLookupContext<'a> {
1552 resolve: &'a Resolve,
1553 world: &'a World,
1554 id: Option<InterfaceId>,
1555 import: bool,
1556 key: Option<WorldKey>,
1557}
1558
1559trait NameMangling {
1581 fn import_root(&self) -> &str;
1582 fn import_non_root_prefix(&self) -> &str;
1583 fn import_exported_intrinsic_prefix(&self) -> &str;
1584 fn export_memory(&self) -> &str;
1585 fn export_initialize(&self) -> &str;
1586 fn export_realloc(&self) -> &str;
1587 fn export_indirect_function_table(&self) -> Option<&str>;
1588 fn export_wasm_task_hook(&self) -> Option<&str>;
1589 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1590 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1591 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1592 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1593 fn task_cancel(&self, name: &str) -> bool;
1594 fn backpressure_inc(&self, name: &str) -> bool;
1595 fn backpressure_dec(&self, name: &str) -> bool;
1596 fn waitable_set_new(&self, name: &str) -> bool;
1597 fn waitable_set_wait(&self, name: &str) -> Option<ValType>;
1598 fn waitable_set_poll(&self, name: &str) -> Option<ValType>;
1599 fn waitable_set_drop(&self, name: &str) -> bool;
1600 fn waitable_join(&self, name: &str) -> bool;
1601 fn subtask_drop(&self, name: &str) -> bool;
1602 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1603 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1604 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1605 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1606 fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1607 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1608 fn error_context_drop(&self, name: &str) -> bool;
1609 fn context_get(&self, name: &str) -> Option<(ValType, u32)>;
1610 fn context_set(&self, name: &str) -> Option<(ValType, u32)>;
1611 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1612 fn future_write(
1613 &self,
1614 lookup_context: &PayloadLookupContext,
1615 name: &str,
1616 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1617 fn future_read(
1618 &self,
1619 lookup_context: &PayloadLookupContext,
1620 name: &str,
1621 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1622 fn future_cancel_write(
1623 &self,
1624 lookup_context: &PayloadLookupContext,
1625 name: &str,
1626 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1627 fn future_cancel_read(
1628 &self,
1629 lookup_context: &PayloadLookupContext,
1630 name: &str,
1631 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1632 fn future_drop_writable(
1633 &self,
1634 lookup_context: &PayloadLookupContext,
1635 name: &str,
1636 ) -> Option<PayloadInfo>;
1637 fn future_drop_readable(
1638 &self,
1639 lookup_context: &PayloadLookupContext,
1640 name: &str,
1641 ) -> Option<PayloadInfo>;
1642 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1643 fn stream_write(
1644 &self,
1645 lookup_context: &PayloadLookupContext,
1646 name: &str,
1647 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1648 fn stream_read(
1649 &self,
1650 lookup_context: &PayloadLookupContext,
1651 name: &str,
1652 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1653 fn stream_cancel_write(
1654 &self,
1655 lookup_context: &PayloadLookupContext,
1656 name: &str,
1657 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1658 fn stream_cancel_read(
1659 &self,
1660 lookup_context: &PayloadLookupContext,
1661 name: &str,
1662 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1663 fn stream_drop_writable(
1664 &self,
1665 lookup_context: &PayloadLookupContext,
1666 name: &str,
1667 ) -> Option<PayloadInfo>;
1668 fn stream_drop_readable(
1669 &self,
1670 lookup_context: &PayloadLookupContext,
1671 name: &str,
1672 ) -> Option<PayloadInfo>;
1673 fn thread_index(&self, name: &str) -> bool;
1674 fn thread_new_indirect(&self, name: &str) -> bool;
1675 fn thread_resume_later(&self, name: &str) -> bool;
1676 fn thread_suspend(&self, name: &str) -> bool;
1677 fn thread_yield(&self, name: &str) -> bool;
1678 fn thread_suspend_then_resume(&self, name: &str) -> bool;
1679 fn thread_yield_then_resume(&self, name: &str) -> bool;
1680 fn thread_suspend_then_promote(&self, name: &str) -> bool;
1681 fn thread_yield_then_promote(&self, name: &str) -> bool;
1682 fn module_to_interface(
1683 &self,
1684 module: &str,
1685 resolve: &Resolve,
1686 items: &IndexMap<WorldKey, WorldItem>,
1687 ) -> Result<(WorldKey, InterfaceId)>;
1688 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1689 fn match_wit_export<'a>(
1690 &self,
1691 export_name: &str,
1692 resolve: &'a Resolve,
1693 world: WorldId,
1694 exports: &'a IndexSet<WorldKey>,
1695 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1696 fn match_wit_resource_dtor<'a>(
1697 &self,
1698 export_name: &str,
1699 resolve: &'a Resolve,
1700 world: WorldId,
1701 exports: &'a IndexSet<WorldKey>,
1702 ) -> Option<TypeId>;
1703 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1704 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1705 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import>;
1706}
1707
1708struct Standard;
1711
1712const STANDARD: &'static dyn NameMangling = &Standard;
1713
1714impl NameMangling for Standard {
1715 fn import_root(&self) -> &str {
1716 ""
1717 }
1718 fn import_non_root_prefix(&self) -> &str {
1719 "|"
1720 }
1721 fn import_exported_intrinsic_prefix(&self) -> &str {
1722 "_ex_"
1723 }
1724 fn export_memory(&self) -> &str {
1725 "_memory"
1726 }
1727 fn export_initialize(&self) -> &str {
1728 "_initialize"
1729 }
1730 fn export_realloc(&self) -> &str {
1731 "_realloc"
1732 }
1733 fn export_indirect_function_table(&self) -> Option<&str> {
1734 None
1735 }
1736 fn export_wasm_task_hook(&self) -> Option<&str> {
1737 None
1738 }
1739 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1740 name.strip_suffix("_drop")
1741 }
1742 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1743 name.strip_suffix("_new")
1744 }
1745 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1746 name.strip_suffix("_rep")
1747 }
1748 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1749 None
1750 }
1751 fn task_cancel(&self, _name: &str) -> bool {
1752 false
1753 }
1754 fn backpressure_inc(&self, _name: &str) -> bool {
1755 false
1756 }
1757 fn backpressure_dec(&self, _name: &str) -> bool {
1758 false
1759 }
1760 fn waitable_set_new(&self, _name: &str) -> bool {
1761 false
1762 }
1763 fn waitable_set_wait(&self, _name: &str) -> Option<ValType> {
1764 None
1765 }
1766 fn waitable_set_poll(&self, _name: &str) -> Option<ValType> {
1767 None
1768 }
1769 fn waitable_set_drop(&self, _name: &str) -> bool {
1770 false
1771 }
1772 fn waitable_join(&self, _name: &str) -> bool {
1773 false
1774 }
1775 fn subtask_drop(&self, _name: &str) -> bool {
1776 false
1777 }
1778 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1779 None
1780 }
1781 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1782 None
1783 }
1784 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1785 None
1786 }
1787 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1788 None
1789 }
1790 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1791 None
1792 }
1793 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1794 None
1795 }
1796 fn error_context_drop(&self, _name: &str) -> bool {
1797 false
1798 }
1799 fn context_get(&self, _name: &str) -> Option<(ValType, u32)> {
1800 None
1801 }
1802 fn context_set(&self, _name: &str) -> Option<(ValType, u32)> {
1803 None
1804 }
1805 fn thread_index(&self, _name: &str) -> bool {
1806 false
1807 }
1808 fn thread_new_indirect(&self, _name: &str) -> bool {
1809 false
1810 }
1811 fn thread_resume_later(&self, _name: &str) -> bool {
1812 false
1813 }
1814 fn thread_suspend(&self, _name: &str) -> bool {
1815 false
1816 }
1817 fn thread_yield(&self, _name: &str) -> bool {
1818 false
1819 }
1820 fn thread_suspend_then_resume(&self, _name: &str) -> bool {
1821 false
1822 }
1823 fn thread_yield_then_resume(&self, _name: &str) -> bool {
1824 false
1825 }
1826 fn thread_suspend_then_promote(&self, _name: &str) -> bool {
1827 false
1828 }
1829 fn thread_yield_then_promote(&self, _name: &str) -> bool {
1830 false
1831 }
1832 fn future_new(
1833 &self,
1834 _lookup_context: &PayloadLookupContext,
1835 _name: &str,
1836 ) -> Option<PayloadInfo> {
1837 None
1838 }
1839 fn future_write(
1840 &self,
1841 _lookup_context: &PayloadLookupContext,
1842 _name: &str,
1843 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1844 None
1845 }
1846 fn future_read(
1847 &self,
1848 _lookup_context: &PayloadLookupContext,
1849 _name: &str,
1850 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1851 None
1852 }
1853 fn future_cancel_write(
1854 &self,
1855 _lookup_context: &PayloadLookupContext,
1856 _name: &str,
1857 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1858 None
1859 }
1860 fn future_cancel_read(
1861 &self,
1862 _lookup_context: &PayloadLookupContext,
1863 _name: &str,
1864 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1865 None
1866 }
1867 fn future_drop_writable(
1868 &self,
1869 _lookup_context: &PayloadLookupContext,
1870 _name: &str,
1871 ) -> Option<PayloadInfo> {
1872 None
1873 }
1874 fn future_drop_readable(
1875 &self,
1876 _lookup_context: &PayloadLookupContext,
1877 _name: &str,
1878 ) -> Option<PayloadInfo> {
1879 None
1880 }
1881 fn stream_new(
1882 &self,
1883 _lookup_context: &PayloadLookupContext,
1884 _name: &str,
1885 ) -> Option<PayloadInfo> {
1886 None
1887 }
1888 fn stream_write(
1889 &self,
1890 _lookup_context: &PayloadLookupContext,
1891 _name: &str,
1892 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1893 None
1894 }
1895 fn stream_read(
1896 &self,
1897 _lookup_context: &PayloadLookupContext,
1898 _name: &str,
1899 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1900 None
1901 }
1902 fn stream_cancel_write(
1903 &self,
1904 _lookup_context: &PayloadLookupContext,
1905 _name: &str,
1906 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1907 None
1908 }
1909 fn stream_cancel_read(
1910 &self,
1911 _lookup_context: &PayloadLookupContext,
1912 _name: &str,
1913 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1914 None
1915 }
1916 fn stream_drop_writable(
1917 &self,
1918 _lookup_context: &PayloadLookupContext,
1919 _name: &str,
1920 ) -> Option<PayloadInfo> {
1921 None
1922 }
1923 fn stream_drop_readable(
1924 &self,
1925 _lookup_context: &PayloadLookupContext,
1926 _name: &str,
1927 ) -> Option<PayloadInfo> {
1928 None
1929 }
1930 fn module_to_interface(
1931 &self,
1932 interface: &str,
1933 resolve: &Resolve,
1934 items: &IndexMap<WorldKey, WorldItem>,
1935 ) -> Result<(WorldKey, InterfaceId)> {
1936 for (key, item) in items.iter() {
1937 let id = match key {
1938 WorldKey::Name(name) => match item {
1940 WorldItem::Interface { id, .. } if name == interface => *id,
1941 _ => continue,
1942 },
1943 WorldKey::Interface(id) => {
1945 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1946 continue;
1947 }
1948 *id
1949 }
1950 };
1951 return Ok((key.clone(), id));
1952 }
1953 bail!("failed to find world item corresponding to interface `{interface}`")
1954 }
1955 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1956 name.strip_suffix("_post")
1957 }
1958 fn match_wit_export<'a>(
1959 &self,
1960 export_name: &str,
1961 resolve: &'a Resolve,
1962 world: WorldId,
1963 exports: &'a IndexSet<WorldKey>,
1964 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1965 if let Some(world_export_name) = export_name.strip_prefix("||") {
1966 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1967 match &resolve.worlds[world].exports[key] {
1968 WorldItem::Function(f) => return Some((key, None, f)),
1969 _ => return None,
1970 }
1971 }
1972
1973 let (key, id, func_name) =
1974 self.match_wit_interface(export_name, resolve, world, exports)?;
1975 let func = resolve.interfaces[id].functions.get(func_name)?;
1976 Some((key, Some(id), func))
1977 }
1978
1979 fn match_wit_resource_dtor<'a>(
1980 &self,
1981 export_name: &str,
1982 resolve: &'a Resolve,
1983 world: WorldId,
1984 exports: &'a IndexSet<WorldKey>,
1985 ) -> Option<TypeId> {
1986 let (_key, id, name) =
1987 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1988 let ty = *resolve.interfaces[id].types.get(name)?;
1989 match resolve.types[ty].kind {
1990 TypeDefKind::Resource => Some(ty),
1991 _ => None,
1992 }
1993 }
1994
1995 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1996 (name, AbiVariant::GuestImport)
1997 }
1998 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1999 (name, AbiVariant::GuestImport)
2000 }
2001 fn env_import(&self, _name: &str, _ty: &FuncType) -> Option<Import> {
2002 None
2003 }
2004}
2005
2006impl Standard {
2007 fn match_wit_interface<'a, 'b>(
2008 &self,
2009 export_name: &'b str,
2010 resolve: &'a Resolve,
2011 world: WorldId,
2012 exports: &'a IndexSet<WorldKey>,
2013 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
2014 let world = &resolve.worlds[world];
2015 let export_name = export_name.strip_prefix("|")?;
2016
2017 for export in exports {
2018 let id = match &world.exports[export] {
2019 WorldItem::Interface { id, .. } => *id,
2020 WorldItem::Function(_) => continue,
2021 WorldItem::Type { .. } => unreachable!(),
2022 };
2023 let remaining = match export {
2024 WorldKey::Name(name) => export_name.strip_prefix(name),
2025 WorldKey::Interface(_) => {
2026 let prefix = resolve.canonicalized_id_of(id).unwrap();
2027 export_name.strip_prefix(&prefix)
2028 }
2029 };
2030 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
2031 Some(name) => name,
2032 None => continue,
2033 };
2034 return Some((export, id, item_name));
2035 }
2036
2037 None
2038 }
2039}
2040
2041struct Legacy;
2044
2045const LEGACY: &'static dyn NameMangling = &Legacy;
2046
2047impl Legacy {
2048 fn prefixed_payload(
2054 &self,
2055 lookup_context: &PayloadLookupContext,
2056 name: &str,
2057 prefix: &str,
2058 ) -> Option<PayloadInfo> {
2059 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2062 let ty = match index_or_unit {
2063 "unit" => {
2064 if name.starts_with("[future") {
2065 PayloadType::UnitFuture
2066 } else if name.starts_with("[stream") {
2067 PayloadType::UnitStream
2068 } else {
2069 unreachable!()
2070 }
2071 }
2072 other => {
2073 let type_index = other.parse::<u32>().ok()? as usize;
2077
2078 let function = get_function(
2083 lookup_context.resolve,
2084 lookup_context.world,
2085 func_name,
2086 lookup_context.id,
2087 lookup_context.import,
2088 )
2089 .ok()?;
2090 PayloadType::Type {
2091 id: *function
2092 .find_futures_and_streams(lookup_context.resolve)
2093 .get(type_index)?,
2094 function: function.name.clone(),
2095 }
2096 }
2097 };
2098
2099 Some(PayloadInfo {
2101 name: name.to_string(),
2102 ty,
2103 key: lookup_context
2104 .key
2105 .clone()
2106 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2107 interface: lookup_context.id,
2108 imported: lookup_context.import,
2109 })
2110 }
2111
2112 fn maybe_async_lowered_payload(
2113 &self,
2114 lookup_context: &PayloadLookupContext,
2115 name: &str,
2116 prefix: &str,
2117 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2118 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2119 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2120 Some(MaybeAsyncLowered {
2121 inner: payload,
2122 async_lowered,
2123 })
2124 }
2125
2126 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2127 name.strip_prefix("[async-lower]")
2128 .map_or((false, name), |s| (true, s))
2129 }
2130 fn match_with_async_lowered_prefix(
2131 &self,
2132 name: &str,
2133 expected: &str,
2134 ) -> Option<MaybeAsyncLowered<()>> {
2135 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2136 if clean_name == expected {
2137 Some(MaybeAsyncLowered {
2138 inner: (),
2139 async_lowered,
2140 })
2141 } else {
2142 None
2143 }
2144 }
2145
2146 fn match_with_optional_type_suffix(name: &str, match_prefix: &str) -> Option<ValType> {
2150 let tail = name.strip_prefix(match_prefix)?.strip_suffix(']')?;
2151 if tail.is_empty() {
2152 Some(ValType::I32)
2153 } else {
2154 match tail.strip_prefix('-')? {
2155 "i32" => Some(ValType::I32),
2156 "i64" => Some(ValType::I64),
2157 _ => None,
2159 }
2160 }
2161 }
2162}
2163
2164impl NameMangling for Legacy {
2165 fn import_root(&self) -> &str {
2166 "$root"
2167 }
2168 fn import_non_root_prefix(&self) -> &str {
2169 ""
2170 }
2171 fn import_exported_intrinsic_prefix(&self) -> &str {
2172 "[export]"
2173 }
2174 fn export_memory(&self) -> &str {
2175 "memory"
2176 }
2177 fn export_initialize(&self) -> &str {
2178 "_initialize"
2179 }
2180 fn export_realloc(&self) -> &str {
2181 "cabi_realloc"
2182 }
2183 fn export_indirect_function_table(&self) -> Option<&str> {
2184 Some("__indirect_function_table")
2185 }
2186 fn export_wasm_task_hook(&self) -> Option<&str> {
2187 Some(crate::linking::metadata::TASK_HOOK)
2188 }
2189 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2190 name.strip_prefix("[resource-drop]")
2191 }
2192 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2193 name.strip_prefix("[resource-new]")
2194 }
2195 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2196 name.strip_prefix("[resource-rep]")
2197 }
2198 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2199 name.strip_prefix("[task-return]")
2200 }
2201 fn task_cancel(&self, name: &str) -> bool {
2202 name == "[task-cancel]"
2203 }
2204 fn backpressure_inc(&self, name: &str) -> bool {
2205 name == "[backpressure-inc]"
2206 }
2207 fn backpressure_dec(&self, name: &str) -> bool {
2208 name == "[backpressure-dec]"
2209 }
2210 fn waitable_set_new(&self, name: &str) -> bool {
2211 name == "[waitable-set-new]"
2212 }
2213 fn waitable_set_wait(&self, name: &str) -> Option<ValType> {
2214 let result_ty = Legacy::match_with_optional_type_suffix(name, "[waitable-set-wait")?;
2215 Some(result_ty)
2216 }
2217 fn waitable_set_poll(&self, name: &str) -> Option<ValType> {
2218 let result_ty = Legacy::match_with_optional_type_suffix(name, "[waitable-set-poll")?;
2219 Some(result_ty)
2220 }
2221 fn waitable_set_drop(&self, name: &str) -> bool {
2222 name == "[waitable-set-drop]"
2223 }
2224 fn waitable_join(&self, name: &str) -> bool {
2225 name == "[waitable-join]"
2226 }
2227 fn subtask_drop(&self, name: &str) -> bool {
2228 name == "[subtask-drop]"
2229 }
2230 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2231 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2232 }
2233 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2234 name.strip_prefix("[callback][async-lift]")
2235 }
2236 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2237 name.strip_prefix("[async-lift]")
2238 }
2239 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2240 name.strip_prefix("[async-lift-stackful]")
2241 }
2242 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2243 match name {
2244 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2245 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2246 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2247 _ => None,
2248 }
2249 }
2250 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2251 match name {
2252 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2253 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2254 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2255 _ => None,
2256 }
2257 }
2258 fn error_context_drop(&self, name: &str) -> bool {
2259 name == "[error-context-drop]"
2260 }
2261 fn context_get(&self, name: &str) -> Option<(ValType, u32)> {
2262 parse_context_name(name, "[context-get-")
2263 }
2264 fn context_set(&self, name: &str) -> Option<(ValType, u32)> {
2265 parse_context_name(name, "[context-set-")
2266 }
2267 fn thread_index(&self, name: &str) -> bool {
2268 name == "[thread-index]"
2269 }
2270 fn thread_new_indirect(&self, name: &str) -> bool {
2271 name == "[thread-new-indirect-v0]"
2273 }
2274 fn thread_resume_later(&self, name: &str) -> bool {
2275 name == "[thread-resume-later]"
2276 }
2277 fn thread_suspend(&self, name: &str) -> bool {
2278 name == "[thread-suspend]"
2279 }
2280 fn thread_yield(&self, name: &str) -> bool {
2281 name == "[thread-yield]"
2282 }
2283 fn thread_suspend_then_resume(&self, name: &str) -> bool {
2284 name == "[thread-suspend-then-resume]"
2285 }
2286 fn thread_yield_then_resume(&self, name: &str) -> bool {
2287 name == "[thread-yield-then-resume]"
2288 }
2289 fn thread_suspend_then_promote(&self, name: &str) -> bool {
2290 name == "[thread-suspend-then-promote]"
2291 }
2292 fn thread_yield_then_promote(&self, name: &str) -> bool {
2293 name == "[thread-yield-then-promote]"
2294 }
2295 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2296 self.prefixed_payload(lookup_context, name, "[future-new-")
2297 }
2298 fn future_write(
2299 &self,
2300 lookup_context: &PayloadLookupContext,
2301 name: &str,
2302 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2303 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2304 }
2305 fn future_read(
2306 &self,
2307 lookup_context: &PayloadLookupContext,
2308 name: &str,
2309 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2310 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2311 }
2312 fn future_cancel_write(
2313 &self,
2314 lookup_context: &PayloadLookupContext,
2315 name: &str,
2316 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2317 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2318 }
2319 fn future_cancel_read(
2320 &self,
2321 lookup_context: &PayloadLookupContext,
2322 name: &str,
2323 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2324 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2325 }
2326 fn future_drop_writable(
2327 &self,
2328 lookup_context: &PayloadLookupContext,
2329 name: &str,
2330 ) -> Option<PayloadInfo> {
2331 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2332 }
2333 fn future_drop_readable(
2334 &self,
2335 lookup_context: &PayloadLookupContext,
2336 name: &str,
2337 ) -> Option<PayloadInfo> {
2338 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2339 }
2340 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2341 self.prefixed_payload(lookup_context, name, "[stream-new-")
2342 }
2343 fn stream_write(
2344 &self,
2345 lookup_context: &PayloadLookupContext,
2346 name: &str,
2347 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2348 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2349 }
2350 fn stream_read(
2351 &self,
2352 lookup_context: &PayloadLookupContext,
2353 name: &str,
2354 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2355 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2356 }
2357 fn stream_cancel_write(
2358 &self,
2359 lookup_context: &PayloadLookupContext,
2360 name: &str,
2361 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2362 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2363 }
2364 fn stream_cancel_read(
2365 &self,
2366 lookup_context: &PayloadLookupContext,
2367 name: &str,
2368 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2369 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2370 }
2371 fn stream_drop_writable(
2372 &self,
2373 lookup_context: &PayloadLookupContext,
2374 name: &str,
2375 ) -> Option<PayloadInfo> {
2376 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2377 }
2378 fn stream_drop_readable(
2379 &self,
2380 lookup_context: &PayloadLookupContext,
2381 name: &str,
2382 ) -> Option<PayloadInfo> {
2383 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2384 }
2385 fn module_to_interface(
2386 &self,
2387 module: &str,
2388 resolve: &Resolve,
2389 items: &IndexMap<WorldKey, WorldItem>,
2390 ) -> Result<(WorldKey, InterfaceId)> {
2391 let bare_name = WorldKey::Name(module.to_string());
2393 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2394 return Ok((bare_name, *id));
2395 }
2396
2397 let kebab_name = ComponentName::new(module, 0);
2403 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2404 Ok(ComponentNameKind::Interface(name)) => name,
2405 _ => bail!("module requires an import interface named `{module}`"),
2406 };
2407
2408 let version = name.version(None)?;
2412
2413 let pkgname = PackageName {
2415 namespace: name.namespace().to_string(),
2416 name: name.package().to_string(),
2417 version: version.clone(),
2418 };
2419 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2420 if let Some(id) = resolve.packages[*pkg]
2421 .interfaces
2422 .get(name.interface().as_str())
2423 {
2424 let key = WorldKey::Interface(*id);
2427 if items.contains_key(&key) {
2428 return Ok((key, *id));
2429 }
2430
2431 for k in items.keys() {
2437 let i = match *k {
2438 WorldKey::Interface(id) => id,
2439 WorldKey::Name(_) => continue,
2440 };
2441 if resolve.interfaces[i].clone_of == Some(*id) {
2442 return Ok((WorldKey::Interface(i), i));
2443 }
2444 }
2445 }
2446 }
2447
2448 for (key, _) in items {
2453 let id = match key {
2454 WorldKey::Interface(id) => *id,
2455 WorldKey::Name(_) => continue,
2456 };
2457 let interface = &resolve.interfaces[id];
2459 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2460 continue;
2461 }
2462
2463 let pkg = &resolve.packages[interface.package.unwrap()];
2465 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2466 continue;
2467 }
2468
2469 let module_version = match &version {
2470 Some(version) => version,
2471 None => continue,
2472 };
2473 let pkg_version = match &pkg.name.version {
2474 Some(version) => version,
2475 None => continue,
2476 };
2477
2478 let module_compat = PackageName::version_compat_track(&module_version);
2480 let pkg_compat = PackageName::version_compat_track(pkg_version);
2481 if module_compat == pkg_compat {
2482 return Ok((key.clone(), id));
2483 }
2484 }
2485
2486 bail!("module requires an import interface named `{module}`")
2487 }
2488 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2489 name.strip_prefix("cabi_post_")
2490 }
2491 fn match_wit_export<'a>(
2492 &self,
2493 export_name: &str,
2494 resolve: &'a Resolve,
2495 world: WorldId,
2496 exports: &'a IndexSet<WorldKey>,
2497 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2498 let world = &resolve.worlds[world];
2499 for name in exports {
2500 match &world.exports[name] {
2501 WorldItem::Function(f) => {
2502 if f.legacy_core_export_name(None) == export_name {
2503 return Some((name, None, f));
2504 }
2505 }
2506 WorldItem::Interface { id, .. } => {
2507 let string = resolve.name_world_key(name);
2508 for (_, func) in resolve.interfaces[*id].functions.iter() {
2509 if func.legacy_core_export_name(Some(&string)) == export_name {
2510 return Some((name, Some(*id), func));
2511 }
2512 }
2513 }
2514
2515 WorldItem::Type { .. } => unreachable!(),
2516 }
2517 }
2518
2519 None
2520 }
2521
2522 fn match_wit_resource_dtor<'a>(
2523 &self,
2524 export_name: &str,
2525 resolve: &'a Resolve,
2526 world: WorldId,
2527 exports: &'a IndexSet<WorldKey>,
2528 ) -> Option<TypeId> {
2529 let world = &resolve.worlds[world];
2530 for name in exports {
2531 let id = match &world.exports[name] {
2532 WorldItem::Interface { id, .. } => *id,
2533 WorldItem::Function(_) => continue,
2534 WorldItem::Type { .. } => unreachable!(),
2535 };
2536 let name = resolve.name_world_key(name);
2537 let resource = match export_name
2538 .strip_prefix(&name)
2539 .and_then(|s| s.strip_prefix("#[dtor]"))
2540 .and_then(|r| resolve.interfaces[id].types.get(r))
2541 {
2542 Some(id) => *id,
2543 None => continue,
2544 };
2545
2546 match resolve.types[resource].kind {
2547 TypeDefKind::Resource => {}
2548 _ => continue,
2549 }
2550
2551 return Some(resource);
2552 }
2553
2554 None
2555 }
2556
2557 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2558 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2559 (
2560 name,
2561 if async_abi {
2562 AbiVariant::GuestImportAsync
2563 } else {
2564 AbiVariant::GuestImport
2565 },
2566 )
2567 }
2568 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2569 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2570 (
2571 name,
2572 if async_abi {
2573 AbiVariant::GuestImportAsync
2574 } else {
2575 AbiVariant::GuestImport
2576 },
2577 )
2578 }
2579 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import> {
2580 match name {
2581 "__wasm_get_stack_pointer" => {
2582 let ty = *ty.results().get(0)?;
2583 Some(Import::ContextGet { ty, slot: 0 })
2584 }
2585 "__wasm_set_stack_pointer" => {
2586 let ty = *ty.params().get(0)?;
2587 Some(Import::ContextSet { ty, slot: 0 })
2588 }
2589 "__wasm_get_tls_base" => {
2593 let ty = *ty.results().get(0)?;
2594 Some(Import::TlsBaseGet { ty })
2595 }
2596 "__wasm_set_tls_base" => {
2597 let ty = *ty.params().get(0)?;
2598 Some(Import::TlsBaseSet { ty })
2599 }
2600 _ => None,
2601 }
2602 }
2603}
2604
2605pub fn validate_module(
2617 encoder: &ComponentEncoder,
2618 bytes: &[u8],
2619 import_map: Option<&ModuleImportMap>,
2620) -> Result<ValidatedModule> {
2621 ValidatedModule::new(
2622 encoder,
2623 bytes,
2624 &encoder.main_module_exports,
2625 import_map,
2626 None,
2627 )
2628}
2629
2630pub fn validate_adapter_module(
2648 encoder: &ComponentEncoder,
2649 bytes: &[u8],
2650 required_by_import: &IndexMap<String, FuncType>,
2651 exports: &IndexSet<WorldKey>,
2652 library_info: Option<&LibraryInfo>,
2653) -> Result<ValidatedModule> {
2654 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2655
2656 for (name, required_ty) in required_by_import {
2657 let actual = match ret.exports.raw_exports.get(name) {
2658 Some(ty) => ty,
2659 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2660 };
2661 validate_func_sig(name, required_ty, &actual)?;
2662 }
2663
2664 Ok(ret)
2665}
2666
2667#[derive(Debug, Clone)]
2674pub struct AdapterModuleDidNotExport(String);
2675
2676impl fmt::Display for AdapterModuleDidNotExport {
2677 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2678 write!(f, "adapter module did not export `{}`", self.0)
2679 }
2680}
2681
2682impl std::error::Error for AdapterModuleDidNotExport {}
2683
2684fn resource_test_for_interface<'a>(
2685 resolve: &'a Resolve,
2686 id: InterfaceId,
2687) -> impl Fn(&str) -> Option<TypeId> + 'a {
2688 let interface = &resolve.interfaces[id];
2689 move |name: &str| {
2690 let ty = match interface.types.get(name) {
2691 Some(ty) => *ty,
2692 None => return None,
2693 };
2694 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2695 Some(ty)
2696 } else {
2697 None
2698 }
2699 }
2700}
2701
2702fn resource_test_for_world<'a>(
2703 resolve: &'a Resolve,
2704 id: WorldId,
2705) -> impl Fn(&str) -> Option<TypeId> + 'a {
2706 let world = &resolve.worlds[id];
2707 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2708 WorldItem::Type { id, .. } => {
2709 if matches!(resolve.types[*id].kind, TypeDefKind::Resource) {
2710 Some(*id)
2711 } else {
2712 None
2713 }
2714 }
2715 _ => None,
2716 }
2717}
2718
2719fn validate_func(
2720 resolve: &Resolve,
2721 ty: &wasmparser::FuncType,
2722 func: &Function,
2723 abi: AbiVariant,
2724) -> Result<()> {
2725 validate_func_sig(
2726 &func.name,
2727 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2728 ty,
2729 )
2730}
2731
2732fn validate_post_return(
2733 resolve: &Resolve,
2734 ty: &wasmparser::FuncType,
2735 func: &Function,
2736) -> Result<()> {
2737 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2743 sig.params = mem::take(&mut sig.results);
2744 validate_func_sig(
2745 &format!("{} post-return", func.name),
2746 &wasm_sig_to_func_type(sig),
2747 ty,
2748 )
2749}
2750
2751fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2752 if ty != expected {
2753 bail!(
2754 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2755 name,
2756 expected.params(),
2757 expected.results(),
2758 ty.params(),
2759 ty.results()
2760 );
2761 }
2762
2763 Ok(())
2764}
2765
2766fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2768 assert!(prefix.starts_with("["));
2769 assert!(prefix.ends_with("-"));
2770 let suffix = name.strip_prefix(prefix)?;
2771 let index = suffix.find(']')?;
2772 let rest = &suffix[index + 1..];
2773 Some((&suffix[..index], rest))
2774}
2775
2776fn parse_context_name(name: &str, prefix: &str) -> Option<(ValType, u32)> {
2782 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2783 if !rest.is_empty() {
2784 return None;
2785 }
2786 let (ty, slot) = match suffix.split_once('-') {
2787 Some(("i64", slot)) => (ValType::I64, slot),
2788 Some(("i32", slot)) => (ValType::I32, slot),
2789 _ => (ValType::I32, suffix),
2790 };
2791 let slot = slot.parse().ok()?;
2792 Some((ty, slot))
2793}
2794
2795fn get_function<'a>(
2796 resolve: &'a Resolve,
2797 world: &'a World,
2798 name: &str,
2799 interface: Option<InterfaceId>,
2800 imported: bool,
2801) -> Result<&'a Function> {
2802 let function = if let Some(id) = interface {
2803 return resolve.interfaces[id]
2804 .functions
2805 .get(name)
2806 .ok_or_else(|| anyhow!("no export `{name}` found"));
2807 } else if imported {
2808 world.imports.get(&WorldKey::Name(name.to_string()))
2809 } else {
2810 world.exports.get(&WorldKey::Name(name.to_string()))
2811 };
2812 let Some(WorldItem::Function(function)) = function else {
2813 bail!("no export `{name}` found");
2814 };
2815 Ok(function)
2816}