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 BackpressureInc,
295
296 BackpressureDec,
298
299 WaitableSetNew,
301
302 WaitableSetWait { cancellable: bool },
308
309 WaitableSetPoll { cancellable: bool },
315
316 WaitableSetDrop,
318
319 WaitableJoin,
321
322 SubtaskDrop,
326
327 SubtaskCancel { async_: bool },
331
332 StreamNew(PayloadInfo),
336
337 StreamRead { async_: bool, info: PayloadInfo },
342
343 StreamWrite { async_: bool, info: PayloadInfo },
348
349 StreamCancelRead { info: PayloadInfo, async_: bool },
354
355 StreamCancelWrite { info: PayloadInfo, async_: bool },
360
361 StreamDropReadable(PayloadInfo),
365
366 StreamDropWritable(PayloadInfo),
370
371 FutureNew(PayloadInfo),
375
376 FutureRead { async_: bool, info: PayloadInfo },
381
382 FutureWrite { async_: bool, info: PayloadInfo },
386
387 FutureCancelRead { info: PayloadInfo, async_: bool },
392
393 FutureCancelWrite { info: PayloadInfo, async_: bool },
398
399 FutureDropReadable(PayloadInfo),
403
404 FutureDropWritable(PayloadInfo),
408
409 ErrorContextNew { encoding: StringEncoding },
414
415 ErrorContextDebugMessage { encoding: StringEncoding },
421
422 ErrorContextDrop,
427
428 ThreadIndex,
432
433 ThreadNewIndirect,
437
438 ThreadResumeLater,
440
441 ThreadSuspend { cancellable: bool },
443
444 ThreadYield { cancellable: bool },
446
447 ThreadSuspendThenResume { cancellable: bool },
449
450 ThreadYieldThenResume { cancellable: bool },
452
453 ThreadSuspendThenPromote { cancellable: bool },
455
456 ThreadYieldThenPromote { cancellable: bool },
458}
459
460impl ImportMap {
461 pub fn required_from_adapter(&self, name: &str) -> IndexMap<String, FuncType> {
463 let names = match self.names.get(name) {
464 Some(ImportInstance::Names(names)) => names,
465 _ => return IndexMap::new(),
466 };
467 names
468 .iter()
469 .map(|(_, import)| match import {
470 Import::AdapterExport { ty, func, adapter } => {
471 assert_eq!(adapter, name);
472 (func.clone(), ty.clone())
473 }
474 _ => unreachable!(),
475 })
476 .collect()
477 }
478
479 pub fn imports(&self) -> impl Iterator<Item = (&str, &str, &Import)> + '_ {
483 self.names
484 .iter()
485 .filter_map(|(module, m)| match m {
486 ImportInstance::Names(names) => Some((module, names)),
487 ImportInstance::Whole(_) => None,
488 })
489 .flat_map(|(module, m)| {
490 m.iter()
491 .map(move |(field, import)| (module.as_str(), field.as_str(), import))
492 })
493 }
494
495 pub fn modules(&self) -> &IndexMap<String, ImportInstance> {
497 &self.names
498 }
499
500 fn add(
503 &mut self,
504 import: wasmparser::Import<'_>,
505 encoder: &ComponentEncoder,
506 import_map: Option<&ModuleImportMap>,
507 library_info: Option<&LibraryInfo>,
508 types: TypesRef<'_>,
509 ) -> Result<()> {
510 if self.classify_import_with_library(import, library_info)? {
511 return Ok(());
512 }
513 let mut import_to_classify = import;
514 if let Some(map) = import_map {
515 if let Some(original_name) = map.original_name(&import) {
516 import_to_classify.name = original_name;
517 }
518 }
519 let item = self
520 .classify(import_to_classify, encoder, types)
521 .with_context(|| {
522 format!(
523 "failed to resolve import `{}::{}`",
524 import.module, import.name,
525 )
526 })?;
527 self.insert_import(import, item)
528 }
529
530 fn classify(
536 &self,
537 import: wasmparser::Import<'_>,
538 encoder: &ComponentEncoder,
539 types: TypesRef<'_>,
540 ) -> Result<Import> {
541 if import.module == "env" && import.name == "memory" {
544 return Ok(Import::MainModuleMemory);
545 }
546
547 if import.module == "__main_module__" {
549 return Ok(Import::MainModuleExport {
550 name: import.name.to_string(),
551 kind: match import.ty {
552 TypeRef::Func(_) => ExportKind::Func,
553 TypeRef::Table(_) => ExportKind::Table,
554 TypeRef::Memory(_) => ExportKind::Memory,
555 TypeRef::Global(_) => ExportKind::Global,
556 TypeRef::Tag(_) => ExportKind::Tag,
557 TypeRef::FuncExact(_) => bail!("Unexpected func_exact export"),
558 },
559 });
560 }
561
562 let ty_index = match import.ty {
563 TypeRef::Func(ty) => ty,
564 _ => bail!("module is only allowed to import functions"),
565 };
566 let ty = types[types.core_type_at_in_module(ty_index)].unwrap_func();
567
568 if encoder.adapters.contains_key(import.module) {
571 return Ok(Import::AdapterExport {
572 adapter: import.module.to_string(),
573 func: import.name.to_string(),
574 ty: ty.clone(),
575 });
576 }
577
578 let (module, names) = match import.module.strip_prefix("cm32p2") {
579 Some(suffix) => (suffix, STANDARD),
580 None if encoder.reject_legacy_names => (import.module, STANDARD),
581 None => (import.module, LEGACY),
582 };
583 self.classify_component_model_import(module, import.name, encoder, ty, names)
584 }
585
586 fn classify_component_model_import(
589 &self,
590 module: &str,
591 name: &str,
592 encoder: &ComponentEncoder,
593 ty: &FuncType,
594 names: &dyn NameMangling,
595 ) -> Result<Import> {
596 let resolve = &encoder.metadata.resolve;
597 let world_id = encoder.metadata.world;
598 let world = &resolve.worlds[world_id];
599
600 if module == names.import_root() {
601 if names.error_context_drop(name) {
602 let expected = FuncType::new([ValType::I32], []);
603 validate_func_sig(name, &expected, ty)?;
604 return Ok(Import::ErrorContextDrop);
605 }
606
607 if names.backpressure_inc(name) {
608 let expected = FuncType::new([], []);
609 validate_func_sig(name, &expected, ty)?;
610 return Ok(Import::BackpressureInc);
611 }
612
613 if names.backpressure_dec(name) {
614 let expected = FuncType::new([], []);
615 validate_func_sig(name, &expected, ty)?;
616 return Ok(Import::BackpressureDec);
617 }
618
619 if names.waitable_set_new(name) {
620 let expected = FuncType::new([], [ValType::I32]);
621 validate_func_sig(name, &expected, ty)?;
622 return Ok(Import::WaitableSetNew);
623 }
624
625 if let Some((info, result_ty)) = names.waitable_set_wait(name) {
626 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
627 validate_func_sig(name, &expected, ty)?;
628 return Ok(Import::WaitableSetWait {
629 cancellable: info.cancellable,
630 });
631 }
632
633 if let Some((info, result_ty)) = names.waitable_set_poll(name) {
634 let expected = FuncType::new([ValType::I32, result_ty], [ValType::I32]);
635 validate_func_sig(name, &expected, ty)?;
636 return Ok(Import::WaitableSetPoll {
637 cancellable: info.cancellable,
638 });
639 }
640
641 if names.waitable_set_drop(name) {
642 let expected = FuncType::new([ValType::I32], []);
643 validate_func_sig(name, &expected, ty)?;
644 return Ok(Import::WaitableSetDrop);
645 }
646
647 if names.waitable_join(name) {
648 let expected = FuncType::new([ValType::I32; 2], []);
649 validate_func_sig(name, &expected, ty)?;
650 return Ok(Import::WaitableJoin);
651 }
652
653 if names.subtask_drop(name) {
654 let expected = FuncType::new([ValType::I32], []);
655 validate_func_sig(name, &expected, ty)?;
656 return Ok(Import::SubtaskDrop);
657 }
658
659 if let Some(info) = names.subtask_cancel(name) {
660 let expected = FuncType::new([ValType::I32], [ValType::I32]);
661 validate_func_sig(name, &expected, ty)?;
662 return Ok(Import::SubtaskCancel {
663 async_: info.async_lowered,
664 });
665 }
666
667 if let Some(encoding) = names.error_context_new(name) {
668 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
669 validate_func_sig(name, &expected, ty)?;
670 return Ok(Import::ErrorContextNew { encoding });
671 }
672
673 if let Some(encoding) = names.error_context_debug_message(name) {
674 let expected = FuncType::new([ValType::I32; 2], []);
675 validate_func_sig(name, &expected, ty)?;
676 return Ok(Import::ErrorContextDebugMessage { encoding });
677 }
678
679 if let Some((slot_ty, slot)) = names.context_get(name) {
680 let expected = FuncType::new([], [slot_ty]);
681 validate_func_sig(name, &expected, ty)?;
682 return Ok(Import::ContextGet { ty: slot_ty, slot });
683 }
684 if let Some((slot_ty, slot)) = names.context_set(name) {
685 let expected = FuncType::new([slot_ty], []);
686 validate_func_sig(name, &expected, ty)?;
687 return Ok(Import::ContextSet { ty: slot_ty, slot });
688 }
689 if names.thread_index(name) {
690 let expected = FuncType::new([], [ValType::I32]);
691 validate_func_sig(name, &expected, ty)?;
692 return Ok(Import::ThreadIndex);
693 }
694 if names.thread_new_indirect(name) {
695 let expected = FuncType::new([ValType::I32; 2], [ValType::I32]);
696 validate_func_sig(name, &expected, ty)?;
697 return Ok(Import::ThreadNewIndirect);
698 }
699 if names.thread_resume_later(name) {
700 let expected = FuncType::new([ValType::I32], []);
701 validate_func_sig(name, &expected, ty)?;
702 return Ok(Import::ThreadResumeLater);
703 }
704 if let Some(info) = names.thread_suspend(name) {
705 let expected = FuncType::new([], [ValType::I32]);
706 validate_func_sig(name, &expected, ty)?;
707 return Ok(Import::ThreadSuspend {
708 cancellable: info.cancellable,
709 });
710 }
711 if let Some(info) = names.thread_yield(name) {
712 let expected = FuncType::new([], [ValType::I32]);
713 validate_func_sig(name, &expected, ty)?;
714 return Ok(Import::ThreadYield {
715 cancellable: info.cancellable,
716 });
717 }
718 if let Some(info) = names.thread_suspend_then_resume(name) {
719 let expected = FuncType::new([ValType::I32], [ValType::I32]);
720 validate_func_sig(name, &expected, ty)?;
721 return Ok(Import::ThreadSuspendThenResume {
722 cancellable: info.cancellable,
723 });
724 }
725 if let Some(info) = names.thread_yield_then_resume(name) {
726 let expected = FuncType::new([ValType::I32], [ValType::I32]);
727 validate_func_sig(name, &expected, ty)?;
728 return Ok(Import::ThreadYieldThenResume {
729 cancellable: info.cancellable,
730 });
731 }
732 if let Some(info) = names.thread_suspend_then_promote(name) {
733 let expected = FuncType::new([ValType::I32], [ValType::I32]);
734 validate_func_sig(name, &expected, ty)?;
735 return Ok(Import::ThreadSuspendThenPromote {
736 cancellable: info.cancellable,
737 });
738 }
739 if let Some(info) = names.thread_yield_then_promote(name) {
740 let expected = FuncType::new([ValType::I32], [ValType::I32]);
741 validate_func_sig(name, &expected, ty)?;
742 return Ok(Import::ThreadYieldThenPromote {
743 cancellable: info.cancellable,
744 });
745 }
746
747 let (key_name, abi) = names.world_key_name_and_abi(name);
748 let key = WorldKey::Name(key_name.to_string());
749 if let Some(WorldItem::Function(func)) = world.imports.get(&key) {
750 validate_func(resolve, ty, func, abi)?;
751 return Ok(Import::WorldFunc(key, func.name.clone(), abi));
752 }
753
754 if let Some(import) =
755 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, true, names)?
756 {
757 return Ok(import);
758 }
759
760 match world.imports.get(&key) {
761 Some(_) => bail!("expected world top-level import `{name}` to be a function"),
762 None => bail!("no top-level imported function `{name}` specified"),
763 }
764 }
765
766 if matches!(
768 module.strip_prefix(names.import_exported_intrinsic_prefix()),
769 Some(module) if module == names.import_root()
770 ) {
771 if let Some(import) =
772 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
773 {
774 return Ok(import);
775 }
776 }
777
778 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
779 Some(name) => name,
780 None => bail!("unknown or invalid component model import syntax"),
781 };
782
783 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
784 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
785
786 if let Some(import) =
787 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
788 {
789 return Ok(import);
790 }
791 bail!("unknown function `{name}`")
792 }
793
794 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
795 let interface = &resolve.interfaces[id];
796 let (function_name, abi) = names.interface_function_name_and_abi(name);
797 if let Some(f) = interface.functions.get(function_name) {
798 validate_func(resolve, ty, f, abi).with_context(|| {
799 let name = resolve.name_world_key(&key);
800 format!("failed to validate import interface `{name}`")
801 })?;
802 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
803 }
804
805 if let Some(import) =
806 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
807 {
808 return Ok(import);
809 }
810 bail!(
811 "import interface `{module}` is missing function \
812 `{name}` that is required by the module",
813 )
814 }
815
816 fn maybe_classify_wit_intrinsic(
844 &self,
845 name: &str,
846 key_and_id: Option<(WorldKey, InterfaceId)>,
847 encoder: &ComponentEncoder,
848 ty: &FuncType,
849 import: bool,
850 names: &dyn NameMangling,
851 ) -> Result<Option<Import>> {
852 let resolve = &encoder.metadata.resolve;
853 let world_id = encoder.metadata.world;
854 let world = &resolve.worlds[world_id];
855
856 let (key, id) = match key_and_id {
861 Some((key, id)) => (Some(key), Some(id)),
862 None => (None, None),
863 };
864
865 let resource_test = |name: &str| match id {
867 Some(id) => resource_test_for_interface(resolve, id)(name),
868 None => resource_test_for_world(resolve, world_id)(name),
869 };
870
871 if let Some(resource) = names.resource_drop_name(name) {
873 if let Some(resource_id) = resource_test(resource) {
874 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
875 let expected = FuncType::new([ValType::I32], []);
876 validate_func_sig(name, &expected, ty)?;
877 return Ok(Some(if import {
878 Import::ImportedResourceDrop(key, id, resource_id)
879 } else {
880 Import::ExportedResourceDrop(key, resource_id)
881 }));
882 }
883 }
884
885 if !import {
888 if let Some(name) = names.resource_new_name(name) {
889 if let Some(id) = resource_test(name) {
890 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
891 let expected = FuncType::new([ValType::I32], [ValType::I32]);
892 validate_func_sig(name, &expected, ty)?;
893 return Ok(Some(Import::ExportedResourceNew(key, id)));
894 }
895 }
896 if let Some(name) = names.resource_rep_name(name) {
897 if let Some(id) = resource_test(name) {
898 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
899 let expected = FuncType::new([ValType::I32], [ValType::I32]);
900 validate_func_sig(name, &expected, ty)?;
901 return Ok(Some(Import::ExportedResourceRep(key, id)));
902 }
903 }
904 if let Some(name) = names.task_return_name(name) {
905 let func = get_function(resolve, world, name, id, import)?;
906 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
907 return Ok(Some(Import::ExportedTaskReturn(key, id, func.clone())));
910 }
911 if names.task_cancel(name) {
912 let expected = FuncType::new([], []);
913 validate_func_sig(name, &expected, ty)?;
914 return Ok(Some(Import::ExportedTaskCancel));
915 }
916 }
917
918 let lookup_context = PayloadLookupContext {
919 resolve,
920 world,
921 key,
922 id,
923 import,
924 };
925
926 let import = if let Some(info) = names.future_new(&lookup_context, name) {
930 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
931 Import::FutureNew(info)
932 } else if let Some(info) = names.future_write(&lookup_context, name) {
933 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
934 Import::FutureWrite {
935 async_: info.async_lowered,
936 info: info.inner,
937 }
938 } else if let Some(info) = names.future_read(&lookup_context, name) {
939 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
940 Import::FutureRead {
941 async_: info.async_lowered,
942 info: info.inner,
943 }
944 } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
945 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
946 Import::FutureCancelWrite {
947 async_: info.async_lowered,
948 info: info.inner,
949 }
950 } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
951 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
952 Import::FutureCancelRead {
953 async_: info.async_lowered,
954 info: info.inner,
955 }
956 } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
957 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
958 Import::FutureDropWritable(info)
959 } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
960 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
961 Import::FutureDropReadable(info)
962 } else if let Some(info) = names.stream_new(&lookup_context, name) {
963 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
964 Import::StreamNew(info)
965 } else if let Some(info) = names.stream_write(&lookup_context, name) {
966 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
967 Import::StreamWrite {
968 async_: info.async_lowered,
969 info: info.inner,
970 }
971 } else if let Some(info) = names.stream_read(&lookup_context, name) {
972 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
973 Import::StreamRead {
974 async_: info.async_lowered,
975 info: info.inner,
976 }
977 } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
978 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
979 Import::StreamCancelWrite {
980 async_: info.async_lowered,
981 info: info.inner,
982 }
983 } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
984 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
985 Import::StreamCancelRead {
986 async_: info.async_lowered,
987 info: info.inner,
988 }
989 } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
990 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
991 Import::StreamDropWritable(info)
992 } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
993 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
994 Import::StreamDropReadable(info)
995 } else {
996 return Ok(None);
997 };
998 Ok(Some(import))
999 }
1000
1001 fn classify_import_with_library(
1002 &mut self,
1003 import: wasmparser::Import<'_>,
1004 library_info: Option<&LibraryInfo>,
1005 ) -> Result<bool> {
1006 let info = match library_info {
1007 Some(info) => info,
1008 None => return Ok(false),
1009 };
1010 let Some((_, instance)) = info
1011 .arguments
1012 .iter()
1013 .find(|(name, _items)| *name == import.module)
1014 else {
1015 return Ok(false);
1016 };
1017 match instance {
1018 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1019 Some(ImportInstance::Whole(which)) => {
1020 if which != module {
1021 bail!("different whole modules imported under the same name");
1022 }
1023 }
1024 Some(ImportInstance::Names(_)) => {
1025 bail!("cannot mix individual imports and whole module imports")
1026 }
1027 None => {
1028 let instance = ImportInstance::Whole(module.clone());
1029 self.names.insert(import.module.to_string(), instance);
1030 }
1031 },
1032 Instance::Items(items) => {
1033 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1034 return Ok(false);
1035 };
1036 self.insert_import(import, Import::Item(item.clone()))?;
1037 }
1038 }
1039 Ok(true)
1040 }
1041
1042 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1046 let entry = self
1047 .names
1048 .entry(import.module.to_string())
1049 .or_insert(ImportInstance::Names(IndexMap::default()));
1050 let names = match entry {
1051 ImportInstance::Names(names) => names,
1052 _ => bail!("cannot mix individual imports with module imports"),
1053 };
1054 let entry = match names.entry(import.name.to_string()) {
1055 Entry::Occupied(_) => {
1056 bail!(
1057 "module has duplicate import for `{}::{}`",
1058 import.module,
1059 import.name
1060 );
1061 }
1062 Entry::Vacant(v) => v,
1063 };
1064 log::trace!(
1065 "classifying import `{}::{} as {item:?}",
1066 import.module,
1067 import.name
1068 );
1069 entry.insert(item);
1070 Ok(())
1071 }
1072}
1073
1074#[derive(Default)]
1077pub struct ExportMap {
1078 names: IndexMap<String, Export>,
1079 raw_exports: IndexMap<String, FuncType>,
1080}
1081
1082#[derive(Debug)]
1085pub enum Export {
1086 WorldFunc(WorldKey, String, AbiVariant),
1089
1090 WorldFuncPostReturn(WorldKey),
1092
1093 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1095
1096 InterfaceFuncPostReturn(WorldKey, String),
1098
1099 ResourceDtor(TypeId),
1101
1102 Memory,
1104
1105 GeneralPurposeRealloc,
1107
1108 GeneralPurposeExportRealloc,
1110
1111 GeneralPurposeImportRealloc,
1113
1114 Initialize,
1116
1117 ReallocForAdapter,
1119
1120 WorldFuncCallback(WorldKey),
1121
1122 InterfaceFuncCallback(WorldKey, String),
1123
1124 IndirectFunctionTable,
1126
1127 WasmInitTask,
1129
1130 WasmInitAsyncTask,
1132}
1133
1134impl ExportMap {
1135 fn add(
1136 &mut self,
1137 export: wasmparser::Export<'_>,
1138 encoder: &ComponentEncoder,
1139 exports: &IndexSet<WorldKey>,
1140 types: TypesRef<'_>,
1141 ) -> Result<()> {
1142 if let Some(item) = self.classify(export, encoder, exports, types)? {
1143 log::debug!("classifying export `{}` as {item:?}", export.name);
1144 let prev = self.names.insert(export.name.to_string(), item);
1145 assert!(prev.is_none());
1146 }
1147 Ok(())
1148 }
1149
1150 fn classify(
1151 &mut self,
1152 export: wasmparser::Export<'_>,
1153 encoder: &ComponentEncoder,
1154 exports: &IndexSet<WorldKey>,
1155 types: TypesRef<'_>,
1156 ) -> Result<Option<Export>> {
1157 match export.kind {
1158 ExternalKind::Func => {
1159 let ty = types[types.core_function_at(export.index)].unwrap_func();
1160 self.raw_exports.insert(export.name.to_string(), ty.clone());
1161 }
1162 _ => {}
1163 }
1164
1165 if export.name == "canonical_abi_realloc" {
1167 return Ok(Some(Export::GeneralPurposeRealloc));
1168 } else if export.name == "cabi_import_realloc" {
1169 return Ok(Some(Export::GeneralPurposeImportRealloc));
1170 } else if export.name == "cabi_export_realloc" {
1171 return Ok(Some(Export::GeneralPurposeExportRealloc));
1172 } else if export.name == "cabi_realloc_adapter" {
1173 return Ok(Some(Export::ReallocForAdapter));
1174 }
1175
1176 let (name, names) = match export.name.strip_prefix("cm32p2") {
1177 Some(name) => (name, STANDARD),
1178 None if encoder.reject_legacy_names => return Ok(None),
1179 None => (export.name, LEGACY),
1180 };
1181
1182 if let Some(export) = self
1183 .classify_component_export(names, name, &export, encoder, exports, types)
1184 .with_context(|| format!("failed to classify export `{}`", export.name))?
1185 {
1186 return Ok(Some(export));
1187 }
1188 log::debug!("unknown export `{}`", export.name);
1189 Ok(None)
1190 }
1191
1192 fn classify_component_export(
1193 &mut self,
1194 names: &dyn NameMangling,
1195 name: &str,
1196 export: &wasmparser::Export<'_>,
1197 encoder: &ComponentEncoder,
1198 exports: &IndexSet<WorldKey>,
1199 types: TypesRef<'_>,
1200 ) -> Result<Option<Export>> {
1201 let resolve = &encoder.metadata.resolve;
1202 let world = encoder.metadata.world;
1203 match export.kind {
1204 ExternalKind::Func => {}
1205 ExternalKind::Memory => {
1206 if name == names.export_memory() {
1207 return Ok(Some(Export::Memory));
1208 }
1209 return Ok(None);
1210 }
1211 ExternalKind::Table => {
1212 if Some(name) == names.export_indirect_function_table() {
1213 return Ok(Some(Export::IndirectFunctionTable));
1214 }
1215 return Ok(None);
1216 }
1217 _ => return Ok(None),
1218 }
1219 let ty = types[types.core_function_at(export.index)].unwrap_func();
1220
1221 if name == names.export_realloc() {
1223 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1224 validate_func_sig(name, &expected, ty)?;
1225 return Ok(Some(Export::GeneralPurposeRealloc));
1226 } else if name == names.export_initialize() {
1227 let expected = FuncType::new([], []);
1228 validate_func_sig(name, &expected, ty)?;
1229 return Ok(Some(Export::Initialize));
1230 } else if Some(name) == names.export_wasm_init_task() {
1231 let expected = FuncType::new([], []);
1232 validate_func_sig(name, &expected, ty)?;
1233 return Ok(Some(Export::WasmInitTask));
1234 } else if Some(name) == names.export_wasm_init_async_task() {
1235 let expected = FuncType::new([], []);
1236 validate_func_sig(name, &expected, ty)?;
1237 return Ok(Some(Export::WasmInitAsyncTask));
1238 }
1239
1240 let full_name = name;
1241 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1242 (AbiVariant::GuestExportAsync, name)
1243 } else if let Some(name) = names.async_lift_stackful_name(name) {
1244 (AbiVariant::GuestExportAsyncStackful, name)
1245 } else {
1246 (AbiVariant::GuestExport, name)
1247 };
1248
1249 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1251 validate_func(resolve, ty, f, abi).with_context(|| {
1252 let key = resolve.name_world_key(key);
1253 format!("failed to validate export for `{key}`")
1254 })?;
1255 match id {
1256 Some(id) => {
1257 return Ok(Some(Export::InterfaceFunc(
1258 key.clone(),
1259 id,
1260 f.name.clone(),
1261 abi,
1262 )));
1263 }
1264 None => {
1265 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1266 }
1267 }
1268 }
1269
1270 if let Some(remaining) = names.strip_post_return(name) {
1272 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1273 validate_post_return(resolve, ty, f).with_context(|| {
1274 let key = resolve.name_world_key(key);
1275 format!("failed to validate export for `{key}`")
1276 })?;
1277 match id {
1278 Some(_id) => {
1279 return Ok(Some(Export::InterfaceFuncPostReturn(
1280 key.clone(),
1281 f.name.clone(),
1282 )));
1283 }
1284 None => {
1285 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1286 }
1287 }
1288 }
1289 }
1290
1291 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1292 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1293 validate_func_sig(
1294 full_name,
1295 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1296 ty,
1297 )?;
1298 return Ok(Some(if id.is_some() {
1299 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1300 } else {
1301 Export::WorldFuncCallback(key.clone())
1302 }));
1303 }
1304 }
1305
1306 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1308 let expected = FuncType::new([ValType::I32], []);
1309 validate_func_sig(full_name, &expected, ty)?;
1310 return Ok(Some(Export::ResourceDtor(dtor)));
1311 }
1312
1313 Ok(None)
1314 }
1315
1316 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1319 self.find(|m| match m {
1320 Export::WorldFuncPostReturn(k) => k == key,
1321 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1322 _ => false,
1323 })
1324 }
1325
1326 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1329 self.find(|m| match m {
1330 Export::WorldFuncCallback(k) => k == key,
1331 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1332 _ => false,
1333 })
1334 }
1335
1336 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1337 self.names.values().find_map(|m| match m {
1338 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1339 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1340 _ => None,
1341 })
1342 }
1343
1344 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1347 let _ = (key, func);
1351
1352 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1353 return Some(name);
1354 }
1355 self.general_purpose_realloc()
1356 }
1357
1358 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1361 let _ = (interface, func);
1365
1366 self.import_realloc_fallback()
1367 }
1368
1369 pub fn import_realloc_fallback(&self) -> Option<&str> {
1373 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1374 return Some(name);
1375 }
1376 self.general_purpose_realloc()
1377 }
1378
1379 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1381 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1382 return Some(name);
1383 }
1384 self.general_purpose_realloc()
1385 }
1386
1387 fn general_purpose_realloc(&self) -> Option<&str> {
1388 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1389 }
1390
1391 pub fn memory(&self) -> Option<&str> {
1393 self.find(|m| matches!(m, Export::Memory))
1394 }
1395
1396 pub fn indirect_function_table(&self) -> Option<&str> {
1398 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1399 }
1400
1401 pub fn wasm_init_task(&self) -> Option<&str> {
1403 self.find(|t| matches!(t, Export::WasmInitTask))
1404 }
1405
1406 pub fn wasm_init_async_task(&self) -> Option<&str> {
1408 self.find(|t| matches!(t, Export::WasmInitAsyncTask))
1409 }
1410
1411 pub fn initialize(&self) -> Option<&str> {
1413 self.find(|m| matches!(m, Export::Initialize))
1414 }
1415
1416 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1418 self.find(|m| match m {
1419 Export::ResourceDtor(t) => *t == ty,
1420 _ => false,
1421 })
1422 }
1423
1424 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1427 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1428 Some(name)
1429 }
1430
1431 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1433 self.names.iter().map(|(n, e)| (n.as_str(), e))
1434 }
1435
1436 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1437 let resolve = &encoder.metadata.resolve;
1438 let world = encoder.metadata.world;
1439 if self
1442 .names
1443 .values()
1444 .filter(|m| matches!(m, Export::Memory))
1445 .count()
1446 > 1
1447 {
1448 bail!("cannot componentize module that exports multiple memories")
1449 }
1450
1451 for (name, export) in &self.names {
1453 match export {
1454 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1455 if !matches!(
1456 self.names.get(&format!("[callback]{name}")),
1457 Some(Export::WorldFuncCallback(_))
1458 ) {
1459 bail!("missing callback for `{name}`");
1460 }
1461 }
1462 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1463 if !matches!(
1464 self.names.get(&format!("[callback]{name}")),
1465 Some(Export::InterfaceFuncCallback(_, _))
1466 ) {
1467 bail!("missing callback for `{name}`");
1468 }
1469 }
1470 _ => {}
1471 }
1472 }
1473
1474 for export in exports {
1476 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1477 let result = self.find(|e| match e {
1478 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1479 _ => false,
1480 });
1481 if result.is_some() {
1482 Ok(())
1483 } else {
1484 let export = resolve.name_world_key(export);
1485 bail!("failed to find export of interface `{export}` function `{name}`")
1486 }
1487 };
1488 let require_world_func = |name: &str| -> Result<()> {
1489 let result = self.find(|e| match e {
1490 Export::WorldFunc(_, s, _) => name == s,
1491 _ => false,
1492 });
1493 if result.is_some() {
1494 Ok(())
1495 } else {
1496 bail!("failed to find export of function `{name}`")
1497 }
1498 };
1499 match &resolve.worlds[world].exports[export] {
1500 WorldItem::Interface { id, .. } => {
1501 for (name, _) in resolve.interfaces[*id].functions.iter() {
1502 require_interface_func(*id, name)?;
1503 }
1504 }
1505 WorldItem::Function(f) => {
1506 require_world_func(&f.name)?;
1507 }
1508 WorldItem::Type { .. } => unreachable!(),
1509 }
1510 }
1511
1512 Ok(())
1513 }
1514}
1515
1516struct MaybeCancellable<T> {
1518 #[allow(unused)]
1519 inner: T,
1520 cancellable: bool,
1521}
1522
1523struct MaybeAsyncLowered<T> {
1525 inner: T,
1526 async_lowered: bool,
1527}
1528
1529struct PayloadLookupContext<'a> {
1532 resolve: &'a Resolve,
1533 world: &'a World,
1534 id: Option<InterfaceId>,
1535 import: bool,
1536 key: Option<WorldKey>,
1537}
1538
1539trait NameMangling {
1561 fn import_root(&self) -> &str;
1562 fn import_non_root_prefix(&self) -> &str;
1563 fn import_exported_intrinsic_prefix(&self) -> &str;
1564 fn export_memory(&self) -> &str;
1565 fn export_initialize(&self) -> &str;
1566 fn export_realloc(&self) -> &str;
1567 fn export_indirect_function_table(&self) -> Option<&str>;
1568 fn export_wasm_init_task(&self) -> Option<&str>;
1569 fn export_wasm_init_async_task(&self) -> Option<&str>;
1570 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1571 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1572 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1573 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1574 fn task_cancel(&self, name: &str) -> bool;
1575 fn backpressure_inc(&self, name: &str) -> bool;
1576 fn backpressure_dec(&self, name: &str) -> bool;
1577 fn waitable_set_new(&self, name: &str) -> bool;
1578 fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1579 fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1580 fn waitable_set_drop(&self, name: &str) -> bool;
1581 fn waitable_join(&self, name: &str) -> bool;
1582 fn subtask_drop(&self, name: &str) -> bool;
1583 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1584 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1585 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1586 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1587 fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1588 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1589 fn error_context_drop(&self, name: &str) -> bool;
1590 fn context_get(&self, name: &str) -> Option<(ValType, u32)>;
1591 fn context_set(&self, name: &str) -> Option<(ValType, u32)>;
1592 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1593 fn future_write(
1594 &self,
1595 lookup_context: &PayloadLookupContext,
1596 name: &str,
1597 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1598 fn future_read(
1599 &self,
1600 lookup_context: &PayloadLookupContext,
1601 name: &str,
1602 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1603 fn future_cancel_write(
1604 &self,
1605 lookup_context: &PayloadLookupContext,
1606 name: &str,
1607 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1608 fn future_cancel_read(
1609 &self,
1610 lookup_context: &PayloadLookupContext,
1611 name: &str,
1612 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1613 fn future_drop_writable(
1614 &self,
1615 lookup_context: &PayloadLookupContext,
1616 name: &str,
1617 ) -> Option<PayloadInfo>;
1618 fn future_drop_readable(
1619 &self,
1620 lookup_context: &PayloadLookupContext,
1621 name: &str,
1622 ) -> Option<PayloadInfo>;
1623 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1624 fn stream_write(
1625 &self,
1626 lookup_context: &PayloadLookupContext,
1627 name: &str,
1628 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1629 fn stream_read(
1630 &self,
1631 lookup_context: &PayloadLookupContext,
1632 name: &str,
1633 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1634 fn stream_cancel_write(
1635 &self,
1636 lookup_context: &PayloadLookupContext,
1637 name: &str,
1638 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1639 fn stream_cancel_read(
1640 &self,
1641 lookup_context: &PayloadLookupContext,
1642 name: &str,
1643 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1644 fn stream_drop_writable(
1645 &self,
1646 lookup_context: &PayloadLookupContext,
1647 name: &str,
1648 ) -> Option<PayloadInfo>;
1649 fn stream_drop_readable(
1650 &self,
1651 lookup_context: &PayloadLookupContext,
1652 name: &str,
1653 ) -> Option<PayloadInfo>;
1654 fn thread_index(&self, name: &str) -> bool;
1655 fn thread_new_indirect(&self, name: &str) -> bool;
1656 fn thread_resume_later(&self, name: &str) -> bool;
1657 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1658 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1659 fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1660 fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1661 fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1662 fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1663 fn module_to_interface(
1664 &self,
1665 module: &str,
1666 resolve: &Resolve,
1667 items: &IndexMap<WorldKey, WorldItem>,
1668 ) -> Result<(WorldKey, InterfaceId)>;
1669 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1670 fn match_wit_export<'a>(
1671 &self,
1672 export_name: &str,
1673 resolve: &'a Resolve,
1674 world: WorldId,
1675 exports: &'a IndexSet<WorldKey>,
1676 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1677 fn match_wit_resource_dtor<'a>(
1678 &self,
1679 export_name: &str,
1680 resolve: &'a Resolve,
1681 world: WorldId,
1682 exports: &'a IndexSet<WorldKey>,
1683 ) -> Option<TypeId>;
1684 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1685 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1686}
1687
1688struct Standard;
1691
1692const STANDARD: &'static dyn NameMangling = &Standard;
1693
1694impl NameMangling for Standard {
1695 fn import_root(&self) -> &str {
1696 ""
1697 }
1698 fn import_non_root_prefix(&self) -> &str {
1699 "|"
1700 }
1701 fn import_exported_intrinsic_prefix(&self) -> &str {
1702 "_ex_"
1703 }
1704 fn export_memory(&self) -> &str {
1705 "_memory"
1706 }
1707 fn export_initialize(&self) -> &str {
1708 "_initialize"
1709 }
1710 fn export_realloc(&self) -> &str {
1711 "_realloc"
1712 }
1713 fn export_indirect_function_table(&self) -> Option<&str> {
1714 None
1715 }
1716 fn export_wasm_init_task(&self) -> Option<&str> {
1717 None
1718 }
1719 fn export_wasm_init_async_task(&self) -> Option<&str> {
1720 None
1721 }
1722 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1723 name.strip_suffix("_drop")
1724 }
1725 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1726 name.strip_suffix("_new")
1727 }
1728 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1729 name.strip_suffix("_rep")
1730 }
1731 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1732 None
1733 }
1734 fn task_cancel(&self, _name: &str) -> bool {
1735 false
1736 }
1737 fn backpressure_inc(&self, _name: &str) -> bool {
1738 false
1739 }
1740 fn backpressure_dec(&self, _name: &str) -> bool {
1741 false
1742 }
1743 fn waitable_set_new(&self, _name: &str) -> bool {
1744 false
1745 }
1746 fn waitable_set_wait(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1747 None
1748 }
1749 fn waitable_set_poll(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1750 None
1751 }
1752 fn waitable_set_drop(&self, _name: &str) -> bool {
1753 false
1754 }
1755 fn waitable_join(&self, _name: &str) -> bool {
1756 false
1757 }
1758 fn subtask_drop(&self, _name: &str) -> bool {
1759 false
1760 }
1761 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1762 None
1763 }
1764 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1765 None
1766 }
1767 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1768 None
1769 }
1770 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1771 None
1772 }
1773 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1774 None
1775 }
1776 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1777 None
1778 }
1779 fn error_context_drop(&self, _name: &str) -> bool {
1780 false
1781 }
1782 fn context_get(&self, _name: &str) -> Option<(ValType, u32)> {
1783 None
1784 }
1785 fn context_set(&self, _name: &str) -> Option<(ValType, u32)> {
1786 None
1787 }
1788 fn thread_index(&self, _name: &str) -> bool {
1789 false
1790 }
1791 fn thread_new_indirect(&self, _name: &str) -> bool {
1792 false
1793 }
1794 fn thread_resume_later(&self, _name: &str) -> bool {
1795 false
1796 }
1797 fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1798 None
1799 }
1800 fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1801 None
1802 }
1803 fn thread_suspend_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1804 None
1805 }
1806 fn thread_yield_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1807 None
1808 }
1809 fn thread_suspend_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1810 None
1811 }
1812 fn thread_yield_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1813 None
1814 }
1815 fn future_new(
1816 &self,
1817 _lookup_context: &PayloadLookupContext,
1818 _name: &str,
1819 ) -> Option<PayloadInfo> {
1820 None
1821 }
1822 fn future_write(
1823 &self,
1824 _lookup_context: &PayloadLookupContext,
1825 _name: &str,
1826 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1827 None
1828 }
1829 fn future_read(
1830 &self,
1831 _lookup_context: &PayloadLookupContext,
1832 _name: &str,
1833 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1834 None
1835 }
1836 fn future_cancel_write(
1837 &self,
1838 _lookup_context: &PayloadLookupContext,
1839 _name: &str,
1840 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1841 None
1842 }
1843 fn future_cancel_read(
1844 &self,
1845 _lookup_context: &PayloadLookupContext,
1846 _name: &str,
1847 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1848 None
1849 }
1850 fn future_drop_writable(
1851 &self,
1852 _lookup_context: &PayloadLookupContext,
1853 _name: &str,
1854 ) -> Option<PayloadInfo> {
1855 None
1856 }
1857 fn future_drop_readable(
1858 &self,
1859 _lookup_context: &PayloadLookupContext,
1860 _name: &str,
1861 ) -> Option<PayloadInfo> {
1862 None
1863 }
1864 fn stream_new(
1865 &self,
1866 _lookup_context: &PayloadLookupContext,
1867 _name: &str,
1868 ) -> Option<PayloadInfo> {
1869 None
1870 }
1871 fn stream_write(
1872 &self,
1873 _lookup_context: &PayloadLookupContext,
1874 _name: &str,
1875 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1876 None
1877 }
1878 fn stream_read(
1879 &self,
1880 _lookup_context: &PayloadLookupContext,
1881 _name: &str,
1882 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1883 None
1884 }
1885 fn stream_cancel_write(
1886 &self,
1887 _lookup_context: &PayloadLookupContext,
1888 _name: &str,
1889 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1890 None
1891 }
1892 fn stream_cancel_read(
1893 &self,
1894 _lookup_context: &PayloadLookupContext,
1895 _name: &str,
1896 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1897 None
1898 }
1899 fn stream_drop_writable(
1900 &self,
1901 _lookup_context: &PayloadLookupContext,
1902 _name: &str,
1903 ) -> Option<PayloadInfo> {
1904 None
1905 }
1906 fn stream_drop_readable(
1907 &self,
1908 _lookup_context: &PayloadLookupContext,
1909 _name: &str,
1910 ) -> Option<PayloadInfo> {
1911 None
1912 }
1913 fn module_to_interface(
1914 &self,
1915 interface: &str,
1916 resolve: &Resolve,
1917 items: &IndexMap<WorldKey, WorldItem>,
1918 ) -> Result<(WorldKey, InterfaceId)> {
1919 for (key, item) in items.iter() {
1920 let id = match key {
1921 WorldKey::Name(name) => match item {
1923 WorldItem::Interface { id, .. } if name == interface => *id,
1924 _ => continue,
1925 },
1926 WorldKey::Interface(id) => {
1928 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1929 continue;
1930 }
1931 *id
1932 }
1933 };
1934 return Ok((key.clone(), id));
1935 }
1936 bail!("failed to find world item corresponding to interface `{interface}`")
1937 }
1938 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1939 name.strip_suffix("_post")
1940 }
1941 fn match_wit_export<'a>(
1942 &self,
1943 export_name: &str,
1944 resolve: &'a Resolve,
1945 world: WorldId,
1946 exports: &'a IndexSet<WorldKey>,
1947 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1948 if let Some(world_export_name) = export_name.strip_prefix("||") {
1949 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1950 match &resolve.worlds[world].exports[key] {
1951 WorldItem::Function(f) => return Some((key, None, f)),
1952 _ => return None,
1953 }
1954 }
1955
1956 let (key, id, func_name) =
1957 self.match_wit_interface(export_name, resolve, world, exports)?;
1958 let func = resolve.interfaces[id].functions.get(func_name)?;
1959 Some((key, Some(id), func))
1960 }
1961
1962 fn match_wit_resource_dtor<'a>(
1963 &self,
1964 export_name: &str,
1965 resolve: &'a Resolve,
1966 world: WorldId,
1967 exports: &'a IndexSet<WorldKey>,
1968 ) -> Option<TypeId> {
1969 let (_key, id, name) =
1970 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1971 let ty = *resolve.interfaces[id].types.get(name)?;
1972 match resolve.types[ty].kind {
1973 TypeDefKind::Resource => Some(ty),
1974 _ => None,
1975 }
1976 }
1977
1978 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1979 (name, AbiVariant::GuestImport)
1980 }
1981 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1982 (name, AbiVariant::GuestImport)
1983 }
1984}
1985
1986impl Standard {
1987 fn match_wit_interface<'a, 'b>(
1988 &self,
1989 export_name: &'b str,
1990 resolve: &'a Resolve,
1991 world: WorldId,
1992 exports: &'a IndexSet<WorldKey>,
1993 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
1994 let world = &resolve.worlds[world];
1995 let export_name = export_name.strip_prefix("|")?;
1996
1997 for export in exports {
1998 let id = match &world.exports[export] {
1999 WorldItem::Interface { id, .. } => *id,
2000 WorldItem::Function(_) => continue,
2001 WorldItem::Type { .. } => unreachable!(),
2002 };
2003 let remaining = match export {
2004 WorldKey::Name(name) => export_name.strip_prefix(name),
2005 WorldKey::Interface(_) => {
2006 let prefix = resolve.canonicalized_id_of(id).unwrap();
2007 export_name.strip_prefix(&prefix)
2008 }
2009 };
2010 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
2011 Some(name) => name,
2012 None => continue,
2013 };
2014 return Some((export, id, item_name));
2015 }
2016
2017 None
2018 }
2019}
2020
2021struct Legacy;
2024
2025const LEGACY: &'static dyn NameMangling = &Legacy;
2026
2027impl Legacy {
2028 fn prefixed_payload(
2034 &self,
2035 lookup_context: &PayloadLookupContext,
2036 name: &str,
2037 prefix: &str,
2038 ) -> Option<PayloadInfo> {
2039 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2042 let ty = match index_or_unit {
2043 "unit" => {
2044 if name.starts_with("[future") {
2045 PayloadType::UnitFuture
2046 } else if name.starts_with("[stream") {
2047 PayloadType::UnitStream
2048 } else {
2049 unreachable!()
2050 }
2051 }
2052 other => {
2053 let type_index = other.parse::<u32>().ok()? as usize;
2057
2058 let function = get_function(
2063 lookup_context.resolve,
2064 lookup_context.world,
2065 func_name,
2066 lookup_context.id,
2067 lookup_context.import,
2068 )
2069 .ok()?;
2070 PayloadType::Type {
2071 id: *function
2072 .find_futures_and_streams(lookup_context.resolve)
2073 .get(type_index)?,
2074 function: function.name.clone(),
2075 }
2076 }
2077 };
2078
2079 Some(PayloadInfo {
2081 name: name.to_string(),
2082 ty,
2083 key: lookup_context
2084 .key
2085 .clone()
2086 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2087 interface: lookup_context.id,
2088 imported: lookup_context.import,
2089 })
2090 }
2091
2092 fn maybe_async_lowered_payload(
2093 &self,
2094 lookup_context: &PayloadLookupContext,
2095 name: &str,
2096 prefix: &str,
2097 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2098 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2099 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2100 Some(MaybeAsyncLowered {
2101 inner: payload,
2102 async_lowered,
2103 })
2104 }
2105
2106 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2107 name.strip_prefix("[async-lower]")
2108 .map_or((false, name), |s| (true, s))
2109 }
2110 fn match_with_async_lowered_prefix(
2111 &self,
2112 name: &str,
2113 expected: &str,
2114 ) -> Option<MaybeAsyncLowered<()>> {
2115 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2116 if clean_name == expected {
2117 Some(MaybeAsyncLowered {
2118 inner: (),
2119 async_lowered,
2120 })
2121 } else {
2122 None
2123 }
2124 }
2125 fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2126 name.strip_prefix("[cancellable]")
2127 .map_or((false, name), |s| (true, s))
2128 }
2129 fn match_with_cancellable_prefix(
2130 &self,
2131 name: &str,
2132 expected: &str,
2133 ) -> Option<MaybeCancellable<()>> {
2134 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2135 if clean_name == expected {
2136 Some(MaybeCancellable {
2137 inner: (),
2138 cancellable,
2139 })
2140 } else {
2141 None
2142 }
2143 }
2144
2145 fn match_with_optional_type_suffix(name: &str, match_prefix: &str) -> Option<ValType> {
2149 let tail = name.strip_prefix(match_prefix)?.strip_suffix(']')?;
2150 if tail.is_empty() {
2151 Some(ValType::I32)
2152 } else {
2153 match tail.strip_prefix('-')? {
2154 "i32" => Some(ValType::I32),
2155 "i64" => Some(ValType::I64),
2156 _ => None,
2158 }
2159 }
2160 }
2161}
2162
2163impl NameMangling for Legacy {
2164 fn import_root(&self) -> &str {
2165 "$root"
2166 }
2167 fn import_non_root_prefix(&self) -> &str {
2168 ""
2169 }
2170 fn import_exported_intrinsic_prefix(&self) -> &str {
2171 "[export]"
2172 }
2173 fn export_memory(&self) -> &str {
2174 "memory"
2175 }
2176 fn export_initialize(&self) -> &str {
2177 "_initialize"
2178 }
2179 fn export_realloc(&self) -> &str {
2180 "cabi_realloc"
2181 }
2182 fn export_indirect_function_table(&self) -> Option<&str> {
2183 Some("__indirect_function_table")
2184 }
2185 fn export_wasm_init_task(&self) -> Option<&str> {
2186 Some("__wasm_init_task")
2187 }
2188 fn export_wasm_init_async_task(&self) -> Option<&str> {
2189 Some("__wasm_init_async_task")
2190 }
2191 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2192 name.strip_prefix("[resource-drop]")
2193 }
2194 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2195 name.strip_prefix("[resource-new]")
2196 }
2197 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2198 name.strip_prefix("[resource-rep]")
2199 }
2200 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2201 name.strip_prefix("[task-return]")
2202 }
2203 fn task_cancel(&self, name: &str) -> bool {
2204 name == "[task-cancel]"
2205 }
2206 fn backpressure_inc(&self, name: &str) -> bool {
2207 name == "[backpressure-inc]"
2208 }
2209 fn backpressure_dec(&self, name: &str) -> bool {
2210 name == "[backpressure-dec]"
2211 }
2212 fn waitable_set_new(&self, name: &str) -> bool {
2213 name == "[waitable-set-new]"
2214 }
2215 fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2216 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2217 let mb_cancellable = MaybeCancellable {
2218 inner: (),
2219 cancellable,
2220 };
2221 let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-wait")?;
2222 Some((mb_cancellable, result_ty))
2223 }
2224 fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2225 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2226 let mb_cancellable = MaybeCancellable {
2227 inner: (),
2228 cancellable,
2229 };
2230 let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-poll")?;
2231 Some((mb_cancellable, result_ty))
2232 }
2233 fn waitable_set_drop(&self, name: &str) -> bool {
2234 name == "[waitable-set-drop]"
2235 }
2236 fn waitable_join(&self, name: &str) -> bool {
2237 name == "[waitable-join]"
2238 }
2239 fn subtask_drop(&self, name: &str) -> bool {
2240 name == "[subtask-drop]"
2241 }
2242 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2243 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2244 }
2245 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2246 name.strip_prefix("[callback][async-lift]")
2247 }
2248 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2249 name.strip_prefix("[async-lift]")
2250 }
2251 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2252 name.strip_prefix("[async-lift-stackful]")
2253 }
2254 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2255 match name {
2256 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2257 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2258 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2259 _ => None,
2260 }
2261 }
2262 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2263 match name {
2264 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2265 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2266 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2267 _ => None,
2268 }
2269 }
2270 fn error_context_drop(&self, name: &str) -> bool {
2271 name == "[error-context-drop]"
2272 }
2273 fn context_get(&self, name: &str) -> Option<(ValType, u32)> {
2274 parse_context_name(name, "[context-get-")
2275 }
2276 fn context_set(&self, name: &str) -> Option<(ValType, u32)> {
2277 parse_context_name(name, "[context-set-")
2278 }
2279 fn thread_index(&self, name: &str) -> bool {
2280 name == "[thread-index]"
2281 }
2282 fn thread_new_indirect(&self, name: &str) -> bool {
2283 name == "[thread-new-indirect-v0]"
2285 }
2286 fn thread_resume_later(&self, name: &str) -> bool {
2287 name == "[thread-resume-later]"
2288 }
2289 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2290 self.match_with_cancellable_prefix(name, "[thread-suspend]")
2291 }
2292 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2293 self.match_with_cancellable_prefix(name, "[thread-yield]")
2294 }
2295 fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2296 self.match_with_cancellable_prefix(name, "[thread-suspend-then-resume]")
2297 }
2298 fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2299 self.match_with_cancellable_prefix(name, "[thread-yield-then-resume]")
2300 }
2301 fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2302 self.match_with_cancellable_prefix(name, "[thread-suspend-then-promote]")
2303 }
2304 fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2305 self.match_with_cancellable_prefix(name, "[thread-yield-then-promote]")
2306 }
2307 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2308 self.prefixed_payload(lookup_context, name, "[future-new-")
2309 }
2310 fn future_write(
2311 &self,
2312 lookup_context: &PayloadLookupContext,
2313 name: &str,
2314 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2315 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2316 }
2317 fn future_read(
2318 &self,
2319 lookup_context: &PayloadLookupContext,
2320 name: &str,
2321 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2322 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2323 }
2324 fn future_cancel_write(
2325 &self,
2326 lookup_context: &PayloadLookupContext,
2327 name: &str,
2328 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2329 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2330 }
2331 fn future_cancel_read(
2332 &self,
2333 lookup_context: &PayloadLookupContext,
2334 name: &str,
2335 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2336 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2337 }
2338 fn future_drop_writable(
2339 &self,
2340 lookup_context: &PayloadLookupContext,
2341 name: &str,
2342 ) -> Option<PayloadInfo> {
2343 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2344 }
2345 fn future_drop_readable(
2346 &self,
2347 lookup_context: &PayloadLookupContext,
2348 name: &str,
2349 ) -> Option<PayloadInfo> {
2350 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2351 }
2352 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2353 self.prefixed_payload(lookup_context, name, "[stream-new-")
2354 }
2355 fn stream_write(
2356 &self,
2357 lookup_context: &PayloadLookupContext,
2358 name: &str,
2359 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2360 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2361 }
2362 fn stream_read(
2363 &self,
2364 lookup_context: &PayloadLookupContext,
2365 name: &str,
2366 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2367 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2368 }
2369 fn stream_cancel_write(
2370 &self,
2371 lookup_context: &PayloadLookupContext,
2372 name: &str,
2373 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2374 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2375 }
2376 fn stream_cancel_read(
2377 &self,
2378 lookup_context: &PayloadLookupContext,
2379 name: &str,
2380 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2381 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2382 }
2383 fn stream_drop_writable(
2384 &self,
2385 lookup_context: &PayloadLookupContext,
2386 name: &str,
2387 ) -> Option<PayloadInfo> {
2388 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2389 }
2390 fn stream_drop_readable(
2391 &self,
2392 lookup_context: &PayloadLookupContext,
2393 name: &str,
2394 ) -> Option<PayloadInfo> {
2395 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2396 }
2397 fn module_to_interface(
2398 &self,
2399 module: &str,
2400 resolve: &Resolve,
2401 items: &IndexMap<WorldKey, WorldItem>,
2402 ) -> Result<(WorldKey, InterfaceId)> {
2403 let bare_name = WorldKey::Name(module.to_string());
2405 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2406 return Ok((bare_name, *id));
2407 }
2408
2409 let kebab_name = ComponentName::new(module, 0);
2415 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2416 Ok(ComponentNameKind::Interface(name)) => name,
2417 _ => bail!("module requires an import interface named `{module}`"),
2418 };
2419
2420 let version = name.version(None)?;
2424
2425 let pkgname = PackageName {
2427 namespace: name.namespace().to_string(),
2428 name: name.package().to_string(),
2429 version: version.clone(),
2430 };
2431 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2432 if let Some(id) = resolve.packages[*pkg]
2433 .interfaces
2434 .get(name.interface().as_str())
2435 {
2436 let key = WorldKey::Interface(*id);
2439 if items.contains_key(&key) {
2440 return Ok((key, *id));
2441 }
2442
2443 for k in items.keys() {
2449 let i = match *k {
2450 WorldKey::Interface(id) => id,
2451 WorldKey::Name(_) => continue,
2452 };
2453 if resolve.interfaces[i].clone_of == Some(*id) {
2454 return Ok((WorldKey::Interface(i), i));
2455 }
2456 }
2457 }
2458 }
2459
2460 for (key, _) in items {
2465 let id = match key {
2466 WorldKey::Interface(id) => *id,
2467 WorldKey::Name(_) => continue,
2468 };
2469 let interface = &resolve.interfaces[id];
2471 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2472 continue;
2473 }
2474
2475 let pkg = &resolve.packages[interface.package.unwrap()];
2477 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2478 continue;
2479 }
2480
2481 let module_version = match &version {
2482 Some(version) => version,
2483 None => continue,
2484 };
2485 let pkg_version = match &pkg.name.version {
2486 Some(version) => version,
2487 None => continue,
2488 };
2489
2490 let module_compat = PackageName::version_compat_track(&module_version);
2492 let pkg_compat = PackageName::version_compat_track(pkg_version);
2493 if module_compat == pkg_compat {
2494 return Ok((key.clone(), id));
2495 }
2496 }
2497
2498 bail!("module requires an import interface named `{module}`")
2499 }
2500 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2501 name.strip_prefix("cabi_post_")
2502 }
2503 fn match_wit_export<'a>(
2504 &self,
2505 export_name: &str,
2506 resolve: &'a Resolve,
2507 world: WorldId,
2508 exports: &'a IndexSet<WorldKey>,
2509 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2510 let world = &resolve.worlds[world];
2511 for name in exports {
2512 match &world.exports[name] {
2513 WorldItem::Function(f) => {
2514 if f.legacy_core_export_name(None) == export_name {
2515 return Some((name, None, f));
2516 }
2517 }
2518 WorldItem::Interface { id, .. } => {
2519 let string = resolve.name_world_key(name);
2520 for (_, func) in resolve.interfaces[*id].functions.iter() {
2521 if func.legacy_core_export_name(Some(&string)) == export_name {
2522 return Some((name, Some(*id), func));
2523 }
2524 }
2525 }
2526
2527 WorldItem::Type { .. } => unreachable!(),
2528 }
2529 }
2530
2531 None
2532 }
2533
2534 fn match_wit_resource_dtor<'a>(
2535 &self,
2536 export_name: &str,
2537 resolve: &'a Resolve,
2538 world: WorldId,
2539 exports: &'a IndexSet<WorldKey>,
2540 ) -> Option<TypeId> {
2541 let world = &resolve.worlds[world];
2542 for name in exports {
2543 let id = match &world.exports[name] {
2544 WorldItem::Interface { id, .. } => *id,
2545 WorldItem::Function(_) => continue,
2546 WorldItem::Type { .. } => unreachable!(),
2547 };
2548 let name = resolve.name_world_key(name);
2549 let resource = match export_name
2550 .strip_prefix(&name)
2551 .and_then(|s| s.strip_prefix("#[dtor]"))
2552 .and_then(|r| resolve.interfaces[id].types.get(r))
2553 {
2554 Some(id) => *id,
2555 None => continue,
2556 };
2557
2558 match resolve.types[resource].kind {
2559 TypeDefKind::Resource => {}
2560 _ => continue,
2561 }
2562
2563 return Some(resource);
2564 }
2565
2566 None
2567 }
2568
2569 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2570 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2571 (
2572 name,
2573 if async_abi {
2574 AbiVariant::GuestImportAsync
2575 } else {
2576 AbiVariant::GuestImport
2577 },
2578 )
2579 }
2580 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2581 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2582 (
2583 name,
2584 if async_abi {
2585 AbiVariant::GuestImportAsync
2586 } else {
2587 AbiVariant::GuestImport
2588 },
2589 )
2590 }
2591}
2592
2593pub fn validate_module(
2605 encoder: &ComponentEncoder,
2606 bytes: &[u8],
2607 import_map: Option<&ModuleImportMap>,
2608) -> Result<ValidatedModule> {
2609 ValidatedModule::new(
2610 encoder,
2611 bytes,
2612 &encoder.main_module_exports,
2613 import_map,
2614 None,
2615 )
2616}
2617
2618pub fn validate_adapter_module(
2636 encoder: &ComponentEncoder,
2637 bytes: &[u8],
2638 required_by_import: &IndexMap<String, FuncType>,
2639 exports: &IndexSet<WorldKey>,
2640 library_info: Option<&LibraryInfo>,
2641) -> Result<ValidatedModule> {
2642 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2643
2644 for (name, required_ty) in required_by_import {
2645 let actual = match ret.exports.raw_exports.get(name) {
2646 Some(ty) => ty,
2647 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2648 };
2649 validate_func_sig(name, required_ty, &actual)?;
2650 }
2651
2652 Ok(ret)
2653}
2654
2655#[derive(Debug, Clone)]
2662pub struct AdapterModuleDidNotExport(String);
2663
2664impl fmt::Display for AdapterModuleDidNotExport {
2665 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2666 write!(f, "adapter module did not export `{}`", self.0)
2667 }
2668}
2669
2670impl std::error::Error for AdapterModuleDidNotExport {}
2671
2672fn resource_test_for_interface<'a>(
2673 resolve: &'a Resolve,
2674 id: InterfaceId,
2675) -> impl Fn(&str) -> Option<TypeId> + 'a {
2676 let interface = &resolve.interfaces[id];
2677 move |name: &str| {
2678 let ty = match interface.types.get(name) {
2679 Some(ty) => *ty,
2680 None => return None,
2681 };
2682 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2683 Some(ty)
2684 } else {
2685 None
2686 }
2687 }
2688}
2689
2690fn resource_test_for_world<'a>(
2691 resolve: &'a Resolve,
2692 id: WorldId,
2693) -> impl Fn(&str) -> Option<TypeId> + 'a {
2694 let world = &resolve.worlds[id];
2695 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2696 WorldItem::Type { id, .. } => {
2697 if matches!(resolve.types[*id].kind, TypeDefKind::Resource) {
2698 Some(*id)
2699 } else {
2700 None
2701 }
2702 }
2703 _ => None,
2704 }
2705}
2706
2707fn validate_func(
2708 resolve: &Resolve,
2709 ty: &wasmparser::FuncType,
2710 func: &Function,
2711 abi: AbiVariant,
2712) -> Result<()> {
2713 validate_func_sig(
2714 &func.name,
2715 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2716 ty,
2717 )
2718}
2719
2720fn validate_post_return(
2721 resolve: &Resolve,
2722 ty: &wasmparser::FuncType,
2723 func: &Function,
2724) -> Result<()> {
2725 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2731 sig.params = mem::take(&mut sig.results);
2732 validate_func_sig(
2733 &format!("{} post-return", func.name),
2734 &wasm_sig_to_func_type(sig),
2735 ty,
2736 )
2737}
2738
2739fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2740 if ty != expected {
2741 bail!(
2742 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2743 name,
2744 expected.params(),
2745 expected.results(),
2746 ty.params(),
2747 ty.results()
2748 );
2749 }
2750
2751 Ok(())
2752}
2753
2754fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2756 assert!(prefix.starts_with("["));
2757 assert!(prefix.ends_with("-"));
2758 let suffix = name.strip_prefix(prefix)?;
2759 let index = suffix.find(']')?;
2760 let rest = &suffix[index + 1..];
2761 Some((&suffix[..index], rest))
2762}
2763
2764fn parse_context_name(name: &str, prefix: &str) -> Option<(ValType, u32)> {
2770 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2771 if !rest.is_empty() {
2772 return None;
2773 }
2774 let (ty, slot) = match suffix.split_once('-') {
2775 Some(("i64", slot)) => (ValType::I64, slot),
2776 Some(("i32", slot)) => (ValType::I32, slot),
2777 _ => (ValType::I32, suffix),
2778 };
2779 let slot = slot.parse().ok()?;
2780 Some((ty, slot))
2781}
2782
2783fn get_function<'a>(
2784 resolve: &'a Resolve,
2785 world: &'a World,
2786 name: &str,
2787 interface: Option<InterfaceId>,
2788 imported: bool,
2789) -> Result<&'a Function> {
2790 let function = if let Some(id) = interface {
2791 return resolve.interfaces[id]
2792 .functions
2793 .get(name)
2794 .ok_or_else(|| anyhow!("no export `{name}` found"));
2795 } else if imported {
2796 world.imports.get(&WorldKey::Name(name.to_string()))
2797 } else {
2798 world.exports.get(&WorldKey::Name(name.to_string()))
2799 };
2800 let Some(WorldItem::Function(function)) = function else {
2801 bail!("no export `{name}` found");
2802 };
2803 Ok(function)
2804}