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 module == "env" {
767 if let Some(import) = names.env_import(name, ty) {
768 return Ok(import);
769 }
770 }
771
772 if matches!(
774 module.strip_prefix(names.import_exported_intrinsic_prefix()),
775 Some(module) if module == names.import_root()
776 ) {
777 if let Some(import) =
778 self.maybe_classify_wit_intrinsic(name, None, encoder, ty, false, names)?
779 {
780 return Ok(import);
781 }
782 }
783
784 let interface = match module.strip_prefix(names.import_non_root_prefix()) {
785 Some(name) => name,
786 None => bail!("unknown or invalid component model import syntax"),
787 };
788
789 if let Some(interface) = interface.strip_prefix(names.import_exported_intrinsic_prefix()) {
790 let (key, id) = names.module_to_interface(interface, resolve, &world.exports)?;
791
792 if let Some(import) =
793 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, false, names)?
794 {
795 return Ok(import);
796 }
797 bail!("unknown function `{name}`")
798 }
799
800 let (key, id) = names.module_to_interface(interface, resolve, &world.imports)?;
801 let interface = &resolve.interfaces[id];
802 let (function_name, abi) = names.interface_function_name_and_abi(name);
803 if let Some(f) = interface.functions.get(function_name) {
804 validate_func(resolve, ty, f, abi).with_context(|| {
805 let name = resolve.name_world_key(&key);
806 format!("failed to validate import interface `{name}`")
807 })?;
808 return Ok(Import::InterfaceFunc(key, id, f.name.clone(), abi));
809 }
810
811 if let Some(import) =
812 self.maybe_classify_wit_intrinsic(name, Some((key, id)), encoder, ty, true, names)?
813 {
814 return Ok(import);
815 }
816 bail!(
817 "import interface `{module}` is missing function \
818 `{name}` that is required by the module",
819 )
820 }
821
822 fn maybe_classify_wit_intrinsic(
850 &self,
851 name: &str,
852 key_and_id: Option<(WorldKey, InterfaceId)>,
853 encoder: &ComponentEncoder,
854 ty: &FuncType,
855 import: bool,
856 names: &dyn NameMangling,
857 ) -> Result<Option<Import>> {
858 let resolve = &encoder.metadata.resolve;
859 let world_id = encoder.metadata.world;
860 let world = &resolve.worlds[world_id];
861
862 let (key, id) = match key_and_id {
867 Some((key, id)) => (Some(key), Some(id)),
868 None => (None, None),
869 };
870
871 let resource_test = |name: &str| match id {
873 Some(id) => resource_test_for_interface(resolve, id)(name),
874 None => resource_test_for_world(resolve, world_id)(name),
875 };
876
877 if let Some(resource) = names.resource_drop_name(name) {
879 if let Some(resource_id) = resource_test(resource) {
880 let key = key.unwrap_or_else(|| WorldKey::Name(resource.to_string()));
881 let expected = FuncType::new([ValType::I32], []);
882 validate_func_sig(name, &expected, ty)?;
883 return Ok(Some(if import {
884 Import::ImportedResourceDrop(key, id, resource_id)
885 } else {
886 Import::ExportedResourceDrop(key, resource_id)
887 }));
888 }
889 }
890
891 if !import {
894 if let Some(name) = names.resource_new_name(name) {
895 if let Some(id) = resource_test(name) {
896 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
897 let expected = FuncType::new([ValType::I32], [ValType::I32]);
898 validate_func_sig(name, &expected, ty)?;
899 return Ok(Some(Import::ExportedResourceNew(key, id)));
900 }
901 }
902 if let Some(name) = names.resource_rep_name(name) {
903 if let Some(id) = resource_test(name) {
904 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
905 let expected = FuncType::new([ValType::I32], [ValType::I32]);
906 validate_func_sig(name, &expected, ty)?;
907 return Ok(Some(Import::ExportedResourceRep(key, id)));
908 }
909 }
910 if let Some(name) = names.task_return_name(name) {
911 let func = get_function(resolve, world, name, id, import)?;
912 let key = key.unwrap_or_else(|| WorldKey::Name(name.to_string()));
913 return Ok(Some(Import::ExportedTaskReturn(key, id, func.clone())));
916 }
917 if names.task_cancel(name) {
918 let expected = FuncType::new([], []);
919 validate_func_sig(name, &expected, ty)?;
920 return Ok(Some(Import::ExportedTaskCancel));
921 }
922 }
923
924 let lookup_context = PayloadLookupContext {
925 resolve,
926 world,
927 key,
928 id,
929 import,
930 };
931
932 let import = if let Some(info) = names.future_new(&lookup_context, name) {
936 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
937 Import::FutureNew(info)
938 } else if let Some(info) = names.future_write(&lookup_context, name) {
939 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
940 Import::FutureWrite {
941 async_: info.async_lowered,
942 info: info.inner,
943 }
944 } else if let Some(info) = names.future_read(&lookup_context, name) {
945 validate_func_sig(name, &FuncType::new([ValType::I32; 2], [ValType::I32]), ty)?;
946 Import::FutureRead {
947 async_: info.async_lowered,
948 info: info.inner,
949 }
950 } else if let Some(info) = names.future_cancel_write(&lookup_context, name) {
951 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
952 Import::FutureCancelWrite {
953 async_: info.async_lowered,
954 info: info.inner,
955 }
956 } else if let Some(info) = names.future_cancel_read(&lookup_context, name) {
957 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
958 Import::FutureCancelRead {
959 async_: info.async_lowered,
960 info: info.inner,
961 }
962 } else if let Some(info) = names.future_drop_writable(&lookup_context, name) {
963 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
964 Import::FutureDropWritable(info)
965 } else if let Some(info) = names.future_drop_readable(&lookup_context, name) {
966 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
967 Import::FutureDropReadable(info)
968 } else if let Some(info) = names.stream_new(&lookup_context, name) {
969 validate_func_sig(name, &FuncType::new([], [ValType::I64]), ty)?;
970 Import::StreamNew(info)
971 } else if let Some(info) = names.stream_write(&lookup_context, name) {
972 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
973 Import::StreamWrite {
974 async_: info.async_lowered,
975 info: info.inner,
976 }
977 } else if let Some(info) = names.stream_read(&lookup_context, name) {
978 validate_func_sig(name, &FuncType::new([ValType::I32; 3], [ValType::I32]), ty)?;
979 Import::StreamRead {
980 async_: info.async_lowered,
981 info: info.inner,
982 }
983 } else if let Some(info) = names.stream_cancel_write(&lookup_context, name) {
984 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
985 Import::StreamCancelWrite {
986 async_: info.async_lowered,
987 info: info.inner,
988 }
989 } else if let Some(info) = names.stream_cancel_read(&lookup_context, name) {
990 validate_func_sig(name, &FuncType::new([ValType::I32], [ValType::I32]), ty)?;
991 Import::StreamCancelRead {
992 async_: info.async_lowered,
993 info: info.inner,
994 }
995 } else if let Some(info) = names.stream_drop_writable(&lookup_context, name) {
996 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
997 Import::StreamDropWritable(info)
998 } else if let Some(info) = names.stream_drop_readable(&lookup_context, name) {
999 validate_func_sig(name, &FuncType::new([ValType::I32], []), ty)?;
1000 Import::StreamDropReadable(info)
1001 } else {
1002 return Ok(None);
1003 };
1004 Ok(Some(import))
1005 }
1006
1007 fn classify_import_with_library(
1008 &mut self,
1009 import: wasmparser::Import<'_>,
1010 library_info: Option<&LibraryInfo>,
1011 ) -> Result<bool> {
1012 let info = match library_info {
1013 Some(info) => info,
1014 None => return Ok(false),
1015 };
1016 let Some((_, instance)) = info
1017 .arguments
1018 .iter()
1019 .find(|(name, _items)| *name == import.module)
1020 else {
1021 return Ok(false);
1022 };
1023 match instance {
1024 Instance::MainOrAdapter(module) => match self.names.get(import.module) {
1025 Some(ImportInstance::Whole(which)) => {
1026 if which != module {
1027 bail!("different whole modules imported under the same name");
1028 }
1029 }
1030 Some(ImportInstance::Names(_)) => {
1031 bail!("cannot mix individual imports and whole module imports")
1032 }
1033 None => {
1034 let instance = ImportInstance::Whole(module.clone());
1035 self.names.insert(import.module.to_string(), instance);
1036 }
1037 },
1038 Instance::Items(items) => {
1039 let Some(item) = items.iter().find(|i| i.alias == import.name) else {
1040 return Ok(false);
1041 };
1042 self.insert_import(import, Import::Item(item.clone()))?;
1043 }
1044 }
1045 Ok(true)
1046 }
1047
1048 fn insert_import(&mut self, import: wasmparser::Import<'_>, item: Import) -> Result<()> {
1052 let entry = self
1053 .names
1054 .entry(import.module.to_string())
1055 .or_insert(ImportInstance::Names(IndexMap::default()));
1056 let names = match entry {
1057 ImportInstance::Names(names) => names,
1058 _ => bail!("cannot mix individual imports with module imports"),
1059 };
1060 let entry = match names.entry(import.name.to_string()) {
1061 Entry::Occupied(_) => {
1062 bail!(
1063 "module has duplicate import for `{}::{}`",
1064 import.module,
1065 import.name
1066 );
1067 }
1068 Entry::Vacant(v) => v,
1069 };
1070 log::trace!(
1071 "classifying import `{}::{} as {item:?}",
1072 import.module,
1073 import.name
1074 );
1075 entry.insert(item);
1076 Ok(())
1077 }
1078}
1079
1080#[derive(Default)]
1083pub struct ExportMap {
1084 names: IndexMap<String, Export>,
1085 raw_exports: IndexMap<String, FuncType>,
1086}
1087
1088#[derive(Debug)]
1091pub enum Export {
1092 WorldFunc(WorldKey, String, AbiVariant),
1095
1096 WorldFuncPostReturn(WorldKey),
1098
1099 InterfaceFunc(WorldKey, InterfaceId, String, AbiVariant),
1101
1102 InterfaceFuncPostReturn(WorldKey, String),
1104
1105 ResourceDtor(TypeId),
1107
1108 Memory,
1110
1111 GeneralPurposeRealloc,
1113
1114 GeneralPurposeExportRealloc,
1116
1117 GeneralPurposeImportRealloc,
1119
1120 Initialize,
1122
1123 ReallocForAdapter,
1125
1126 WorldFuncCallback(WorldKey),
1127
1128 InterfaceFuncCallback(WorldKey, String),
1129
1130 IndirectFunctionTable,
1132
1133 WasmInitTask,
1135
1136 WasmInitAsyncTask,
1138}
1139
1140impl ExportMap {
1141 fn add(
1142 &mut self,
1143 export: wasmparser::Export<'_>,
1144 encoder: &ComponentEncoder,
1145 exports: &IndexSet<WorldKey>,
1146 types: TypesRef<'_>,
1147 ) -> Result<()> {
1148 if let Some(item) = self.classify(export, encoder, exports, types)? {
1149 log::debug!("classifying export `{}` as {item:?}", export.name);
1150 let prev = self.names.insert(export.name.to_string(), item);
1151 assert!(prev.is_none());
1152 }
1153 Ok(())
1154 }
1155
1156 fn classify(
1157 &mut self,
1158 export: wasmparser::Export<'_>,
1159 encoder: &ComponentEncoder,
1160 exports: &IndexSet<WorldKey>,
1161 types: TypesRef<'_>,
1162 ) -> Result<Option<Export>> {
1163 match export.kind {
1164 ExternalKind::Func => {
1165 let ty = types[types.core_function_at(export.index)].unwrap_func();
1166 self.raw_exports.insert(export.name.to_string(), ty.clone());
1167 }
1168 _ => {}
1169 }
1170
1171 if export.name == "canonical_abi_realloc" {
1173 return Ok(Some(Export::GeneralPurposeRealloc));
1174 } else if export.name == "cabi_import_realloc" {
1175 return Ok(Some(Export::GeneralPurposeImportRealloc));
1176 } else if export.name == "cabi_export_realloc" {
1177 return Ok(Some(Export::GeneralPurposeExportRealloc));
1178 } else if export.name == "cabi_realloc_adapter" {
1179 return Ok(Some(Export::ReallocForAdapter));
1180 }
1181
1182 let (name, names) = match export.name.strip_prefix("cm32p2") {
1183 Some(name) => (name, STANDARD),
1184 None if encoder.reject_legacy_names => return Ok(None),
1185 None => (export.name, LEGACY),
1186 };
1187
1188 if let Some(export) = self
1189 .classify_component_export(names, name, &export, encoder, exports, types)
1190 .with_context(|| format!("failed to classify export `{}`", export.name))?
1191 {
1192 return Ok(Some(export));
1193 }
1194 log::debug!("unknown export `{}`", export.name);
1195 Ok(None)
1196 }
1197
1198 fn classify_component_export(
1199 &mut self,
1200 names: &dyn NameMangling,
1201 name: &str,
1202 export: &wasmparser::Export<'_>,
1203 encoder: &ComponentEncoder,
1204 exports: &IndexSet<WorldKey>,
1205 types: TypesRef<'_>,
1206 ) -> Result<Option<Export>> {
1207 let resolve = &encoder.metadata.resolve;
1208 let world = encoder.metadata.world;
1209 match export.kind {
1210 ExternalKind::Func => {}
1211 ExternalKind::Memory => {
1212 if name == names.export_memory() {
1213 return Ok(Some(Export::Memory));
1214 }
1215 return Ok(None);
1216 }
1217 ExternalKind::Table => {
1218 if Some(name) == names.export_indirect_function_table() {
1219 return Ok(Some(Export::IndirectFunctionTable));
1220 }
1221 return Ok(None);
1222 }
1223 _ => return Ok(None),
1224 }
1225 let ty = types[types.core_function_at(export.index)].unwrap_func();
1226
1227 if name == names.export_realloc() {
1229 let expected = FuncType::new([ValType::I32; 4], [ValType::I32]);
1230 validate_func_sig(name, &expected, ty)?;
1231 return Ok(Some(Export::GeneralPurposeRealloc));
1232 } else if name == names.export_initialize() {
1233 let expected = FuncType::new([], []);
1234 validate_func_sig(name, &expected, ty)?;
1235 return Ok(Some(Export::Initialize));
1236 } else if Some(name) == names.export_wasm_init_task() {
1237 let expected = FuncType::new([], []);
1238 validate_func_sig(name, &expected, ty)?;
1239 return Ok(Some(Export::WasmInitTask));
1240 } else if Some(name) == names.export_wasm_init_async_task() {
1241 let expected = FuncType::new([], []);
1242 validate_func_sig(name, &expected, ty)?;
1243 return Ok(Some(Export::WasmInitAsyncTask));
1244 }
1245
1246 let full_name = name;
1247 let (abi, name) = if let Some(name) = names.async_lift_name(name) {
1248 (AbiVariant::GuestExportAsync, name)
1249 } else if let Some(name) = names.async_lift_stackful_name(name) {
1250 (AbiVariant::GuestExportAsyncStackful, name)
1251 } else {
1252 (AbiVariant::GuestExport, name)
1253 };
1254
1255 if let Some((key, id, f)) = names.match_wit_export(name, resolve, world, exports) {
1257 validate_func(resolve, ty, f, abi).with_context(|| {
1258 let key = resolve.name_world_key(key);
1259 format!("failed to validate export for `{key}`")
1260 })?;
1261 match id {
1262 Some(id) => {
1263 return Ok(Some(Export::InterfaceFunc(
1264 key.clone(),
1265 id,
1266 f.name.clone(),
1267 abi,
1268 )));
1269 }
1270 None => {
1271 return Ok(Some(Export::WorldFunc(key.clone(), f.name.clone(), abi)));
1272 }
1273 }
1274 }
1275
1276 if let Some(remaining) = names.strip_post_return(name) {
1278 if let Some((key, id, f)) = names.match_wit_export(remaining, resolve, world, exports) {
1279 validate_post_return(resolve, ty, f).with_context(|| {
1280 let key = resolve.name_world_key(key);
1281 format!("failed to validate export for `{key}`")
1282 })?;
1283 match id {
1284 Some(_id) => {
1285 return Ok(Some(Export::InterfaceFuncPostReturn(
1286 key.clone(),
1287 f.name.clone(),
1288 )));
1289 }
1290 None => {
1291 return Ok(Some(Export::WorldFuncPostReturn(key.clone())));
1292 }
1293 }
1294 }
1295 }
1296
1297 if let Some(suffix) = names.async_lift_callback_name(full_name) {
1298 if let Some((key, id, f)) = names.match_wit_export(suffix, resolve, world, exports) {
1299 validate_func_sig(
1300 full_name,
1301 &FuncType::new([ValType::I32; 3], [ValType::I32]),
1302 ty,
1303 )?;
1304 return Ok(Some(if id.is_some() {
1305 Export::InterfaceFuncCallback(key.clone(), f.name.clone())
1306 } else {
1307 Export::WorldFuncCallback(key.clone())
1308 }));
1309 }
1310 }
1311
1312 if let Some(dtor) = names.match_wit_resource_dtor(name, resolve, world, exports) {
1314 let expected = FuncType::new([ValType::I32], []);
1315 validate_func_sig(full_name, &expected, ty)?;
1316 return Ok(Some(Export::ResourceDtor(dtor)));
1317 }
1318
1319 Ok(None)
1320 }
1321
1322 pub fn post_return(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1325 self.find(|m| match m {
1326 Export::WorldFuncPostReturn(k) => k == key,
1327 Export::InterfaceFuncPostReturn(k, f) => k == key && func.name == *f,
1328 _ => false,
1329 })
1330 }
1331
1332 pub fn callback(&self, key: &WorldKey, func: &Function) -> Option<&str> {
1335 self.find(|m| match m {
1336 Export::WorldFuncCallback(k) => k == key,
1337 Export::InterfaceFuncCallback(k, f) => k == key && func.name == *f,
1338 _ => false,
1339 })
1340 }
1341
1342 pub fn abi(&self, key: &WorldKey, func: &Function) -> Option<AbiVariant> {
1343 self.names.values().find_map(|m| match m {
1344 Export::WorldFunc(k, f, abi) if k == key && func.name == *f => Some(*abi),
1345 Export::InterfaceFunc(k, _, f, abi) if k == key && func.name == *f => Some(*abi),
1346 _ => None,
1347 })
1348 }
1349
1350 pub fn export_realloc_for(&self, key: &WorldKey, func: &str) -> Option<&str> {
1353 let _ = (key, func);
1357
1358 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeExportRealloc)) {
1359 return Some(name);
1360 }
1361 self.general_purpose_realloc()
1362 }
1363
1364 pub fn import_realloc_for(&self, interface: Option<InterfaceId>, func: &str) -> Option<&str> {
1367 let _ = (interface, func);
1371
1372 self.import_realloc_fallback()
1373 }
1374
1375 pub fn import_realloc_fallback(&self) -> Option<&str> {
1379 if let Some(name) = self.find(|m| matches!(m, Export::GeneralPurposeImportRealloc)) {
1380 return Some(name);
1381 }
1382 self.general_purpose_realloc()
1383 }
1384
1385 pub fn realloc_to_import_into_adapter(&self) -> Option<&str> {
1387 if let Some(name) = self.find(|m| matches!(m, Export::ReallocForAdapter)) {
1388 return Some(name);
1389 }
1390 self.general_purpose_realloc()
1391 }
1392
1393 fn general_purpose_realloc(&self) -> Option<&str> {
1394 self.find(|m| matches!(m, Export::GeneralPurposeRealloc))
1395 }
1396
1397 pub fn memory(&self) -> Option<&str> {
1399 self.find(|m| matches!(m, Export::Memory))
1400 }
1401
1402 pub fn indirect_function_table(&self) -> Option<&str> {
1404 self.find(|t| matches!(t, Export::IndirectFunctionTable))
1405 }
1406
1407 pub fn wasm_init_task(&self) -> Option<&str> {
1409 self.find(|t| matches!(t, Export::WasmInitTask))
1410 }
1411
1412 pub fn wasm_init_async_task(&self) -> Option<&str> {
1414 self.find(|t| matches!(t, Export::WasmInitAsyncTask))
1415 }
1416
1417 pub fn initialize(&self) -> Option<&str> {
1419 self.find(|m| matches!(m, Export::Initialize))
1420 }
1421
1422 pub fn resource_dtor(&self, ty: TypeId) -> Option<&str> {
1424 self.find(|m| match m {
1425 Export::ResourceDtor(t) => *t == ty,
1426 _ => false,
1427 })
1428 }
1429
1430 fn find(&self, f: impl Fn(&Export) -> bool) -> Option<&str> {
1433 let (name, _) = self.names.iter().filter(|(_, m)| f(m)).next()?;
1434 Some(name)
1435 }
1436
1437 pub fn iter(&self) -> impl Iterator<Item = (&str, &Export)> + '_ {
1439 self.names.iter().map(|(n, e)| (n.as_str(), e))
1440 }
1441
1442 fn validate(&self, encoder: &ComponentEncoder, exports: &IndexSet<WorldKey>) -> Result<()> {
1443 let resolve = &encoder.metadata.resolve;
1444 let world = encoder.metadata.world;
1445 if self
1448 .names
1449 .values()
1450 .filter(|m| matches!(m, Export::Memory))
1451 .count()
1452 > 1
1453 {
1454 bail!("cannot componentize module that exports multiple memories")
1455 }
1456
1457 for (name, export) in &self.names {
1459 match export {
1460 Export::WorldFunc(_, _, AbiVariant::GuestExportAsync) => {
1461 if !matches!(
1462 self.names.get(&format!("[callback]{name}")),
1463 Some(Export::WorldFuncCallback(_))
1464 ) {
1465 bail!("missing callback for `{name}`");
1466 }
1467 }
1468 Export::InterfaceFunc(_, _, _, AbiVariant::GuestExportAsync) => {
1469 if !matches!(
1470 self.names.get(&format!("[callback]{name}")),
1471 Some(Export::InterfaceFuncCallback(_, _))
1472 ) {
1473 bail!("missing callback for `{name}`");
1474 }
1475 }
1476 _ => {}
1477 }
1478 }
1479
1480 for export in exports {
1482 let require_interface_func = |interface: InterfaceId, name: &str| -> Result<()> {
1483 let result = self.find(|e| match e {
1484 Export::InterfaceFunc(_, id, s, _) => interface == *id && name == s,
1485 _ => false,
1486 });
1487 if result.is_some() {
1488 Ok(())
1489 } else {
1490 let export = resolve.name_world_key(export);
1491 bail!("failed to find export of interface `{export}` function `{name}`")
1492 }
1493 };
1494 let require_world_func = |name: &str| -> Result<()> {
1495 let result = self.find(|e| match e {
1496 Export::WorldFunc(_, s, _) => name == s,
1497 _ => false,
1498 });
1499 if result.is_some() {
1500 Ok(())
1501 } else {
1502 bail!("failed to find export of function `{name}`")
1503 }
1504 };
1505 match &resolve.worlds[world].exports[export] {
1506 WorldItem::Interface { id, .. } => {
1507 for (name, _) in resolve.interfaces[*id].functions.iter() {
1508 require_interface_func(*id, name)?;
1509 }
1510 }
1511 WorldItem::Function(f) => {
1512 require_world_func(&f.name)?;
1513 }
1514 WorldItem::Type { .. } => unreachable!(),
1515 }
1516 }
1517
1518 Ok(())
1519 }
1520}
1521
1522struct MaybeCancellable<T> {
1524 #[allow(unused)]
1525 inner: T,
1526 cancellable: bool,
1527}
1528
1529struct MaybeAsyncLowered<T> {
1531 inner: T,
1532 async_lowered: bool,
1533}
1534
1535struct PayloadLookupContext<'a> {
1538 resolve: &'a Resolve,
1539 world: &'a World,
1540 id: Option<InterfaceId>,
1541 import: bool,
1542 key: Option<WorldKey>,
1543}
1544
1545trait NameMangling {
1567 fn import_root(&self) -> &str;
1568 fn import_non_root_prefix(&self) -> &str;
1569 fn import_exported_intrinsic_prefix(&self) -> &str;
1570 fn export_memory(&self) -> &str;
1571 fn export_initialize(&self) -> &str;
1572 fn export_realloc(&self) -> &str;
1573 fn export_indirect_function_table(&self) -> Option<&str>;
1574 fn export_wasm_init_task(&self) -> Option<&str>;
1575 fn export_wasm_init_async_task(&self) -> Option<&str>;
1576 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1577 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1578 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1579 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1580 fn task_cancel(&self, name: &str) -> bool;
1581 fn backpressure_inc(&self, name: &str) -> bool;
1582 fn backpressure_dec(&self, name: &str) -> bool;
1583 fn waitable_set_new(&self, name: &str) -> bool;
1584 fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1585 fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)>;
1586 fn waitable_set_drop(&self, name: &str) -> bool;
1587 fn waitable_join(&self, name: &str) -> bool;
1588 fn subtask_drop(&self, name: &str) -> bool;
1589 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>>;
1590 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1591 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1592 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str>;
1593 fn error_context_new(&self, name: &str) -> Option<StringEncoding>;
1594 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding>;
1595 fn error_context_drop(&self, name: &str) -> bool;
1596 fn context_get(&self, name: &str) -> Option<(ValType, u32)>;
1597 fn context_set(&self, name: &str) -> Option<(ValType, u32)>;
1598 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1599 fn future_write(
1600 &self,
1601 lookup_context: &PayloadLookupContext,
1602 name: &str,
1603 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1604 fn future_read(
1605 &self,
1606 lookup_context: &PayloadLookupContext,
1607 name: &str,
1608 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1609 fn future_cancel_write(
1610 &self,
1611 lookup_context: &PayloadLookupContext,
1612 name: &str,
1613 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1614 fn future_cancel_read(
1615 &self,
1616 lookup_context: &PayloadLookupContext,
1617 name: &str,
1618 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1619 fn future_drop_writable(
1620 &self,
1621 lookup_context: &PayloadLookupContext,
1622 name: &str,
1623 ) -> Option<PayloadInfo>;
1624 fn future_drop_readable(
1625 &self,
1626 lookup_context: &PayloadLookupContext,
1627 name: &str,
1628 ) -> Option<PayloadInfo>;
1629 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo>;
1630 fn stream_write(
1631 &self,
1632 lookup_context: &PayloadLookupContext,
1633 name: &str,
1634 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1635 fn stream_read(
1636 &self,
1637 lookup_context: &PayloadLookupContext,
1638 name: &str,
1639 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1640 fn stream_cancel_write(
1641 &self,
1642 lookup_context: &PayloadLookupContext,
1643 name: &str,
1644 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1645 fn stream_cancel_read(
1646 &self,
1647 lookup_context: &PayloadLookupContext,
1648 name: &str,
1649 ) -> Option<MaybeAsyncLowered<PayloadInfo>>;
1650 fn stream_drop_writable(
1651 &self,
1652 lookup_context: &PayloadLookupContext,
1653 name: &str,
1654 ) -> Option<PayloadInfo>;
1655 fn stream_drop_readable(
1656 &self,
1657 lookup_context: &PayloadLookupContext,
1658 name: &str,
1659 ) -> Option<PayloadInfo>;
1660 fn thread_index(&self, name: &str) -> bool;
1661 fn thread_new_indirect(&self, name: &str) -> bool;
1662 fn thread_resume_later(&self, name: &str) -> bool;
1663 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>>;
1664 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>>;
1665 fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1666 fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>>;
1667 fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1668 fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>>;
1669 fn module_to_interface(
1670 &self,
1671 module: &str,
1672 resolve: &Resolve,
1673 items: &IndexMap<WorldKey, WorldItem>,
1674 ) -> Result<(WorldKey, InterfaceId)>;
1675 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str>;
1676 fn match_wit_export<'a>(
1677 &self,
1678 export_name: &str,
1679 resolve: &'a Resolve,
1680 world: WorldId,
1681 exports: &'a IndexSet<WorldKey>,
1682 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)>;
1683 fn match_wit_resource_dtor<'a>(
1684 &self,
1685 export_name: &str,
1686 resolve: &'a Resolve,
1687 world: WorldId,
1688 exports: &'a IndexSet<WorldKey>,
1689 ) -> Option<TypeId>;
1690 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1691 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant);
1692 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import>;
1693}
1694
1695struct Standard;
1698
1699const STANDARD: &'static dyn NameMangling = &Standard;
1700
1701impl NameMangling for Standard {
1702 fn import_root(&self) -> &str {
1703 ""
1704 }
1705 fn import_non_root_prefix(&self) -> &str {
1706 "|"
1707 }
1708 fn import_exported_intrinsic_prefix(&self) -> &str {
1709 "_ex_"
1710 }
1711 fn export_memory(&self) -> &str {
1712 "_memory"
1713 }
1714 fn export_initialize(&self) -> &str {
1715 "_initialize"
1716 }
1717 fn export_realloc(&self) -> &str {
1718 "_realloc"
1719 }
1720 fn export_indirect_function_table(&self) -> Option<&str> {
1721 None
1722 }
1723 fn export_wasm_init_task(&self) -> Option<&str> {
1724 None
1725 }
1726 fn export_wasm_init_async_task(&self) -> Option<&str> {
1727 None
1728 }
1729 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1730 name.strip_suffix("_drop")
1731 }
1732 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1733 name.strip_suffix("_new")
1734 }
1735 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
1736 name.strip_suffix("_rep")
1737 }
1738 fn task_return_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1739 None
1740 }
1741 fn task_cancel(&self, _name: &str) -> bool {
1742 false
1743 }
1744 fn backpressure_inc(&self, _name: &str) -> bool {
1745 false
1746 }
1747 fn backpressure_dec(&self, _name: &str) -> bool {
1748 false
1749 }
1750 fn waitable_set_new(&self, _name: &str) -> bool {
1751 false
1752 }
1753 fn waitable_set_wait(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1754 None
1755 }
1756 fn waitable_set_poll(&self, _name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
1757 None
1758 }
1759 fn waitable_set_drop(&self, _name: &str) -> bool {
1760 false
1761 }
1762 fn waitable_join(&self, _name: &str) -> bool {
1763 false
1764 }
1765 fn subtask_drop(&self, _name: &str) -> bool {
1766 false
1767 }
1768 fn subtask_cancel(&self, _name: &str) -> Option<MaybeAsyncLowered<()>> {
1769 None
1770 }
1771 fn async_lift_callback_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1772 None
1773 }
1774 fn async_lift_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1775 None
1776 }
1777 fn async_lift_stackful_name<'a>(&self, _name: &'a str) -> Option<&'a str> {
1778 None
1779 }
1780 fn error_context_new(&self, _name: &str) -> Option<StringEncoding> {
1781 None
1782 }
1783 fn error_context_debug_message(&self, _name: &str) -> Option<StringEncoding> {
1784 None
1785 }
1786 fn error_context_drop(&self, _name: &str) -> bool {
1787 false
1788 }
1789 fn context_get(&self, _name: &str) -> Option<(ValType, u32)> {
1790 None
1791 }
1792 fn context_set(&self, _name: &str) -> Option<(ValType, u32)> {
1793 None
1794 }
1795 fn thread_index(&self, _name: &str) -> bool {
1796 false
1797 }
1798 fn thread_new_indirect(&self, _name: &str) -> bool {
1799 false
1800 }
1801 fn thread_resume_later(&self, _name: &str) -> bool {
1802 false
1803 }
1804 fn thread_suspend(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1805 None
1806 }
1807 fn thread_yield(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1808 None
1809 }
1810 fn thread_suspend_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1811 None
1812 }
1813 fn thread_yield_then_resume(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1814 None
1815 }
1816 fn thread_suspend_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1817 None
1818 }
1819 fn thread_yield_then_promote(&self, _name: &str) -> Option<MaybeCancellable<()>> {
1820 None
1821 }
1822 fn future_new(
1823 &self,
1824 _lookup_context: &PayloadLookupContext,
1825 _name: &str,
1826 ) -> Option<PayloadInfo> {
1827 None
1828 }
1829 fn future_write(
1830 &self,
1831 _lookup_context: &PayloadLookupContext,
1832 _name: &str,
1833 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1834 None
1835 }
1836 fn future_read(
1837 &self,
1838 _lookup_context: &PayloadLookupContext,
1839 _name: &str,
1840 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1841 None
1842 }
1843 fn future_cancel_write(
1844 &self,
1845 _lookup_context: &PayloadLookupContext,
1846 _name: &str,
1847 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1848 None
1849 }
1850 fn future_cancel_read(
1851 &self,
1852 _lookup_context: &PayloadLookupContext,
1853 _name: &str,
1854 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1855 None
1856 }
1857 fn future_drop_writable(
1858 &self,
1859 _lookup_context: &PayloadLookupContext,
1860 _name: &str,
1861 ) -> Option<PayloadInfo> {
1862 None
1863 }
1864 fn future_drop_readable(
1865 &self,
1866 _lookup_context: &PayloadLookupContext,
1867 _name: &str,
1868 ) -> Option<PayloadInfo> {
1869 None
1870 }
1871 fn stream_new(
1872 &self,
1873 _lookup_context: &PayloadLookupContext,
1874 _name: &str,
1875 ) -> Option<PayloadInfo> {
1876 None
1877 }
1878 fn stream_write(
1879 &self,
1880 _lookup_context: &PayloadLookupContext,
1881 _name: &str,
1882 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1883 None
1884 }
1885 fn stream_read(
1886 &self,
1887 _lookup_context: &PayloadLookupContext,
1888 _name: &str,
1889 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1890 None
1891 }
1892 fn stream_cancel_write(
1893 &self,
1894 _lookup_context: &PayloadLookupContext,
1895 _name: &str,
1896 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1897 None
1898 }
1899 fn stream_cancel_read(
1900 &self,
1901 _lookup_context: &PayloadLookupContext,
1902 _name: &str,
1903 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
1904 None
1905 }
1906 fn stream_drop_writable(
1907 &self,
1908 _lookup_context: &PayloadLookupContext,
1909 _name: &str,
1910 ) -> Option<PayloadInfo> {
1911 None
1912 }
1913 fn stream_drop_readable(
1914 &self,
1915 _lookup_context: &PayloadLookupContext,
1916 _name: &str,
1917 ) -> Option<PayloadInfo> {
1918 None
1919 }
1920 fn module_to_interface(
1921 &self,
1922 interface: &str,
1923 resolve: &Resolve,
1924 items: &IndexMap<WorldKey, WorldItem>,
1925 ) -> Result<(WorldKey, InterfaceId)> {
1926 for (key, item) in items.iter() {
1927 let id = match key {
1928 WorldKey::Name(name) => match item {
1930 WorldItem::Interface { id, .. } if name == interface => *id,
1931 _ => continue,
1932 },
1933 WorldKey::Interface(id) => {
1935 if resolve.canonicalized_id_of(*id).as_deref() != Some(interface) {
1936 continue;
1937 }
1938 *id
1939 }
1940 };
1941 return Ok((key.clone(), id));
1942 }
1943 bail!("failed to find world item corresponding to interface `{interface}`")
1944 }
1945 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
1946 name.strip_suffix("_post")
1947 }
1948 fn match_wit_export<'a>(
1949 &self,
1950 export_name: &str,
1951 resolve: &'a Resolve,
1952 world: WorldId,
1953 exports: &'a IndexSet<WorldKey>,
1954 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
1955 if let Some(world_export_name) = export_name.strip_prefix("||") {
1956 let key = exports.get(&WorldKey::Name(world_export_name.to_string()))?;
1957 match &resolve.worlds[world].exports[key] {
1958 WorldItem::Function(f) => return Some((key, None, f)),
1959 _ => return None,
1960 }
1961 }
1962
1963 let (key, id, func_name) =
1964 self.match_wit_interface(export_name, resolve, world, exports)?;
1965 let func = resolve.interfaces[id].functions.get(func_name)?;
1966 Some((key, Some(id), func))
1967 }
1968
1969 fn match_wit_resource_dtor<'a>(
1970 &self,
1971 export_name: &str,
1972 resolve: &'a Resolve,
1973 world: WorldId,
1974 exports: &'a IndexSet<WorldKey>,
1975 ) -> Option<TypeId> {
1976 let (_key, id, name) =
1977 self.match_wit_interface(export_name.strip_suffix("_dtor")?, resolve, world, exports)?;
1978 let ty = *resolve.interfaces[id].types.get(name)?;
1979 match resolve.types[ty].kind {
1980 TypeDefKind::Resource => Some(ty),
1981 _ => None,
1982 }
1983 }
1984
1985 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1986 (name, AbiVariant::GuestImport)
1987 }
1988 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
1989 (name, AbiVariant::GuestImport)
1990 }
1991 fn env_import(&self, _name: &str, _ty: &FuncType) -> Option<Import> {
1992 None
1993 }
1994}
1995
1996impl Standard {
1997 fn match_wit_interface<'a, 'b>(
1998 &self,
1999 export_name: &'b str,
2000 resolve: &'a Resolve,
2001 world: WorldId,
2002 exports: &'a IndexSet<WorldKey>,
2003 ) -> Option<(&'a WorldKey, InterfaceId, &'b str)> {
2004 let world = &resolve.worlds[world];
2005 let export_name = export_name.strip_prefix("|")?;
2006
2007 for export in exports {
2008 let id = match &world.exports[export] {
2009 WorldItem::Interface { id, .. } => *id,
2010 WorldItem::Function(_) => continue,
2011 WorldItem::Type { .. } => unreachable!(),
2012 };
2013 let remaining = match export {
2014 WorldKey::Name(name) => export_name.strip_prefix(name),
2015 WorldKey::Interface(_) => {
2016 let prefix = resolve.canonicalized_id_of(id).unwrap();
2017 export_name.strip_prefix(&prefix)
2018 }
2019 };
2020 let item_name = match remaining.and_then(|s| s.strip_prefix("|")) {
2021 Some(name) => name,
2022 None => continue,
2023 };
2024 return Some((export, id, item_name));
2025 }
2026
2027 None
2028 }
2029}
2030
2031struct Legacy;
2034
2035const LEGACY: &'static dyn NameMangling = &Legacy;
2036
2037impl Legacy {
2038 fn prefixed_payload(
2044 &self,
2045 lookup_context: &PayloadLookupContext,
2046 name: &str,
2047 prefix: &str,
2048 ) -> Option<PayloadInfo> {
2049 let (index_or_unit, func_name) = prefixed_intrinsic(name, prefix)?;
2052 let ty = match index_or_unit {
2053 "unit" => {
2054 if name.starts_with("[future") {
2055 PayloadType::UnitFuture
2056 } else if name.starts_with("[stream") {
2057 PayloadType::UnitStream
2058 } else {
2059 unreachable!()
2060 }
2061 }
2062 other => {
2063 let type_index = other.parse::<u32>().ok()? as usize;
2067
2068 let function = get_function(
2073 lookup_context.resolve,
2074 lookup_context.world,
2075 func_name,
2076 lookup_context.id,
2077 lookup_context.import,
2078 )
2079 .ok()?;
2080 PayloadType::Type {
2081 id: *function
2082 .find_futures_and_streams(lookup_context.resolve)
2083 .get(type_index)?,
2084 function: function.name.clone(),
2085 }
2086 }
2087 };
2088
2089 Some(PayloadInfo {
2091 name: name.to_string(),
2092 ty,
2093 key: lookup_context
2094 .key
2095 .clone()
2096 .unwrap_or_else(|| WorldKey::Name(name.to_string())),
2097 interface: lookup_context.id,
2098 imported: lookup_context.import,
2099 })
2100 }
2101
2102 fn maybe_async_lowered_payload(
2103 &self,
2104 lookup_context: &PayloadLookupContext,
2105 name: &str,
2106 prefix: &str,
2107 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2108 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2109 let payload = self.prefixed_payload(lookup_context, clean_name, prefix)?;
2110 Some(MaybeAsyncLowered {
2111 inner: payload,
2112 async_lowered,
2113 })
2114 }
2115
2116 fn strip_async_lowered_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2117 name.strip_prefix("[async-lower]")
2118 .map_or((false, name), |s| (true, s))
2119 }
2120 fn match_with_async_lowered_prefix(
2121 &self,
2122 name: &str,
2123 expected: &str,
2124 ) -> Option<MaybeAsyncLowered<()>> {
2125 let (async_lowered, clean_name) = self.strip_async_lowered_prefix(name);
2126 if clean_name == expected {
2127 Some(MaybeAsyncLowered {
2128 inner: (),
2129 async_lowered,
2130 })
2131 } else {
2132 None
2133 }
2134 }
2135 fn strip_cancellable_prefix<'a>(&self, name: &'a str) -> (bool, &'a str) {
2136 name.strip_prefix("[cancellable]")
2137 .map_or((false, name), |s| (true, s))
2138 }
2139 fn match_with_cancellable_prefix(
2140 &self,
2141 name: &str,
2142 expected: &str,
2143 ) -> Option<MaybeCancellable<()>> {
2144 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2145 if clean_name == expected {
2146 Some(MaybeCancellable {
2147 inner: (),
2148 cancellable,
2149 })
2150 } else {
2151 None
2152 }
2153 }
2154
2155 fn match_with_optional_type_suffix(name: &str, match_prefix: &str) -> Option<ValType> {
2159 let tail = name.strip_prefix(match_prefix)?.strip_suffix(']')?;
2160 if tail.is_empty() {
2161 Some(ValType::I32)
2162 } else {
2163 match tail.strip_prefix('-')? {
2164 "i32" => Some(ValType::I32),
2165 "i64" => Some(ValType::I64),
2166 _ => None,
2168 }
2169 }
2170 }
2171}
2172
2173impl NameMangling for Legacy {
2174 fn import_root(&self) -> &str {
2175 "$root"
2176 }
2177 fn import_non_root_prefix(&self) -> &str {
2178 ""
2179 }
2180 fn import_exported_intrinsic_prefix(&self) -> &str {
2181 "[export]"
2182 }
2183 fn export_memory(&self) -> &str {
2184 "memory"
2185 }
2186 fn export_initialize(&self) -> &str {
2187 "_initialize"
2188 }
2189 fn export_realloc(&self) -> &str {
2190 "cabi_realloc"
2191 }
2192 fn export_indirect_function_table(&self) -> Option<&str> {
2193 Some("__indirect_function_table")
2194 }
2195 fn export_wasm_init_task(&self) -> Option<&str> {
2196 Some("__wasm_init_task")
2197 }
2198 fn export_wasm_init_async_task(&self) -> Option<&str> {
2199 Some("__wasm_init_async_task")
2200 }
2201 fn resource_drop_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2202 name.strip_prefix("[resource-drop]")
2203 }
2204 fn resource_new_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2205 name.strip_prefix("[resource-new]")
2206 }
2207 fn resource_rep_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2208 name.strip_prefix("[resource-rep]")
2209 }
2210 fn task_return_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2211 name.strip_prefix("[task-return]")
2212 }
2213 fn task_cancel(&self, name: &str) -> bool {
2214 name == "[task-cancel]"
2215 }
2216 fn backpressure_inc(&self, name: &str) -> bool {
2217 name == "[backpressure-inc]"
2218 }
2219 fn backpressure_dec(&self, name: &str) -> bool {
2220 name == "[backpressure-dec]"
2221 }
2222 fn waitable_set_new(&self, name: &str) -> bool {
2223 name == "[waitable-set-new]"
2224 }
2225 fn waitable_set_wait(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2226 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2227 let mb_cancellable = MaybeCancellable {
2228 inner: (),
2229 cancellable,
2230 };
2231 let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-wait")?;
2232 Some((mb_cancellable, result_ty))
2233 }
2234 fn waitable_set_poll(&self, name: &str) -> Option<(MaybeCancellable<()>, ValType)> {
2235 let (cancellable, clean_name) = self.strip_cancellable_prefix(name);
2236 let mb_cancellable = MaybeCancellable {
2237 inner: (),
2238 cancellable,
2239 };
2240 let result_ty = Legacy::match_with_optional_type_suffix(clean_name, "[waitable-set-poll")?;
2241 Some((mb_cancellable, result_ty))
2242 }
2243 fn waitable_set_drop(&self, name: &str) -> bool {
2244 name == "[waitable-set-drop]"
2245 }
2246 fn waitable_join(&self, name: &str) -> bool {
2247 name == "[waitable-join]"
2248 }
2249 fn subtask_drop(&self, name: &str) -> bool {
2250 name == "[subtask-drop]"
2251 }
2252 fn subtask_cancel(&self, name: &str) -> Option<MaybeAsyncLowered<()>> {
2253 self.match_with_async_lowered_prefix(name, "[subtask-cancel]")
2254 }
2255 fn async_lift_callback_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2256 name.strip_prefix("[callback][async-lift]")
2257 }
2258 fn async_lift_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2259 name.strip_prefix("[async-lift]")
2260 }
2261 fn async_lift_stackful_name<'a>(&self, name: &'a str) -> Option<&'a str> {
2262 name.strip_prefix("[async-lift-stackful]")
2263 }
2264 fn error_context_new(&self, name: &str) -> Option<StringEncoding> {
2265 match name {
2266 "[error-context-new-utf8]" => Some(StringEncoding::UTF8),
2267 "[error-context-new-utf16]" => Some(StringEncoding::UTF16),
2268 "[error-context-new-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2269 _ => None,
2270 }
2271 }
2272 fn error_context_debug_message(&self, name: &str) -> Option<StringEncoding> {
2273 match name {
2274 "[error-context-debug-message-utf8]" => Some(StringEncoding::UTF8),
2275 "[error-context-debug-message-utf16]" => Some(StringEncoding::UTF16),
2276 "[error-context-debug-message-latin1+utf16]" => Some(StringEncoding::CompactUTF16),
2277 _ => None,
2278 }
2279 }
2280 fn error_context_drop(&self, name: &str) -> bool {
2281 name == "[error-context-drop]"
2282 }
2283 fn context_get(&self, name: &str) -> Option<(ValType, u32)> {
2284 parse_context_name(name, "[context-get-")
2285 }
2286 fn context_set(&self, name: &str) -> Option<(ValType, u32)> {
2287 parse_context_name(name, "[context-set-")
2288 }
2289 fn thread_index(&self, name: &str) -> bool {
2290 name == "[thread-index]"
2291 }
2292 fn thread_new_indirect(&self, name: &str) -> bool {
2293 name == "[thread-new-indirect-v0]"
2295 }
2296 fn thread_resume_later(&self, name: &str) -> bool {
2297 name == "[thread-resume-later]"
2298 }
2299 fn thread_suspend(&self, name: &str) -> Option<MaybeCancellable<()>> {
2300 self.match_with_cancellable_prefix(name, "[thread-suspend]")
2301 }
2302 fn thread_yield(&self, name: &str) -> Option<MaybeCancellable<()>> {
2303 self.match_with_cancellable_prefix(name, "[thread-yield]")
2304 }
2305 fn thread_suspend_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2306 self.match_with_cancellable_prefix(name, "[thread-suspend-then-resume]")
2307 }
2308 fn thread_yield_then_resume(&self, name: &str) -> Option<MaybeCancellable<()>> {
2309 self.match_with_cancellable_prefix(name, "[thread-yield-then-resume]")
2310 }
2311 fn thread_suspend_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2312 self.match_with_cancellable_prefix(name, "[thread-suspend-then-promote]")
2313 }
2314 fn thread_yield_then_promote(&self, name: &str) -> Option<MaybeCancellable<()>> {
2315 self.match_with_cancellable_prefix(name, "[thread-yield-then-promote]")
2316 }
2317 fn future_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2318 self.prefixed_payload(lookup_context, name, "[future-new-")
2319 }
2320 fn future_write(
2321 &self,
2322 lookup_context: &PayloadLookupContext,
2323 name: &str,
2324 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2325 self.maybe_async_lowered_payload(lookup_context, name, "[future-write-")
2326 }
2327 fn future_read(
2328 &self,
2329 lookup_context: &PayloadLookupContext,
2330 name: &str,
2331 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2332 self.maybe_async_lowered_payload(lookup_context, name, "[future-read-")
2333 }
2334 fn future_cancel_write(
2335 &self,
2336 lookup_context: &PayloadLookupContext,
2337 name: &str,
2338 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2339 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-write-")
2340 }
2341 fn future_cancel_read(
2342 &self,
2343 lookup_context: &PayloadLookupContext,
2344 name: &str,
2345 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2346 self.maybe_async_lowered_payload(lookup_context, name, "[future-cancel-read-")
2347 }
2348 fn future_drop_writable(
2349 &self,
2350 lookup_context: &PayloadLookupContext,
2351 name: &str,
2352 ) -> Option<PayloadInfo> {
2353 self.prefixed_payload(lookup_context, name, "[future-drop-writable-")
2354 }
2355 fn future_drop_readable(
2356 &self,
2357 lookup_context: &PayloadLookupContext,
2358 name: &str,
2359 ) -> Option<PayloadInfo> {
2360 self.prefixed_payload(lookup_context, name, "[future-drop-readable-")
2361 }
2362 fn stream_new(&self, lookup_context: &PayloadLookupContext, name: &str) -> Option<PayloadInfo> {
2363 self.prefixed_payload(lookup_context, name, "[stream-new-")
2364 }
2365 fn stream_write(
2366 &self,
2367 lookup_context: &PayloadLookupContext,
2368 name: &str,
2369 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2370 self.maybe_async_lowered_payload(lookup_context, name, "[stream-write-")
2371 }
2372 fn stream_read(
2373 &self,
2374 lookup_context: &PayloadLookupContext,
2375 name: &str,
2376 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2377 self.maybe_async_lowered_payload(lookup_context, name, "[stream-read-")
2378 }
2379 fn stream_cancel_write(
2380 &self,
2381 lookup_context: &PayloadLookupContext,
2382 name: &str,
2383 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2384 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-write-")
2385 }
2386 fn stream_cancel_read(
2387 &self,
2388 lookup_context: &PayloadLookupContext,
2389 name: &str,
2390 ) -> Option<MaybeAsyncLowered<PayloadInfo>> {
2391 self.maybe_async_lowered_payload(lookup_context, name, "[stream-cancel-read-")
2392 }
2393 fn stream_drop_writable(
2394 &self,
2395 lookup_context: &PayloadLookupContext,
2396 name: &str,
2397 ) -> Option<PayloadInfo> {
2398 self.prefixed_payload(lookup_context, name, "[stream-drop-writable-")
2399 }
2400 fn stream_drop_readable(
2401 &self,
2402 lookup_context: &PayloadLookupContext,
2403 name: &str,
2404 ) -> Option<PayloadInfo> {
2405 self.prefixed_payload(lookup_context, name, "[stream-drop-readable-")
2406 }
2407 fn module_to_interface(
2408 &self,
2409 module: &str,
2410 resolve: &Resolve,
2411 items: &IndexMap<WorldKey, WorldItem>,
2412 ) -> Result<(WorldKey, InterfaceId)> {
2413 let bare_name = WorldKey::Name(module.to_string());
2415 if let Some(WorldItem::Interface { id, .. }) = items.get(&bare_name) {
2416 return Ok((bare_name, *id));
2417 }
2418
2419 let kebab_name = ComponentName::new(module, 0);
2425 let name = match kebab_name.as_ref().map(|k| k.kind()) {
2426 Ok(ComponentNameKind::Interface(name)) => name,
2427 _ => bail!("module requires an import interface named `{module}`"),
2428 };
2429
2430 let version = name.version(None)?;
2434
2435 let pkgname = PackageName {
2437 namespace: name.namespace().to_string(),
2438 name: name.package().to_string(),
2439 version: version.clone(),
2440 };
2441 if let Some(pkg) = resolve.package_names.get(&pkgname) {
2442 if let Some(id) = resolve.packages[*pkg]
2443 .interfaces
2444 .get(name.interface().as_str())
2445 {
2446 let key = WorldKey::Interface(*id);
2449 if items.contains_key(&key) {
2450 return Ok((key, *id));
2451 }
2452
2453 for k in items.keys() {
2459 let i = match *k {
2460 WorldKey::Interface(id) => id,
2461 WorldKey::Name(_) => continue,
2462 };
2463 if resolve.interfaces[i].clone_of == Some(*id) {
2464 return Ok((WorldKey::Interface(i), i));
2465 }
2466 }
2467 }
2468 }
2469
2470 for (key, _) in items {
2475 let id = match key {
2476 WorldKey::Interface(id) => *id,
2477 WorldKey::Name(_) => continue,
2478 };
2479 let interface = &resolve.interfaces[id];
2481 if interface.name.as_ref().unwrap() != name.interface().as_str() {
2482 continue;
2483 }
2484
2485 let pkg = &resolve.packages[interface.package.unwrap()];
2487 if pkg.name.namespace != pkgname.namespace || pkg.name.name != pkgname.name {
2488 continue;
2489 }
2490
2491 let module_version = match &version {
2492 Some(version) => version,
2493 None => continue,
2494 };
2495 let pkg_version = match &pkg.name.version {
2496 Some(version) => version,
2497 None => continue,
2498 };
2499
2500 let module_compat = PackageName::version_compat_track(&module_version);
2502 let pkg_compat = PackageName::version_compat_track(pkg_version);
2503 if module_compat == pkg_compat {
2504 return Ok((key.clone(), id));
2505 }
2506 }
2507
2508 bail!("module requires an import interface named `{module}`")
2509 }
2510 fn strip_post_return<'a>(&self, name: &'a str) -> Option<&'a str> {
2511 name.strip_prefix("cabi_post_")
2512 }
2513 fn match_wit_export<'a>(
2514 &self,
2515 export_name: &str,
2516 resolve: &'a Resolve,
2517 world: WorldId,
2518 exports: &'a IndexSet<WorldKey>,
2519 ) -> Option<(&'a WorldKey, Option<InterfaceId>, &'a Function)> {
2520 let world = &resolve.worlds[world];
2521 for name in exports {
2522 match &world.exports[name] {
2523 WorldItem::Function(f) => {
2524 if f.legacy_core_export_name(None) == export_name {
2525 return Some((name, None, f));
2526 }
2527 }
2528 WorldItem::Interface { id, .. } => {
2529 let string = resolve.name_world_key(name);
2530 for (_, func) in resolve.interfaces[*id].functions.iter() {
2531 if func.legacy_core_export_name(Some(&string)) == export_name {
2532 return Some((name, Some(*id), func));
2533 }
2534 }
2535 }
2536
2537 WorldItem::Type { .. } => unreachable!(),
2538 }
2539 }
2540
2541 None
2542 }
2543
2544 fn match_wit_resource_dtor<'a>(
2545 &self,
2546 export_name: &str,
2547 resolve: &'a Resolve,
2548 world: WorldId,
2549 exports: &'a IndexSet<WorldKey>,
2550 ) -> Option<TypeId> {
2551 let world = &resolve.worlds[world];
2552 for name in exports {
2553 let id = match &world.exports[name] {
2554 WorldItem::Interface { id, .. } => *id,
2555 WorldItem::Function(_) => continue,
2556 WorldItem::Type { .. } => unreachable!(),
2557 };
2558 let name = resolve.name_world_key(name);
2559 let resource = match export_name
2560 .strip_prefix(&name)
2561 .and_then(|s| s.strip_prefix("#[dtor]"))
2562 .and_then(|r| resolve.interfaces[id].types.get(r))
2563 {
2564 Some(id) => *id,
2565 None => continue,
2566 };
2567
2568 match resolve.types[resource].kind {
2569 TypeDefKind::Resource => {}
2570 _ => continue,
2571 }
2572
2573 return Some(resource);
2574 }
2575
2576 None
2577 }
2578
2579 fn world_key_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2580 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2581 (
2582 name,
2583 if async_abi {
2584 AbiVariant::GuestImportAsync
2585 } else {
2586 AbiVariant::GuestImport
2587 },
2588 )
2589 }
2590 fn interface_function_name_and_abi<'a>(&self, name: &'a str) -> (&'a str, AbiVariant) {
2591 let (async_abi, name) = self.strip_async_lowered_prefix(name);
2592 (
2593 name,
2594 if async_abi {
2595 AbiVariant::GuestImportAsync
2596 } else {
2597 AbiVariant::GuestImport
2598 },
2599 )
2600 }
2601 fn env_import(&self, name: &str, ty: &FuncType) -> Option<Import> {
2602 match name {
2603 "__wasm_get_stack_pointer" => {
2604 let ty = *ty.results().get(0)?;
2605 Some(Import::ContextGet { ty, slot: 0 })
2606 }
2607 "__wasm_set_stack_pointer" => {
2608 let ty = *ty.params().get(0)?;
2609 Some(Import::ContextSet { ty, slot: 0 })
2610 }
2611 "__wasm_get_tls_base" => {
2612 let ty = *ty.results().get(0)?;
2613 Some(Import::ContextGet { ty, slot: 1 })
2614 }
2615 "__wasm_set_tls_base" => {
2616 let ty = *ty.params().get(0)?;
2617 Some(Import::ContextSet { ty, slot: 1 })
2618 }
2619 _ => None,
2620 }
2621 }
2622}
2623
2624pub fn validate_module(
2636 encoder: &ComponentEncoder,
2637 bytes: &[u8],
2638 import_map: Option<&ModuleImportMap>,
2639) -> Result<ValidatedModule> {
2640 ValidatedModule::new(
2641 encoder,
2642 bytes,
2643 &encoder.main_module_exports,
2644 import_map,
2645 None,
2646 )
2647}
2648
2649pub fn validate_adapter_module(
2667 encoder: &ComponentEncoder,
2668 bytes: &[u8],
2669 required_by_import: &IndexMap<String, FuncType>,
2670 exports: &IndexSet<WorldKey>,
2671 library_info: Option<&LibraryInfo>,
2672) -> Result<ValidatedModule> {
2673 let ret = ValidatedModule::new(encoder, bytes, exports, None, library_info)?;
2674
2675 for (name, required_ty) in required_by_import {
2676 let actual = match ret.exports.raw_exports.get(name) {
2677 Some(ty) => ty,
2678 None => return Err(AdapterModuleDidNotExport(name.clone()).into()),
2679 };
2680 validate_func_sig(name, required_ty, &actual)?;
2681 }
2682
2683 Ok(ret)
2684}
2685
2686#[derive(Debug, Clone)]
2693pub struct AdapterModuleDidNotExport(String);
2694
2695impl fmt::Display for AdapterModuleDidNotExport {
2696 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2697 write!(f, "adapter module did not export `{}`", self.0)
2698 }
2699}
2700
2701impl std::error::Error for AdapterModuleDidNotExport {}
2702
2703fn resource_test_for_interface<'a>(
2704 resolve: &'a Resolve,
2705 id: InterfaceId,
2706) -> impl Fn(&str) -> Option<TypeId> + 'a {
2707 let interface = &resolve.interfaces[id];
2708 move |name: &str| {
2709 let ty = match interface.types.get(name) {
2710 Some(ty) => *ty,
2711 None => return None,
2712 };
2713 if matches!(resolve.types[ty].kind, TypeDefKind::Resource) {
2714 Some(ty)
2715 } else {
2716 None
2717 }
2718 }
2719}
2720
2721fn resource_test_for_world<'a>(
2722 resolve: &'a Resolve,
2723 id: WorldId,
2724) -> impl Fn(&str) -> Option<TypeId> + 'a {
2725 let world = &resolve.worlds[id];
2726 move |name: &str| match world.imports.get(&WorldKey::Name(name.to_string()))? {
2727 WorldItem::Type { id, .. } => {
2728 if matches!(resolve.types[*id].kind, TypeDefKind::Resource) {
2729 Some(*id)
2730 } else {
2731 None
2732 }
2733 }
2734 _ => None,
2735 }
2736}
2737
2738fn validate_func(
2739 resolve: &Resolve,
2740 ty: &wasmparser::FuncType,
2741 func: &Function,
2742 abi: AbiVariant,
2743) -> Result<()> {
2744 validate_func_sig(
2745 &func.name,
2746 &wasm_sig_to_func_type(resolve.wasm_signature(abi, func)),
2747 ty,
2748 )
2749}
2750
2751fn validate_post_return(
2752 resolve: &Resolve,
2753 ty: &wasmparser::FuncType,
2754 func: &Function,
2755) -> Result<()> {
2756 let mut sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
2762 sig.params = mem::take(&mut sig.results);
2763 validate_func_sig(
2764 &format!("{} post-return", func.name),
2765 &wasm_sig_to_func_type(sig),
2766 ty,
2767 )
2768}
2769
2770fn validate_func_sig(name: &str, expected: &FuncType, ty: &wasmparser::FuncType) -> Result<()> {
2771 if ty != expected {
2772 bail!(
2773 "type mismatch for function `{}`: expected `{:?} -> {:?}` but found `{:?} -> {:?}`",
2774 name,
2775 expected.params(),
2776 expected.results(),
2777 ty.params(),
2778 ty.results()
2779 );
2780 }
2781
2782 Ok(())
2783}
2784
2785fn prefixed_intrinsic<'a>(name: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> {
2787 assert!(prefix.starts_with("["));
2788 assert!(prefix.ends_with("-"));
2789 let suffix = name.strip_prefix(prefix)?;
2790 let index = suffix.find(']')?;
2791 let rest = &suffix[index + 1..];
2792 Some((&suffix[..index], rest))
2793}
2794
2795fn parse_context_name(name: &str, prefix: &str) -> Option<(ValType, u32)> {
2801 let (suffix, rest) = prefixed_intrinsic(name, prefix)?;
2802 if !rest.is_empty() {
2803 return None;
2804 }
2805 let (ty, slot) = match suffix.split_once('-') {
2806 Some(("i64", slot)) => (ValType::I64, slot),
2807 Some(("i32", slot)) => (ValType::I32, slot),
2808 _ => (ValType::I32, suffix),
2809 };
2810 let slot = slot.parse().ok()?;
2811 Some((ty, slot))
2812}
2813
2814fn get_function<'a>(
2815 resolve: &'a Resolve,
2816 world: &'a World,
2817 name: &str,
2818 interface: Option<InterfaceId>,
2819 imported: bool,
2820) -> Result<&'a Function> {
2821 let function = if let Some(id) = interface {
2822 return resolve.interfaces[id]
2823 .functions
2824 .get(name)
2825 .ok_or_else(|| anyhow!("no export `{name}` found"));
2826 } else if imported {
2827 world.imports.get(&WorldKey::Name(name.to_string()))
2828 } else {
2829 world.exports.get(&WorldKey::Name(name.to_string()))
2830 };
2831 let Some(WorldItem::Function(function)) = function else {
2832 bail!("no export `{name}` found");
2833 };
2834 Ok(function)
2835}