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, Parser, Payload, TypeRef, ValType, ValidPayload, Validator,
12 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
113pub enum ImportInstance {
114 Whole(MainOrAdapter),
117
118 Names(IndexMap<String, Import>),
120}
121
122#[derive(Debug, Eq, PartialEq, Clone, Hash)]
139pub struct PayloadInfo {
140 pub name: String,
143 pub ty: PayloadType,
148 pub key: WorldKey,
150 pub interface: Option<InterfaceId>,
152 pub imported: bool,
157}
158
159#[derive(Debug, Eq, PartialEq, Clone, Hash)]
161pub enum PayloadType {
162 Type {
165 id: TypeId,
166 function: String,
169 },
170 UnitFuture,
172 UnitStream,
174}
175
176impl PayloadInfo {
177 pub fn payload(&self, resolve: &Resolve) -> Option<Type> {
179 let id = match self.ty {
180 PayloadType::Type { id, .. } => id,
181 PayloadType::UnitFuture | PayloadType::UnitStream => return None,
182 };
183 match resolve.types[id].kind {
184 TypeDefKind::Future(payload) | TypeDefKind::Stream(payload) => payload,
185 _ => unreachable!(),
186 }
187 }
188}
189
190#[derive(Debug, Clone)]
197pub enum Import {
198 WorldFunc(WorldKey, String, AbiVariant),
201
202 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
208
209 ImportedResourceDrop(WorldKey, Option<InterfaceId>, TypeId),
215
216 ExportedResourceDrop(WorldKey, TypeId),
222
223 ExportedResourceNew(WorldKey, TypeId),
229
230 ExportedResourceRep(WorldKey, TypeId),
236
237 AdapterExport {
243 adapter: String,
244 func: String,
245 ty: FuncType,
246 },
247
248 MainModuleMemory,
252
253 MainModuleExport { name: String, kind: ExportKind },
255
256 Item(Item),
262
263 ExportedTaskReturn(WorldKey, Option<InterfaceId>, Function),
272
273 ExportedTaskCancel,
277
278 ContextGet {
280 ty: ValType,
282 slot: u32,
284 },
285 ContextSet {
287 ty: ValType,
289 slot: u32,
291 },
292
293 TlsBaseGet {
301 ty: ValType,
303 },
304
305 TlsBaseSet {
307 ty: ValType,
309 },
310
311 BackpressureInc,
313
314 BackpressureDec,
316
317 WaitableSetNew,
319
320 WaitableSetWait { cancellable: bool },
326
327 WaitableSetPoll { cancellable: bool },
333
334 WaitableSetDrop,
336
337 WaitableJoin,
339
340 SubtaskDrop,
344
345 SubtaskCancel { async_: bool },
349
350 StreamNew(PayloadInfo),
354
355 StreamRead { async_: bool, info: PayloadInfo },
360
361 StreamWrite { async_: bool, info: PayloadInfo },
366
367 StreamCancelRead { info: PayloadInfo, async_: bool },
372
373 StreamCancelWrite { info: PayloadInfo, async_: bool },
378
379 StreamDropReadable(PayloadInfo),
383
384 StreamDropWritable(PayloadInfo),
388
389 FutureNew(PayloadInfo),
393
394 FutureRead { async_: bool, info: PayloadInfo },
399
400 FutureWrite { async_: bool, info: PayloadInfo },
404
405 FutureCancelRead { info: PayloadInfo, async_: bool },
410
411 FutureCancelWrite { info: PayloadInfo, async_: bool },
416
417 FutureDropReadable(PayloadInfo),
421
422 FutureDropWritable(PayloadInfo),
426
427 ErrorContextNew { encoding: StringEncoding },
432
433 ErrorContextDebugMessage { encoding: StringEncoding },
439
440 ErrorContextDrop,
445
446 ThreadIndex,
450
451 ThreadNewIndirect,
455
456 ThreadResumeLater,
458
459 ThreadSuspend { cancellable: bool },
461
462 ThreadYield { cancellable: bool },
464
465 ThreadSuspendThenResume { cancellable: bool },
467
468 ThreadYieldThenResume { cancellable: bool },
470
471 ThreadSuspendThenPromote { cancellable: bool },
473
474 ThreadYieldThenPromote { cancellable: bool },
476}
477
478impl ImportMap {
479 pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
481 let names = match self.names.get(name) {
482 Some(ImportInstance::Names(names)) => names,
483 _ => return IndexMap::new(),
484 };
485 names
486 .iter()
487 .map(|(_, import)| match import {
488 Import::AdapterExport { ty, func, adapter } => {
489 assert_eq!(adapter, name);
490 (func.clone(), ty.clone())
491 }
492 _ => unreachable!(),
493 })
494 .collect()
495 }
496
497 pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
501 self.names
502 .iter()
503 .filter_map(|(module, m)| match m {
504 ImportInstance::Names(names) => Some((module, names)),
505 ImportInstance::Whole(_) => None,
506 })
507 .flat_map(|(module, m)| {
508 m.iter()
509 .map(move |(field, import)| (module.as_str(), field.as_str(), import))
510 })
511 }
512
513 pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
515 &self.names
516 }
517
518 fn add(
521 &mut self,
522 import: wasmparser::Import<'_>,
523 encoder: &ComponentEncoder,
524 import_map: Option<&ModuleImportMap>,
525 library_info: Option<&LibraryInfo>,
526 types: TypesRef<'_>,
527 ) -> Result<()> {
528 if self.classify_import_with_library(import, library_info)? {
529 return Ok(());
530 }
531 let mut import_to_classify = import;
532 if let Some(map) = import_map {
533 if let Some(original_name) = map.original_name(&import) {
534 import_to_classify.name = original_name;
535 }
536 }
537 let item = self
538 .classify(import_to_classify, encoder, types)
539 .with_context(|| {
540 format!(
541 "failed to resolve import `{}::{}`",
542 import.module, import.name,
543 )
544 })?;
545 self.insert_import(import, item)
546 }
547
548 fn classify(
554 &self,
555 import: wasmparser::Import<'_>,
556 encoder: &ComponentEncoder,
557 types: TypesRef<'_>,
558 ) -> Result<Import> {
559 if import.module == "env" && import.name == "memory" {
562 return Ok(Import::MainModuleMemory);
563 }
564
565 if import.module == "__main_module__" {
567 return Ok(Import::MainModuleExport {
568 name: import.name.to_string(),
569 kind: match import.ty {
570 TypeRef::Func(_) => ExportKind::Func,
571 TypeRef::Table(_) => ExportKind::Table,
572 TypeRef::Memory(_) => ExportKind::Memory,
573 TypeRef::Global(_) => ExportKind::Global,
574 TypeRef::Tag(_) => ExportKind::Tag,
575 TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
576 },
577 });
578 }
579
580 let ty_index = match import.ty {
581 TypeRef::Func(ty) => ty,
582 _ => bail!("module is only allowed to import functions"),
583 };
584 let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
585
586 if encoder.adapters.contains_key(import.module) {
589 return Ok(Import::AdapterExport {
590 adapter: import.module.to_string(),
591 func: import.name.to_string(),
592 ty: ty.clone(),
593 });
594 }
595
596 let (module, names) = match import.module.strip_prefix("cm32p2") {
597 Some(suffix) => (suffix, STANDARD),
598 None if encoder.reject_legacy_names => (import.module, STANDARD),
599 None => (import.module, LEGACY),
600 };
601 self.classify_component_model_import(module, import.name, encoder, ty, names)
602 }
603
604 fn classify_component_model_import(
607 &self,
608 module: &str,
609 name: &str,
610 encoder: &ComponentEncoder,
611 ty: &FuncType,
612 names: &dyn NameMangling,
613 ) -> Result<Import> {
614 let resolve = &encoder.metadata.resolve;
615 let world_id = encoder.metadata.world;
616 let world = &resolve.worlds[world_id];
617
618 if module == names.import_root() {
619 if names.error_context_drop(name) {
620 let expected = FuncType::new([ValType::I32], []);
621 validate_func_sig(name, &expected, ty)?;
622 return Ok(Import::ErrorContextDrop);
623 }
624
625 if names.backpressure_inc(name) {
626 let expected = FuncType::new([], []);
627 validate_func_sig(name, &expected, ty)?;
628 return Ok(Import::BackpressureInc);
629 }
630
631 if names.backpressure_dec(name) {
632 let expected = FuncType::new([], []);
633 validate_func_sig(name, &expected, ty)?;
634 return Ok(Import::BackpressureDec);
635 }
636
637 if names.waitable_set_new(name) {
638 let expected = FuncType::new([], [ValType::I32]);
639 validate_func_sig(name, &expected, ty)?;
640 return Ok(Import::WaitableSetNew);
641 }
642
643 if let Some((info, result_ty)) = names.waitable_set_wait(name) {
644 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
645 validate_func_sig(name, &expected, ty)?;
646 return Ok(Import::WaitableSetWait {
647 cancellable: info.cancellable,
648 });
649 }
650
651 if let Some((info, result_ty)) = names.waitable_set_poll(name) {
652 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
653 validate_func_sig(name, &expected, ty)?;
654 return Ok(Import::WaitableSetPoll {
655 cancellable: info.cancellable,
656 });
657 }
658
659 if names.waitable_set_drop(name) {
660 let expected = FuncType::new([ValType::I32], []);
661 validate_func_sig(name, &expected, ty)?;
662 return Ok(Import::WaitableSetDrop);
663 }
664
665 if names.waitable_join(name) {
666 let expected = FuncType::new([ValType::I32; 2], []);
667 validate_func_sig(name, &expected, ty)?;
668 return Ok(Import::WaitableJoin);
669 }
670
671 if names.subtask_drop(name) {
672 let expected = FuncType::new([ValType::I32], []);
673 validate_func_sig(name, &expected, ty)?;
674 return Ok(Import::SubtaskDrop);
675 }
676
677 if let Some(info) = names.subtask_cancel(name) {
678 let expected = FuncType::new([ValType::I32], [ValType::I32]);
679 validate_func_sig(name, &expected, ty)?;
680 return Ok(Import::SubtaskCancel {
681 async_: info.async_lowered,
682 });
683 }
684
685 if let Some(encoding) = names.error_context_new(name) {
686 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
687 validate_func_sig(name, &expected, ty)?;
688 return Ok(Import::ErrorContextNew { encoding });
689 }
690
691 if let Some(encoding) = names.error_context_debug_message(name) {
692 let expected = FuncType::new([ValType::I32; 2], []);
693 validate_func_sig(name, &expected, ty)?;
694 return Ok(Import::ErrorContextDebugMessage { encoding });
695 }
696
697 if let Some((slot_ty, slot)) = names.context_get(name) {
698 let expected = FuncType::new([], [slot_ty]);
699 validate_func_sig(name, &expected, ty)?;
700 return Ok(Import::ContextGet { ty: slot_ty, slot });
701 }
702 if let Some((slot_ty, slot)) = names.context_set(name) {
703 let expected = FuncType::new([slot_ty], []);
704 validate_func_sig(name, &expected, ty)?;
705 return Ok(Import::ContextSet { ty: slot_ty, slot });
706 }
707 if names.thread_index(name) {
708 let expected = FuncType::new([], [ValType::I32]);
709 validate_func_sig(name, &expected, ty)?;
710 return Ok(Import::ThreadIndex);
711 }
712 if names.thread_new_indirect(name) {
713 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
714 validate_func_sig(name, &expected, ty)?;
715 return Ok(Import::ThreadNewIndirect);
716 }
717 if names.thread_resume_later(name) {
718 let expected = FuncType::new([ValType::I32], []);
719 validate_func_sig(name, &expected, ty)?;
720 return Ok(Import::ThreadResumeLater);
721 }
722 if let Some(info) = names.thread_suspend(name) {
723 let expected = FuncType::new([], [ValType::I32]);
724 validate_func_sig(name, &expected, ty)?;
725 return Ok(Import::ThreadSuspend {
726 cancellable: info.cancellable,
727 });
728 }
729 if let Some(info) = names.thread_yield(name) {
730 let expected = FuncType::new([], [ValType::I32]);
731 validate_func_sig(name, &expected, ty)?;
732 return Ok(Import::ThreadYield {
733 cancellable: info.cancellable,
734 });
735 }
736 if let Some(info) = names.thread_suspend_then_resume(name) {
737 let expected = FuncType::new([ValType::I32], [ValType::I32]);
738 validate_func_sig(name, &expected, ty)?;
739 return Ok(Import::ThreadSuspendThenResume {
740 cancellable: info.cancellable,
741 });
742 }
743 if let Some(info) = names.thread_yield_then_resume(name) {
744 let expected = FuncType::new([ValType::I32], [ValType::I32]);
745 validate_func_sig(name, &expected, ty)?;
746 return Ok(Import::ThreadYieldThenResume {
747 cancellable: info.cancellable,
748 });
749 }
750 if let Some(info) = names.thread_suspend_then_promote(name) {
751 let expected = FuncType::new([ValType::I32], [ValType::I32]);
752 validate_func_sig(name, &expected, ty)?;
753 return Ok(Import::ThreadSuspendThenPromote {
754 cancellable: info.cancellable,
755 });
756 }
757 if let Some(info) = names.thread_yield_then_promote(name) {
758 let expected = FuncType::new([ValType::I32], [ValType::I32]);
759 validate_func_sig(name, &expected, ty)?;
760 return Ok(Import::ThreadYieldThenPromote {
761 cancellable: info.cancellable,
762 });
763 }
764
765 let (key_name, abi) = names.world_key_name_and_abi(name);
766 let key = WorldKey::Name(key_name.to_string());
767 if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
768 validate_func(resolve, ty, func, abi)?;
769 return Ok(Import::WorldFunc(key, func.name.clone(), abi));
770 }
771
772 if let Some(import) =
773 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
774 {
775 return Ok(import);
776 }
777
778 match world.imports.get(&key) {
779 Some(_) => bail!("expected world top-level import `{name}` to be a function"),
780 None => bail!("no top-level imported function `{name}` specified"),
781 }
782 }
783
784 if module == "env" {
785 if let Some(import) = names.env_import(name, ty) {
786 return Ok(import);
787 }
788 }
789
790 if matches!(
792 module.strip_prefix(names.import_exported_intrinsic_prefix()),
793 Some(module) if module == names.import_root()
794 ) {
795 if let Some(import) =
796 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
797 {
798 return Ok(import);
799 }
800 }
801
802 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
803 Some(name) => name,
804 None => bail!("unknown or invalid component model import syntax"),
805 };
806
807 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
808 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
809
810 if let Some(import) =
811 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
812 {
813 return Ok(import);
814 }
815 bail!("unknown function `{name}`")
816 }
817
818 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
819 let interface = &resolve.interfaces[id];
820 let (function_name, abi) = names.interface_function_name_and_abi(name);
821 if let Some(f) = interface.functions.get(function_name) {
822 validate_func(resolve, ty, f, abi).with_context(|| {
823 let name = resolve.name_world_key(&key);
824 format!("failed to validate import interface `{name}`")
825 })?;
826 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
827 }
828
829 if let Some(import) =
830 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
831 {
832 return Ok(import);
833 }
834 bail!(
835 "import interface `{module}` is missing function \
836 `{name}` that is required by the module",
837 )
838 }
839
840 fn maybe_classify_wit_intrinsic(
868 &self,
869 name: &str,
870 key_and_id: Option<(WorldKey, InterfaceId)>,
871 encoder: &ComponentEncoder,
872 ty: &FuncType,
873 import: bool,
874 names: &dyn NameMangling,
875 ) -> Result<Option<Import>> {
876 let resolve = &encoder.metadata.resolve;
877 let world_id = encoder.metadata.world;
878 let world = &resolve.worlds[world_id];
879
880 let (key, id) = match key_and_id {
885 Some((key, id)) => (Some(key), Some(id)),
886 None => (None, None),
887 };
888
889 let resource_test = |name: &str| match id {
891 Some(id) => resource_test_for_interface(resolve, id)(name),
892 None => resource_test_for_world(resolve, world_id)(name),
893 };
894
895 if let Some(resource) = names.resource_drop_name(name) {
897 if let Some(resource_id) = resource_test(resource) {
898 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
899 let expected = FuncType::new([ValType::I32], []);
900 validate_func_sig(name, &expected, ty)?;
901 return Ok(Some(if import {
902 Import::ImportedResourceDrop(key, id, resource_id)
903 } else {
904 Import::ExportedResourceDrop(key, resource_id)
905 }));
906 }
907 }
908
909 if !import {
912 if let Some(name) = names.resource_new_name(name) {
913 if let Some(id) = resource_test(name) {
914 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
915 let expected = FuncType::new([ValType::I32], [ValType::I32]);
916 validate_func_sig(name, &expected, ty)?;
917 return Ok(Some(Import::ExportedResourceNew(key, id)));
918 }
919 }
920 if let Some(name) = names.resource_rep_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::ExportedResourceRep(key, id)));
926 }
927 }
928 if let Some(name) = names.task_return_name(name) {
929 let func = get_function(resolve, world, name, id, import)?;
930 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
931 return Ok(Some(Import::ExportedTaskReturn(key, id, func.clone())));
934 }
935 if names.task_cancel(name) {
936 let expected = FuncType::new([], []);
937 validate_func_sig(name, &expected, ty)?;
938 return Ok(Some(Import::ExportedTaskCancel));
939 }
940 }
941
942 let lookup_context = PayloadLookupContext {
943 resolve,
944 world,
945 key,
946 id,
947 import,
948 };
949
950 let import = if let Some(info) = names.future_new(&lookup_context, name) {
954 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
955 Import::FutureNew(info)
956 } else if let Some(info) = names.future_write(&lookup_context, name) {
957 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
958 Import::FutureWrite {
959 async_: info.async_lowered,
960 info: info.inner,
961 }
962 } else if let Some(info) = names.future_read(&lookup_context, name) {
963 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
964 Import::FutureRead {
965 async_: info.async_lowered,
966 info: info.inner,
967 }
968 } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
969 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
970 Import::FutureCancelWrite {
971 async_: info.async_lowered,
972 info: info.inner,
973 }
974 } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
975 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
976 Import::FutureCancelRead {
977 async_: info.async_lowered,
978 info: info.inner,
979 }
980 } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
981 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
982 Import::FutureDropWritable(info)
983 } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
984 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
985 Import::FutureDropReadable(info)
986 } else if let Some(info) = names.stream_new(&lookup_context, name) {
987 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
988 Import::StreamNew(info)
989 } else if let Some(info) = names.stream_write(&lookup_context, name) {
990 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
991 Import::StreamWrite {
992 async_: info.async_lowered,
993 info: info.inner,
994 }
995 } else if let Some(info) = names.stream_read(&lookup_context, name) {
996 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
997 Import::StreamRead {
998 async_: info.async_lowered,
999 info: info.inner,
1000 }
1001 } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
1002 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
1003 Import::StreamCancelWrite {
1004 async_: info.async_lowered,
1005 info: info.inner,
1006 }
1007 } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
1008 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
1009 Import::StreamCancelRead {
1010 async_: info.async_lowered,
1011 info: info.inner,
1012 }
1013 } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
1014 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1015 Import::StreamDropWritable(info)
1016 } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
1017 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1018 Import::StreamDropReadable(info)
1019 } else {
1020 return Ok(None);
1021 };
1022 Ok(Some(import))
1023 }
1024
1025 fn classify_import_with_library(
1026 &mut self,
1027 import: wasmparser::Import<'_>,
1028 library_info: Option<&LibraryInfo>,
1029 ) -> Result<bool> {
1030 let info = match library_info {
1031 Some(info) => info,
1032 None => return Ok(false),
1033 };
1034 let Some((_, instance)) = info
1035 .arguments
1036 .iter()
1037 .find(|(name, _items)| *name == import.module)
1038 else {
1039 return Ok(false);
1040 };
1041 match instance {
1042 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1043 Some(ImportInstance::Whole(which)) => {
1044 if which != module {
1045 bail!("different whole modules imported under the same name");
1046 }
1047 }
1048 Some(ImportInstance::Names(_)) => {
1049 bail!("cannot mix individual imports and whole module imports")
1050 }
1051 None => {
1052 let instance = ImportInstance::Whole(module.clone());
1053 self.names.insert(import.module.to_string(), instance);
1054 }
1055 },
1056 Instance::Items(items) => {
1057 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1058 return Ok(false);
1059 };
1060 self.insert_import(import, Import::Item(item.clone()))?;
1061 }
1062 }
1063 Ok(true)
1064 }
1065
1066 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1070 let entry = self
1071 .names
1072 .entry(import.module.to_string())
1073 .or_insert(ImportInstance::Names(IndexMap::default()));
1074 let names = match entry {
1075 ImportInstance::Names(names) => names,
1076 _ => bail!("cannot mix individual imports with module imports"),
1077 };
1078 let entry = match names.entry(import.name.to_string()) {
1079 Entry::Occupied(_) => {
1080 bail!(
1081 "module has duplicate import for `{}::{}`",
1082 import.module,
1083 import.name
1084 );
1085 }
1086 Entry::Vacant(v) => v,
1087 };
1088 log::trace!(
1089 "classifying import `{}::{} as {item:?}",
1090 import.module,
1091 import.name
1092 );
1093 entry.insert(item);
1094 Ok(())
1095 }
1096}
1097
1098#[derive(Default)]
1101pub struct ExportMap {
1102 names: IndexMap<String, Export>,
1103 raw_exports: IndexMap<String, FuncType>,
1104}
1105
1106#[derive(Debug)]
1109pub enum Export {
1110 WorldFunc(WorldKey, String, AbiVariant),
1113
1114 WorldFuncPostReturn(WorldKey),
1116
1117 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1119
1120 InterfaceFuncPostReturn(WorldKey, String),
1122
1123 ResourceDtor(TypeId),
1125
1126 Memory,
1128
1129 GeneralPurposeRealloc,
1131
1132 GeneralPurposeExportRealloc,
1134
1135 GeneralPurposeImportRealloc,
1137
1138 Initialize,
1140
1141 ReallocForAdapter,
1143
1144 WorldFuncCallback(WorldKey),
1145
1146 InterfaceFuncCallback(WorldKey, String),
1147
1148 IndirectFunctionTable,
1150
1151 WasmInitTask,
1153
1154 WasmInitAsyncTask,
1156}
1157
1158impl ExportMap {
1159 fn add(
1160 &mut self,
1161 export: wasmparser::Export<'_>,
1162 encoder: &ComponentEncoder,
1163 exports: &IndexSet<WorldKey>,
1164 types: TypesRef<'_>,
1165 ) -> Result<()> {
1166 if let Some(item) = self.classify(export, encoder, exports, types)? {
1167 log::debug!("classifying export `{}` as {item:?}", export.name);
1168 let prev = self.names.insert(export.name.to_string(), item);
1169 assert!(prev.is_none());
1170 }
1171 Ok(())
1172 }
1173
1174 fn classify(
1175 &mut self,
1176 export: wasmparser::Export<'_>,
1177 encoder: &ComponentEncoder,
1178 exports: &IndexSet<WorldKey>,
1179 types: TypesRef<'_>,
1180 ) -> Result<Option<Export>> {
1181 match export.kind {
1182 ExternalKind::Func => {
1183 let ty = types[types.core_function_at(export.index)].unwrap_func();
1184 self.raw_exports.insert(export.name.to_string(), ty.clone());
1185 }
1186 _ => {}
1187 }
1188
1189 if export.name == "canonical_abi_realloc" {
1191 return Ok(Some(Export::GeneralPurposeRealloc));
1192 } else if export.name == "cabi_import_realloc" {
1193 return Ok(Some(Export::GeneralPurposeImportRealloc));
1194 } else if export.name == "cabi_export_realloc" {
1195 return Ok(Some(Export::GeneralPurposeExportRealloc));
1196 } else if export.name == "cabi_realloc_adapter" {
1197 return Ok(Some(Export::ReallocForAdapter));
1198 }
1199
1200 let (name, names) = match export.name.strip_prefix("cm32p2") {
1201 Some(name) => (name, STANDARD),
1202 None if encoder.reject_legacy_names => return Ok(None),
1203 None => (export.name, LEGACY),
1204 };
1205
1206 if let Some(export) = self
1207 .classify_component_export(names, name, &export, encoder, exports, types)
1208 .with_context(|| format!("failed to classify export `{}`", export.name))?
1209 {
1210 return Ok(Some(export));
1211 }
1212 log::debug!("unknown export `{}`", export.name);
1213 Ok(None)
1214 }
1215
1216 fn classify_component_export(
1217 &mut self,
1218 names: &dyn NameMangling,
1219 name: &str,
1220 export: &wasmparser::Export<'_>,
1221 encoder: &ComponentEncoder,
1222 exports: &IndexSet<WorldKey>,
1223 types: TypesRef<'_>,
1224 ) -> Result<Option<Export>> {
1225 let resolve = &encoder.metadata.resolve;
1226 let world = encoder.metadata.world;
1227 match export.kind {
1228 ExternalKind::Func => {}
1229 ExternalKind::Memory => {
1230 if name == names.export_memory() {
1231 return Ok(Some(Export::Memory));
1232 }
1233 return Ok(None);
1234 }
1235 ExternalKind::Table => {
1236 if Some(name) == names.export_indirect_function_table() {
1237 return Ok(Some(Export::IndirectFunctionTable));
1238 }
1239 return Ok(None);
1240 }
1241 _ => return Ok(None),
1242 }
1243 let ty = types[types.core_function_at(export.index)].unwrap_func();
1244
1245 if name == names.export_realloc() {
1247 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1248 validate_func_sig(name, &expected, ty)?;
1249 return Ok(Some(Export::GeneralPurposeRealloc));
1250 } else if name == names.export_initialize() {
1251 let expected = FuncType::new([], []);
1252 validate_func_sig(name, &expected, ty)?;
1253 return Ok(Some(Export::Initialize));
1254 } else if Some(name) == names.export_wasm_init_task() {
1255 let expected = FuncType::new([], []);
1256 validate_func_sig(name, &expected, ty)?;
1257 return Ok(Some(Export::WasmInitTask));
1258 } else if Some(name) == names.export_wasm_init_async_task() {
1259 let expected = FuncType::new([], []);
1260 validate_func_sig(name, &expected, ty)?;
1261 return Ok(Some(Export::WasmInitAsyncTask));
1262 }
1263
1264 let full_name = name;
1265 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1266 (AbiVariant::GuestExportAsync, name)
1267 } else if let Some(name) = names.async_lift_stackful_name(name) {
1268 (AbiVariant::GuestExportAsyncStackful, name)
1269 } else {
1270 (AbiVariant::GuestExport, name)
1271 };
1272
1273 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1275 validate_func(resolve, ty, f, abi).with_context(|| {
1276 let key = resolve.name_world_key(key);
1277 format!("failed to validate export for `{key}`")
1278 })?;
1279 match id {
1280 Some(id) => {
1281 return Ok(Some(Export::InterfaceFunc(
1282 key.clone(),
1283 id,
1284 f.name.clone(),
1285 abi,
1286 )));
1287 }
1288 None => {
1289 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1290 }
1291 }
1292 }
1293
1294 if let Some(remaining) = names.strip_post_return(name) {
1296 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1297 validate_post_return(resolve, ty, f).with_context(|| {
1298 let key = resolve.name_world_key(key);
1299 format!("failed to validate export for `{key}`")
1300 })?;
1301 match id {
1302 Some(_id) => {
1303 return Ok(Some(Export::InterfaceFuncPostReturn(
1304 key.clone(),
1305 f.name.clone(),
1306 )));
1307 }
1308 None => {
1309 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1310 }
1311 }
1312 }
1313 }
1314
1315 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1316 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1317 validate_func_sig(
1318 full_name,
1319 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1320 ty,
1321 )?;
1322 return Ok(Some(if id.is_some() {
1323 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1324 } else {
1325 Export::WorldFuncCallback(key.clone())
1326 }));
1327 }
1328 }
1329
1330 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1332 let expected = FuncType::new([ValType::I32], []);
1333 validate_func_sig(full_name, &expected, ty)?;
1334 return Ok(Some(Export::ResourceDtor(dtor)));
1335 }
1336
1337 Ok(None)
1338 }
1339
1340 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1343 self.find(|m| match m {
1344 Export::WorldFuncPostReturn(k) => k == key,
1345 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1346 _ => false,
1347 })
1348 }
1349
1350 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1353 self.find(|m| match m {
1354 Export::WorldFuncCallback(k) => k == key,
1355 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1356 _ => false,
1357 })
1358 }
1359
1360 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1361 self.names.values().find_map(|m| match m {
1362 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1363 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1364 _ => None,
1365 })
1366 }
1367
1368 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1371 let _ = (key, func);
1375
1376 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1377 return Some(name);
1378 }
1379 self.general_purpose_realloc()
1380 }
1381
1382 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1385 let _ = (interface, func);
1389
1390 self.import_realloc_fallback()
1391 }
1392
1393 pub fn import_realloc_fallback(&self) -> Option<&str> {
1397 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1398 return Some(name);
1399 }
1400 self.general_purpose_realloc()
1401 }
1402
1403 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1405 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1406 return Some(name);
1407 }
1408 self.general_purpose_realloc()
1409 }
1410
1411 fn general_purpose_realloc(&self) -> Option<&str> {
1412 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1413 }
1414
1415 pub fn memory(&self) -> Option<&str> {
1417 self.find(|m| matches!(m, Export::Memory))
1418 }
1419
1420 pub fn indirect_function_table(&self) -> Option<&str> {
1422 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1423 }
1424
1425 pub fn wasm_init_task(&self) -> Option<&str> {
1427 self.find(|t| matches!(t, Export::WasmInitTask))
1428 }
1429
1430 pub fn wasm_init_async_task(&self) -> Option<&str> {
1432 self.find(|t| matches!(t, Export::WasmInitAsyncTask))
1433 }
1434
1435 pub fn initialize(&self) -> Option<&str> {
1437 self.find(|m| matches!(m, Export::Initialize))
1438 }
1439
1440 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1442 self.find(|m| match m {
1443 Export::ResourceDtor(t) => *t == ty,
1444 _ => false,
1445 })
1446 }
1447
1448 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1451 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1452 Some(name)
1453 }
1454
1455 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1457 self.names.iter().map(|(n, e)| (n.as_str(), e))
1458 }
1459
1460 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1461 let resolve = &encoder.metadata.resolve;
1462 let world = encoder.metadata.world;
1463 if self
1466 .names
1467 .values()
1468 .filter(|m| matches!(m, Export::Memory))
1469 .count()
1470 > 1
1471 {
1472 bail!("cannot componentize module that exports multiple memories")
1473 }
1474
1475 for (name, export) in &self.names {
1477 match export {
1478 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1479 if !matches!(
1480 self.names.get(&format!("[callback]{name}")),
1481 Some(Export::WorldFuncCallback(_))
1482 ) {
1483 bail!("missing callback for `{name}`");
1484 }
1485 }
1486 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1487 if !matches!(
1488 self.names.get(&format!("[callback]{name}")),
1489 Some(Export::InterfaceFuncCallback(_, _))
1490 ) {
1491 bail!("missing callback for `{name}`");
1492 }
1493 }
1494 _ => {}
1495 }
1496 }
1497
1498 for export in exports {
1500 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1501 let result = self.find(|e| match e {
1502 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1503 _ => false,
1504 });
1505 if result.is_some() {
1506 Ok(())
1507 } else {
1508 let export = resolve.name_world_key(export);
1509 bail!("failed to find export of interface `{export}` function `{name}`")
1510 }
1511 };
1512 let require_world_func = |name: &str| -> Result<()> {
1513 let result = self.find(|e| match e {
1514 Export::WorldFunc(_, s, _) => name == s,
1515 _ => false,
1516 });
1517 if result.is_some() {
1518 Ok(())
1519 } else {
1520 bail!("failed to find export of function `{name}`")
1521 }
1522 };
1523 match &resolve.worlds[world].exports[export] {
1524 WorldItem::Interface { id, .. } => {
1525 for (name, _) in resolve.interfaces[*id].functions.iter() {
1526 require_interface_func(*id, name)?;
1527 }
1528 }
1529 WorldItem::Function(f) => {
1530 require_world_func(&f.name)?;
1531 }
1532 WorldItem::Type { .. } => unreachable!(),
1533 }
1534 }
1535
1536 Ok(())
1537 }
1538}
1539
1540struct MaybeCancellable<T> {
1542 #[allow(unused)]
1543 inner: T,
1544 cancellable: bool,
1545}
1546
1547struct MaybeAsyncLowered<T> {
1549 inner: T,
1550 async_lowered: bool,
1551}
1552
1553struct PayloadLookupContext<'a> {
1556 resolve: &'a Resolve,
1557 world: &'a World,
1558 id: Option<InterfaceId>,
1559 import: bool,
1560 key: Option<WorldKey>,
1561}
1562
1563trait NameMangling {
1585 fn import_root(&self) -> &str;
1586 fn import_non_root_prefix(&self) -> &str;
1587 fn import_exported_intrinsic_prefix(&self) -> &str;
1588 fn export_memory(&self) -> &str;
1589 fn export_initialize(&self) -> &str;
1590 fn export_realloc(&self) -> &str;
1591 fn export_indirect_function_table(&self) -> Option<&str>;
1592 fn export_wasm_init_task(&self) -> Option<&str>;
1593 fn export_wasm_init_async_task(&self) -> Option<&str>;
1594 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1595 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1596 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1597 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1598 fn task_cancel(&self, name: &str) -> bool;
1599 fn backpressure_inc(&self, name: &str) -> bool;
1600 fn backpressure_dec(&self, name: &str) -> bool;
1601 fn waitable_set_new(&self, name: &str) -> bool;
1602 fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1603 fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1604 fn waitable_set_drop(&self, name: &str) -> bool;
1605 fn waitable_join(&self, name: &str) -> bool;
1606 fn subtask_drop(&self, name: &str) -> bool;
1607 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1608 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1609 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1610 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1611 fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1612 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1613 fn error_context_drop(&self, name: &str) -> bool;
1614 fn context_get(&self, name: &str) -> Option<(ValType, u32)>;
1615 fn context_set(&self, name: &str) -> Option<(ValType, u32)>;
1616 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1617 fn future_write(
1618 &self,
1619 lookup_context: &PayloadLookupContext,
1620 name: &str,
1621 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1622 fn future_read(
1623 &self,
1624 lookup_context: &PayloadLookupContext,
1625 name: &str,
1626 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1627 fn future_cancel_write(
1628 &self,
1629 lookup_context: &PayloadLookupContext,
1630 name: &str,
1631 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1632 fn future_cancel_read(
1633 &self,
1634 lookup_context: &PayloadLookupContext,
1635 name: &str,
1636 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1637 fn future_drop_writable(
1638 &self,
1639 lookup_context: &PayloadLookupContext,
1640 name: &str,
1641 ) -> Option<PayloadInfo>;
1642 fn future_drop_readable(
1643 &self,
1644 lookup_context: &PayloadLookupContext,
1645 name: &str,
1646 ) -> Option<PayloadInfo>;
1647 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1648 fn stream_write(
1649 &self,
1650 lookup_context: &PayloadLookupContext,
1651 name: &str,
1652 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1653 fn stream_read(
1654 &self,
1655 lookup_context: &PayloadLookupContext,
1656 name: &str,
1657 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1658 fn stream_cancel_write(
1659 &self,
1660 lookup_context: &PayloadLookupContext,
1661 name: &str,
1662 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1663 fn stream_cancel_read(
1664 &self,
1665 lookup_context: &PayloadLookupContext,
1666 name: &str,
1667 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1668 fn stream_drop_writable(
1669 &self,
1670 lookup_context: &PayloadLookupContext,
1671 name: &str,
1672 ) -> Option<PayloadInfo>;
1673 fn stream_drop_readable(
1674 &self,
1675 lookup_context: &PayloadLookupContext,
1676 name: &str,
1677 ) -> Option<PayloadInfo>;
1678 fn thread_index(&self, name: &str) -> bool;
1679 fn thread_new_indirect(&self, name: &str) -> bool;
1680 fn thread_resume_later(&self, name: &str) -> bool;
1681 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1682 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1683 fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1684 fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1685 fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1686 fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1687 fn module_to_interface(
1688 &self,
1689 module: &str,
1690 resolve: &Resolve,
1691 items: &IndexMap<WorldKey, WorldItem>,
1692 ) -> Result<(WorldKey, InterfaceId)>;
1693 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1694 fn match_wit_export<'a>(
1695 &self,
1696 export_name: &str,
1697 resolve: &'a Resolve,
1698 world: WorldId,
1699 exports: &'a IndexSet<WorldKey>,
1700 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1701 fn match_wit_resource_dtor<'a>(
1702 &self,
1703 export_name: &str,
1704 resolve: &'a Resolve,
1705 world: WorldId,
1706 exports: &'a IndexSet<WorldKey>,
1707 ) -> Option<TypeId>;
1708 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1709 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1710 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import>;
1711}
1712
1713struct Standard;
1716
1717const STANDARD: &'static dyn NameMangling = &Standard;
1718
1719impl NameMangling for Standard {
1720 fn import_root(&self) -> &str {
1721 ""
1722 }
1723 fn import_non_root_prefix(&self) -> &str {
1724 "|"
1725 }
1726 fn import_exported_intrinsic_prefix(&self) -> &str {
1727 "_ex_"
1728 }
1729 fn export_memory(&self) -> &str {
1730 "_memory"
1731 }
1732 fn export_initialize(&self) -> &str {
1733 "_initialize"
1734 }
1735 fn export_realloc(&self) -> &str {
1736 "_realloc"
1737 }
1738 fn export_indirect_function_table(&self) -> Option<&str> {
1739 None
1740 }
1741 fn export_wasm_init_task(&self) -> Option<&str> {
1742 None
1743 }
1744 fn export_wasm_init_async_task(&self) -> Option<&str> {
1745 None
1746 }
1747 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1748 name.strip_suffix("_drop")
1749 }
1750 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1751 name.strip_suffix("_new")
1752 }
1753 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1754 name.strip_suffix("_rep")
1755 }
1756 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1757 None
1758 }
1759 fn task_cancel(&self, _name: &str) -> bool {
1760 false
1761 }
1762 fn backpressure_inc(&self, _name: &str) -> bool {
1763 false
1764 }
1765 fn backpressure_dec(&self, _name: &str) -> bool {
1766 false
1767 }
1768 fn waitable_set_new(&self, _name: &str) -> bool {
1769 false
1770 }
1771 fn waitable_set_wait(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1772 None
1773 }
1774 fn waitable_set_poll(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1775 None
1776 }
1777 fn waitable_set_drop(&self, _name: &str) -> bool {
1778 false
1779 }
1780 fn waitable_join(&self, _name: &str) -> bool {
1781 false
1782 }
1783 fn subtask_drop(&self, _name: &str) -> bool {
1784 false
1785 }
1786 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1787 None
1788 }
1789 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1790 None
1791 }
1792 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1793 None
1794 }
1795 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1796 None
1797 }
1798 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1799 None
1800 }
1801 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1802 None
1803 }
1804 fn error_context_drop(&self, _name: &str) -> bool {
1805 false
1806 }
1807 fn context_get(&self, _name: &str) -> Option<(ValType, u32)> {
1808 None
1809 }
1810 fn context_set(&self, _name: &str) -> Option<(ValType, u32)> {
1811 None
1812 }
1813 fn thread_index(&self, _name: &str) -> bool {
1814 false
1815 }
1816 fn thread_new_indirect(&self, _name: &str) -> bool {
1817 false
1818 }
1819 fn thread_resume_later(&self, _name: &str) -> bool {
1820 false
1821 }
1822 fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1823 None
1824 }
1825 fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1826 None
1827 }
1828 fn thread_suspend_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1829 None
1830 }
1831 fn thread_yield_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1832 None
1833 }
1834 fn thread_suspend_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1835 None
1836 }
1837 fn thread_yield_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1838 None
1839 }
1840 fn future_new(
1841 &self,
1842 _lookup_context: &PayloadLookupContext,
1843 _name: &str,
1844 ) -> Option<PayloadInfo> {
1845 None
1846 }
1847 fn future_write(
1848 &self,
1849 _lookup_context: &PayloadLookupContext,
1850 _name: &str,
1851 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1852 None
1853 }
1854 fn future_read(
1855 &self,
1856 _lookup_context: &PayloadLookupContext,
1857 _name: &str,
1858 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1859 None
1860 }
1861 fn future_cancel_write(
1862 &self,
1863 _lookup_context: &PayloadLookupContext,
1864 _name: &str,
1865 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1866 None
1867 }
1868 fn future_cancel_read(
1869 &self,
1870 _lookup_context: &PayloadLookupContext,
1871 _name: &str,
1872 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1873 None
1874 }
1875 fn future_drop_writable(
1876 &self,
1877 _lookup_context: &PayloadLookupContext,
1878 _name: &str,
1879 ) -> Option<PayloadInfo> {
1880 None
1881 }
1882 fn future_drop_readable(
1883 &self,
1884 _lookup_context: &PayloadLookupContext,
1885 _name: &str,
1886 ) -> Option<PayloadInfo> {
1887 None
1888 }
1889 fn stream_new(
1890 &self,
1891 _lookup_context: &PayloadLookupContext,
1892 _name: &str,
1893 ) -> Option<PayloadInfo> {
1894 None
1895 }
1896 fn stream_write(
1897 &self,
1898 _lookup_context: &PayloadLookupContext,
1899 _name: &str,
1900 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1901 None
1902 }
1903 fn stream_read(
1904 &self,
1905 _lookup_context: &PayloadLookupContext,
1906 _name: &str,
1907 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1908 None
1909 }
1910 fn stream_cancel_write(
1911 &self,
1912 _lookup_context: &PayloadLookupContext,
1913 _name: &str,
1914 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1915 None
1916 }
1917 fn stream_cancel_read(
1918 &self,
1919 _lookup_context: &PayloadLookupContext,
1920 _name: &str,
1921 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1922 None
1923 }
1924 fn stream_drop_writable(
1925 &self,
1926 _lookup_context: &PayloadLookupContext,
1927 _name: &str,
1928 ) -> Option<PayloadInfo> {
1929 None
1930 }
1931 fn stream_drop_readable(
1932 &self,
1933 _lookup_context: &PayloadLookupContext,
1934 _name: &str,
1935 ) -> Option<PayloadInfo> {
1936 None
1937 }
1938 fn module_to_interface(
1939 &self,
1940 interface: &str,
1941 resolve: &Resolve,
1942 items: &IndexMap<WorldKey, WorldItem>,
1943 ) -> Result<(WorldKey, InterfaceId)> {
1944 for (key, item) in items.iter() {
1945 let id = match key {
1946 WorldKey::Name(name) => match item {
1948 WorldItem::Interface { id, .. } if name == interface => *id,
1949 _ => continue,
1950 },
1951 WorldKey::Interface(id) => {
1953 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1954 continue;
1955 }
1956 *id
1957 }
1958 };
1959 return Ok((key.clone(), id));
1960 }
1961 bail!("failed to find world item corresponding to interface `{interface}`")
1962 }
1963 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1964 name.strip_suffix("_post")
1965 }
1966 fn match_wit_export<'a>(
1967 &self,
1968 export_name: &str,
1969 resolve: &'a Resolve,
1970 world: WorldId,
1971 exports: &'a IndexSet<WorldKey>,
1972 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1973 if let Some(world_export_name) = export_name.strip_prefix("||") {
1974 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1975 match &resolve.worlds[world].exports[key] {
1976 WorldItem::Function(f) => return Some((key, None, f)),
1977 _ => return None,
1978 }
1979 }
1980
1981 let (key, id, func_name) =
1982 self.match_wit_interface(export_name, resolve, world, exports)?;
1983 let func = resolve.interfaces[id].functions.get(func_name)?;
1984 Some((key, Some(id), func))
1985 }
1986
1987 fn match_wit_resource_dtor<'a>(
1988 &self,
1989 export_name: &str,
1990 resolve: &'a Resolve,
1991 world: WorldId,
1992 exports: &'a IndexSet<WorldKey>,
1993 ) -> Option<TypeId> {
1994 let (_key, id, name) =
1995 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1996 let ty = *resolve.interfaces[id].types.get(name)?;
1997 match resolve.types[ty].kind {
1998 TypeDefKind::Resource => Some(ty),
1999 _ => None,
2000 }
2001 }
2002
2003 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2004 (name, AbiVariant::GuestImport)
2005 }
2006 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2007 (name, AbiVariant::GuestImport)
2008 }
2009 fn env_import(&self, _name: &str, _ty: &FuncType) -> Option<Import> {
2010 None
2011 }
2012}
2013
2014impl Standard {
2015 fn match_wit_interface<'a, 'b>(
2016 &self,
2017 export_name: &'b str,
2018 resolve: &'a Resolve,
2019 world: WorldId,
2020 exports: &'a IndexSet<WorldKey>,
2021 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
2022 let world = &resolve.worlds[world];
2023 let export_name = export_name.strip_prefix("|")?;
2024
2025 for export in exports {
2026 let id = match &world.exports[export] {
2027 WorldItem::Interface { id, .. } => *id,
2028 WorldItem::Function(_) => continue,
2029 WorldItem::Type { .. } => unreachable!(),
2030 };
2031 let remaining = match export {
2032 WorldKey::Name(name) => export_name.strip_prefix(name),
2033 WorldKey::Interface(_) => {
2034 let prefix = resolve.canonicalized_id_of(id).unwrap();
2035 export_name.strip_prefix(&prefix)
2036 }
2037 };
2038 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
2039 Some(name) => name,
2040 None => continue,
2041 };
2042 return Some((export, id, item_name));
2043 }
2044
2045 None
2046 }
2047}
2048
2049struct Legacy;
2052
2053const LEGACY: &'static dyn NameMangling = &Legacy;
2054
2055impl Legacy {
2056 fn prefixed_payload(
2062 &self,
2063 lookup_context: &PayloadLookupContext,
2064 name: &str,
2065 prefix: &str,
2066 ) -> Option<PayloadInfo> {
2067 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2070 let ty = match index_or_unit {
2071 "unit" => {
2072 if name.starts_with("[future") {
2073 PayloadType::UnitFuture
2074 } else if name.starts_with("[stream") {
2075 PayloadType::UnitStream
2076 } else {
2077 unreachable!()
2078 }
2079 }
2080 other => {
2081 let type_index = other.parse::<u32>().ok()? as usize;
2085
2086 let function = get_function(
2091 lookup_context.resolve,
2092 lookup_context.world,
2093 func_name,
2094 lookup_context.id,
2095 lookup_context.import,
2096 )
2097 .ok()?;
2098 PayloadType::Type {
2099 id: *function
2100 .find_futures_and_streams(lookup_context.resolve)
2101 .get(type_index)?,
2102 function: function.name.clone(),
2103 }
2104 }
2105 };
2106
2107 Some(PayloadInfo {
2109 name: name.to_string(),
2110 ty,
2111 key: lookup_context
2112 .key
2113 .clone()
2114 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2115 interface: lookup_context.id,
2116 imported: lookup_context.import,
2117 })
2118 }
2119
2120 fn maybe_async_lowered_payload(
2121 &self,
2122 lookup_context: &PayloadLookupContext,
2123 name: &str,
2124 prefix: &str,
2125 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2126 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2127 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2128 Some(MaybeAsyncLowered {
2129 inner: payload,
2130 async_lowered,
2131 })
2132 }
2133
2134 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2135 name.strip_prefix("[async-lower]")
2136 .map_or((false, name), |s| (true, s))
2137 }
2138 fn match_with_async_lowered_prefix(
2139 &self,
2140 name: &str,
2141 expected: &str,
2142 ) -> Option<MaybeAsyncLowered<()>> {
2143 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2144 if clean_name == expected {
2145 Some(MaybeAsyncLowered {
2146 inner: (),
2147 async_lowered,
2148 })
2149 } else {
2150 None
2151 }
2152 }
2153 fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2154 name.strip_prefix("[cancellable]")
2155 .map_or((false, name), |s| (true, s))
2156 }
2157 fn match_with_cancellable_prefix(
2158 &self,
2159 name: &str,
2160 expected: &str,
2161 ) -> Option<MaybeCancellable<()>> {
2162 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2163 if clean_name == expected {
2164 Some(MaybeCancellable {
2165 inner: (),
2166 cancellable,
2167 })
2168 } else {
2169 None
2170 }
2171 }
2172
2173 fn match_with_optional_type_suffix(name: &str, match_prefix: &str) -> Option<ValType> {
2177 let tail = name.strip_prefix(match_prefix)?.strip_suffix(']')?;
2178 if tail.is_empty() {
2179 Some(ValType::I32)
2180 } else {
2181 match tail.strip_prefix('-')? {
2182 "i32" => Some(ValType::I32),
2183 "i64" => Some(ValType::I64),
2184 _ => None,
2186 }
2187 }
2188 }
2189}
2190
2191impl NameMangling for Legacy {
2192 fn import_root(&self) -> &str {
2193 "$root"
2194 }
2195 fn import_non_root_prefix(&self) -> &str {
2196 ""
2197 }
2198 fn import_exported_intrinsic_prefix(&self) -> &str {
2199 "[export]"
2200 }
2201 fn export_memory(&self) -> &str {
2202 "memory"
2203 }
2204 fn export_initialize(&self) -> &str {
2205 "_initialize"
2206 }
2207 fn export_realloc(&self) -> &str {
2208 "cabi_realloc"
2209 }
2210 fn export_indirect_function_table(&self) -> Option<&str> {
2211 Some("__indirect_function_table")
2212 }
2213 fn export_wasm_init_task(&self) -> Option<&str> {
2214 Some("__wasm_init_task")
2215 }
2216 fn export_wasm_init_async_task(&self) -> Option<&str> {
2217 Some("__wasm_init_async_task")
2218 }
2219 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2220 name.strip_prefix("[resource-drop]")
2221 }
2222 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2223 name.strip_prefix("[resource-new]")
2224 }
2225 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2226 name.strip_prefix("[resource-rep]")
2227 }
2228 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2229 name.strip_prefix("[task-return]")
2230 }
2231 fn task_cancel(&self, name: &str) -> bool {
2232 name == "[task-cancel]"
2233 }
2234 fn backpressure_inc(&self, name: &str) -> bool {
2235 name == "[backpressure-inc]"
2236 }
2237 fn backpressure_dec(&self, name: &str) -> bool {
2238 name == "[backpressure-dec]"
2239 }
2240 fn waitable_set_new(&self, name: &str) -> bool {
2241 name == "[waitable-set-new]"
2242 }
2243 fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2244 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2245 let mb_cancellable = MaybeCancellable {
2246 inner: (),
2247 cancellable,
2248 };
2249 let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-wait")?;
2250 Some((mb_cancellable, result_ty))
2251 }
2252 fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2253 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2254 let mb_cancellable = MaybeCancellable {
2255 inner: (),
2256 cancellable,
2257 };
2258 let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-poll")?;
2259 Some((mb_cancellable, result_ty))
2260 }
2261 fn waitable_set_drop(&self, name: &str) -> bool {
2262 name == "[waitable-set-drop]"
2263 }
2264 fn waitable_join(&self, name: &str) -> bool {
2265 name == "[waitable-join]"
2266 }
2267 fn subtask_drop(&self, name: &str) -> bool {
2268 name == "[subtask-drop]"
2269 }
2270 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2271 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2272 }
2273 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2274 name.strip_prefix("[callback][async-lift]")
2275 }
2276 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2277 name.strip_prefix("[async-lift]")
2278 }
2279 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2280 name.strip_prefix("[async-lift-stackful]")
2281 }
2282 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2283 match name {
2284 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2285 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2286 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2287 _ => None,
2288 }
2289 }
2290 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2291 match name {
2292 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2293 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2294 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2295 _ => None,
2296 }
2297 }
2298 fn error_context_drop(&self, name: &str) -> bool {
2299 name == "[error-context-drop]"
2300 }
2301 fn context_get(&self, name: &str) -> Option<(ValType, u32)> {
2302 parse_context_name(name, "[context-get-")
2303 }
2304 fn context_set(&self, name: &str) -> Option<(ValType, u32)> {
2305 parse_context_name(name, "[context-set-")
2306 }
2307 fn thread_index(&self, name: &str) -> bool {
2308 name == "[thread-index]"
2309 }
2310 fn thread_new_indirect(&self, name: &str) -> bool {
2311 name == "[thread-new-indirect-v0]"
2313 }
2314 fn thread_resume_later(&self, name: &str) -> bool {
2315 name == "[thread-resume-later]"
2316 }
2317 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2318 self.match_with_cancellable_prefix(name, "[thread-suspend]")
2319 }
2320 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2321 self.match_with_cancellable_prefix(name, "[thread-yield]")
2322 }
2323 fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2324 self.match_with_cancellable_prefix(name, "[thread-suspend-then-resume]")
2325 }
2326 fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2327 self.match_with_cancellable_prefix(name, "[thread-yield-then-resume]")
2328 }
2329 fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2330 self.match_with_cancellable_prefix(name, "[thread-suspend-then-promote]")
2331 }
2332 fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2333 self.match_with_cancellable_prefix(name, "[thread-yield-then-promote]")
2334 }
2335 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2336 self.prefixed_payload(lookup_context, name, "[future-new-")
2337 }
2338 fn future_write(
2339 &self,
2340 lookup_context: &PayloadLookupContext,
2341 name: &str,
2342 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2343 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2344 }
2345 fn future_read(
2346 &self,
2347 lookup_context: &PayloadLookupContext,
2348 name: &str,
2349 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2350 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2351 }
2352 fn future_cancel_write(
2353 &self,
2354 lookup_context: &PayloadLookupContext,
2355 name: &str,
2356 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2357 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2358 }
2359 fn future_cancel_read(
2360 &self,
2361 lookup_context: &PayloadLookupContext,
2362 name: &str,
2363 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2364 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2365 }
2366 fn future_drop_writable(
2367 &self,
2368 lookup_context: &PayloadLookupContext,
2369 name: &str,
2370 ) -> Option<PayloadInfo> {
2371 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2372 }
2373 fn future_drop_readable(
2374 &self,
2375 lookup_context: &PayloadLookupContext,
2376 name: &str,
2377 ) -> Option<PayloadInfo> {
2378 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2379 }
2380 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2381 self.prefixed_payload(lookup_context, name, "[stream-new-")
2382 }
2383 fn stream_write(
2384 &self,
2385 lookup_context: &PayloadLookupContext,
2386 name: &str,
2387 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2388 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2389 }
2390 fn stream_read(
2391 &self,
2392 lookup_context: &PayloadLookupContext,
2393 name: &str,
2394 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2395 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2396 }
2397 fn stream_cancel_write(
2398 &self,
2399 lookup_context: &PayloadLookupContext,
2400 name: &str,
2401 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2402 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2403 }
2404 fn stream_cancel_read(
2405 &self,
2406 lookup_context: &PayloadLookupContext,
2407 name: &str,
2408 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2409 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2410 }
2411 fn stream_drop_writable(
2412 &self,
2413 lookup_context: &PayloadLookupContext,
2414 name: &str,
2415 ) -> Option<PayloadInfo> {
2416 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2417 }
2418 fn stream_drop_readable(
2419 &self,
2420 lookup_context: &PayloadLookupContext,
2421 name: &str,
2422 ) -> Option<PayloadInfo> {
2423 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2424 }
2425 fn module_to_interface(
2426 &self,
2427 module: &str,
2428 resolve: &Resolve,
2429 items: &IndexMap<WorldKey, WorldItem>,
2430 ) -> Result<(WorldKey, InterfaceId)> {
2431 let bare_name = WorldKey::Name(module.to_string());
2433 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2434 return Ok((bare_name, *id));
2435 }
2436
2437 let kebab_name = ComponentName::new(module, 0);
2443 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2444 Ok(ComponentNameKind::Interface(name)) => name,
2445 _ => bail!("module requires an import interface named `{module}`"),
2446 };
2447
2448 let version = name.version(None)?;
2452
2453 let pkgname = PackageName {
2455 namespace: name.namespace().to_string(),
2456 name: name.package().to_string(),
2457 version: version.clone(),
2458 };
2459 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2460 if let Some(id) = resolve.packages[*pkg]
2461 .interfaces
2462 .get(name.interface().as_str())
2463 {
2464 let key = WorldKey::Interface(*id);
2467 if items.contains_key(&key) {
2468 return Ok((key, *id));
2469 }
2470
2471 for k in items.keys() {
2477 let i = match *k {
2478 WorldKey::Interface(id) => id,
2479 WorldKey::Name(_) => continue,
2480 };
2481 if resolve.interfaces[i].clone_of == Some(*id) {
2482 return Ok((WorldKey::Interface(i), i));
2483 }
2484 }
2485 }
2486 }
2487
2488 for (key, _) in items {
2493 let id = match key {
2494 WorldKey::Interface(id) => *id,
2495 WorldKey::Name(_) => continue,
2496 };
2497 let interface = &resolve.interfaces[id];
2499 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2500 continue;
2501 }
2502
2503 let pkg = &resolve.packages[interface.package.unwrap()];
2505 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2506 continue;
2507 }
2508
2509 let module_version = match &version {
2510 Some(version) => version,
2511 None => continue,
2512 };
2513 let pkg_version = match &pkg.name.version {
2514 Some(version) => version,
2515 None => continue,
2516 };
2517
2518 let module_compat = PackageName::version_compat_track(&module_version);
2520 let pkg_compat = PackageName::version_compat_track(pkg_version);
2521 if module_compat == pkg_compat {
2522 return Ok((key.clone(), id));
2523 }
2524 }
2525
2526 bail!("module requires an import interface named `{module}`")
2527 }
2528 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2529 name.strip_prefix("cabi_post_")
2530 }
2531 fn match_wit_export<'a>(
2532 &self,
2533 export_name: &str,
2534 resolve: &'a Resolve,
2535 world: WorldId,
2536 exports: &'a IndexSet<WorldKey>,
2537 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2538 let world = &resolve.worlds[world];
2539 for name in exports {
2540 match &world.exports[name] {
2541 WorldItem::Function(f) => {
2542 if f.legacy_core_export_name(None) == export_name {
2543 return Some((name, None, f));
2544 }
2545 }
2546 WorldItem::Interface { id, .. } => {
2547 let string = resolve.name_world_key(name);
2548 for (_, func) in resolve.interfaces[*id].functions.iter() {
2549 if func.legacy_core_export_name(Some(&string)) == export_name {
2550 return Some((name, Some(*id), func));
2551 }
2552 }
2553 }
2554
2555 WorldItem::Type { .. } => unreachable!(),
2556 }
2557 }
2558
2559 None
2560 }
2561
2562 fn match_wit_resource_dtor<'a>(
2563 &self,
2564 export_name: &str,
2565 resolve: &'a Resolve,
2566 world: WorldId,
2567 exports: &'a IndexSet<WorldKey>,
2568 ) -> Option<TypeId> {
2569 let world = &resolve.worlds[world];
2570 for name in exports {
2571 let id = match &world.exports[name] {
2572 WorldItem::Interface { id, .. } => *id,
2573 WorldItem::Function(_) => continue,
2574 WorldItem::Type { .. } => unreachable!(),
2575 };
2576 let name = resolve.name_world_key(name);
2577 let resource = match export_name
2578 .strip_prefix(&name)
2579 .and_then(|s| s.strip_prefix("#[dtor]"))
2580 .and_then(|r| resolve.interfaces[id].types.get(r))
2581 {
2582 Some(id) => *id,
2583 None => continue,
2584 };
2585
2586 match resolve.types[resource].kind {
2587 TypeDefKind::Resource => {}
2588 _ => continue,
2589 }
2590
2591 return Some(resource);
2592 }
2593
2594 None
2595 }
2596
2597 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2598 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2599 (
2600 name,
2601 if async_abi {
2602 AbiVariant::GuestImportAsync
2603 } else {
2604 AbiVariant::GuestImport
2605 },
2606 )
2607 }
2608 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2609 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2610 (
2611 name,
2612 if async_abi {
2613 AbiVariant::GuestImportAsync
2614 } else {
2615 AbiVariant::GuestImport
2616 },
2617 )
2618 }
2619 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import> {
2620 match name {
2621 "__wasm_get_stack_pointer" => {
2622 let ty = *ty.results().get(0)?;
2623 Some(Import::ContextGet { ty, slot: 0 })
2624 }
2625 "__wasm_set_stack_pointer" => {
2626 let ty = *ty.params().get(0)?;
2627 Some(Import::ContextSet { ty, slot: 0 })
2628 }
2629 "__wasm_get_tls_base" => {
2633 let ty = *ty.results().get(0)?;
2634 Some(Import::TlsBaseGet { ty })
2635 }
2636 "__wasm_set_tls_base" => {
2637 let ty = *ty.params().get(0)?;
2638 Some(Import::TlsBaseSet { ty })
2639 }
2640 _ => None,
2641 }
2642 }
2643}
2644
2645pub fn validate_module(
2657 encoder: &ComponentEncoder,
2658 bytes: &[u8],
2659 import_map: Option<&ModuleImportMap>,
2660) -> Result<ValidatedModule> {
2661 ValidatedModule::new(
2662 encoder,
2663 bytes,
2664 &encoder.main_module_exports,
2665 import_map,
2666 None,
2667 )
2668}
2669
2670pub fn validate_adapter_module(
2688 encoder: &ComponentEncoder,
2689 bytes: &[u8],
2690 required_by_import: &IndexMap<String, FuncType>,
2691 exports: &IndexSet<WorldKey>,
2692 library_info: Option<&LibraryInfo>,
2693) -> Result<ValidatedModule> {
2694 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2695
2696 for (name, required_ty) in required_by_import {
2697 let actual = match ret.exports.raw_exports.get(name) {
2698 Some(ty) => ty,
2699 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2700 };
2701 validate_func_sig(name, required_ty, &actual)?;
2702 }
2703
2704 Ok(ret)
2705}
2706
2707#[derive(Debug, Clone)]
2714pub struct AdapterModuleDidNotExport(String);
2715
2716impl fmt::Display for AdapterModuleDidNotExport {
2717 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2718 write!(f, "adapter module did not export `{}`", self.0)
2719 }
2720}
2721
2722impl std::error::Error for AdapterModuleDidNotExport {}
2723
2724fn resource_test_for_interface<'a>(
2725 resolve: &'a Resolve,
2726 id: InterfaceId,
2727) -> impl Fn(&str) -> Option<TypeId> + 'a {
2728 let interface = &resolve.interfaces[id];
2729 move |name: &str| {
2730 let ty = match interface.types.get(name) {
2731 Some(ty) => *ty,
2732 None => return None,
2733 };
2734 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2735 Some(ty)
2736 } else {
2737 None
2738 }
2739 }
2740}
2741
2742fn resource_test_for_world<'a>(
2743 resolve: &'a Resolve,
2744 id: WorldId,
2745) -> impl Fn(&str) -> Option<TypeId> + 'a {
2746 let world = &resolve.worlds[id];
2747 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2748 WorldItem::Type { id, .. } => {
2749 if matches!(resolve.types[*id].kind, TypeDefKind::Resource) {
2750 Some(*id)
2751 } else {
2752 None
2753 }
2754 }
2755 _ => None,
2756 }
2757}
2758
2759fn validate_func(
2760 resolve: &Resolve,
2761 ty: &wasmparser::FuncType,
2762 func: &Function,
2763 abi: AbiVariant,
2764) -> Result<()> {
2765 validate_func_sig(
2766 &func.name,
2767 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2768 ty,
2769 )
2770}
2771
2772fn validate_post_return(
2773 resolve: &Resolve,
2774 ty: &wasmparser::FuncType,
2775 func: &Function,
2776) -> Result<()> {
2777 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2783 sig.params = mem::take(&mut sig.results);
2784 validate_func_sig(
2785 &format!("{} post-return", func.name),
2786 &wasm_sig_to_func_type(sig),
2787 ty,
2788 )
2789}
2790
2791fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2792 if ty != expected {
2793 bail!(
2794 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2795 name,
2796 expected.params(),
2797 expected.results(),
2798 ty.params(),
2799 ty.results()
2800 );
2801 }
2802
2803 Ok(())
2804}
2805
2806fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2808 assert!(prefix.starts_with("["));
2809 assert!(prefix.ends_with("-"));
2810 let suffix = name.strip_prefix(prefix)?;
2811 let index = suffix.find(']')?;
2812 let rest = &suffix[index + 1..];
2813 Some((&suffix[..index], rest))
2814}
2815
2816fn parse_context_name(name: &str, prefix: &str) -> Option<(ValType, u32)> {
2822 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2823 if !rest.is_empty() {
2824 return None;
2825 }
2826 let (ty, slot) = match suffix.split_once('-') {
2827 Some(("i64", slot)) => (ValType::I64, slot),
2828 Some(("i32", slot)) => (ValType::I32, slot),
2829 _ => (ValType::I32, suffix),
2830 };
2831 let slot = slot.parse().ok()?;
2832 Some((ty, slot))
2833}
2834
2835fn get_function<'a>(
2836 resolve: &'a Resolve,
2837 world: &'a World,
2838 name: &str,
2839 interface: Option<InterfaceId>,
2840 imported: bool,
2841) -> Result<&'a Function> {
2842 let function = if let Some(id) = interface {
2843 return resolve.interfaces[id]
2844 .functions
2845 .get(name)
2846 .ok_or_else(|| anyhow!("no export `{name}` found"));
2847 } else if imported {
2848 world.imports.get(&WorldKey::Name(name.to_string()))
2849 } else {
2850 world.exports.get(&WorldKey::Name(name.to_string()))
2851 };
2852 let Some(WorldItem::Function(function)) = function else {
2853 bail!("no export `{name}` found");
2854 };
2855 Ok(function)
2856}