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 { cancellable: bool },
329
330 WaitableSetPoll { cancellable: bool },
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 { cancellable: bool },
464
465 ThreadYield { cancellable: bool },
467
468 ThreadSuspendThenResume { cancellable: bool },
470
471 ThreadYieldThenResume { cancellable: bool },
473
474 ThreadSuspendThenPromote { cancellable: bool },
476
477 ThreadYieldThenPromote { cancellable: bool },
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((info, 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 cancellable: info.cancellable,
658 });
659 }
660
661 if let Some((info, result_ty)) = names.waitable_set_poll(name) {
662 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
663 validate_func_sig(name, &expected, ty)?;
664 return Ok(Import::WaitableSetPoll {
665 cancellable: info.cancellable,
666 });
667 }
668
669 if names.waitable_set_drop(name) {
670 let expected = FuncType::new([ValType::I32], []);
671 validate_func_sig(name, &expected, ty)?;
672 return Ok(Import::WaitableSetDrop);
673 }
674
675 if names.waitable_join(name) {
676 let expected = FuncType::new([ValType::I32; 2], []);
677 validate_func_sig(name, &expected, ty)?;
678 return Ok(Import::WaitableJoin);
679 }
680
681 if names.subtask_drop(name) {
682 let expected = FuncType::new([ValType::I32], []);
683 validate_func_sig(name, &expected, ty)?;
684 return Ok(Import::SubtaskDrop);
685 }
686
687 if let Some(info) = names.subtask_cancel(name) {
688 let expected = FuncType::new([ValType::I32], [ValType::I32]);
689 validate_func_sig(name, &expected, ty)?;
690 return Ok(Import::SubtaskCancel {
691 async_: info.async_lowered,
692 });
693 }
694
695 if let Some(encoding) = names.error_context_new(name) {
696 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
697 validate_func_sig(name, &expected, ty)?;
698 return Ok(Import::ErrorContextNew { encoding });
699 }
700
701 if let Some(encoding) = names.error_context_debug_message(name) {
702 let expected = FuncType::new([ValType::I32; 2], []);
703 validate_func_sig(name, &expected, ty)?;
704 return Ok(Import::ErrorContextDebugMessage { encoding });
705 }
706
707 if let Some((slot_ty, slot)) = names.context_get(name) {
708 let expected = FuncType::new([], [slot_ty]);
709 validate_func_sig(name, &expected, ty)?;
710 return Ok(Import::ContextGet { ty: slot_ty, slot });
711 }
712 if let Some((slot_ty, slot)) = names.context_set(name) {
713 let expected = FuncType::new([slot_ty], []);
714 validate_func_sig(name, &expected, ty)?;
715 return Ok(Import::ContextSet { ty: slot_ty, slot });
716 }
717 if names.thread_index(name) {
718 let expected = FuncType::new([], [ValType::I32]);
719 validate_func_sig(name, &expected, ty)?;
720 return Ok(Import::ThreadIndex);
721 }
722 if names.thread_new_indirect(name) {
723 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
724 validate_func_sig(name, &expected, ty)?;
725 return Ok(Import::ThreadNewIndirect);
726 }
727 if names.thread_resume_later(name) {
728 let expected = FuncType::new([ValType::I32], []);
729 validate_func_sig(name, &expected, ty)?;
730 return Ok(Import::ThreadResumeLater);
731 }
732 if let Some(info) = names.thread_suspend(name) {
733 let expected = FuncType::new([], [ValType::I32]);
734 validate_func_sig(name, &expected, ty)?;
735 return Ok(Import::ThreadSuspend {
736 cancellable: info.cancellable,
737 });
738 }
739 if let Some(info) = names.thread_yield(name) {
740 let expected = FuncType::new([], [ValType::I32]);
741 validate_func_sig(name, &expected, ty)?;
742 return Ok(Import::ThreadYield {
743 cancellable: info.cancellable,
744 });
745 }
746 if let Some(info) = names.thread_suspend_then_resume(name) {
747 let expected = FuncType::new([ValType::I32], [ValType::I32]);
748 validate_func_sig(name, &expected, ty)?;
749 return Ok(Import::ThreadSuspendThenResume {
750 cancellable: info.cancellable,
751 });
752 }
753 if let Some(info) = names.thread_yield_then_resume(name) {
754 let expected = FuncType::new([ValType::I32], [ValType::I32]);
755 validate_func_sig(name, &expected, ty)?;
756 return Ok(Import::ThreadYieldThenResume {
757 cancellable: info.cancellable,
758 });
759 }
760 if let Some(info) = names.thread_suspend_then_promote(name) {
761 let expected = FuncType::new([ValType::I32], [ValType::I32]);
762 validate_func_sig(name, &expected, ty)?;
763 return Ok(Import::ThreadSuspendThenPromote {
764 cancellable: info.cancellable,
765 });
766 }
767 if let Some(info) = names.thread_yield_then_promote(name) {
768 let expected = FuncType::new([ValType::I32], [ValType::I32]);
769 validate_func_sig(name, &expected, ty)?;
770 return Ok(Import::ThreadYieldThenPromote {
771 cancellable: info.cancellable,
772 });
773 }
774
775 let (key_name, abi) = names.world_key_name_and_abi(name);
776 let key = WorldKey::Name(key_name.to_string());
777 if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
778 validate_func(resolve, ty, func, abi)?;
779 return Ok(Import::WorldFunc(key, func.name.clone(), abi));
780 }
781
782 if let Some(import) =
783 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
784 {
785 return Ok(import);
786 }
787
788 match world.imports.get(&key) {
789 Some(_) => bail!("expected world top-level import `{name}` to be a function"),
790 None => bail!("no top-level imported function `{name}` specified"),
791 }
792 }
793
794 if module == "env" {
795 if let Some(import) = names.env_import(name, ty) {
796 return Ok(import);
797 }
798 }
799
800 if matches!(
802 module.strip_prefix(names.import_exported_intrinsic_prefix()),
803 Some(module) if module == names.import_root()
804 ) {
805 if let Some(import) =
806 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
807 {
808 return Ok(import);
809 }
810 }
811
812 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
813 Some(name) => name,
814 None => bail!("unknown or invalid component model import syntax"),
815 };
816
817 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
818 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
819
820 if let Some(import) =
821 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
822 {
823 return Ok(import);
824 }
825 bail!("unknown function `{name}`")
826 }
827
828 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
829 let interface = &resolve.interfaces[id];
830 let (function_name, abi) = names.interface_function_name_and_abi(name);
831 if let Some(f) = interface.functions.get(function_name) {
832 validate_func(resolve, ty, f, abi).with_context(|| {
833 let name = resolve.name_world_key(&key);
834 format!("failed to validate import interface `{name}`")
835 })?;
836 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
837 }
838
839 if let Some(import) =
840 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
841 {
842 return Ok(import);
843 }
844 bail!(
845 "import interface `{module}` is missing function \
846 `{name}` that is required by the module",
847 )
848 }
849
850 fn maybe_classify_wit_intrinsic(
878 &self,
879 name: &str,
880 key_and_id: Option<(WorldKey, InterfaceId)>,
881 encoder: &ComponentEncoder,
882 ty: &FuncType,
883 import: bool,
884 names: &dyn NameMangling,
885 ) -> Result<Option<Import>> {
886 let resolve = &encoder.metadata.resolve;
887 let world_id = encoder.metadata.world;
888 let world = &resolve.worlds[world_id];
889
890 let (key, id) = match key_and_id {
895 Some((key, id)) => (Some(key), Some(id)),
896 None => (None, None),
897 };
898
899 let resource_test = |name: &str| match id {
901 Some(id) => resource_test_for_interface(resolve, id)(name),
902 None => resource_test_for_world(resolve, world_id)(name),
903 };
904
905 if let Some(resource) = names.resource_drop_name(name) {
907 if let Some(resource_id) = resource_test(resource) {
908 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
909 let expected = FuncType::new([ValType::I32], []);
910 validate_func_sig(name, &expected, ty)?;
911 return Ok(Some(if import {
912 Import::ImportedResourceDrop(key, id, resource_id)
913 } else {
914 Import::ExportedResourceDrop(key, resource_id)
915 }));
916 }
917 }
918
919 if !import {
922 if let Some(name) = names.resource_new_name(name) {
923 if let Some(id) = resource_test(name) {
924 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
925 let expected = FuncType::new([ValType::I32], [ValType::I32]);
926 validate_func_sig(name, &expected, ty)?;
927 return Ok(Some(Import::ExportedResourceNew(key, id)));
928 }
929 }
930 if let Some(name) = names.resource_rep_name(name) {
931 if let Some(id) = resource_test(name) {
932 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
933 let expected = FuncType::new([ValType::I32], [ValType::I32]);
934 validate_func_sig(name, &expected, ty)?;
935 return Ok(Some(Import::ExportedResourceRep(key, id)));
936 }
937 }
938 if let Some(name) = names.task_return_name(name) {
939 let func = get_function(resolve, world, name, id, import)?;
940 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
941 return Ok(Some(Import::ExportedTaskReturn(key, id, func.clone())));
944 }
945 if names.task_cancel(name) {
946 let expected = FuncType::new([], []);
947 validate_func_sig(name, &expected, ty)?;
948 return Ok(Some(Import::ExportedTaskCancel));
949 }
950 }
951
952 let lookup_context = PayloadLookupContext {
953 resolve,
954 world,
955 key,
956 id,
957 import,
958 };
959
960 let import = if let Some(info) = names.future_new(&lookup_context, name) {
964 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
965 Import::FutureNew(info)
966 } else if let Some(info) = names.future_write(&lookup_context, name) {
967 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
968 Import::FutureWrite {
969 async_: info.async_lowered,
970 info: info.inner,
971 }
972 } else if let Some(info) = names.future_read(&lookup_context, name) {
973 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
974 Import::FutureRead {
975 async_: info.async_lowered,
976 info: info.inner,
977 }
978 } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
979 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
980 Import::FutureCancelWrite {
981 async_: info.async_lowered,
982 info: info.inner,
983 }
984 } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
985 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
986 Import::FutureCancelRead {
987 async_: info.async_lowered,
988 info: info.inner,
989 }
990 } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
991 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
992 Import::FutureDropWritable(info)
993 } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
994 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
995 Import::FutureDropReadable(info)
996 } else if let Some(info) = names.stream_new(&lookup_context, name) {
997 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
998 Import::StreamNew(info)
999 } else if let Some(info) = names.stream_write(&lookup_context, name) {
1000 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
1001 Import::StreamWrite {
1002 async_: info.async_lowered,
1003 info: info.inner,
1004 }
1005 } else if let Some(info) = names.stream_read(&lookup_context, name) {
1006 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
1007 Import::StreamRead {
1008 async_: info.async_lowered,
1009 info: info.inner,
1010 }
1011 } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
1012 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
1013 Import::StreamCancelWrite {
1014 async_: info.async_lowered,
1015 info: info.inner,
1016 }
1017 } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
1018 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
1019 Import::StreamCancelRead {
1020 async_: info.async_lowered,
1021 info: info.inner,
1022 }
1023 } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
1024 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1025 Import::StreamDropWritable(info)
1026 } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
1027 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1028 Import::StreamDropReadable(info)
1029 } else {
1030 return Ok(None);
1031 };
1032 Ok(Some(import))
1033 }
1034
1035 fn classify_import_with_library(
1036 &mut self,
1037 import: wasmparser::Import<'_>,
1038 library_info: Option<&LibraryInfo>,
1039 ) -> Result<bool> {
1040 let info = match library_info {
1041 Some(info) => info,
1042 None => return Ok(false),
1043 };
1044 let Some((_, instance)) = info
1045 .arguments
1046 .iter()
1047 .find(|(name, _items)| *name == import.module)
1048 else {
1049 return Ok(false);
1050 };
1051 match instance {
1052 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1053 Some(ImportInstance::Whole(which)) => {
1054 if which != module {
1055 bail!("different whole modules imported under the same name");
1056 }
1057 }
1058 Some(ImportInstance::Names(_)) => {
1059 bail!("cannot mix individual imports and whole module imports")
1060 }
1061 None => {
1062 let instance = ImportInstance::Whole(module.clone());
1063 self.names.insert(import.module.to_string(), instance);
1064 }
1065 },
1066 Instance::Items(items) => {
1067 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1068 return Ok(false);
1069 };
1070 self.insert_import(import, Import::Item(item.clone()))?;
1071 }
1072 }
1073 Ok(true)
1074 }
1075
1076 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1080 if let Import::MainModuleMemory(ty) = item {
1081 if self.imported_memory.is_some() {
1082 bail!("module has multiple imports for memory");
1083 }
1084 self.imported_memory = Some(ty);
1085 }
1086 let entry = self
1087 .names
1088 .entry(import.module.to_string())
1089 .or_insert(ImportInstance::Names(IndexMap::default()));
1090 let names = match entry {
1091 ImportInstance::Names(names) => names,
1092 _ => bail!("cannot mix individual imports with module imports"),
1093 };
1094 let entry = match names.entry(import.name.to_string()) {
1095 Entry::Occupied(_) => {
1096 bail!(
1097 "module has duplicate import for `{}::{}`",
1098 import.module,
1099 import.name
1100 );
1101 }
1102 Entry::Vacant(v) => v,
1103 };
1104 log::trace!(
1105 "classifying import `{}::{} as {item:?}",
1106 import.module,
1107 import.name
1108 );
1109 entry.insert(item);
1110 Ok(())
1111 }
1112}
1113
1114#[derive(Default)]
1117pub struct ExportMap {
1118 names: IndexMap<String, Export>,
1119 raw_exports: IndexMap<String, FuncType>,
1120}
1121
1122#[derive(Debug)]
1125pub enum Export {
1126 WorldFunc(WorldKey, String, AbiVariant),
1129
1130 WorldFuncPostReturn(WorldKey),
1132
1133 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1135
1136 InterfaceFuncPostReturn(WorldKey, String),
1138
1139 ResourceDtor(TypeId),
1141
1142 Memory,
1144
1145 GeneralPurposeRealloc,
1147
1148 GeneralPurposeExportRealloc,
1150
1151 GeneralPurposeImportRealloc,
1153
1154 Initialize,
1156
1157 ReallocForAdapter,
1159
1160 WorldFuncCallback(WorldKey),
1161
1162 InterfaceFuncCallback(WorldKey, String),
1163
1164 IndirectFunctionTable,
1166
1167 WasmTaskHook,
1169}
1170
1171impl ExportMap {
1172 fn add(
1173 &mut self,
1174 export: wasmparser::Export<'_>,
1175 encoder: &ComponentEncoder,
1176 exports: &IndexSet<WorldKey>,
1177 types: TypesRef<'_>,
1178 ) -> Result<()> {
1179 if let Some(item) = self.classify(export, encoder, exports, types)? {
1180 log::debug!("classifying export `{}` as {item:?}", export.name);
1181 let prev = self.names.insert(export.name.to_string(), item);
1182 assert!(prev.is_none());
1183 }
1184 Ok(())
1185 }
1186
1187 fn classify(
1188 &mut self,
1189 export: wasmparser::Export<'_>,
1190 encoder: &ComponentEncoder,
1191 exports: &IndexSet<WorldKey>,
1192 types: TypesRef<'_>,
1193 ) -> Result<Option<Export>> {
1194 match export.kind {
1195 ExternalKind::Func => {
1196 let ty = types[types.core_function_at(export.index)].unwrap_func();
1197 self.raw_exports.insert(export.name.to_string(), ty.clone());
1198 }
1199 _ => {}
1200 }
1201
1202 if export.name == "canonical_abi_realloc" {
1204 return Ok(Some(Export::GeneralPurposeRealloc));
1205 } else if export.name == "cabi_import_realloc" {
1206 return Ok(Some(Export::GeneralPurposeImportRealloc));
1207 } else if export.name == "cabi_export_realloc" {
1208 return Ok(Some(Export::GeneralPurposeExportRealloc));
1209 } else if export.name == "cabi_realloc_adapter" {
1210 return Ok(Some(Export::ReallocForAdapter));
1211 }
1212
1213 let (name, names) = match export.name.strip_prefix("cm32p2") {
1214 Some(name) => (name, STANDARD),
1215 None if encoder.reject_legacy_names => return Ok(None),
1216 None => (export.name, LEGACY),
1217 };
1218
1219 if let Some(export) = self
1220 .classify_component_export(names, name, &export, encoder, exports, types)
1221 .with_context(|| format!("failed to classify export `{}`", export.name))?
1222 {
1223 return Ok(Some(export));
1224 }
1225 log::debug!("unknown export `{}`", export.name);
1226 Ok(None)
1227 }
1228
1229 fn classify_component_export(
1230 &mut self,
1231 names: &dyn NameMangling,
1232 name: &str,
1233 export: &wasmparser::Export<'_>,
1234 encoder: &ComponentEncoder,
1235 exports: &IndexSet<WorldKey>,
1236 types: TypesRef<'_>,
1237 ) -> Result<Option<Export>> {
1238 let resolve = &encoder.metadata.resolve;
1239 let world = encoder.metadata.world;
1240 match export.kind {
1241 ExternalKind::Func => {}
1242 ExternalKind::Memory => {
1243 if name == names.export_memory() {
1244 return Ok(Some(Export::Memory));
1245 }
1246 return Ok(None);
1247 }
1248 ExternalKind::Table => {
1249 if Some(name) == names.export_indirect_function_table() {
1250 return Ok(Some(Export::IndirectFunctionTable));
1251 }
1252 return Ok(None);
1253 }
1254 _ => return Ok(None),
1255 }
1256 let ty = types[types.core_function_at(export.index)].unwrap_func();
1257
1258 if name == names.export_realloc() {
1260 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1261 validate_func_sig(name, &expected, ty)?;
1262 return Ok(Some(Export::GeneralPurposeRealloc));
1263 } else if name == names.export_initialize() {
1264 let expected = FuncType::new([], []);
1265 validate_func_sig(name, &expected, ty)?;
1266 return Ok(Some(Export::Initialize));
1267 } else if Some(name) == names.export_wasm_task_hook() {
1268 let expected = FuncType::new([ValType::I32], []);
1269 validate_func_sig(name, &expected, ty)?;
1270 return Ok(Some(Export::WasmTaskHook));
1271 }
1272
1273 let full_name = name;
1274 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1275 (AbiVariant::GuestExportAsync, name)
1276 } else if let Some(name) = names.async_lift_stackful_name(name) {
1277 (AbiVariant::GuestExportAsyncStackful, name)
1278 } else {
1279 (AbiVariant::GuestExport, name)
1280 };
1281
1282 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1284 validate_func(resolve, ty, f, abi).with_context(|| {
1285 let key = resolve.name_world_key(key);
1286 format!("failed to validate export for `{key}`")
1287 })?;
1288 match id {
1289 Some(id) => {
1290 return Ok(Some(Export::InterfaceFunc(
1291 key.clone(),
1292 id,
1293 f.name.clone(),
1294 abi,
1295 )));
1296 }
1297 None => {
1298 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1299 }
1300 }
1301 }
1302
1303 if let Some(remaining) = names.strip_post_return(name) {
1305 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1306 validate_post_return(resolve, ty, f).with_context(|| {
1307 let key = resolve.name_world_key(key);
1308 format!("failed to validate export for `{key}`")
1309 })?;
1310 match id {
1311 Some(_id) => {
1312 return Ok(Some(Export::InterfaceFuncPostReturn(
1313 key.clone(),
1314 f.name.clone(),
1315 )));
1316 }
1317 None => {
1318 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1319 }
1320 }
1321 }
1322 }
1323
1324 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1325 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1326 validate_func_sig(
1327 full_name,
1328 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1329 ty,
1330 )?;
1331 return Ok(Some(if id.is_some() {
1332 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1333 } else {
1334 Export::WorldFuncCallback(key.clone())
1335 }));
1336 }
1337 }
1338
1339 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1341 let expected = FuncType::new([ValType::I32], []);
1342 validate_func_sig(full_name, &expected, ty)?;
1343 return Ok(Some(Export::ResourceDtor(dtor)));
1344 }
1345
1346 Ok(None)
1347 }
1348
1349 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1352 self.find(|m| match m {
1353 Export::WorldFuncPostReturn(k) => k == key,
1354 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1355 _ => false,
1356 })
1357 }
1358
1359 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1362 self.find(|m| match m {
1363 Export::WorldFuncCallback(k) => k == key,
1364 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1365 _ => false,
1366 })
1367 }
1368
1369 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1370 self.names.values().find_map(|m| match m {
1371 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1372 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1373 _ => None,
1374 })
1375 }
1376
1377 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1380 let _ = (key, func);
1384
1385 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1386 return Some(name);
1387 }
1388 self.general_purpose_realloc()
1389 }
1390
1391 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1394 let _ = (interface, func);
1398
1399 self.import_realloc_fallback()
1400 }
1401
1402 pub fn import_realloc_fallback(&self) -> Option<&str> {
1406 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1407 return Some(name);
1408 }
1409 self.general_purpose_realloc()
1410 }
1411
1412 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1414 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1415 return Some(name);
1416 }
1417 self.general_purpose_realloc()
1418 }
1419
1420 pub fn general_purpose_realloc(&self) -> Option<&str> {
1421 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1422 }
1423
1424 pub fn reallocs(&self) -> impl Iterator<Item = &str> + '_ {
1431 self.names.iter().filter_map(|(name, export)| match export {
1432 Export::GeneralPurposeRealloc
1433 | Export::GeneralPurposeExportRealloc
1434 | Export::GeneralPurposeImportRealloc => Some(name.as_str()),
1435 _ => None,
1436 })
1437 }
1438
1439 pub fn memory(&self) -> Option<&str> {
1441 self.find(|m| matches!(m, Export::Memory))
1442 }
1443
1444 pub fn indirect_function_table(&self) -> Option<&str> {
1446 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1447 }
1448
1449 pub fn wasm_task_hook(&self) -> Option<&str> {
1451 self.find(|t| matches!(t, Export::WasmTaskHook))
1452 }
1453
1454 pub fn initialize(&self) -> Option<&str> {
1456 self.find(|m| matches!(m, Export::Initialize))
1457 }
1458
1459 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1461 self.find(|m| match m {
1462 Export::ResourceDtor(t) => *t == ty,
1463 _ => false,
1464 })
1465 }
1466
1467 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1470 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1471 Some(name)
1472 }
1473
1474 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1476 self.names.iter().map(|(n, e)| (n.as_str(), e))
1477 }
1478
1479 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1480 let resolve = &encoder.metadata.resolve;
1481 let world = encoder.metadata.world;
1482 if self
1485 .names
1486 .values()
1487 .filter(|m| matches!(m, Export::Memory))
1488 .count()
1489 > 1
1490 {
1491 bail!("cannot componentize module that exports multiple memories")
1492 }
1493
1494 for (name, export) in &self.names {
1496 match export {
1497 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1498 if !matches!(
1499 self.names.get(&format!("[callback]{name}")),
1500 Some(Export::WorldFuncCallback(_))
1501 ) {
1502 bail!("missing callback for `{name}`");
1503 }
1504 }
1505 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1506 if !matches!(
1507 self.names.get(&format!("[callback]{name}")),
1508 Some(Export::InterfaceFuncCallback(_, _))
1509 ) {
1510 bail!("missing callback for `{name}`");
1511 }
1512 }
1513 _ => {}
1514 }
1515 }
1516
1517 for export in exports {
1519 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1520 let result = self.find(|e| match e {
1521 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1522 _ => false,
1523 });
1524 if result.is_some() {
1525 Ok(())
1526 } else {
1527 let export = resolve.name_world_key(export);
1528 bail!("failed to find export of interface `{export}` function `{name}`")
1529 }
1530 };
1531 let require_world_func = |name: &str| -> Result<()> {
1532 let result = self.find(|e| match e {
1533 Export::WorldFunc(_, s, _) => name == s,
1534 _ => false,
1535 });
1536 if result.is_some() {
1537 Ok(())
1538 } else {
1539 bail!("failed to find export of function `{name}`")
1540 }
1541 };
1542 match &resolve.worlds[world].exports[export] {
1543 WorldItem::Interface { id, .. } => {
1544 for (name, _) in resolve.interfaces[*id].functions.iter() {
1545 require_interface_func(*id, name)?;
1546 }
1547 }
1548 WorldItem::Function(f) => {
1549 require_world_func(&f.name)?;
1550 }
1551 WorldItem::Type { .. } => unreachable!(),
1552 }
1553 }
1554
1555 Ok(())
1556 }
1557}
1558
1559struct MaybeCancellable<T> {
1561 #[allow(unused)]
1562 inner: T,
1563 cancellable: bool,
1564}
1565
1566struct MaybeAsyncLowered<T> {
1568 inner: T,
1569 async_lowered: bool,
1570}
1571
1572struct PayloadLookupContext<'a> {
1575 resolve: &'a Resolve,
1576 world: &'a World,
1577 id: Option<InterfaceId>,
1578 import: bool,
1579 key: Option<WorldKey>,
1580}
1581
1582trait NameMangling {
1604 fn import_root(&self) -> &str;
1605 fn import_non_root_prefix(&self) -> &str;
1606 fn import_exported_intrinsic_prefix(&self) -> &str;
1607 fn export_memory(&self) -> &str;
1608 fn export_initialize(&self) -> &str;
1609 fn export_realloc(&self) -> &str;
1610 fn export_indirect_function_table(&self) -> Option<&str>;
1611 fn export_wasm_task_hook(&self) -> Option<&str>;
1612 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1613 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1614 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1615 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1616 fn task_cancel(&self, name: &str) -> bool;
1617 fn backpressure_inc(&self, name: &str) -> bool;
1618 fn backpressure_dec(&self, name: &str) -> bool;
1619 fn waitable_set_new(&self, name: &str) -> bool;
1620 fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1621 fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1622 fn waitable_set_drop(&self, name: &str) -> bool;
1623 fn waitable_join(&self, name: &str) -> bool;
1624 fn subtask_drop(&self, name: &str) -> bool;
1625 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1626 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1627 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1628 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1629 fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1630 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1631 fn error_context_drop(&self, name: &str) -> bool;
1632 fn context_get(&self, name: &str) -> Option<(ValType, u32)>;
1633 fn context_set(&self, name: &str) -> Option<(ValType, u32)>;
1634 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1635 fn future_write(
1636 &self,
1637 lookup_context: &PayloadLookupContext,
1638 name: &str,
1639 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1640 fn future_read(
1641 &self,
1642 lookup_context: &PayloadLookupContext,
1643 name: &str,
1644 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1645 fn future_cancel_write(
1646 &self,
1647 lookup_context: &PayloadLookupContext,
1648 name: &str,
1649 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1650 fn future_cancel_read(
1651 &self,
1652 lookup_context: &PayloadLookupContext,
1653 name: &str,
1654 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1655 fn future_drop_writable(
1656 &self,
1657 lookup_context: &PayloadLookupContext,
1658 name: &str,
1659 ) -> Option<PayloadInfo>;
1660 fn future_drop_readable(
1661 &self,
1662 lookup_context: &PayloadLookupContext,
1663 name: &str,
1664 ) -> Option<PayloadInfo>;
1665 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1666 fn stream_write(
1667 &self,
1668 lookup_context: &PayloadLookupContext,
1669 name: &str,
1670 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1671 fn stream_read(
1672 &self,
1673 lookup_context: &PayloadLookupContext,
1674 name: &str,
1675 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1676 fn stream_cancel_write(
1677 &self,
1678 lookup_context: &PayloadLookupContext,
1679 name: &str,
1680 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1681 fn stream_cancel_read(
1682 &self,
1683 lookup_context: &PayloadLookupContext,
1684 name: &str,
1685 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1686 fn stream_drop_writable(
1687 &self,
1688 lookup_context: &PayloadLookupContext,
1689 name: &str,
1690 ) -> Option<PayloadInfo>;
1691 fn stream_drop_readable(
1692 &self,
1693 lookup_context: &PayloadLookupContext,
1694 name: &str,
1695 ) -> Option<PayloadInfo>;
1696 fn thread_index(&self, name: &str) -> bool;
1697 fn thread_new_indirect(&self, name: &str) -> bool;
1698 fn thread_resume_later(&self, name: &str) -> bool;
1699 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1700 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1701 fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1702 fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1703 fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1704 fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1705 fn module_to_interface(
1706 &self,
1707 module: &str,
1708 resolve: &Resolve,
1709 items: &IndexMap<WorldKey, WorldItem>,
1710 ) -> Result<(WorldKey, InterfaceId)>;
1711 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1712 fn match_wit_export<'a>(
1713 &self,
1714 export_name: &str,
1715 resolve: &'a Resolve,
1716 world: WorldId,
1717 exports: &'a IndexSet<WorldKey>,
1718 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1719 fn match_wit_resource_dtor<'a>(
1720 &self,
1721 export_name: &str,
1722 resolve: &'a Resolve,
1723 world: WorldId,
1724 exports: &'a IndexSet<WorldKey>,
1725 ) -> Option<TypeId>;
1726 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1727 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1728 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import>;
1729}
1730
1731struct Standard;
1734
1735const STANDARD: &'static dyn NameMangling = &Standard;
1736
1737impl NameMangling for Standard {
1738 fn import_root(&self) -> &str {
1739 ""
1740 }
1741 fn import_non_root_prefix(&self) -> &str {
1742 "|"
1743 }
1744 fn import_exported_intrinsic_prefix(&self) -> &str {
1745 "_ex_"
1746 }
1747 fn export_memory(&self) -> &str {
1748 "_memory"
1749 }
1750 fn export_initialize(&self) -> &str {
1751 "_initialize"
1752 }
1753 fn export_realloc(&self) -> &str {
1754 "_realloc"
1755 }
1756 fn export_indirect_function_table(&self) -> Option<&str> {
1757 None
1758 }
1759 fn export_wasm_task_hook(&self) -> Option<&str> {
1760 None
1761 }
1762 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1763 name.strip_suffix("_drop")
1764 }
1765 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1766 name.strip_suffix("_new")
1767 }
1768 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1769 name.strip_suffix("_rep")
1770 }
1771 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1772 None
1773 }
1774 fn task_cancel(&self, _name: &str) -> bool {
1775 false
1776 }
1777 fn backpressure_inc(&self, _name: &str) -> bool {
1778 false
1779 }
1780 fn backpressure_dec(&self, _name: &str) -> bool {
1781 false
1782 }
1783 fn waitable_set_new(&self, _name: &str) -> bool {
1784 false
1785 }
1786 fn waitable_set_wait(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1787 None
1788 }
1789 fn waitable_set_poll(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1790 None
1791 }
1792 fn waitable_set_drop(&self, _name: &str) -> bool {
1793 false
1794 }
1795 fn waitable_join(&self, _name: &str) -> bool {
1796 false
1797 }
1798 fn subtask_drop(&self, _name: &str) -> bool {
1799 false
1800 }
1801 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1802 None
1803 }
1804 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1805 None
1806 }
1807 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1808 None
1809 }
1810 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1811 None
1812 }
1813 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1814 None
1815 }
1816 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1817 None
1818 }
1819 fn error_context_drop(&self, _name: &str) -> bool {
1820 false
1821 }
1822 fn context_get(&self, _name: &str) -> Option<(ValType, u32)> {
1823 None
1824 }
1825 fn context_set(&self, _name: &str) -> Option<(ValType, u32)> {
1826 None
1827 }
1828 fn thread_index(&self, _name: &str) -> bool {
1829 false
1830 }
1831 fn thread_new_indirect(&self, _name: &str) -> bool {
1832 false
1833 }
1834 fn thread_resume_later(&self, _name: &str) -> bool {
1835 false
1836 }
1837 fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1838 None
1839 }
1840 fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1841 None
1842 }
1843 fn thread_suspend_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1844 None
1845 }
1846 fn thread_yield_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1847 None
1848 }
1849 fn thread_suspend_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1850 None
1851 }
1852 fn thread_yield_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1853 None
1854 }
1855 fn future_new(
1856 &self,
1857 _lookup_context: &PayloadLookupContext,
1858 _name: &str,
1859 ) -> Option<PayloadInfo> {
1860 None
1861 }
1862 fn future_write(
1863 &self,
1864 _lookup_context: &PayloadLookupContext,
1865 _name: &str,
1866 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1867 None
1868 }
1869 fn future_read(
1870 &self,
1871 _lookup_context: &PayloadLookupContext,
1872 _name: &str,
1873 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1874 None
1875 }
1876 fn future_cancel_write(
1877 &self,
1878 _lookup_context: &PayloadLookupContext,
1879 _name: &str,
1880 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1881 None
1882 }
1883 fn future_cancel_read(
1884 &self,
1885 _lookup_context: &PayloadLookupContext,
1886 _name: &str,
1887 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1888 None
1889 }
1890 fn future_drop_writable(
1891 &self,
1892 _lookup_context: &PayloadLookupContext,
1893 _name: &str,
1894 ) -> Option<PayloadInfo> {
1895 None
1896 }
1897 fn future_drop_readable(
1898 &self,
1899 _lookup_context: &PayloadLookupContext,
1900 _name: &str,
1901 ) -> Option<PayloadInfo> {
1902 None
1903 }
1904 fn stream_new(
1905 &self,
1906 _lookup_context: &PayloadLookupContext,
1907 _name: &str,
1908 ) -> Option<PayloadInfo> {
1909 None
1910 }
1911 fn stream_write(
1912 &self,
1913 _lookup_context: &PayloadLookupContext,
1914 _name: &str,
1915 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1916 None
1917 }
1918 fn stream_read(
1919 &self,
1920 _lookup_context: &PayloadLookupContext,
1921 _name: &str,
1922 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1923 None
1924 }
1925 fn stream_cancel_write(
1926 &self,
1927 _lookup_context: &PayloadLookupContext,
1928 _name: &str,
1929 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1930 None
1931 }
1932 fn stream_cancel_read(
1933 &self,
1934 _lookup_context: &PayloadLookupContext,
1935 _name: &str,
1936 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1937 None
1938 }
1939 fn stream_drop_writable(
1940 &self,
1941 _lookup_context: &PayloadLookupContext,
1942 _name: &str,
1943 ) -> Option<PayloadInfo> {
1944 None
1945 }
1946 fn stream_drop_readable(
1947 &self,
1948 _lookup_context: &PayloadLookupContext,
1949 _name: &str,
1950 ) -> Option<PayloadInfo> {
1951 None
1952 }
1953 fn module_to_interface(
1954 &self,
1955 interface: &str,
1956 resolve: &Resolve,
1957 items: &IndexMap<WorldKey, WorldItem>,
1958 ) -> Result<(WorldKey, InterfaceId)> {
1959 for (key, item) in items.iter() {
1960 let id = match key {
1961 WorldKey::Name(name) => match item {
1963 WorldItem::Interface { id, .. } if name == interface => *id,
1964 _ => continue,
1965 },
1966 WorldKey::Interface(id) => {
1968 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1969 continue;
1970 }
1971 *id
1972 }
1973 };
1974 return Ok((key.clone(), id));
1975 }
1976 bail!("failed to find world item corresponding to interface `{interface}`")
1977 }
1978 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1979 name.strip_suffix("_post")
1980 }
1981 fn match_wit_export<'a>(
1982 &self,
1983 export_name: &str,
1984 resolve: &'a Resolve,
1985 world: WorldId,
1986 exports: &'a IndexSet<WorldKey>,
1987 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1988 if let Some(world_export_name) = export_name.strip_prefix("||") {
1989 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1990 match &resolve.worlds[world].exports[key] {
1991 WorldItem::Function(f) => return Some((key, None, f)),
1992 _ => return None,
1993 }
1994 }
1995
1996 let (key, id, func_name) =
1997 self.match_wit_interface(export_name, resolve, world, exports)?;
1998 let func = resolve.interfaces[id].functions.get(func_name)?;
1999 Some((key, Some(id), func))
2000 }
2001
2002 fn match_wit_resource_dtor<'a>(
2003 &self,
2004 export_name: &str,
2005 resolve: &'a Resolve,
2006 world: WorldId,
2007 exports: &'a IndexSet<WorldKey>,
2008 ) -> Option<TypeId> {
2009 let (_key, id, name) =
2010 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
2011 let ty = *resolve.interfaces[id].types.get(name)?;
2012 match resolve.types[ty].kind {
2013 TypeDefKind::Resource => Some(ty),
2014 _ => None,
2015 }
2016 }
2017
2018 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2019 (name, AbiVariant::GuestImport)
2020 }
2021 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2022 (name, AbiVariant::GuestImport)
2023 }
2024 fn env_import(&self, _name: &str, _ty: &FuncType) -> Option<Import> {
2025 None
2026 }
2027}
2028
2029impl Standard {
2030 fn match_wit_interface<'a, 'b>(
2031 &self,
2032 export_name: &'b str,
2033 resolve: &'a Resolve,
2034 world: WorldId,
2035 exports: &'a IndexSet<WorldKey>,
2036 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
2037 let world = &resolve.worlds[world];
2038 let export_name = export_name.strip_prefix("|")?;
2039
2040 for export in exports {
2041 let id = match &world.exports[export] {
2042 WorldItem::Interface { id, .. } => *id,
2043 WorldItem::Function(_) => continue,
2044 WorldItem::Type { .. } => unreachable!(),
2045 };
2046 let remaining = match export {
2047 WorldKey::Name(name) => export_name.strip_prefix(name),
2048 WorldKey::Interface(_) => {
2049 let prefix = resolve.canonicalized_id_of(id).unwrap();
2050 export_name.strip_prefix(&prefix)
2051 }
2052 };
2053 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
2054 Some(name) => name,
2055 None => continue,
2056 };
2057 return Some((export, id, item_name));
2058 }
2059
2060 None
2061 }
2062}
2063
2064struct Legacy;
2067
2068const LEGACY: &'static dyn NameMangling = &Legacy;
2069
2070impl Legacy {
2071 fn prefixed_payload(
2077 &self,
2078 lookup_context: &PayloadLookupContext,
2079 name: &str,
2080 prefix: &str,
2081 ) -> Option<PayloadInfo> {
2082 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2085 let ty = match index_or_unit {
2086 "unit" => {
2087 if name.starts_with("[future") {
2088 PayloadType::UnitFuture
2089 } else if name.starts_with("[stream") {
2090 PayloadType::UnitStream
2091 } else {
2092 unreachable!()
2093 }
2094 }
2095 other => {
2096 let type_index = other.parse::<u32>().ok()? as usize;
2100
2101 let function = get_function(
2106 lookup_context.resolve,
2107 lookup_context.world,
2108 func_name,
2109 lookup_context.id,
2110 lookup_context.import,
2111 )
2112 .ok()?;
2113 PayloadType::Type {
2114 id: *function
2115 .find_futures_and_streams(lookup_context.resolve)
2116 .get(type_index)?,
2117 function: function.name.clone(),
2118 }
2119 }
2120 };
2121
2122 Some(PayloadInfo {
2124 name: name.to_string(),
2125 ty,
2126 key: lookup_context
2127 .key
2128 .clone()
2129 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2130 interface: lookup_context.id,
2131 imported: lookup_context.import,
2132 })
2133 }
2134
2135 fn maybe_async_lowered_payload(
2136 &self,
2137 lookup_context: &PayloadLookupContext,
2138 name: &str,
2139 prefix: &str,
2140 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2141 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2142 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2143 Some(MaybeAsyncLowered {
2144 inner: payload,
2145 async_lowered,
2146 })
2147 }
2148
2149 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2150 name.strip_prefix("[async-lower]")
2151 .map_or((false, name), |s| (true, s))
2152 }
2153 fn match_with_async_lowered_prefix(
2154 &self,
2155 name: &str,
2156 expected: &str,
2157 ) -> Option<MaybeAsyncLowered<()>> {
2158 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2159 if clean_name == expected {
2160 Some(MaybeAsyncLowered {
2161 inner: (),
2162 async_lowered,
2163 })
2164 } else {
2165 None
2166 }
2167 }
2168 fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2169 name.strip_prefix("[cancellable]")
2170 .map_or((false, name), |s| (true, s))
2171 }
2172 fn match_with_cancellable_prefix(
2173 &self,
2174 name: &str,
2175 expected: &str,
2176 ) -> Option<MaybeCancellable<()>> {
2177 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2178 if clean_name == expected {
2179 Some(MaybeCancellable {
2180 inner: (),
2181 cancellable,
2182 })
2183 } else {
2184 None
2185 }
2186 }
2187
2188 fn match_with_optional_type_suffix(name: &str, match_prefix: &str) -> Option<ValType> {
2192 let tail = name.strip_prefix(match_prefix)?.strip_suffix(']')?;
2193 if tail.is_empty() {
2194 Some(ValType::I32)
2195 } else {
2196 match tail.strip_prefix('-')? {
2197 "i32" => Some(ValType::I32),
2198 "i64" => Some(ValType::I64),
2199 _ => None,
2201 }
2202 }
2203 }
2204}
2205
2206impl NameMangling for Legacy {
2207 fn import_root(&self) -> &str {
2208 "$root"
2209 }
2210 fn import_non_root_prefix(&self) -> &str {
2211 ""
2212 }
2213 fn import_exported_intrinsic_prefix(&self) -> &str {
2214 "[export]"
2215 }
2216 fn export_memory(&self) -> &str {
2217 "memory"
2218 }
2219 fn export_initialize(&self) -> &str {
2220 "_initialize"
2221 }
2222 fn export_realloc(&self) -> &str {
2223 "cabi_realloc"
2224 }
2225 fn export_indirect_function_table(&self) -> Option<&str> {
2226 Some("__indirect_function_table")
2227 }
2228 fn export_wasm_task_hook(&self) -> Option<&str> {
2229 Some(crate::linking::metadata::TASK_HOOK)
2230 }
2231 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2232 name.strip_prefix("[resource-drop]")
2233 }
2234 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2235 name.strip_prefix("[resource-new]")
2236 }
2237 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2238 name.strip_prefix("[resource-rep]")
2239 }
2240 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2241 name.strip_prefix("[task-return]")
2242 }
2243 fn task_cancel(&self, name: &str) -> bool {
2244 name == "[task-cancel]"
2245 }
2246 fn backpressure_inc(&self, name: &str) -> bool {
2247 name == "[backpressure-inc]"
2248 }
2249 fn backpressure_dec(&self, name: &str) -> bool {
2250 name == "[backpressure-dec]"
2251 }
2252 fn waitable_set_new(&self, name: &str) -> bool {
2253 name == "[waitable-set-new]"
2254 }
2255 fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2256 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2257 let mb_cancellable = MaybeCancellable {
2258 inner: (),
2259 cancellable,
2260 };
2261 let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-wait")?;
2262 Some((mb_cancellable, result_ty))
2263 }
2264 fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2265 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2266 let mb_cancellable = MaybeCancellable {
2267 inner: (),
2268 cancellable,
2269 };
2270 let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-poll")?;
2271 Some((mb_cancellable, result_ty))
2272 }
2273 fn waitable_set_drop(&self, name: &str) -> bool {
2274 name == "[waitable-set-drop]"
2275 }
2276 fn waitable_join(&self, name: &str) -> bool {
2277 name == "[waitable-join]"
2278 }
2279 fn subtask_drop(&self, name: &str) -> bool {
2280 name == "[subtask-drop]"
2281 }
2282 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2283 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2284 }
2285 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2286 name.strip_prefix("[callback][async-lift]")
2287 }
2288 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2289 name.strip_prefix("[async-lift]")
2290 }
2291 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2292 name.strip_prefix("[async-lift-stackful]")
2293 }
2294 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2295 match name {
2296 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2297 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2298 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2299 _ => None,
2300 }
2301 }
2302 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2303 match name {
2304 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2305 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2306 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2307 _ => None,
2308 }
2309 }
2310 fn error_context_drop(&self, name: &str) -> bool {
2311 name == "[error-context-drop]"
2312 }
2313 fn context_get(&self, name: &str) -> Option<(ValType, u32)> {
2314 parse_context_name(name, "[context-get-")
2315 }
2316 fn context_set(&self, name: &str) -> Option<(ValType, u32)> {
2317 parse_context_name(name, "[context-set-")
2318 }
2319 fn thread_index(&self, name: &str) -> bool {
2320 name == "[thread-index]"
2321 }
2322 fn thread_new_indirect(&self, name: &str) -> bool {
2323 name == "[thread-new-indirect-v0]"
2325 }
2326 fn thread_resume_later(&self, name: &str) -> bool {
2327 name == "[thread-resume-later]"
2328 }
2329 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2330 self.match_with_cancellable_prefix(name, "[thread-suspend]")
2331 }
2332 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2333 self.match_with_cancellable_prefix(name, "[thread-yield]")
2334 }
2335 fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2336 self.match_with_cancellable_prefix(name, "[thread-suspend-then-resume]")
2337 }
2338 fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2339 self.match_with_cancellable_prefix(name, "[thread-yield-then-resume]")
2340 }
2341 fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2342 self.match_with_cancellable_prefix(name, "[thread-suspend-then-promote]")
2343 }
2344 fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2345 self.match_with_cancellable_prefix(name, "[thread-yield-then-promote]")
2346 }
2347 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2348 self.prefixed_payload(lookup_context, name, "[future-new-")
2349 }
2350 fn future_write(
2351 &self,
2352 lookup_context: &PayloadLookupContext,
2353 name: &str,
2354 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2355 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2356 }
2357 fn future_read(
2358 &self,
2359 lookup_context: &PayloadLookupContext,
2360 name: &str,
2361 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2362 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2363 }
2364 fn future_cancel_write(
2365 &self,
2366 lookup_context: &PayloadLookupContext,
2367 name: &str,
2368 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2369 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2370 }
2371 fn future_cancel_read(
2372 &self,
2373 lookup_context: &PayloadLookupContext,
2374 name: &str,
2375 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2376 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2377 }
2378 fn future_drop_writable(
2379 &self,
2380 lookup_context: &PayloadLookupContext,
2381 name: &str,
2382 ) -> Option<PayloadInfo> {
2383 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2384 }
2385 fn future_drop_readable(
2386 &self,
2387 lookup_context: &PayloadLookupContext,
2388 name: &str,
2389 ) -> Option<PayloadInfo> {
2390 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2391 }
2392 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2393 self.prefixed_payload(lookup_context, name, "[stream-new-")
2394 }
2395 fn stream_write(
2396 &self,
2397 lookup_context: &PayloadLookupContext,
2398 name: &str,
2399 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2400 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2401 }
2402 fn stream_read(
2403 &self,
2404 lookup_context: &PayloadLookupContext,
2405 name: &str,
2406 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2407 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2408 }
2409 fn stream_cancel_write(
2410 &self,
2411 lookup_context: &PayloadLookupContext,
2412 name: &str,
2413 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2414 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2415 }
2416 fn stream_cancel_read(
2417 &self,
2418 lookup_context: &PayloadLookupContext,
2419 name: &str,
2420 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2421 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2422 }
2423 fn stream_drop_writable(
2424 &self,
2425 lookup_context: &PayloadLookupContext,
2426 name: &str,
2427 ) -> Option<PayloadInfo> {
2428 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2429 }
2430 fn stream_drop_readable(
2431 &self,
2432 lookup_context: &PayloadLookupContext,
2433 name: &str,
2434 ) -> Option<PayloadInfo> {
2435 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2436 }
2437 fn module_to_interface(
2438 &self,
2439 module: &str,
2440 resolve: &Resolve,
2441 items: &IndexMap<WorldKey, WorldItem>,
2442 ) -> Result<(WorldKey, InterfaceId)> {
2443 let bare_name = WorldKey::Name(module.to_string());
2445 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2446 return Ok((bare_name, *id));
2447 }
2448
2449 let kebab_name = ComponentName::new(module, 0);
2455 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2456 Ok(ComponentNameKind::Interface(name)) => name,
2457 _ => bail!("module requires an import interface named `{module}`"),
2458 };
2459
2460 let version = name.version(None)?;
2464
2465 let pkgname = PackageName {
2467 namespace: name.namespace().to_string(),
2468 name: name.package().to_string(),
2469 version: version.clone(),
2470 };
2471 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2472 if let Some(id) = resolve.packages[*pkg]
2473 .interfaces
2474 .get(name.interface().as_str())
2475 {
2476 let key = WorldKey::Interface(*id);
2479 if items.contains_key(&key) {
2480 return Ok((key, *id));
2481 }
2482
2483 for k in items.keys() {
2489 let i = match *k {
2490 WorldKey::Interface(id) => id,
2491 WorldKey::Name(_) => continue,
2492 };
2493 if resolve.interfaces[i].clone_of == Some(*id) {
2494 return Ok((WorldKey::Interface(i), i));
2495 }
2496 }
2497 }
2498 }
2499
2500 for (key, _) in items {
2505 let id = match key {
2506 WorldKey::Interface(id) => *id,
2507 WorldKey::Name(_) => continue,
2508 };
2509 let interface = &resolve.interfaces[id];
2511 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2512 continue;
2513 }
2514
2515 let pkg = &resolve.packages[interface.package.unwrap()];
2517 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2518 continue;
2519 }
2520
2521 let module_version = match &version {
2522 Some(version) => version,
2523 None => continue,
2524 };
2525 let pkg_version = match &pkg.name.version {
2526 Some(version) => version,
2527 None => continue,
2528 };
2529
2530 let module_compat = PackageName::version_compat_track(&module_version);
2532 let pkg_compat = PackageName::version_compat_track(pkg_version);
2533 if module_compat == pkg_compat {
2534 return Ok((key.clone(), id));
2535 }
2536 }
2537
2538 bail!("module requires an import interface named `{module}`")
2539 }
2540 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2541 name.strip_prefix("cabi_post_")
2542 }
2543 fn match_wit_export<'a>(
2544 &self,
2545 export_name: &str,
2546 resolve: &'a Resolve,
2547 world: WorldId,
2548 exports: &'a IndexSet<WorldKey>,
2549 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2550 let world = &resolve.worlds[world];
2551 for name in exports {
2552 match &world.exports[name] {
2553 WorldItem::Function(f) => {
2554 if f.legacy_core_export_name(None) == export_name {
2555 return Some((name, None, f));
2556 }
2557 }
2558 WorldItem::Interface { id, .. } => {
2559 let string = resolve.name_world_key(name);
2560 for (_, func) in resolve.interfaces[*id].functions.iter() {
2561 if func.legacy_core_export_name(Some(&string)) == export_name {
2562 return Some((name, Some(*id), func));
2563 }
2564 }
2565 }
2566
2567 WorldItem::Type { .. } => unreachable!(),
2568 }
2569 }
2570
2571 None
2572 }
2573
2574 fn match_wit_resource_dtor<'a>(
2575 &self,
2576 export_name: &str,
2577 resolve: &'a Resolve,
2578 world: WorldId,
2579 exports: &'a IndexSet<WorldKey>,
2580 ) -> Option<TypeId> {
2581 let world = &resolve.worlds[world];
2582 for name in exports {
2583 let id = match &world.exports[name] {
2584 WorldItem::Interface { id, .. } => *id,
2585 WorldItem::Function(_) => continue,
2586 WorldItem::Type { .. } => unreachable!(),
2587 };
2588 let name = resolve.name_world_key(name);
2589 let resource = match export_name
2590 .strip_prefix(&name)
2591 .and_then(|s| s.strip_prefix("#[dtor]"))
2592 .and_then(|r| resolve.interfaces[id].types.get(r))
2593 {
2594 Some(id) => *id,
2595 None => continue,
2596 };
2597
2598 match resolve.types[resource].kind {
2599 TypeDefKind::Resource => {}
2600 _ => continue,
2601 }
2602
2603 return Some(resource);
2604 }
2605
2606 None
2607 }
2608
2609 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2610 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2611 (
2612 name,
2613 if async_abi {
2614 AbiVariant::GuestImportAsync
2615 } else {
2616 AbiVariant::GuestImport
2617 },
2618 )
2619 }
2620 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2621 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2622 (
2623 name,
2624 if async_abi {
2625 AbiVariant::GuestImportAsync
2626 } else {
2627 AbiVariant::GuestImport
2628 },
2629 )
2630 }
2631 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import> {
2632 match name {
2633 "__wasm_get_stack_pointer" => {
2634 let ty = *ty.results().get(0)?;
2635 Some(Import::ContextGet { ty, slot: 0 })
2636 }
2637 "__wasm_set_stack_pointer" => {
2638 let ty = *ty.params().get(0)?;
2639 Some(Import::ContextSet { ty, slot: 0 })
2640 }
2641 "__wasm_get_tls_base" => {
2645 let ty = *ty.results().get(0)?;
2646 Some(Import::TlsBaseGet { ty })
2647 }
2648 "__wasm_set_tls_base" => {
2649 let ty = *ty.params().get(0)?;
2650 Some(Import::TlsBaseSet { ty })
2651 }
2652 _ => None,
2653 }
2654 }
2655}
2656
2657pub fn validate_module(
2669 encoder: &ComponentEncoder,
2670 bytes: &[u8],
2671 import_map: Option<&ModuleImportMap>,
2672) -> Result<ValidatedModule> {
2673 ValidatedModule::new(
2674 encoder,
2675 bytes,
2676 &encoder.main_module_exports,
2677 import_map,
2678 None,
2679 )
2680}
2681
2682pub fn validate_adapter_module(
2700 encoder: &ComponentEncoder,
2701 bytes: &[u8],
2702 required_by_import: &IndexMap<String, FuncType>,
2703 exports: &IndexSet<WorldKey>,
2704 library_info: Option<&LibraryInfo>,
2705) -> Result<ValidatedModule> {
2706 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2707
2708 for (name, required_ty) in required_by_import {
2709 let actual = match ret.exports.raw_exports.get(name) {
2710 Some(ty) => ty,
2711 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2712 };
2713 validate_func_sig(name, required_ty, &actual)?;
2714 }
2715
2716 Ok(ret)
2717}
2718
2719#[derive(Debug, Clone)]
2726pub struct AdapterModuleDidNotExport(String);
2727
2728impl fmt::Display for AdapterModuleDidNotExport {
2729 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2730 write!(f, "adapter module did not export `{}`", self.0)
2731 }
2732}
2733
2734impl std::error::Error for AdapterModuleDidNotExport {}
2735
2736fn resource_test_for_interface<'a>(
2737 resolve: &'a Resolve,
2738 id: InterfaceId,
2739) -> impl Fn(&str) -> Option<TypeId> + 'a {
2740 let interface = &resolve.interfaces[id];
2741 move |name: &str| {
2742 let ty = match interface.types.get(name) {
2743 Some(ty) => *ty,
2744 None => return None,
2745 };
2746 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2747 Some(ty)
2748 } else {
2749 None
2750 }
2751 }
2752}
2753
2754fn resource_test_for_world<'a>(
2755 resolve: &'a Resolve,
2756 id: WorldId,
2757) -> impl Fn(&str) -> Option<TypeId> + 'a {
2758 let world = &resolve.worlds[id];
2759 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2760 WorldItem::Type { id, .. } => {
2761 if matches!(resolve.types[*id].kind, TypeDefKind::Resource) {
2762 Some(*id)
2763 } else {
2764 None
2765 }
2766 }
2767 _ => None,
2768 }
2769}
2770
2771fn validate_func(
2772 resolve: &Resolve,
2773 ty: &wasmparser::FuncType,
2774 func: &Function,
2775 abi: AbiVariant,
2776) -> Result<()> {
2777 validate_func_sig(
2778 &func.name,
2779 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2780 ty,
2781 )
2782}
2783
2784fn validate_post_return(
2785 resolve: &Resolve,
2786 ty: &wasmparser::FuncType,
2787 func: &Function,
2788) -> Result<()> {
2789 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2795 sig.params = mem::take(&mut sig.results);
2796 validate_func_sig(
2797 &format!("{} post-return", func.name),
2798 &wasm_sig_to_func_type(sig),
2799 ty,
2800 )
2801}
2802
2803fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2804 if ty != expected {
2805 bail!(
2806 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2807 name,
2808 expected.params(),
2809 expected.results(),
2810 ty.params(),
2811 ty.results()
2812 );
2813 }
2814
2815 Ok(())
2816}
2817
2818fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2820 assert!(prefix.starts_with("["));
2821 assert!(prefix.ends_with("-"));
2822 let suffix = name.strip_prefix(prefix)?;
2823 let index = suffix.find(']')?;
2824 let rest = &suffix[index + 1..];
2825 Some((&suffix[..index], rest))
2826}
2827
2828fn parse_context_name(name: &str, prefix: &str) -> Option<(ValType, u32)> {
2834 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2835 if !rest.is_empty() {
2836 return None;
2837 }
2838 let (ty, slot) = match suffix.split_once('-') {
2839 Some(("i64", slot)) => (ValType::I64, slot),
2840 Some(("i32", slot)) => (ValType::I32, slot),
2841 _ => (ValType::I32, suffix),
2842 };
2843 let slot = slot.parse().ok()?;
2844 Some((ty, slot))
2845}
2846
2847fn get_function<'a>(
2848 resolve: &'a Resolve,
2849 world: &'a World,
2850 name: &str,
2851 interface: Option<InterfaceId>,
2852 imported: bool,
2853) -> Result<&'a Function> {
2854 let function = if let Some(id) = interface {
2855 return resolve.interfaces[id]
2856 .functions
2857 .get(name)
2858 .ok_or_else(|| anyhow!("no export `{name}` found"));
2859 } else if imported {
2860 world.imports.get(&WorldKey::Name(name.to_string()))
2861 } else {
2862 world.exports.get(&WorldKey::Name(name.to_string()))
2863 };
2864 let Some(WorldItem::Function(function)) = function else {
2865 bail!("no export `{name}` found");
2866 };
2867 Ok(function)
2868}