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 StreamForward(PayloadInfo),
376
377 StreamCancelRead { info: PayloadInfo, async_: bool },
382
383 StreamCancelWrite { info: PayloadInfo, async_: bool },
388
389 StreamDropReadable(PayloadInfo),
393
394 StreamDropWritable(PayloadInfo),
398
399 FutureNew(PayloadInfo),
403
404 FutureRead { async_: bool, info: PayloadInfo },
409
410 FutureWrite { async_: bool, info: PayloadInfo },
414
415 FutureForward(PayloadInfo),
421
422 FutureCancelRead { info: PayloadInfo, async_: bool },
427
428 FutureCancelWrite { info: PayloadInfo, async_: bool },
433
434 FutureDropReadable(PayloadInfo),
438
439 FutureDropWritable(PayloadInfo),
443
444 ErrorContextNew { encoding: StringEncoding },
449
450 ErrorContextDebugMessage { encoding: StringEncoding },
456
457 ErrorContextDrop,
462
463 ThreadIndex,
467
468 ThreadNewIndirect,
472
473 ThreadResumeLater,
475
476 ThreadSuspend,
478
479 ThreadYield,
481
482 ThreadSuspendThenResume,
484
485 ThreadYieldThenResume,
487
488 ThreadSuspendThenPromote,
490
491 ThreadYieldThenPromote,
493}
494
495impl ImportMap {
496 pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
498 let names = match self.names.get(name) {
499 Some(ImportInstance::Names(names)) => names,
500 _ => return IndexMap::new(),
501 };
502 names
503 .iter()
504 .map(|(_, import)| match import {
505 Import::AdapterExport { ty, func, adapter } => {
506 assert_eq!(adapter, name);
507 (func.clone(), ty.clone())
508 }
509 _ => unreachable!(),
510 })
511 .collect()
512 }
513
514 pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
518 self.names
519 .iter()
520 .filter_map(|(module, m)| match m {
521 ImportInstance::Names(names) => Some((module, names)),
522 ImportInstance::Whole(_) => None,
523 })
524 .flat_map(|(module, m)| {
525 m.iter()
526 .map(move |(field, import)| (module.as_str(), field.as_str(), import))
527 })
528 }
529
530 pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
532 &self.names
533 }
534
535 pub fn imported_memory(&self) -> Option<MemoryType> {
537 self.imported_memory
538 }
539
540 fn add(
543 &mut self,
544 import: wasmparser::Import<'_>,
545 encoder: &ComponentEncoder,
546 import_map: Option<&ModuleImportMap>,
547 library_info: Option<&LibraryInfo>,
548 types: TypesRef<'_>,
549 ) -> Result<()> {
550 if self.classify_import_with_library(import, library_info)? {
551 return Ok(());
552 }
553 let mut import_to_classify = import;
554 if let Some(map) = import_map {
555 if let Some(original_name) = map.original_name(&import) {
556 import_to_classify.name = original_name;
557 }
558 }
559 let item = self
560 .classify(import_to_classify, encoder, types)
561 .with_context(|| {
562 format!(
563 "failed to resolve import `{}::{}`",
564 import.module, import.name,
565 )
566 })?;
567 self.insert_import(import, item)
568 }
569
570 fn classify(
576 &self,
577 import: wasmparser::Import<'_>,
578 encoder: &ComponentEncoder,
579 types: TypesRef<'_>,
580 ) -> Result<Import> {
581 if import.module == "env" && import.name == "memory" {
584 if let TypeRef::Memory(ty) = import.ty {
585 return Ok(Import::MainModuleMemory(ty));
586 }
587 }
588
589 if import.module == "__main_module__" {
591 return Ok(Import::MainModuleExport {
592 name: import.name.to_string(),
593 kind: match import.ty {
594 TypeRef::Func(_) => ExportKind::Func,
595 TypeRef::Table(_) => ExportKind::Table,
596 TypeRef::Memory(_) => ExportKind::Memory,
597 TypeRef::Global(_) => ExportKind::Global,
598 TypeRef::Tag(_) => ExportKind::Tag,
599 TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
600 },
601 });
602 }
603
604 let ty_index = match import.ty {
605 TypeRef::Func(ty) => ty,
606 _ => bail!("module is only allowed to import functions"),
607 };
608 let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
609
610 if encoder.adapters.contains_key(import.module) {
613 return Ok(Import::AdapterExport {
614 adapter: import.module.to_string(),
615 func: import.name.to_string(),
616 ty: ty.clone(),
617 });
618 }
619
620 let (module, names) = match import.module.strip_prefix("cm32p2") {
621 Some(suffix) => (suffix, STANDARD),
622 None if encoder.reject_legacy_names => (import.module, STANDARD),
623 None => (import.module, LEGACY),
624 };
625 self.classify_component_model_import(module, import.name, encoder, ty, names)
626 }
627
628 fn classify_component_model_import(
631 &self,
632 module: &str,
633 name: &str,
634 encoder: &ComponentEncoder,
635 ty: &FuncType,
636 names: &dyn NameMangling,
637 ) -> Result<Import> {
638 let resolve = &encoder.metadata.resolve;
639 let world_id = encoder.metadata.world;
640 let world = &resolve.worlds[world_id];
641
642 if module == names.import_root() {
643 if names.error_context_drop(name) {
644 let expected = FuncType::new([ValType::I32], []);
645 validate_func_sig(name, &expected, ty)?;
646 return Ok(Import::ErrorContextDrop);
647 }
648
649 if names.backpressure_inc(name) {
650 let expected = FuncType::new([], []);
651 validate_func_sig(name, &expected, ty)?;
652 return Ok(Import::BackpressureInc);
653 }
654
655 if names.backpressure_dec(name) {
656 let expected = FuncType::new([], []);
657 validate_func_sig(name, &expected, ty)?;
658 return Ok(Import::BackpressureDec);
659 }
660
661 if names.waitable_set_new(name) {
662 let expected = FuncType::new([], [ValType::I32]);
663 validate_func_sig(name, &expected, ty)?;
664 return Ok(Import::WaitableSetNew);
665 }
666
667 if let Some(result_ty) = names.waitable_set_wait(name) {
668 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
669 validate_func_sig(name, &expected, ty)?;
670 return Ok(Import::WaitableSetWait);
671 }
672
673 if let Some(result_ty) = names.waitable_set_poll(name) {
674 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
675 validate_func_sig(name, &expected, ty)?;
676 return Ok(Import::WaitableSetPoll);
677 }
678
679 if names.waitable_set_drop(name) {
680 let expected = FuncType::new([ValType::I32], []);
681 validate_func_sig(name, &expected, ty)?;
682 return Ok(Import::WaitableSetDrop);
683 }
684
685 if names.waitable_join(name) {
686 let expected = FuncType::new([ValType::I32; 2], []);
687 validate_func_sig(name, &expected, ty)?;
688 return Ok(Import::WaitableJoin);
689 }
690
691 if names.subtask_drop(name) {
692 let expected = FuncType::new([ValType::I32], []);
693 validate_func_sig(name, &expected, ty)?;
694 return Ok(Import::SubtaskDrop);
695 }
696
697 if let Some(info) = names.subtask_cancel(name) {
698 let expected = FuncType::new([ValType::I32], [ValType::I32]);
699 validate_func_sig(name, &expected, ty)?;
700 return Ok(Import::SubtaskCancel {
701 async_: info.async_lowered,
702 });
703 }
704
705 if let Some(encoding) = names.error_context_new(name) {
706 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
707 validate_func_sig(name, &expected, ty)?;
708 return Ok(Import::ErrorContextNew { encoding });
709 }
710
711 if let Some(encoding) = names.error_context_debug_message(name) {
712 let expected = FuncType::new([ValType::I32; 2], []);
713 validate_func_sig(name, &expected, ty)?;
714 return Ok(Import::ErrorContextDebugMessage { encoding });
715 }
716
717 if let Some((slot_ty, slot)) = names.context_get(name) {
718 let expected = FuncType::new([], [slot_ty]);
719 validate_func_sig(name, &expected, ty)?;
720 return Ok(Import::ContextGet { ty: slot_ty, slot });
721 }
722 if let Some((slot_ty, slot)) = names.context_set(name) {
723 let expected = FuncType::new([slot_ty], []);
724 validate_func_sig(name, &expected, ty)?;
725 return Ok(Import::ContextSet { ty: slot_ty, slot });
726 }
727 if names.thread_index(name) {
728 let expected = FuncType::new([], [ValType::I32]);
729 validate_func_sig(name, &expected, ty)?;
730 return Ok(Import::ThreadIndex);
731 }
732 if names.thread_new_indirect(name) {
733 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
734 validate_func_sig(name, &expected, ty)?;
735 return Ok(Import::ThreadNewIndirect);
736 }
737 if names.thread_resume_later(name) {
738 let expected = FuncType::new([ValType::I32], []);
739 validate_func_sig(name, &expected, ty)?;
740 return Ok(Import::ThreadResumeLater);
741 }
742 if names.thread_suspend(name) {
743 let expected = FuncType::new([], [ValType::I32]);
744 validate_func_sig(name, &expected, ty)?;
745 return Ok(Import::ThreadSuspend);
746 }
747 if names.thread_yield(name) {
748 let expected = FuncType::new([], [ValType::I32]);
749 validate_func_sig(name, &expected, ty)?;
750 return Ok(Import::ThreadYield);
751 }
752 if names.thread_suspend_then_resume(name) {
753 let expected = FuncType::new([ValType::I32], [ValType::I32]);
754 validate_func_sig(name, &expected, ty)?;
755 return Ok(Import::ThreadSuspendThenResume);
756 }
757 if names.thread_yield_then_resume(name) {
758 let expected = FuncType::new([ValType::I32], [ValType::I32]);
759 validate_func_sig(name, &expected, ty)?;
760 return Ok(Import::ThreadYieldThenResume);
761 }
762 if names.thread_suspend_then_promote(name) {
763 let expected = FuncType::new([ValType::I32], [ValType::I32]);
764 validate_func_sig(name, &expected, ty)?;
765 return Ok(Import::ThreadSuspendThenPromote);
766 }
767 if 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 }
772
773 let (key_name, abi) = names.world_key_name_and_abi(name);
774 let key = WorldKey::Name(key_name.to_string());
775 if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
776 validate_func(resolve, ty, func, abi)?;
777 return Ok(Import::WorldFunc(key, func.name.clone(), abi));
778 }
779
780 if let Some(import) =
781 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
782 {
783 return Ok(import);
784 }
785
786 match world.imports.get(&key) {
787 Some(_) => bail!("expected world top-level import `{name}` to be a function"),
788 None => bail!("no top-level imported function `{name}` specified"),
789 }
790 }
791
792 if module == "env" {
793 if let Some(import) = names.env_import(name, ty) {
794 return Ok(import);
795 }
796 }
797
798 if matches!(
800 module.strip_prefix(names.import_exported_intrinsic_prefix()),
801 Some(module) if module == names.import_root()
802 ) {
803 if let Some(import) =
804 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
805 {
806 return Ok(import);
807 }
808 }
809
810 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
811 Some(name) => name,
812 None => bail!("unknown or invalid component model import syntax"),
813 };
814
815 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
816 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
817
818 if let Some(import) =
819 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
820 {
821 return Ok(import);
822 }
823 bail!("unknown function `{name}`")
824 }
825
826 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
827 let interface = &resolve.interfaces[id];
828 let (function_name, abi) = names.interface_function_name_and_abi(name);
829 if let Some(f) = interface.functions.get(function_name) {
830 validate_func(resolve, ty, f, abi).with_context(|| {
831 let name = resolve.name_world_key(&key);
832 format!("failed to validate import interface `{name}`")
833 })?;
834 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
835 }
836
837 if let Some(import) =
838 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
839 {
840 return Ok(import);
841 }
842 bail!(
843 "import interface `{module}` is missing function \
844 `{name}` that is required by the module",
845 )
846 }
847
848 fn maybe_classify_wit_intrinsic(
876 &self,
877 name: &str,
878 key_and_id: Option<(WorldKey, InterfaceId)>,
879 encoder: &ComponentEncoder,
880 ty: &FuncType,
881 import: bool,
882 names: &dyn NameMangling,
883 ) -> Result<Option<Import>> {
884 let resolve = &encoder.metadata.resolve;
885 let world_id = encoder.metadata.world;
886 let world = &resolve.worlds[world_id];
887
888 let (key, id) = match key_and_id {
893 Some((key, id)) => (Some(key), Some(id)),
894 None => (None, None),
895 };
896
897 let resource_test = |name: &str| match id {
899 Some(id) => resource_test_for_interface(resolve, id)(name),
900 None => resource_test_for_world(resolve, world_id)(name),
901 };
902
903 if let Some(resource) = names.resource_drop_name(name) {
905 if let Some(resource_id) = resource_test(resource) {
906 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
907 let expected = FuncType::new([ValType::I32], []);
908 validate_func_sig(name, &expected, ty)?;
909 return Ok(Some(if import {
910 Import::ImportedResourceDrop(key, id, resource_id)
911 } else {
912 Import::ExportedResourceDrop(key, resource_id)
913 }));
914 }
915 }
916
917 if !import {
920 if let Some(name) = names.resource_new_name(name) {
921 if let Some(id) = resource_test(name) {
922 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
923 let expected = FuncType::new([ValType::I32], [ValType::I32]);
924 validate_func_sig(name, &expected, ty)?;
925 return Ok(Some(Import::ExportedResourceNew(key, id)));
926 }
927 }
928 if let Some(name) = names.resource_rep_name(name) {
929 if let Some(id) = resource_test(name) {
930 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
931 let expected = FuncType::new([ValType::I32], [ValType::I32]);
932 validate_func_sig(name, &expected, ty)?;
933 return Ok(Some(Import::ExportedResourceRep(key, id)));
934 }
935 }
936 if let Some(name) = names.task_return_name(name) {
937 let func = get_function(resolve, world, name, id, import)?;
938 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
939 return Ok(Some(Import::ExportedTaskReturn(key, id, func.clone())));
942 }
943 if names.task_cancel(name) {
944 let expected = FuncType::new([], []);
945 validate_func_sig(name, &expected, ty)?;
946 return Ok(Some(Import::ExportedTaskCancel));
947 }
948 }
949
950 let lookup_context = PayloadLookupContext {
951 resolve,
952 world,
953 key,
954 id,
955 import,
956 };
957
958 let import = if let Some(info) = names.future_new(&lookup_context, name) {
962 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
963 Import::FutureNew(info)
964 } else if let Some(info) = names.future_write(&lookup_context, name) {
965 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
966 Import::FutureWrite {
967 async_: info.async_lowered,
968 info: info.inner,
969 }
970 } else if let Some(info) = names.future_read(&lookup_context, name) {
971 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
972 Import::FutureRead {
973 async_: info.async_lowered,
974 info: info.inner,
975 }
976 } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
977 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
978 Import::FutureCancelWrite {
979 async_: info.async_lowered,
980 info: info.inner,
981 }
982 } else if let Some(info) = names.future_forward(&lookup_context, name) {
983 validate_func_sig(name, &FuncType::new([ValType::I32; 2], []), ty)?;
984 Import::FutureForward(info)
985 } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
986 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
987 Import::FutureCancelRead {
988 async_: info.async_lowered,
989 info: info.inner,
990 }
991 } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
992 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
993 Import::FutureDropWritable(info)
994 } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
995 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
996 Import::FutureDropReadable(info)
997 } else if let Some(info) = names.stream_new(&lookup_context, name) {
998 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
999 Import::StreamNew(info)
1000 } else if let Some(info) = names.stream_write(&lookup_context, name) {
1001 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
1002 Import::StreamWrite {
1003 async_: info.async_lowered,
1004 info: info.inner,
1005 }
1006 } else if let Some(info) = names.stream_read(&lookup_context, name) {
1007 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
1008 Import::StreamRead {
1009 async_: info.async_lowered,
1010 info: info.inner,
1011 }
1012 } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
1013 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
1014 Import::StreamCancelWrite {
1015 async_: info.async_lowered,
1016 info: info.inner,
1017 }
1018 } else if let Some(info) = names.stream_forward(&lookup_context, name) {
1019 validate_func_sig(name, &FuncType::new([ValType::I32; 2], []), ty)?;
1020 Import::StreamForward(info)
1021 } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
1022 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
1023 Import::StreamCancelRead {
1024 async_: info.async_lowered,
1025 info: info.inner,
1026 }
1027 } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
1028 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1029 Import::StreamDropWritable(info)
1030 } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
1031 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1032 Import::StreamDropReadable(info)
1033 } else {
1034 return Ok(None);
1035 };
1036 Ok(Some(import))
1037 }
1038
1039 fn classify_import_with_library(
1040 &mut self,
1041 import: wasmparser::Import<'_>,
1042 library_info: Option<&LibraryInfo>,
1043 ) -> Result<bool> {
1044 let info = match library_info {
1045 Some(info) => info,
1046 None => return Ok(false),
1047 };
1048 let Some((_, instance)) = info
1049 .arguments
1050 .iter()
1051 .find(|(name, _items)| *name == import.module)
1052 else {
1053 return Ok(false);
1054 };
1055 match instance {
1056 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1057 Some(ImportInstance::Whole(which)) => {
1058 if which != module {
1059 bail!("different whole modules imported under the same name");
1060 }
1061 }
1062 Some(ImportInstance::Names(_)) => {
1063 bail!("cannot mix individual imports and whole module imports")
1064 }
1065 None => {
1066 let instance = ImportInstance::Whole(module.clone());
1067 self.names.insert(import.module.to_string(), instance);
1068 }
1069 },
1070 Instance::Items(items) => {
1071 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1072 return Ok(false);
1073 };
1074 self.insert_import(import, Import::Item(item.clone()))?;
1075 }
1076 }
1077 Ok(true)
1078 }
1079
1080 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1084 if let Import::MainModuleMemory(ty) = item {
1085 if self.imported_memory.is_some() {
1086 bail!("module has multiple imports for memory");
1087 }
1088 self.imported_memory = Some(ty);
1089 }
1090 let entry = self
1091 .names
1092 .entry(import.module.to_string())
1093 .or_insert(ImportInstance::Names(IndexMap::default()));
1094 let names = match entry {
1095 ImportInstance::Names(names) => names,
1096 _ => bail!("cannot mix individual imports with module imports"),
1097 };
1098 let entry = match names.entry(import.name.to_string()) {
1099 Entry::Occupied(_) => {
1100 bail!(
1101 "module has duplicate import for `{}::{}`",
1102 import.module,
1103 import.name
1104 );
1105 }
1106 Entry::Vacant(v) => v,
1107 };
1108 log::trace!(
1109 "classifying import `{}::{} as {item:?}",
1110 import.module,
1111 import.name
1112 );
1113 entry.insert(item);
1114 Ok(())
1115 }
1116}
1117
1118#[derive(Default)]
1121pub struct ExportMap {
1122 names: IndexMap<String, Export>,
1123 raw_exports: IndexMap<String, FuncType>,
1124}
1125
1126#[derive(Debug)]
1129pub enum Export {
1130 WorldFunc(WorldKey, String, AbiVariant),
1133
1134 WorldFuncPostReturn(WorldKey),
1136
1137 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1139
1140 InterfaceFuncPostReturn(WorldKey, String),
1142
1143 ResourceDtor(TypeId),
1145
1146 Memory(MemoryType),
1148
1149 GeneralPurposeRealloc,
1151
1152 GeneralPurposeExportRealloc,
1154
1155 GeneralPurposeImportRealloc,
1157
1158 Initialize,
1160
1161 ReallocForAdapter,
1163
1164 WorldFuncCallback(WorldKey),
1165
1166 InterfaceFuncCallback(WorldKey, String),
1167
1168 IndirectFunctionTable,
1170
1171 WasmTaskHook,
1173}
1174
1175impl ExportMap {
1176 fn add(
1177 &mut self,
1178 export: wasmparser::Export<'_>,
1179 encoder: &ComponentEncoder,
1180 exports: &IndexSet<WorldKey>,
1181 types: TypesRef<'_>,
1182 ) -> Result<()> {
1183 if let Some(item) = self.classify(export, encoder, exports, types)? {
1184 log::debug!("classifying export `{}` as {item:?}", export.name);
1185 let prev = self.names.insert(export.name.to_string(), item);
1186 assert!(prev.is_none());
1187 }
1188 Ok(())
1189 }
1190
1191 fn classify(
1192 &mut self,
1193 export: wasmparser::Export<'_>,
1194 encoder: &ComponentEncoder,
1195 exports: &IndexSet<WorldKey>,
1196 types: TypesRef<'_>,
1197 ) -> Result<Option<Export>> {
1198 match export.kind {
1199 ExternalKind::Func => {
1200 let ty = types[types.core_function_at(export.index)].unwrap_func();
1201 self.raw_exports.insert(export.name.to_string(), ty.clone());
1202 }
1203 _ => {}
1204 }
1205
1206 if export.name == "canonical_abi_realloc" {
1208 return Ok(Some(Export::GeneralPurposeRealloc));
1209 } else if export.name == "cabi_import_realloc" {
1210 return Ok(Some(Export::GeneralPurposeImportRealloc));
1211 } else if export.name == "cabi_export_realloc" {
1212 return Ok(Some(Export::GeneralPurposeExportRealloc));
1213 } else if export.name == "cabi_realloc_adapter" {
1214 return Ok(Some(Export::ReallocForAdapter));
1215 }
1216
1217 let (name, names) = match export.name.strip_prefix("cm32p2") {
1218 Some(name) => (name, STANDARD),
1219 None if encoder.reject_legacy_names => return Ok(None),
1220 None => (export.name, LEGACY),
1221 };
1222
1223 if let Some(export) = self
1224 .classify_component_export(names, name, &export, encoder, exports, types)
1225 .with_context(|| format!("failed to classify export `{}`", export.name))?
1226 {
1227 return Ok(Some(export));
1228 }
1229 log::debug!("unknown export `{}`", export.name);
1230 Ok(None)
1231 }
1232
1233 fn classify_component_export(
1234 &mut self,
1235 names: &dyn NameMangling,
1236 name: &str,
1237 export: &wasmparser::Export<'_>,
1238 encoder: &ComponentEncoder,
1239 exports: &IndexSet<WorldKey>,
1240 types: TypesRef<'_>,
1241 ) -> Result<Option<Export>> {
1242 let resolve = &encoder.metadata.resolve;
1243 let world = encoder.metadata.world;
1244 match export.kind {
1245 ExternalKind::Func => {}
1246 ExternalKind::Memory => {
1247 if name == names.export_memory() {
1248 return Ok(Some(Export::Memory(types.memory_at(export.index))));
1249 }
1250 return Ok(None);
1251 }
1252 ExternalKind::Table => {
1253 if Some(name) == names.export_indirect_function_table() {
1254 return Ok(Some(Export::IndirectFunctionTable));
1255 }
1256 return Ok(None);
1257 }
1258 _ => return Ok(None),
1259 }
1260 let ty = types[types.core_function_at(export.index)].unwrap_func();
1261
1262 if name == names.export_realloc() {
1264 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1265 validate_func_sig(name, &expected, ty)?;
1266 return Ok(Some(Export::GeneralPurposeRealloc));
1267 } else if name == names.export_initialize() {
1268 let expected = FuncType::new([], []);
1269 validate_func_sig(name, &expected, ty)?;
1270 return Ok(Some(Export::Initialize));
1271 } else if Some(name) == names.export_wasm_task_hook() {
1272 let expected = FuncType::new([ValType::I32], []);
1273 validate_func_sig(name, &expected, ty)?;
1274 return Ok(Some(Export::WasmTaskHook));
1275 }
1276
1277 let full_name = name;
1278 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1279 (AbiVariant::GuestExportAsync, name)
1280 } else if let Some(name) = names.async_lift_stackful_name(name) {
1281 (AbiVariant::GuestExportAsyncStackful, name)
1282 } else {
1283 (AbiVariant::GuestExport, name)
1284 };
1285
1286 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1288 validate_func(resolve, ty, f, abi).with_context(|| {
1289 let key = resolve.name_world_key(key);
1290 format!("failed to validate export for `{key}`")
1291 })?;
1292 match id {
1293 Some(id) => {
1294 return Ok(Some(Export::InterfaceFunc(
1295 key.clone(),
1296 id,
1297 f.name.clone(),
1298 abi,
1299 )));
1300 }
1301 None => {
1302 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1303 }
1304 }
1305 }
1306
1307 if let Some(remaining) = names.strip_post_return(name) {
1309 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1310 validate_post_return(resolve, ty, f).with_context(|| {
1311 let key = resolve.name_world_key(key);
1312 format!("failed to validate export for `{key}`")
1313 })?;
1314 match id {
1315 Some(_id) => {
1316 return Ok(Some(Export::InterfaceFuncPostReturn(
1317 key.clone(),
1318 f.name.clone(),
1319 )));
1320 }
1321 None => {
1322 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1323 }
1324 }
1325 }
1326 }
1327
1328 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1329 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1330 validate_func_sig(
1331 full_name,
1332 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1333 ty,
1334 )?;
1335 return Ok(Some(if id.is_some() {
1336 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1337 } else {
1338 Export::WorldFuncCallback(key.clone())
1339 }));
1340 }
1341 }
1342
1343 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1345 let expected = FuncType::new([ValType::I32], []);
1346 validate_func_sig(full_name, &expected, ty)?;
1347 return Ok(Some(Export::ResourceDtor(dtor)));
1348 }
1349
1350 Ok(None)
1351 }
1352
1353 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1356 self.find(|m| match m {
1357 Export::WorldFuncPostReturn(k) => k == key,
1358 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1359 _ => false,
1360 })
1361 }
1362
1363 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1366 self.find(|m| match m {
1367 Export::WorldFuncCallback(k) => k == key,
1368 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1369 _ => false,
1370 })
1371 }
1372
1373 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1374 self.names.values().find_map(|m| match m {
1375 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1376 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1377 _ => None,
1378 })
1379 }
1380
1381 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1384 let _ = (key, func);
1388
1389 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1390 return Some(name);
1391 }
1392 self.general_purpose_realloc()
1393 }
1394
1395 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1398 let _ = (interface, func);
1402
1403 self.import_realloc_fallback()
1404 }
1405
1406 pub fn import_realloc_fallback(&self) -> Option<&str> {
1410 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1411 return Some(name);
1412 }
1413 self.general_purpose_realloc()
1414 }
1415
1416 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1418 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1419 return Some(name);
1420 }
1421 self.general_purpose_realloc()
1422 }
1423
1424 pub fn general_purpose_realloc(&self) -> Option<&str> {
1425 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1426 }
1427
1428 pub fn reallocs(&self) -> impl Iterator<Item = &str> + '_ {
1435 self.names.iter().filter_map(|(name, export)| match export {
1436 Export::GeneralPurposeRealloc
1437 | Export::GeneralPurposeExportRealloc
1438 | Export::GeneralPurposeImportRealloc => Some(name.as_str()),
1439 _ => None,
1440 })
1441 }
1442
1443 pub fn memory(&self) -> Option<(&str, MemoryType)> {
1445 self.names.iter().find_map(|(name, m)| match m {
1446 Export::Memory(ty) => Some((name.as_str(), *ty)),
1447 _ => None,
1448 })
1449 }
1450
1451 pub fn indirect_function_table(&self) -> Option<&str> {
1453 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1454 }
1455
1456 pub fn wasm_task_hook(&self) -> Option<&str> {
1458 self.find(|t| matches!(t, Export::WasmTaskHook))
1459 }
1460
1461 pub fn initialize(&self) -> Option<&str> {
1463 self.find(|m| matches!(m, Export::Initialize))
1464 }
1465
1466 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1468 self.find(|m| match m {
1469 Export::ResourceDtor(t) => *t == ty,
1470 _ => false,
1471 })
1472 }
1473
1474 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1477 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1478 Some(name)
1479 }
1480
1481 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1483 self.names.iter().map(|(n, e)| (n.as_str(), e))
1484 }
1485
1486 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1487 let resolve = &encoder.metadata.resolve;
1488 let world = encoder.metadata.world;
1489 if self
1492 .names
1493 .values()
1494 .filter(|m| matches!(m, Export::Memory(_)))
1495 .count()
1496 > 1
1497 {
1498 bail!("cannot componentize module that exports multiple memories")
1499 }
1500
1501 for (name, export) in &self.names {
1503 match export {
1504 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1505 if !matches!(
1506 self.names.get(&format!("[callback]{name}")),
1507 Some(Export::WorldFuncCallback(_))
1508 ) {
1509 bail!("missing callback for `{name}`");
1510 }
1511 }
1512 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1513 if !matches!(
1514 self.names.get(&format!("[callback]{name}")),
1515 Some(Export::InterfaceFuncCallback(_, _))
1516 ) {
1517 bail!("missing callback for `{name}`");
1518 }
1519 }
1520 _ => {}
1521 }
1522 }
1523
1524 for export in exports {
1526 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1527 let result = self.find(|e| match e {
1528 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1529 _ => false,
1530 });
1531 if result.is_some() {
1532 Ok(())
1533 } else {
1534 let export = resolve.name_world_key(export);
1535 bail!("failed to find export of interface `{export}` function `{name}`")
1536 }
1537 };
1538 let require_world_func = |name: &str| -> Result<()> {
1539 let result = self.find(|e| match e {
1540 Export::WorldFunc(_, s, _) => name == s,
1541 _ => false,
1542 });
1543 if result.is_some() {
1544 Ok(())
1545 } else {
1546 bail!("failed to find export of function `{name}`")
1547 }
1548 };
1549 match &resolve.worlds[world].exports[export] {
1550 WorldItem::Interface { id, .. } => {
1551 for (name, _) in resolve.interfaces[*id].functions.iter() {
1552 require_interface_func(*id, name)?;
1553 }
1554 }
1555 WorldItem::Function(f) => {
1556 require_world_func(&f.name)?;
1557 }
1558 WorldItem::Type { .. } => unreachable!(),
1559 }
1560 }
1561
1562 Ok(())
1563 }
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<ValType>;
1621 fn waitable_set_poll(&self, name: &str) -> Option<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_forward(
1651 &self,
1652 lookup_context: &PayloadLookupContext,
1653 name: &str,
1654 ) -> Option<PayloadInfo>;
1655 fn future_cancel_read(
1656 &self,
1657 lookup_context: &PayloadLookupContext,
1658 name: &str,
1659 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1660 fn future_drop_writable(
1661 &self,
1662 lookup_context: &PayloadLookupContext,
1663 name: &str,
1664 ) -> Option<PayloadInfo>;
1665 fn future_drop_readable(
1666 &self,
1667 lookup_context: &PayloadLookupContext,
1668 name: &str,
1669 ) -> Option<PayloadInfo>;
1670 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1671 fn stream_write(
1672 &self,
1673 lookup_context: &PayloadLookupContext,
1674 name: &str,
1675 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1676 fn stream_read(
1677 &self,
1678 lookup_context: &PayloadLookupContext,
1679 name: &str,
1680 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1681 fn stream_cancel_write(
1682 &self,
1683 lookup_context: &PayloadLookupContext,
1684 name: &str,
1685 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1686 fn stream_forward(
1687 &self,
1688 lookup_context: &PayloadLookupContext,
1689 name: &str,
1690 ) -> Option<PayloadInfo>;
1691 fn stream_cancel_read(
1692 &self,
1693 lookup_context: &PayloadLookupContext,
1694 name: &str,
1695 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1696 fn stream_drop_writable(
1697 &self,
1698 lookup_context: &PayloadLookupContext,
1699 name: &str,
1700 ) -> Option<PayloadInfo>;
1701 fn stream_drop_readable(
1702 &self,
1703 lookup_context: &PayloadLookupContext,
1704 name: &str,
1705 ) -> Option<PayloadInfo>;
1706 fn thread_index(&self, name: &str) -> bool;
1707 fn thread_new_indirect(&self, name: &str) -> bool;
1708 fn thread_resume_later(&self, name: &str) -> bool;
1709 fn thread_suspend(&self, name: &str) -> bool;
1710 fn thread_yield(&self, name: &str) -> bool;
1711 fn thread_suspend_then_resume(&self, name: &str) -> bool;
1712 fn thread_yield_then_resume(&self, name: &str) -> bool;
1713 fn thread_suspend_then_promote(&self, name: &str) -> bool;
1714 fn thread_yield_then_promote(&self, name: &str) -> bool;
1715 fn module_to_interface(
1716 &self,
1717 module: &str,
1718 resolve: &Resolve,
1719 items: &IndexMap<WorldKey, WorldItem>,
1720 ) -> Result<(WorldKey, InterfaceId)>;
1721 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1722 fn match_wit_export<'a>(
1723 &self,
1724 export_name: &str,
1725 resolve: &'a Resolve,
1726 world: WorldId,
1727 exports: &'a IndexSet<WorldKey>,
1728 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1729 fn match_wit_resource_dtor<'a>(
1730 &self,
1731 export_name: &str,
1732 resolve: &'a Resolve,
1733 world: WorldId,
1734 exports: &'a IndexSet<WorldKey>,
1735 ) -> Option<TypeId>;
1736 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1737 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1738 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import>;
1739}
1740
1741struct Standard;
1744
1745const STANDARD: &'static dyn NameMangling = &Standard;
1746
1747impl NameMangling for Standard {
1748 fn import_root(&self) -> &str {
1749 ""
1750 }
1751 fn import_non_root_prefix(&self) -> &str {
1752 "|"
1753 }
1754 fn import_exported_intrinsic_prefix(&self) -> &str {
1755 "_ex_"
1756 }
1757 fn export_memory(&self) -> &str {
1758 "_memory"
1759 }
1760 fn export_initialize(&self) -> &str {
1761 "_initialize"
1762 }
1763 fn export_realloc(&self) -> &str {
1764 "_realloc"
1765 }
1766 fn export_indirect_function_table(&self) -> Option<&str> {
1767 None
1768 }
1769 fn export_wasm_task_hook(&self) -> Option<&str> {
1770 None
1771 }
1772 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1773 name.strip_suffix("_drop")
1774 }
1775 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1776 name.strip_suffix("_new")
1777 }
1778 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1779 name.strip_suffix("_rep")
1780 }
1781 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1782 None
1783 }
1784 fn task_cancel(&self, _name: &str) -> bool {
1785 false
1786 }
1787 fn backpressure_inc(&self, _name: &str) -> bool {
1788 false
1789 }
1790 fn backpressure_dec(&self, _name: &str) -> bool {
1791 false
1792 }
1793 fn waitable_set_new(&self, _name: &str) -> bool {
1794 false
1795 }
1796 fn waitable_set_wait(&self, _name: &str) -> Option<ValType> {
1797 None
1798 }
1799 fn waitable_set_poll(&self, _name: &str) -> Option<ValType> {
1800 None
1801 }
1802 fn waitable_set_drop(&self, _name: &str) -> bool {
1803 false
1804 }
1805 fn waitable_join(&self, _name: &str) -> bool {
1806 false
1807 }
1808 fn subtask_drop(&self, _name: &str) -> bool {
1809 false
1810 }
1811 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1812 None
1813 }
1814 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1815 None
1816 }
1817 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1818 None
1819 }
1820 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1821 None
1822 }
1823 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1824 None
1825 }
1826 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1827 None
1828 }
1829 fn error_context_drop(&self, _name: &str) -> bool {
1830 false
1831 }
1832 fn context_get(&self, _name: &str) -> Option<(ValType, u32)> {
1833 None
1834 }
1835 fn context_set(&self, _name: &str) -> Option<(ValType, u32)> {
1836 None
1837 }
1838 fn thread_index(&self, _name: &str) -> bool {
1839 false
1840 }
1841 fn thread_new_indirect(&self, _name: &str) -> bool {
1842 false
1843 }
1844 fn thread_resume_later(&self, _name: &str) -> bool {
1845 false
1846 }
1847 fn thread_suspend(&self, _name: &str) -> bool {
1848 false
1849 }
1850 fn thread_yield(&self, _name: &str) -> bool {
1851 false
1852 }
1853 fn thread_suspend_then_resume(&self, _name: &str) -> bool {
1854 false
1855 }
1856 fn thread_yield_then_resume(&self, _name: &str) -> bool {
1857 false
1858 }
1859 fn thread_suspend_then_promote(&self, _name: &str) -> bool {
1860 false
1861 }
1862 fn thread_yield_then_promote(&self, _name: &str) -> bool {
1863 false
1864 }
1865 fn future_new(
1866 &self,
1867 _lookup_context: &PayloadLookupContext,
1868 _name: &str,
1869 ) -> Option<PayloadInfo> {
1870 None
1871 }
1872 fn future_write(
1873 &self,
1874 _lookup_context: &PayloadLookupContext,
1875 _name: &str,
1876 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1877 None
1878 }
1879 fn future_read(
1880 &self,
1881 _lookup_context: &PayloadLookupContext,
1882 _name: &str,
1883 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1884 None
1885 }
1886 fn future_cancel_write(
1887 &self,
1888 _lookup_context: &PayloadLookupContext,
1889 _name: &str,
1890 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1891 None
1892 }
1893 fn future_forward(
1894 &self,
1895 _lookup_context: &PayloadLookupContext,
1896 _name: &str,
1897 ) -> Option<PayloadInfo> {
1898 None
1899 }
1900 fn future_cancel_read(
1901 &self,
1902 _lookup_context: &PayloadLookupContext,
1903 _name: &str,
1904 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1905 None
1906 }
1907 fn future_drop_writable(
1908 &self,
1909 _lookup_context: &PayloadLookupContext,
1910 _name: &str,
1911 ) -> Option<PayloadInfo> {
1912 None
1913 }
1914 fn future_drop_readable(
1915 &self,
1916 _lookup_context: &PayloadLookupContext,
1917 _name: &str,
1918 ) -> Option<PayloadInfo> {
1919 None
1920 }
1921 fn stream_new(
1922 &self,
1923 _lookup_context: &PayloadLookupContext,
1924 _name: &str,
1925 ) -> Option<PayloadInfo> {
1926 None
1927 }
1928 fn stream_write(
1929 &self,
1930 _lookup_context: &PayloadLookupContext,
1931 _name: &str,
1932 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1933 None
1934 }
1935 fn stream_read(
1936 &self,
1937 _lookup_context: &PayloadLookupContext,
1938 _name: &str,
1939 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1940 None
1941 }
1942 fn stream_cancel_write(
1943 &self,
1944 _lookup_context: &PayloadLookupContext,
1945 _name: &str,
1946 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1947 None
1948 }
1949 fn stream_forward(
1950 &self,
1951 _lookup_context: &PayloadLookupContext,
1952 _name: &str,
1953 ) -> Option<PayloadInfo> {
1954 None
1955 }
1956 fn stream_cancel_read(
1957 &self,
1958 _lookup_context: &PayloadLookupContext,
1959 _name: &str,
1960 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1961 None
1962 }
1963 fn stream_drop_writable(
1964 &self,
1965 _lookup_context: &PayloadLookupContext,
1966 _name: &str,
1967 ) -> Option<PayloadInfo> {
1968 None
1969 }
1970 fn stream_drop_readable(
1971 &self,
1972 _lookup_context: &PayloadLookupContext,
1973 _name: &str,
1974 ) -> Option<PayloadInfo> {
1975 None
1976 }
1977 fn module_to_interface(
1978 &self,
1979 interface: &str,
1980 resolve: &Resolve,
1981 items: &IndexMap<WorldKey, WorldItem>,
1982 ) -> Result<(WorldKey, InterfaceId)> {
1983 for (key, item) in items.iter() {
1984 let id = match key {
1985 WorldKey::Name(name) => match item {
1987 WorldItem::Interface { id, .. } if name == interface => *id,
1988 _ => continue,
1989 },
1990 WorldKey::Interface(id) => {
1992 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1993 continue;
1994 }
1995 *id
1996 }
1997 };
1998 return Ok((key.clone(), id));
1999 }
2000 bail!("failed to find world item corresponding to interface `{interface}`")
2001 }
2002 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2003 name.strip_suffix("_post")
2004 }
2005 fn match_wit_export<'a>(
2006 &self,
2007 export_name: &str,
2008 resolve: &'a Resolve,
2009 world: WorldId,
2010 exports: &'a IndexSet<WorldKey>,
2011 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2012 if let Some(world_export_name) = export_name.strip_prefix("||") {
2013 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
2014 match &resolve.worlds[world].exports[key] {
2015 WorldItem::Function(f) => return Some((key, None, f)),
2016 _ => return None,
2017 }
2018 }
2019
2020 let (key, id, func_name) =
2021 self.match_wit_interface(export_name, resolve, world, exports)?;
2022 let func = resolve.interfaces[id].functions.get(func_name)?;
2023 Some((key, Some(id), func))
2024 }
2025
2026 fn match_wit_resource_dtor<'a>(
2027 &self,
2028 export_name: &str,
2029 resolve: &'a Resolve,
2030 world: WorldId,
2031 exports: &'a IndexSet<WorldKey>,
2032 ) -> Option<TypeId> {
2033 let (_key, id, name) =
2034 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
2035 let ty = *resolve.interfaces[id].types.get(name)?;
2036 match resolve.types[ty].kind {
2037 TypeDefKind::Resource => Some(ty),
2038 _ => None,
2039 }
2040 }
2041
2042 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2043 (name, AbiVariant::GuestImport)
2044 }
2045 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2046 (name, AbiVariant::GuestImport)
2047 }
2048 fn env_import(&self, _name: &str, _ty: &FuncType) -> Option<Import> {
2049 None
2050 }
2051}
2052
2053impl Standard {
2054 fn match_wit_interface<'a, 'b>(
2055 &self,
2056 export_name: &'b str,
2057 resolve: &'a Resolve,
2058 world: WorldId,
2059 exports: &'a IndexSet<WorldKey>,
2060 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
2061 let world = &resolve.worlds[world];
2062 let export_name = export_name.strip_prefix("|")?;
2063
2064 for export in exports {
2065 let id = match &world.exports[export] {
2066 WorldItem::Interface { id, .. } => *id,
2067 WorldItem::Function(_) => continue,
2068 WorldItem::Type { .. } => unreachable!(),
2069 };
2070 let remaining = match export {
2071 WorldKey::Name(name) => export_name.strip_prefix(name),
2072 WorldKey::Interface(_) => {
2073 let prefix = resolve.canonicalized_id_of(id).unwrap();
2074 export_name.strip_prefix(&prefix)
2075 }
2076 };
2077 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
2078 Some(name) => name,
2079 None => continue,
2080 };
2081 return Some((export, id, item_name));
2082 }
2083
2084 None
2085 }
2086}
2087
2088struct Legacy;
2091
2092const LEGACY: &'static dyn NameMangling = &Legacy;
2093
2094impl Legacy {
2095 fn prefixed_payload(
2101 &self,
2102 lookup_context: &PayloadLookupContext,
2103 name: &str,
2104 prefix: &str,
2105 ) -> Option<PayloadInfo> {
2106 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2109 let ty = match index_or_unit {
2110 "unit" => {
2111 if name.starts_with("[future") {
2112 PayloadType::UnitFuture
2113 } else if name.starts_with("[stream") {
2114 PayloadType::UnitStream
2115 } else {
2116 unreachable!()
2117 }
2118 }
2119 other => {
2120 let type_index = other.parse::<u32>().ok()? as usize;
2124
2125 let function = get_function(
2130 lookup_context.resolve,
2131 lookup_context.world,
2132 func_name,
2133 lookup_context.id,
2134 lookup_context.import,
2135 )
2136 .ok()?;
2137 PayloadType::Type {
2138 id: *function
2139 .find_futures_and_streams(lookup_context.resolve)
2140 .get(type_index)?,
2141 function: function.name.clone(),
2142 }
2143 }
2144 };
2145
2146 Some(PayloadInfo {
2148 name: name.to_string(),
2149 ty,
2150 key: lookup_context
2151 .key
2152 .clone()
2153 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2154 interface: lookup_context.id,
2155 imported: lookup_context.import,
2156 })
2157 }
2158
2159 fn maybe_async_lowered_payload(
2160 &self,
2161 lookup_context: &PayloadLookupContext,
2162 name: &str,
2163 prefix: &str,
2164 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2165 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2166 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2167 Some(MaybeAsyncLowered {
2168 inner: payload,
2169 async_lowered,
2170 })
2171 }
2172
2173 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2174 name.strip_prefix("[async-lower]")
2175 .map_or((false, name), |s| (true, s))
2176 }
2177 fn match_with_async_lowered_prefix(
2178 &self,
2179 name: &str,
2180 expected: &str,
2181 ) -> Option<MaybeAsyncLowered<()>> {
2182 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2183 if clean_name == expected {
2184 Some(MaybeAsyncLowered {
2185 inner: (),
2186 async_lowered,
2187 })
2188 } else {
2189 None
2190 }
2191 }
2192
2193 fn match_with_optional_type_suffix(name: &str, match_prefix: &str) -> Option<ValType> {
2197 let tail = name.strip_prefix(match_prefix)?.strip_suffix(']')?;
2198 if tail.is_empty() {
2199 Some(ValType::I32)
2200 } else {
2201 match tail.strip_prefix('-')? {
2202 "i32" => Some(ValType::I32),
2203 "i64" => Some(ValType::I64),
2204 _ => None,
2206 }
2207 }
2208 }
2209}
2210
2211impl NameMangling for Legacy {
2212 fn import_root(&self) -> &str {
2213 "$root"
2214 }
2215 fn import_non_root_prefix(&self) -> &str {
2216 ""
2217 }
2218 fn import_exported_intrinsic_prefix(&self) -> &str {
2219 "[export]"
2220 }
2221 fn export_memory(&self) -> &str {
2222 "memory"
2223 }
2224 fn export_initialize(&self) -> &str {
2225 "_initialize"
2226 }
2227 fn export_realloc(&self) -> &str {
2228 "cabi_realloc"
2229 }
2230 fn export_indirect_function_table(&self) -> Option<&str> {
2231 Some("__indirect_function_table")
2232 }
2233 fn export_wasm_task_hook(&self) -> Option<&str> {
2234 Some(crate::linking::metadata::TASK_HOOK)
2235 }
2236 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2237 name.strip_prefix("[resource-drop]")
2238 }
2239 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2240 name.strip_prefix("[resource-new]")
2241 }
2242 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2243 name.strip_prefix("[resource-rep]")
2244 }
2245 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2246 name.strip_prefix("[task-return]")
2247 }
2248 fn task_cancel(&self, name: &str) -> bool {
2249 name == "[task-cancel]"
2250 }
2251 fn backpressure_inc(&self, name: &str) -> bool {
2252 name == "[backpressure-inc]"
2253 }
2254 fn backpressure_dec(&self, name: &str) -> bool {
2255 name == "[backpressure-dec]"
2256 }
2257 fn waitable_set_new(&self, name: &str) -> bool {
2258 name == "[waitable-set-new]"
2259 }
2260 fn waitable_set_wait(&self, name: &str) -> Option<ValType> {
2261 let result_ty = Legacy::match_with_optional_type_suffix(name, "[waitable-set-wait")?;
2262 Some(result_ty)
2263 }
2264 fn waitable_set_poll(&self, name: &str) -> Option<ValType> {
2265 let result_ty = Legacy::match_with_optional_type_suffix(name, "[waitable-set-poll")?;
2266 Some(result_ty)
2267 }
2268 fn waitable_set_drop(&self, name: &str) -> bool {
2269 name == "[waitable-set-drop]"
2270 }
2271 fn waitable_join(&self, name: &str) -> bool {
2272 name == "[waitable-join]"
2273 }
2274 fn subtask_drop(&self, name: &str) -> bool {
2275 name == "[subtask-drop]"
2276 }
2277 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2278 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2279 }
2280 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2281 name.strip_prefix("[callback][async-lift]")
2282 }
2283 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2284 name.strip_prefix("[async-lift]")
2285 }
2286 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2287 name.strip_prefix("[async-lift-stackful]")
2288 }
2289 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2290 match name {
2291 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2292 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2293 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2294 _ => None,
2295 }
2296 }
2297 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2298 match name {
2299 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2300 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2301 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2302 _ => None,
2303 }
2304 }
2305 fn error_context_drop(&self, name: &str) -> bool {
2306 name == "[error-context-drop]"
2307 }
2308 fn context_get(&self, name: &str) -> Option<(ValType, u32)> {
2309 parse_context_name(name, "[context-get-")
2310 }
2311 fn context_set(&self, name: &str) -> Option<(ValType, u32)> {
2312 parse_context_name(name, "[context-set-")
2313 }
2314 fn thread_index(&self, name: &str) -> bool {
2315 name == "[thread-index]"
2316 }
2317 fn thread_new_indirect(&self, name: &str) -> bool {
2318 name == "[thread-new-indirect-v0]"
2320 }
2321 fn thread_resume_later(&self, name: &str) -> bool {
2322 name == "[thread-resume-later]"
2323 }
2324 fn thread_suspend(&self, name: &str) -> bool {
2325 name == "[thread-suspend]"
2326 }
2327 fn thread_yield(&self, name: &str) -> bool {
2328 name == "[thread-yield]"
2329 }
2330 fn thread_suspend_then_resume(&self, name: &str) -> bool {
2331 name == "[thread-suspend-then-resume]"
2332 }
2333 fn thread_yield_then_resume(&self, name: &str) -> bool {
2334 name == "[thread-yield-then-resume]"
2335 }
2336 fn thread_suspend_then_promote(&self, name: &str) -> bool {
2337 name == "[thread-suspend-then-promote]"
2338 }
2339 fn thread_yield_then_promote(&self, name: &str) -> bool {
2340 name == "[thread-yield-then-promote]"
2341 }
2342 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2343 self.prefixed_payload(lookup_context, name, "[future-new-")
2344 }
2345 fn future_write(
2346 &self,
2347 lookup_context: &PayloadLookupContext,
2348 name: &str,
2349 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2350 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2351 }
2352 fn future_read(
2353 &self,
2354 lookup_context: &PayloadLookupContext,
2355 name: &str,
2356 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2357 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2358 }
2359 fn future_cancel_write(
2360 &self,
2361 lookup_context: &PayloadLookupContext,
2362 name: &str,
2363 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2364 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2365 }
2366 fn future_forward(
2367 &self,
2368 lookup_context: &PayloadLookupContext,
2369 name: &str,
2370 ) -> Option<PayloadInfo> {
2371 self.prefixed_payload(lookup_context, name, "[future-forward-")
2372 }
2373 fn future_cancel_read(
2374 &self,
2375 lookup_context: &PayloadLookupContext,
2376 name: &str,
2377 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2378 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2379 }
2380 fn future_drop_writable(
2381 &self,
2382 lookup_context: &PayloadLookupContext,
2383 name: &str,
2384 ) -> Option<PayloadInfo> {
2385 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2386 }
2387 fn future_drop_readable(
2388 &self,
2389 lookup_context: &PayloadLookupContext,
2390 name: &str,
2391 ) -> Option<PayloadInfo> {
2392 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2393 }
2394 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2395 self.prefixed_payload(lookup_context, name, "[stream-new-")
2396 }
2397 fn stream_write(
2398 &self,
2399 lookup_context: &PayloadLookupContext,
2400 name: &str,
2401 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2402 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2403 }
2404 fn stream_read(
2405 &self,
2406 lookup_context: &PayloadLookupContext,
2407 name: &str,
2408 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2409 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2410 }
2411 fn stream_cancel_write(
2412 &self,
2413 lookup_context: &PayloadLookupContext,
2414 name: &str,
2415 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2416 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2417 }
2418 fn stream_forward(
2419 &self,
2420 lookup_context: &PayloadLookupContext,
2421 name: &str,
2422 ) -> Option<PayloadInfo> {
2423 self.prefixed_payload(lookup_context, name, "[stream-forward-")
2424 }
2425 fn stream_cancel_read(
2426 &self,
2427 lookup_context: &PayloadLookupContext,
2428 name: &str,
2429 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2430 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2431 }
2432 fn stream_drop_writable(
2433 &self,
2434 lookup_context: &PayloadLookupContext,
2435 name: &str,
2436 ) -> Option<PayloadInfo> {
2437 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2438 }
2439 fn stream_drop_readable(
2440 &self,
2441 lookup_context: &PayloadLookupContext,
2442 name: &str,
2443 ) -> Option<PayloadInfo> {
2444 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2445 }
2446 fn module_to_interface(
2447 &self,
2448 module: &str,
2449 resolve: &Resolve,
2450 items: &IndexMap<WorldKey, WorldItem>,
2451 ) -> Result<(WorldKey, InterfaceId)> {
2452 let bare_name = WorldKey::Name(module.to_string());
2454 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2455 return Ok((bare_name, *id));
2456 }
2457
2458 let kebab_name = ComponentName::new(module, 0);
2464 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2465 Ok(ComponentNameKind::Interface(name)) => name,
2466 _ => bail!("module requires an import interface named `{module}`"),
2467 };
2468
2469 let version = name.version(None)?;
2473
2474 let pkgname = PackageName {
2476 namespace: name.namespace().to_string(),
2477 name: name.package().to_string(),
2478 version: version.clone(),
2479 };
2480 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2481 if let Some(id) = resolve.packages[*pkg]
2482 .interfaces
2483 .get(name.interface().as_str())
2484 {
2485 let key = WorldKey::Interface(*id);
2488 if items.contains_key(&key) {
2489 return Ok((key, *id));
2490 }
2491
2492 for k in items.keys() {
2498 let i = match *k {
2499 WorldKey::Interface(id) => id,
2500 WorldKey::Name(_) => continue,
2501 };
2502 if resolve.interfaces[i].clone_of == Some(*id) {
2503 return Ok((WorldKey::Interface(i), i));
2504 }
2505 }
2506 }
2507 }
2508
2509 for (key, _) in items {
2514 let id = match key {
2515 WorldKey::Interface(id) => *id,
2516 WorldKey::Name(_) => continue,
2517 };
2518 let interface = &resolve.interfaces[id];
2520 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2521 continue;
2522 }
2523
2524 let pkg = &resolve.packages[interface.package.unwrap()];
2526 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2527 continue;
2528 }
2529
2530 let module_version = match &version {
2531 Some(version) => version,
2532 None => continue,
2533 };
2534 let pkg_version = match &pkg.name.version {
2535 Some(version) => version,
2536 None => continue,
2537 };
2538
2539 let (module_compat, _) = PackageName::version_compat_track(&module_version);
2541 let (pkg_compat, _) = PackageName::version_compat_track(pkg_version);
2542 if module_compat == pkg_compat {
2543 return Ok((key.clone(), id));
2544 }
2545 }
2546
2547 bail!("module requires an import interface named `{module}`")
2548 }
2549 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2550 name.strip_prefix("cabi_post_")
2551 }
2552 fn match_wit_export<'a>(
2553 &self,
2554 export_name: &str,
2555 resolve: &'a Resolve,
2556 world: WorldId,
2557 exports: &'a IndexSet<WorldKey>,
2558 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2559 let world = &resolve.worlds[world];
2560 for name in exports {
2561 match &world.exports[name] {
2562 WorldItem::Function(f) => {
2563 if f.legacy_core_export_name(None) == export_name {
2564 return Some((name, None, f));
2565 }
2566 }
2567 WorldItem::Interface { id, .. } => {
2568 let string = resolve.name_world_key(name);
2569 for (_, func) in resolve.interfaces[*id].functions.iter() {
2570 if func.legacy_core_export_name(Some(&string)) == export_name {
2571 return Some((name, Some(*id), func));
2572 }
2573 }
2574 }
2575
2576 WorldItem::Type { .. } => unreachable!(),
2577 }
2578 }
2579
2580 None
2581 }
2582
2583 fn match_wit_resource_dtor<'a>(
2584 &self,
2585 export_name: &str,
2586 resolve: &'a Resolve,
2587 world: WorldId,
2588 exports: &'a IndexSet<WorldKey>,
2589 ) -> Option<TypeId> {
2590 let world = &resolve.worlds[world];
2591 for name in exports {
2592 let id = match &world.exports[name] {
2593 WorldItem::Interface { id, .. } => *id,
2594 WorldItem::Function(_) => continue,
2595 WorldItem::Type { .. } => unreachable!(),
2596 };
2597 let name = resolve.name_world_key(name);
2598 let resource = match export_name
2599 .strip_prefix(&name)
2600 .and_then(|s| s.strip_prefix("#[dtor]"))
2601 .and_then(|r| resolve.interfaces[id].types.get(r))
2602 {
2603 Some(id) => *id,
2604 None => continue,
2605 };
2606
2607 match resolve.types[resource].kind {
2608 TypeDefKind::Resource => {}
2609 _ => continue,
2610 }
2611
2612 return Some(resource);
2613 }
2614
2615 None
2616 }
2617
2618 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2619 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2620 (
2621 name,
2622 if async_abi {
2623 AbiVariant::GuestImportAsync
2624 } else {
2625 AbiVariant::GuestImport
2626 },
2627 )
2628 }
2629 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2630 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2631 (
2632 name,
2633 if async_abi {
2634 AbiVariant::GuestImportAsync
2635 } else {
2636 AbiVariant::GuestImport
2637 },
2638 )
2639 }
2640 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import> {
2641 match name {
2642 "__wasm_get_stack_pointer" => {
2643 let ty = *ty.results().get(0)?;
2644 Some(Import::ContextGet { ty, slot: 0 })
2645 }
2646 "__wasm_set_stack_pointer" => {
2647 let ty = *ty.params().get(0)?;
2648 Some(Import::ContextSet { ty, slot: 0 })
2649 }
2650 "__wasm_get_tls_base" => {
2654 let ty = *ty.results().get(0)?;
2655 Some(Import::TlsBaseGet { ty })
2656 }
2657 "__wasm_set_tls_base" => {
2658 let ty = *ty.params().get(0)?;
2659 Some(Import::TlsBaseSet { ty })
2660 }
2661 _ => None,
2662 }
2663 }
2664}
2665
2666pub fn validate_module(
2678 encoder: &ComponentEncoder,
2679 bytes: &[u8],
2680 import_map: Option<&ModuleImportMap>,
2681) -> Result<ValidatedModule> {
2682 ValidatedModule::new(
2683 encoder,
2684 bytes,
2685 &encoder.main_module_exports,
2686 import_map,
2687 None,
2688 )
2689}
2690
2691pub fn validate_adapter_module(
2709 encoder: &ComponentEncoder,
2710 bytes: &[u8],
2711 required_by_import: &IndexMap<String, FuncType>,
2712 exports: &IndexSet<WorldKey>,
2713 library_info: Option<&LibraryInfo>,
2714) -> Result<ValidatedModule> {
2715 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2716
2717 for (name, required_ty) in required_by_import {
2718 let actual = match ret.exports.raw_exports.get(name) {
2719 Some(ty) => ty,
2720 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2721 };
2722 validate_func_sig(name, required_ty, &actual)?;
2723 }
2724
2725 Ok(ret)
2726}
2727
2728#[derive(Debug, Clone)]
2735pub struct AdapterModuleDidNotExport(String);
2736
2737impl fmt::Display for AdapterModuleDidNotExport {
2738 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2739 write!(f, "adapter module did not export `{}`", self.0)
2740 }
2741}
2742
2743impl std::error::Error for AdapterModuleDidNotExport {}
2744
2745fn resource_test_for_interface<'a>(
2746 resolve: &'a Resolve,
2747 id: InterfaceId,
2748) -> impl Fn(&str) -> Option<TypeId> + 'a {
2749 let interface = &resolve.interfaces[id];
2750 move |name: &str| {
2751 let ty = match interface.types.get(name) {
2752 Some(ty) => *ty,
2753 None => return None,
2754 };
2755 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2756 Some(ty)
2757 } else {
2758 None
2759 }
2760 }
2761}
2762
2763fn resource_test_for_world<'a>(
2764 resolve: &'a Resolve,
2765 id: WorldId,
2766) -> impl Fn(&str) -> Option<TypeId> + 'a {
2767 let world = &resolve.worlds[id];
2768 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2769 WorldItem::Type { id, .. } => {
2770 if matches!(resolve.types[*id].kind, TypeDefKind::Resource) {
2771 Some(*id)
2772 } else {
2773 None
2774 }
2775 }
2776 _ => None,
2777 }
2778}
2779
2780fn validate_func(
2781 resolve: &Resolve,
2782 ty: &wasmparser::FuncType,
2783 func: &Function,
2784 abi: AbiVariant,
2785) -> Result<()> {
2786 validate_func_sig(
2787 &func.name,
2788 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2789 ty,
2790 )
2791}
2792
2793fn validate_post_return(
2794 resolve: &Resolve,
2795 ty: &wasmparser::FuncType,
2796 func: &Function,
2797) -> Result<()> {
2798 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2804 sig.params = mem::take(&mut sig.results);
2805 validate_func_sig(
2806 &format!("{} post-return", func.name),
2807 &wasm_sig_to_func_type(sig),
2808 ty,
2809 )
2810}
2811
2812fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2813 if ty != expected {
2814 bail!(
2815 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2816 name,
2817 expected.params(),
2818 expected.results(),
2819 ty.params(),
2820 ty.results()
2821 );
2822 }
2823
2824 Ok(())
2825}
2826
2827fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2829 assert!(prefix.starts_with("["));
2830 assert!(prefix.ends_with("-"));
2831 let suffix = name.strip_prefix(prefix)?;
2832 let index = suffix.find(']')?;
2833 let rest = &suffix[index + 1..];
2834 Some((&suffix[..index], rest))
2835}
2836
2837fn parse_context_name(name: &str, prefix: &str) -> Option<(ValType, u32)> {
2843 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2844 if !rest.is_empty() {
2845 return None;
2846 }
2847 let (ty, slot) = match suffix.split_once('-') {
2848 Some(("i64", slot)) => (ValType::I64, slot),
2849 Some(("i32", slot)) => (ValType::I32, slot),
2850 _ => (ValType::I32, suffix),
2851 };
2852 let slot = slot.parse().ok()?;
2853 Some((ty, slot))
2854}
2855
2856fn get_function<'a>(
2857 resolve: &'a Resolve,
2858 world: &'a World,
2859 name: &str,
2860 interface: Option<InterfaceId>,
2861 imported: bool,
2862) -> Result<&'a Function> {
2863 let function = if let Some(id) = interface {
2864 return resolve.interfaces[id]
2865 .functions
2866 .get(name)
2867 .ok_or_else(|| anyhow!("no export `{name}` found"));
2868 } else if imported {
2869 world.imports.get(&WorldKey::Name(name.to_string()))
2870 } else {
2871 world.exports.get(&WorldKey::Name(name.to_string()))
2872 };
2873 let Some(WorldItem::Function(function)) = function else {
2874 bail!("no export `{name}` found");
2875 };
2876 Ok(function)
2877}