1#![deny(warnings)]
2#![forbid(unsafe_code)]
3#![warn(missing_docs)]
4#![warn(clippy::missing_docs_in_private_items)]
5
6mod abi;
89
90mod func;
92
93mod identifier;
95
96mod require_matches;
98
99mod types;
101
102mod values;
104
105use std::any::*;
106use std::sync::atomic::*;
107use std::sync::*;
108
109use anyhow::*;
110use fxhash::*;
111use id_arena::*;
112
113use slab::*;
114pub use wasm_runtime_layer::Engine;
115use wasm_runtime_layer::*;
116use wasmtime_environ::component::*;
117use wit_component::*;
118use wit_parser::*;
119
120pub use crate::func::Func;
121pub use crate::func::*;
122pub use crate::identifier::PackageName;
123pub use crate::identifier::*;
124use crate::require_matches::*;
125pub use crate::types::*;
126pub use crate::types::{FuncType, ValueType, VariantCase};
127pub use crate::values::*;
128pub use crate::values::{Enum, Flags, Record, Tuple, Value, Variant};
129
130#[derive(Clone, Debug)]
132pub struct Component(Arc<ComponentInner>);
133
134impl Component {
135 pub fn new<E: backend::WasmEngine>(engine: &Engine<E>, bytes: &[u8]) -> Result<Self> {
137 let (inner, types) = Self::generate_component(engine, bytes)?;
138 Ok(Self(Arc::new(Self::generate_resources(
139 Self::load_exports(Self::extract_initializers(inner, &types)?, &types)?,
140 )?)))
141 }
142
143 pub fn exports(&self) -> &ComponentTypes {
145 &self.0.export_types
146 }
147
148 pub fn imports(&self) -> &ComponentTypes {
151 &self.0.import_types
152 }
153
154 pub fn package(&self) -> &PackageIdentifier {
156 &self.0.package
157 }
158
159 fn generate_component<E: backend::WasmEngine>(
161 engine: &Engine<E>,
162 bytes: &[u8],
163 ) -> Result<(ComponentInner, wasmtime_environ::component::ComponentTypes)> {
164 static ID_COUNTER: AtomicU64 = AtomicU64::new(0);
166
167 let decoded = wit_component::decode(bytes)
168 .context("Could not decode component information from bytes.")?;
169
170 let (mut resolve, world_id) = match decoded {
171 DecodedWasm::WitPackage(..) => bail!("Cannot instantiate WIT package as module."),
172 DecodedWasm::Component(resolve, id) => (resolve, id),
173 };
174
175 let adapter_vec = wasmtime_environ::ScopeVec::new();
176 let (translation, module_data, component_types) =
177 Self::translate_modules(bytes, &adapter_vec)?;
178
179 let export_mapping = Self::generate_export_mapping(&module_data);
180 let mut modules =
181 FxHashMap::with_capacity_and_hasher(module_data.len(), Default::default());
182
183 for (id, module) in module_data {
184 modules.insert(
185 id,
186 ModuleTranslation {
187 module: Module::new(engine, std::io::Cursor::new(module.wasm))?,
188 translation: module.module,
189 },
190 );
191 }
192
193 let mut size_align = SizeAlign::default();
194 size_align.fill(&resolve);
195
196 let package = (&resolve.packages[resolve.worlds[world_id]
197 .package
198 .context("No package associated with world.")?]
199 .name)
200 .into();
201
202 let package_identifiers = Self::generate_package_identifiers(&resolve)?;
203 let interface_identifiers =
204 Self::generate_interface_identifiers(&resolve, &package_identifiers)?;
205
206 let type_identifiers =
207 Self::generate_type_identifiers(&mut resolve, &interface_identifiers);
208
209 Ok((
210 ComponentInner {
211 export_mapping,
212 export_names: FxHashMap::default(),
213 import_types: ComponentTypes::new(),
214 export_types: ComponentTypes::new(),
215 export_info: ExportTypes::default(),
216 extracted_memories: FxHashMap::default(),
217 extracted_reallocs: FxHashMap::default(),
218 extracted_post_returns: FxHashMap::default(),
219 id: ID_COUNTER.fetch_add(1, Ordering::AcqRel),
220 generated_trampolines: FxHashMap::default(),
221 instance_modules: wasmtime_environ::PrimaryMap::default(),
222 interface_identifiers,
223 type_identifiers,
224 modules,
225 resource_map: vec![
226 TypeResourceTableIndex::from_u32(u32::MAX - 1);
227 resolve.types.len()
228 ],
229 resolve,
230 size_align,
231 translation,
232 world_id,
233 package,
234 },
235 component_types,
236 ))
237 }
238
239 fn generate_type_identifiers(
241 resolve: &mut Resolve,
242 interface_ids: &[InterfaceIdentifier],
243 ) -> Vec<Option<TypeIdentifier>> {
244 let mut ids = Vec::with_capacity(resolve.types.len());
245
246 for (_, def) in &mut resolve.types {
247 if let Some(name) = std::mem::take(&mut def.name) {
248 ids.push(Some(TypeIdentifier::new(
249 name,
250 match &def.owner {
251 TypeOwner::Interface(x) => Some(interface_ids[x.index()].clone()),
252 _ => None,
253 },
254 )));
255 } else {
256 ids.push(None);
257 }
258 }
259
260 ids
261 }
262
263 fn generate_export_mapping(
265 module_data: &wasmtime_environ::PrimaryMap<
266 StaticModuleIndex,
267 wasmtime_environ::ModuleTranslation,
268 >,
269 ) -> FxHashMap<StaticModuleIndex, FxHashMap<wasmtime_environ::EntityIndex, String>> {
270 let mut export_mapping =
271 FxHashMap::with_capacity_and_hasher(module_data.len(), Default::default());
272
273 for (idx, module) in module_data {
274 let entry: &mut FxHashMap<wasmtime_environ::EntityIndex, String> =
275 export_mapping.entry(idx).or_default();
276 for (name, index) in module.module.exports.clone() {
277 entry.insert(index, name);
278 }
279 }
280
281 export_mapping
282 }
283
284 fn generate_resources(mut inner: ComponentInner) -> Result<ComponentInner> {
286 for (_key, item) in &inner.resolve.worlds[inner.world_id].imports {
287 match item {
288 WorldItem::Type(x) => {
289 if inner.resolve.types[*x].kind == TypeDefKind::Resource {
290 if let Some(name) = &inner.resolve.types[*x].name {
291 ensure!(
292 inner
293 .import_types
294 .root
295 .resources
296 .insert(
297 name.as_str().into(),
298 ResourceType::from_resolve(
299 inner.type_identifiers[x.index()].clone(),
300 *x,
301 &inner,
302 None
303 )?
304 )
305 .is_none(),
306 "Duplicate resource import."
307 );
308 }
309 }
310 }
311 WorldItem::Interface(x) => {
312 for (name, ty) in &inner.resolve.interfaces[*x].types {
313 if inner.resolve.types[*ty].kind == TypeDefKind::Resource {
314 let ty = ResourceType::from_resolve(
315 inner.type_identifiers[ty.index()].clone(),
316 *ty,
317 &inner,
318 None,
319 )?;
320 let entry = inner
321 .import_types
322 .instances
323 .entry(inner.interface_identifiers[x.index()].clone())
324 .or_insert_with(ComponentTypesInstance::new);
325 ensure!(
326 entry.resources.insert(name.as_str().into(), ty).is_none(),
327 "Duplicate resource import."
328 );
329 }
330 }
331 }
332 _ => {}
333 }
334 }
335
336 for (_key, item) in &inner.resolve.worlds[inner.world_id].exports {
337 match item {
338 WorldItem::Type(x) => {
339 if inner.resolve.types[*x].kind == TypeDefKind::Resource {
340 if let Some(name) = &inner.resolve.types[*x].name {
341 ensure!(
342 inner
343 .export_types
344 .root
345 .resources
346 .insert(
347 name.as_str().into(),
348 ResourceType::from_resolve(
349 inner.type_identifiers[x.index()].clone(),
350 *x,
351 &inner,
352 None
353 )?
354 )
355 .is_none(),
356 "Duplicate resource export."
357 );
358 }
359 }
360 }
361 WorldItem::Interface(x) => {
362 for (name, ty) in &inner.resolve.interfaces[*x].types {
363 if inner.resolve.types[*ty].kind == TypeDefKind::Resource {
364 let ty = ResourceType::from_resolve(
365 inner.type_identifiers[ty.index()].clone(),
366 *ty,
367 &inner,
368 None,
369 )?;
370 let entry = inner
371 .export_types
372 .instances
373 .entry(inner.interface_identifiers[x.index()].clone())
374 .or_insert_with(ComponentTypesInstance::new);
375 ensure!(
376 entry.resources.insert(name.as_str().into(), ty).is_none(),
377 "Duplicate resource export."
378 );
379 }
380 }
381 }
382 _ => {}
383 }
384 }
385
386 Ok(inner)
387 }
388
389 fn generate_package_identifiers(resolve: &Resolve) -> Result<Vec<PackageIdentifier>> {
391 let mut res = Vec::with_capacity(resolve.packages.len());
392
393 for (_, pkg) in &resolve.packages {
394 res.push(PackageIdentifier::from(&pkg.name));
395 }
396
397 Ok(res)
398 }
399
400 fn generate_interface_identifiers(
402 resolve: &Resolve,
403 packages: &[PackageIdentifier],
404 ) -> Result<Vec<InterfaceIdentifier>> {
405 let mut res = Vec::with_capacity(resolve.interfaces.len());
406
407 for (_, iface) in &resolve.interfaces {
408 let pkg = iface
409 .package
410 .context("Interface did not have associated package.")?;
411 res.push(InterfaceIdentifier::new(
412 packages[pkg.index()].clone(),
413 iface
414 .name
415 .as_deref()
416 .context("Exported interface did not have valid name.")?,
417 ));
418 }
419
420 Ok(res)
421 }
422
423 fn extract_initializers(
425 mut inner: ComponentInner,
426 types: &wasmtime_environ::component::ComponentTypes,
427 ) -> Result<ComponentInner> {
428 let lowering_options = Self::get_lowering_options_and_extract_trampolines(
429 &inner.translation.trampolines,
430 &mut inner.generated_trampolines,
431 )?;
432 let mut imports = FxHashMap::default();
433 for (key, _) in &inner.resolve.worlds[inner.world_id].imports {
434 let name = inner.resolve.name_world_key(key);
435 imports.insert(name, key.clone());
436 }
437
438 let _root_name = Arc::<str>::from("$root");
439
440 let mut destructors = FxHashMap::default();
441
442 for initializer in &inner.translation.component.initializers {
443 match initializer {
444 GlobalInitializer::InstantiateModule(InstantiateModule::Static(idx, _def)) => {
445 inner.instance_modules.push(*idx);
446 }
447 GlobalInitializer::ExtractMemory(ExtractMemory { index, export }) => {
448 ensure!(
449 inner
450 .extracted_memories
451 .insert(*index, export.clone())
452 .is_none(),
453 "Extracted the same memory more than once."
454 );
455 }
456 GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }) => {
457 if let CoreDef::Export(export) = def {
458 ensure!(
459 inner
460 .extracted_reallocs
461 .insert(*index, export.clone())
462 .is_none(),
463 "Extracted the same memory more than once."
464 );
465 } else {
466 bail!("Unexpected post return definition type.");
467 }
468 }
469 GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }) => {
470 if let CoreDef::Export(export) = def {
471 ensure!(
472 inner
473 .extracted_post_returns
474 .insert(*index, export.clone())
475 .is_none(),
476 "Extracted the same memory more than once."
477 );
478 } else {
479 bail!("Unexpected post return definition type.");
480 }
481 }
482 GlobalInitializer::LowerImport { index, import } => {
483 let (idx, lowering_opts, index_ty) = lowering_options[*index];
484 let (import_index, path) = &inner.translation.component.imports[*import];
485 let (import_name, _) = &inner.translation.component.import_types[*import_index];
486 let world_key = &imports[import_name];
487
488 let imp = match &inner.resolve.worlds[inner.world_id].imports[world_key] {
489 WorldItem::Function(func) => {
490 assert_eq!(path.len(), 0);
491 ComponentImport {
492 instance: None,
493 name: import_name.as_str().into(),
494 func: func.clone(),
495 options: lowering_opts.clone(),
496 }
497 }
498 WorldItem::Interface(i) => {
499 assert_eq!(path.len(), 1);
500 let iface = &inner.resolve.interfaces[*i];
501 let func = &iface.functions[&path[0]];
502
503 ComponentImport {
504 instance: Some(inner.interface_identifiers[i.index()].clone()),
505 name: path[0].as_str().into(),
506 func: func.clone(),
507 options: lowering_opts.clone(),
508 }
509 }
510 WorldItem::Type(_) => unreachable!(),
511 };
512
513 let ty = crate::types::FuncType::from_component(&imp.func, &inner, None)?;
514 let inst = if let Some(inst) = &imp.instance {
515 inner
516 .import_types
517 .instances
518 .entry(inst.clone())
519 .or_insert_with(ComponentTypesInstance::new)
520 } else {
521 &mut inner.import_types.root
522 };
523
524 Self::update_resource_map(
525 &inner.resolve,
526 types,
527 &imp.func,
528 index_ty,
529 &mut inner.resource_map,
530 );
531
532 ensure!(
533 inst.functions.insert(imp.name.clone(), ty).is_none(),
534 "Attempted to insert duplicate import."
535 );
536
537 ensure!(
538 inner
539 .generated_trampolines
540 .insert(idx, GeneratedTrampoline::ImportedFunction(imp))
541 .is_none(),
542 "Attempted to insert duplicate import."
543 );
544 }
545 GlobalInitializer::Resource(x) => {
546 if let Some(destructor) = x.dtor.clone() {
547 ensure!(
548 destructors.insert(x.index, destructor).is_none(),
549 "Attempted to define duplicate resource."
550 );
551 }
552 }
553 _ => bail!("Not yet implemented {initializer:?}."),
554 }
555 }
556
557 for trampoline in inner.generated_trampolines.values_mut() {
558 if let GeneratedTrampoline::ResourceDrop(x, destructor) = trampoline {
559 let resource = &types[*x];
560 if let Some(resource_idx) = inner
561 .translation
562 .component
563 .defined_resource_index(resource.ty)
564 {
565 *destructor = destructors.remove(&resource_idx);
566 }
567 }
568 }
569
570 Ok(inner)
571 }
572
573 fn get_lowering_options_and_extract_trampolines<'a>(
576 trampolines: &'a wasmtime_environ::PrimaryMap<TrampolineIndex, Trampoline>,
577 output_trampolines: &mut FxHashMap<TrampolineIndex, GeneratedTrampoline>,
578 ) -> Result<
579 wasmtime_environ::PrimaryMap<
580 LoweredIndex,
581 (TrampolineIndex, &'a CanonicalOptions, TypeFuncIndex),
582 >,
583 > {
584 let mut lowers = wasmtime_environ::PrimaryMap::default();
585 for (idx, trampoline) in trampolines {
586 match trampoline {
587 Trampoline::LowerImport {
588 index,
589 lower_ty,
590 options,
591 } => assert!(
592 lowers.push((idx, options, *lower_ty)) == *index,
593 "Indices did not match."
594 ),
595 Trampoline::ResourceNew(x) => {
596 output_trampolines.insert(idx, GeneratedTrampoline::ResourceNew(*x));
597 }
598 Trampoline::ResourceRep(x) => {
599 output_trampolines.insert(idx, GeneratedTrampoline::ResourceRep(*x));
600 }
601 Trampoline::ResourceDrop(x) => {
602 output_trampolines.insert(idx, GeneratedTrampoline::ResourceDrop(*x, None));
603 }
604 _ => bail!("Trampoline not implemented."),
605 }
606 }
607 Ok(lowers)
608 }
609
610 fn translate_modules<'a>(
612 bytes: &'a [u8],
613 scope: &'a wasmtime_environ::ScopeVec<u8>,
614 ) -> Result<(
615 ComponentTranslation,
616 wasmtime_environ::PrimaryMap<StaticModuleIndex, wasmtime_environ::ModuleTranslation<'a>>,
617 wasmtime_environ::component::ComponentTypes,
618 )> {
619 let tunables = wasmtime_environ::Tunables::default_u32();
620 let mut types = ComponentTypesBuilder::default();
621 let mut validator = Self::create_component_validator();
622
623 let (translation, modules) = Translator::new(&tunables, &mut validator, &mut types, scope)
624 .translate(bytes)
625 .context("Could not translate input component to core WASM.")?;
626
627 Ok((
628 translation,
629 modules,
630 types.finish(&Default::default(), [], []).0,
631 ))
632 }
633
634 fn load_exports(
636 mut inner: ComponentInner,
637 types: &wasmtime_environ::component::ComponentTypes,
638 ) -> Result<ComponentInner> {
639 Self::export_names(&mut inner);
640
641 for (export_name, export) in &inner.translation.component.exports {
642 let world_key = &inner.export_names[export_name];
643 let item = &inner.resolve.worlds[inner.world_id].exports[world_key];
644 match export {
645 wasmtime_environ::component::Export::LiftedFunction { ty, func, options } => {
646 let f = match item {
647 WorldItem::Function(f) => f,
648 WorldItem::Interface(_) | WorldItem::Type(_) => unreachable!(),
649 };
650
651 Self::update_resource_map(
652 &inner.resolve,
653 types,
654 f,
655 *ty,
656 &mut inner.resource_map,
657 );
658
659 let export_name = Arc::<str>::from(export_name.as_str());
660 let ty = crate::types::FuncType::from_component(f, &inner, None)?;
661
662 ensure!(
663 inner
664 .export_types
665 .root
666 .functions
667 .insert(export_name.clone(), ty.clone())
668 .is_none(),
669 "Duplicate function definition."
670 );
671
672 ensure!(
673 inner
674 .export_info
675 .root
676 .functions
677 .insert(
678 export_name,
679 ComponentExport {
680 options: options.clone(),
681 def: match func {
682 CoreDef::Export(x) => x.clone(),
683 _ => unreachable!(),
684 },
685 func: f.clone(),
686 ty
687 }
688 )
689 .is_none(),
690 "Duplicate function definition."
691 );
692 }
693 wasmtime_environ::component::Export::Instance { exports, .. } => {
694 let id = match item {
695 WorldItem::Interface(id) => *id,
696 WorldItem::Function(_) | WorldItem::Type(_) => unreachable!(),
697 };
698 for (func_name, export) in exports {
699 let (func, options, ty) = match export {
700 wasmtime_environ::component::Export::LiftedFunction {
701 func,
702 options,
703 ty,
704 } => (func, options, ty),
705 wasmtime_environ::component::Export::Type(_) => continue, _ => unreachable!(),
707 };
708
709 let f = &inner.resolve.interfaces[id].functions[func_name];
710
711 Self::update_resource_map(
712 &inner.resolve,
713 types,
714 f,
715 *ty,
716 &mut inner.resource_map,
717 );
718 let exp = ComponentExport {
719 options: options.clone(),
720 def: match func {
721 CoreDef::Export(x) => x.clone(),
722 _ => unreachable!(),
723 },
724 func: f.clone(),
725 ty: crate::types::FuncType::from_component(f, &inner, None)?,
726 };
727 let func_name = Arc::<str>::from(func_name.as_str());
728 ensure!(
729 inner
730 .export_types
731 .instances
732 .entry(inner.interface_identifiers[id.index()].clone())
733 .or_insert_with(ComponentTypesInstance::new)
734 .functions
735 .insert(func_name.clone(), exp.ty.clone())
736 .is_none(),
737 "Duplicate function definition."
738 );
739 ensure!(
740 inner
741 .export_info
742 .instances
743 .entry(inner.interface_identifiers[id.index()].clone())
744 .or_default()
745 .functions
746 .insert(func_name, exp)
747 .is_none(),
748 "Duplicate function definition."
749 );
750 }
751 }
752
753 wasmtime_environ::component::Export::Type(_) => {}
755
756 wasmtime_environ::component::Export::ModuleStatic(_) => {
758 bail!("Not yet implemented.")
759 }
760 wasmtime_environ::component::Export::ModuleImport { .. } => {
761 bail!("Not yet implemented.")
762 }
763 }
764 }
765
766 Ok(inner)
767 }
768
769 fn export_names(inner: &mut ComponentInner) {
771 let to_iter = &inner.resolve.worlds[inner.world_id].exports;
772 let mut exports = FxHashMap::with_capacity_and_hasher(to_iter.len(), Default::default());
773 for (key, _) in to_iter {
774 let name = inner.resolve.name_world_key(key);
775 exports.insert(name, key.clone());
776 }
777 inner.export_names = exports;
778 }
779
780 fn update_resource_map(
783 resolve: &Resolve,
784 types: &wasmtime_environ::component::ComponentTypes,
785 func: &Function,
786 ty_func_idx: TypeFuncIndex,
787 map: &mut Vec<TypeResourceTableIndex>,
788 ) {
789 let params_ty = &types[types[ty_func_idx].params];
790 for ((_, ty), iface_ty) in func.params.iter().zip(params_ty.types.iter()) {
791 Self::connect_resources(resolve, types, ty, iface_ty, map);
792 }
793 let results_ty = &types[types[ty_func_idx].results];
794 for (ty, iface_ty) in func.results.iter_types().zip(results_ty.types.iter()) {
795 Self::connect_resources(resolve, types, ty, iface_ty, map);
796 }
797 }
798
799 fn connect_resources(
802 resolve: &Resolve,
803 types: &wasmtime_environ::component::ComponentTypes,
804 ty: &Type,
805 iface_ty: &InterfaceType,
806 map: &mut Vec<TypeResourceTableIndex>,
807 ) {
808 let Type::Id(id) = ty else { return };
809 match (&resolve.types[*id].kind, iface_ty) {
810 (TypeDefKind::Flags(_), InterfaceType::Flags(_))
811 | (TypeDefKind::Enum(_), InterfaceType::Enum(_)) => {}
812 (TypeDefKind::Record(t1), InterfaceType::Record(t2)) => {
813 let t2 = &types[*t2];
814 for (f1, f2) in t1.fields.iter().zip(t2.fields.iter()) {
815 Self::connect_resources(resolve, types, &f1.ty, &f2.ty, map);
816 }
817 }
818 (
819 TypeDefKind::Handle(Handle::Own(t1) | Handle::Borrow(t1)),
820 InterfaceType::Own(t2) | InterfaceType::Borrow(t2),
821 ) => {
822 map[t1.index()] = *t2;
823 }
824 (TypeDefKind::Tuple(t1), InterfaceType::Tuple(t2)) => {
825 let t2 = &types[*t2];
826 for (f1, f2) in t1.types.iter().zip(t2.types.iter()) {
827 Self::connect_resources(resolve, types, f1, f2, map);
828 }
829 }
830 (TypeDefKind::Variant(t1), InterfaceType::Variant(t2)) => {
831 let t2 = &types[*t2];
832 for (f1, f2) in t1.cases.iter().zip(t2.cases.iter()) {
833 if let Some(t1) = &f1.ty {
834 Self::connect_resources(resolve, types, t1, f2.ty.as_ref().unwrap(), map);
835 }
836 }
837 }
838 (TypeDefKind::Option(t1), InterfaceType::Option(t2)) => {
839 let t2 = &types[*t2];
840 Self::connect_resources(resolve, types, t1, &t2.ty, map);
841 }
842 (TypeDefKind::Result(t1), InterfaceType::Result(t2)) => {
843 let t2 = &types[*t2];
844 if let Some(t1) = &t1.ok {
845 Self::connect_resources(resolve, types, t1, &t2.ok.unwrap(), map);
846 }
847 if let Some(t1) = &t1.err {
848 Self::connect_resources(resolve, types, t1, &t2.err.unwrap(), map);
849 }
850 }
851 (TypeDefKind::List(t1), InterfaceType::List(t2)) => {
852 let t2 = &types[*t2];
853 Self::connect_resources(resolve, types, t1, &t2.element, map);
854 }
855 (TypeDefKind::Type(ty), _) => {
856 Self::connect_resources(resolve, types, ty, iface_ty, map);
857 }
858 (_, _) => unreachable!(),
859 }
860 }
861
862 fn create_component_validator() -> wasmtime_environ::wasmparser::Validator {
864 wasmtime_environ::wasmparser::Validator::new_with_features(
865 wasmtime_environ::wasmparser::WasmFeatures::all(),
866 )
867 }
868}
869
870struct ComponentInner {
872 pub export_mapping:
874 FxHashMap<StaticModuleIndex, FxHashMap<wasmtime_environ::EntityIndex, String>>,
875 pub export_names: FxHashMap<String, WorldKey>,
877 pub export_types: ComponentTypes,
879 pub export_info: ExportTypes,
881 pub extracted_memories: FxHashMap<RuntimeMemoryIndex, CoreExport<MemoryIndex>>,
883 pub extracted_reallocs:
885 FxHashMap<RuntimeReallocIndex, CoreExport<wasmtime_environ::EntityIndex>>,
886 pub extracted_post_returns:
888 FxHashMap<RuntimePostReturnIndex, CoreExport<wasmtime_environ::EntityIndex>>,
889 pub resource_map: Vec<TypeResourceTableIndex>,
891 pub generated_trampolines: FxHashMap<TrampolineIndex, GeneratedTrampoline>,
893 pub id: u64,
895 pub import_types: ComponentTypes,
897 pub instance_modules: wasmtime_environ::PrimaryMap<RuntimeInstanceIndex, StaticModuleIndex>,
899 pub interface_identifiers: Vec<InterfaceIdentifier>,
901 pub type_identifiers: Vec<Option<TypeIdentifier>>,
903 pub modules: FxHashMap<StaticModuleIndex, ModuleTranslation>,
905 pub resolve: Resolve,
907 pub size_align: SizeAlign,
909 pub translation: ComponentTranslation,
911 pub world_id: Id<World>,
913 pub package: PackageIdentifier,
915}
916
917impl std::fmt::Debug for ComponentInner {
918 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
919 f.debug_struct("ComponentInner").finish()
920 }
921}
922
923struct ModuleTranslation {
925 pub module: Module,
927 pub translation: wasmtime_environ::Module,
929}
930
931#[derive(Debug, Default)]
933struct ExportTypes {
934 root: ExportTypesInstance,
936 instances: FxHashMap<InterfaceIdentifier, ExportTypesInstance>,
938}
939
940#[derive(Debug, Default)]
942struct ExportTypesInstance {
943 functions: FxHashMap<Arc<str>, ComponentExport>,
945}
946
947#[derive(Debug)]
949pub struct ComponentTypes {
950 root: ComponentTypesInstance,
952 instances: FxHashMap<InterfaceIdentifier, ComponentTypesInstance>,
954}
955
956impl ComponentTypes {
957 pub(crate) fn new() -> Self {
959 Self {
960 root: ComponentTypesInstance::new(),
961 instances: FxHashMap::default(),
962 }
963 }
964
965 pub fn root(&self) -> &ComponentTypesInstance {
967 &self.root
968 }
969
970 pub fn instance(&self, name: &InterfaceIdentifier) -> Option<&ComponentTypesInstance> {
972 self.instances.get(name)
973 }
974
975 pub fn instances(
977 &self,
978 ) -> impl Iterator<Item = (&'_ InterfaceIdentifier, &'_ ComponentTypesInstance)> {
979 self.instances.iter()
980 }
981}
982
983#[derive(Debug)]
985pub struct ComponentTypesInstance {
986 functions: FxHashMap<Arc<str>, crate::types::FuncType>,
988 resources: FxHashMap<Arc<str>, ResourceType>,
990}
991
992impl ComponentTypesInstance {
993 pub(crate) fn new() -> Self {
995 Self {
996 functions: FxHashMap::default(),
997 resources: FxHashMap::default(),
998 }
999 }
1000
1001 pub fn func(&self, name: impl AsRef<str>) -> Option<crate::types::FuncType> {
1003 self.functions.get(name.as_ref()).cloned()
1004 }
1005
1006 pub fn funcs(&self) -> impl Iterator<Item = (&'_ str, crate::types::FuncType)> {
1008 self.functions.iter().map(|(k, v)| (&**k, v.clone()))
1009 }
1010
1011 pub fn resource(&self, name: impl AsRef<str>) -> Option<ResourceType> {
1013 self.resources.get(name.as_ref()).cloned()
1014 }
1015
1016 pub fn resources(&self) -> impl Iterator<Item = (&'_ str, crate::types::ResourceType)> {
1018 self.resources.iter().map(|(k, v)| (&**k, v.clone()))
1019 }
1020}
1021
1022#[derive(Clone, Debug, Default)]
1024pub struct Linker {
1025 root: LinkerInstance,
1027 instances: FxHashMap<InterfaceIdentifier, LinkerInstance>,
1029}
1030
1031impl Linker {
1032 pub fn root(&self) -> &LinkerInstance {
1034 &self.root
1035 }
1036
1037 pub fn root_mut(&mut self) -> &mut LinkerInstance {
1039 &mut self.root
1040 }
1041
1042 pub fn define_instance(&mut self, name: InterfaceIdentifier) -> Result<&mut LinkerInstance> {
1045 if self.instance(&name).is_none() {
1046 Ok(self.instances.entry(name).or_default())
1047 } else {
1048 bail!("Duplicate instance definition.");
1049 }
1050 }
1051
1052 pub fn instance(&self, name: &InterfaceIdentifier) -> Option<&LinkerInstance> {
1054 self.instances.get(name)
1055 }
1056
1057 pub fn instance_mut(&mut self, name: &InterfaceIdentifier) -> Option<&mut LinkerInstance> {
1059 self.instances.get_mut(name)
1060 }
1061
1062 pub fn instances(
1064 &self,
1065 ) -> impl ExactSizeIterator<Item = (&'_ InterfaceIdentifier, &'_ LinkerInstance)> {
1066 self.instances.iter()
1067 }
1068
1069 pub fn instances_mut(
1071 &mut self,
1072 ) -> impl ExactSizeIterator<Item = (&'_ InterfaceIdentifier, &'_ mut LinkerInstance)> {
1073 self.instances.iter_mut()
1074 }
1075
1076 pub fn instantiate(&self, ctx: impl AsContextMut, component: &Component) -> Result<Instance> {
1079 Instance::new(ctx, component, self)
1080 }
1081}
1082
1083#[derive(Clone, Debug, Default)]
1085pub struct LinkerInstance {
1086 functions: FxHashMap<Arc<str>, crate::func::Func>,
1088 resources: FxHashMap<Arc<str>, ResourceType>,
1090}
1091
1092impl LinkerInstance {
1093 pub fn define_func(
1096 &mut self,
1097 name: impl Into<Arc<str>>,
1098 func: crate::func::Func,
1099 ) -> Result<()> {
1100 let n = Into::<Arc<str>>::into(name);
1101 if self.functions.contains_key(&n) {
1102 bail!("Duplicate function definition.");
1103 }
1104
1105 self.functions.insert(n, func);
1106 Ok(())
1107 }
1108
1109 pub fn func(&self, name: impl AsRef<str>) -> Option<crate::func::Func> {
1111 self.functions.get(name.as_ref()).cloned()
1112 }
1113
1114 pub fn define_resource(
1117 &mut self,
1118 name: impl Into<Arc<str>>,
1119 resource_ty: ResourceType,
1120 ) -> Result<()> {
1121 ensure!(
1122 resource_ty.is_instantiated(),
1123 "Cannot link with abstract resource type."
1124 );
1125
1126 let n = Into::<Arc<str>>::into(name);
1127 if self.resources.contains_key(&n) {
1128 bail!("Duplicate resource definition.");
1129 }
1130
1131 self.resources.insert(n, resource_ty);
1132 Ok(())
1133 }
1134
1135 pub fn resource(&self, name: impl AsRef<str>) -> Option<ResourceType> {
1137 self.resources.get(name.as_ref()).cloned()
1138 }
1139
1140 pub fn funcs(&self) -> impl Iterator<Item = (&'_ str, crate::func::Func)> {
1142 self.functions.iter().map(|(k, v)| (&**k, v.clone()))
1143 }
1144
1145 pub fn resources(&self) -> impl Iterator<Item = (&'_ str, ResourceType)> {
1147 self.resources.iter().map(|(k, v)| (&**k, v.clone()))
1148 }
1149}
1150
1151#[derive(Clone, Debug)]
1153pub struct Instance(Arc<InstanceInner>);
1154
1155impl Instance {
1156 pub(crate) fn new(
1158 mut ctx: impl AsContextMut,
1159 component: &Component,
1160 linker: &Linker,
1161 ) -> Result<Self> {
1162 static ID_COUNTER: AtomicU64 = AtomicU64::new(0);
1164
1165 let mut instance_flags = wasmtime_environ::PrimaryMap::default();
1166 for _i in 0..component.0.instance_modules.len() {
1167 instance_flags.push(Global::new(
1168 ctx.as_context_mut().inner,
1169 wasm_runtime_layer::Value::I32(
1170 wasmtime_environ::component::FLAG_MAY_LEAVE
1171 | wasmtime_environ::component::FLAG_MAY_ENTER,
1172 ),
1173 true,
1174 ));
1175 }
1176
1177 let id = ID_COUNTER.fetch_add(1, Ordering::AcqRel);
1178 let map = Self::create_resource_instantiation_map(id, component, linker)?;
1179 let types = Self::generate_types(component, &map)?;
1180 let resource_tables = Mutex::new(vec![
1181 HandleTable::default();
1182 component.0.translation.component.num_resource_tables
1183 ]);
1184
1185 let instance = InstanceInner {
1186 component: component.clone(),
1187 exports: Exports::new(),
1188 id,
1189 instances: Default::default(),
1190 instance_flags,
1191 state_table: Arc::new(StateTable {
1192 dropped: AtomicBool::new(false),
1193 resource_tables,
1194 }),
1195 types,
1196 store_id: ctx.as_context().inner.data().id,
1197 };
1198 let initialized = Self::global_initialize(instance, &mut ctx, linker, &map)?;
1199 let exported = Self::load_exports(initialized, &ctx, &map)?;
1200
1201 Ok(Self(Arc::new_cyclic(|w| {
1202 Self::fill_exports(exported, w.clone())
1203 })))
1204 }
1205
1206 pub fn component(&self) -> &Component {
1208 &self.0.component
1209 }
1210
1211 pub fn exports(&self) -> &Exports {
1213 &self.0.exports
1214 }
1215
1216 pub fn drop<T, E: backend::WasmEngine>(&self, ctx: &mut Store<T, E>) -> Result<Vec<Error>> {
1220 ensure!(self.0.store_id == ctx.inner.data().id, "Incorrect store.");
1221 self.0.state_table.dropped.store(true, Ordering::Release);
1222
1223 let mut errors = Vec::new();
1224
1225 let mut tables = self
1226 .0
1227 .state_table
1228 .resource_tables
1229 .try_lock()
1230 .expect("Could not lock resource tables.");
1231 for table in &mut *tables {
1232 if let Some(destructor) = table.destructor.as_ref() {
1233 for (_, val) in table.array.iter() {
1234 if let Err(x) = destructor.call(
1235 &mut ctx.inner,
1236 &[wasm_runtime_layer::Value::I32(val.rep)],
1237 &mut [],
1238 ) {
1239 errors.push(x);
1240 }
1241 }
1242 }
1243 }
1244
1245 Ok(errors)
1246 }
1247
1248 fn fill_exports(mut inner: InstanceInner, final_ptr: Weak<InstanceInner>) -> InstanceInner {
1250 for inst in inner.exports.instances.values_mut() {
1251 inst.instance = final_ptr.clone();
1252 }
1253
1254 inner.exports.root.instance = final_ptr;
1255 inner
1256 }
1257
1258 fn generate_types(
1260 component: &Component,
1261 map: &FxHashMap<ResourceType, ResourceType>,
1262 ) -> Result<Arc<[crate::types::ValueType]>> {
1263 let mut types = Vec::with_capacity(component.0.resolve.types.len());
1264 for (mut id, mut val) in &component.0.resolve.types {
1265 assert!(
1266 types.len() == id.index(),
1267 "Type definition IDs were not equal."
1268 );
1269
1270 while let TypeDefKind::Type(Type::Id(id_ref)) = val.kind {
1271 id = id_ref;
1272 val = &component.0.resolve.types[id_ref];
1273 }
1274
1275 if val.kind == TypeDefKind::Resource {
1276 types.push(crate::types::ValueType::Bool);
1277 } else {
1278 types.push(crate::types::ValueType::from_component_typedef(
1279 id,
1280 &component.0,
1281 Some(map),
1282 )?);
1283 }
1284 }
1285 Ok(types.into())
1286 }
1287
1288 fn create_resource_instantiation_map(
1291 instance_id: u64,
1292 component: &Component,
1293 linker: &Linker,
1294 ) -> Result<FxHashMap<ResourceType, ResourceType>> {
1295 let mut types = FxHashMap::default();
1296
1297 for (name, resource) in component.imports().root().resources() {
1298 let instantiated = linker
1299 .root()
1300 .resource(name)
1301 .ok_or_else(|| Error::msg(format!("Could not find resource {name} in linker.")))?;
1302 types.insert(resource, instantiated);
1303 }
1304
1305 for (id, interface) in component.imports().instances() {
1306 for (name, resource) in interface.resources() {
1307 let instantiated = linker
1308 .instance(id)
1309 .and_then(|x| x.resource(name))
1310 .ok_or_else(|| {
1311 Error::msg(format!(
1312 "Could not find resource {name} from interface {id:?} in linker."
1313 ))
1314 })?;
1315 types.insert(resource, instantiated);
1316 }
1317 }
1318
1319 for (_, resource) in component
1320 .exports()
1321 .instances()
1322 .flat_map(|(_, x)| x.resources())
1323 .chain(component.exports().root().resources())
1324 {
1325 let instantiated = resource.instantiate(instance_id)?;
1326 types.insert(resource, instantiated);
1327 }
1328
1329 Ok(types)
1330 }
1331
1332 fn load_exports(
1334 mut inner: InstanceInner,
1335 ctx: impl AsContext,
1336 map: &FxHashMap<ResourceType, ResourceType>,
1337 ) -> Result<InstanceInner> {
1338 for (name, func) in &inner.component.0.export_info.root.functions {
1339 inner.exports.root.functions.insert(
1340 name.clone(),
1341 Self::export_function(
1342 &inner,
1343 &ctx,
1344 &func.def,
1345 &func.options,
1346 &func.func,
1347 map,
1348 None,
1349 )?,
1350 );
1351 }
1352 for (name, res) in &inner.component.0.export_types.root.resources {
1353 inner
1354 .exports
1355 .root
1356 .resources
1357 .insert(name.clone(), res.instantiate(inner.id)?);
1358 }
1359
1360 let mut generated_functions = Vec::new();
1361 for (inst_name, inst) in &inner.component.0.export_info.instances {
1362 for (name, func) in &inst.functions {
1363 let export = Self::export_function(
1364 &inner,
1365 &ctx,
1366 &func.def,
1367 &func.options,
1368 &func.func,
1369 map,
1370 Some(inst_name.clone()),
1371 )?;
1372 generated_functions.push((inst_name.clone(), name.clone(), export));
1373 }
1374 }
1375
1376 for (inst_name, inst) in &inner.component.0.export_types.instances {
1377 for (name, res) in &inst.resources {
1378 inner
1379 .exports
1380 .instances
1381 .entry(inst_name.clone())
1382 .or_insert_with(ExportInstance::new)
1383 .resources
1384 .insert(name.clone(), res.instantiate(inner.id)?);
1385 }
1386 }
1387
1388 for (inst_name, name, func) in generated_functions {
1389 let interface = inner
1390 .exports
1391 .instances
1392 .entry(inst_name)
1393 .or_insert_with(ExportInstance::new);
1394 interface.functions.insert(name, func);
1395 }
1396
1397 Ok(inner)
1398 }
1399
1400 fn import_function(
1402 inner: &InstanceInner,
1403 ctx: impl AsContext,
1404 options: &CanonicalOptions,
1405 func: &Function,
1406 ) -> GuestInvokeOptions {
1407 let memory = options.memory.map(|idx| {
1408 Self::core_export(inner, &ctx, &inner.component.0.extracted_memories[&idx])
1409 .expect("Could not get runtime memory export.")
1410 .into_memory()
1411 .expect("Export was not of memory type.")
1412 });
1413 let realloc = options.realloc.map(|idx| {
1414 Self::core_export(inner, &ctx, &inner.component.0.extracted_reallocs[&idx])
1415 .expect("Could not get runtime realloc export.")
1416 .into_func()
1417 .expect("Export was not of func type.")
1418 });
1419 let post_return = options.post_return.map(|idx| {
1420 Self::core_export(inner, &ctx, &inner.component.0.extracted_post_returns[&idx])
1421 .expect("Could not get runtime post return export.")
1422 .into_func()
1423 .expect("Export was not of func type.")
1424 });
1425
1426 GuestInvokeOptions {
1427 component: inner.component.0.clone(),
1428 encoding: options.string_encoding,
1429 function: func.clone(),
1430 memory,
1431 realloc,
1432 state_table: inner.state_table.clone(),
1433 post_return,
1434 types: inner.types.clone(),
1435 instance_id: inner.id,
1436 store_id: ctx.as_context().inner.data().id,
1437 }
1438 }
1439
1440 fn export_function(
1442 inner: &InstanceInner,
1443 ctx: impl AsContext,
1444 def: &CoreExport<wasmtime_environ::EntityIndex>,
1445 options: &CanonicalOptions,
1446 func: &Function,
1447 mapping: &FxHashMap<ResourceType, ResourceType>,
1448 interface_id: Option<InterfaceIdentifier>,
1449 ) -> Result<crate::func::Func> {
1450 let callee = Self::core_export(inner, &ctx, def)
1451 .expect("Could not get callee export.")
1452 .into_func()
1453 .expect("Export was not of func type.");
1454 let memory = options.memory.map(|idx| {
1455 Self::core_export(inner, &ctx, &inner.component.0.extracted_memories[&idx])
1456 .expect("Could not get runtime memory export.")
1457 .into_memory()
1458 .expect("Export was not of memory type.")
1459 });
1460 let realloc = options.realloc.map(|idx| {
1461 Self::core_export(inner, &ctx, &inner.component.0.extracted_reallocs[&idx])
1462 .expect("Could not get runtime realloc export.")
1463 .into_func()
1464 .expect("Export was not of func type.")
1465 });
1466 let post_return = options.post_return.map(|idx| {
1467 Self::core_export(inner, &ctx, &inner.component.0.extracted_post_returns[&idx])
1468 .expect("Could not get runtime post return export.")
1469 .into_func()
1470 .expect("Export was not of func type.")
1471 });
1472
1473 Ok(crate::func::Func {
1474 store_id: ctx.as_context().inner.data().id,
1475 ty: crate::types::FuncType::from_component(func, &inner.component.0, Some(mapping))?,
1476 backing: FuncImpl::GuestFunc(
1477 None,
1478 Arc::new(GuestFunc {
1479 callee,
1480 component: inner.component.0.clone(),
1481 encoding: options.string_encoding,
1482 function: func.clone(),
1483 memory,
1484 realloc,
1485 state_table: inner.state_table.clone(),
1486 post_return,
1487 types: inner.types.clone(),
1488 instance_id: inner.id,
1489 interface_id,
1490 }),
1491 ),
1492 })
1493 }
1494
1495 fn core_import(
1497 inner: &InstanceInner,
1498 mut ctx: impl AsContextMut,
1499 def: &CoreDef,
1500 linker: &Linker,
1501 ty: ExternType,
1502 destructors: &mut Vec<TrampolineIndex>,
1503 resource_map: &FxHashMap<ResourceType, ResourceType>,
1504 ) -> Result<Extern> {
1505 match def {
1506 CoreDef::Export(x) => {
1507 Self::core_export(inner, ctx, x).context("Could not find exported function.")
1508 }
1509 CoreDef::Trampoline(x) => {
1510 let ty = if let ExternType::Func(x) = ty {
1511 x
1512 } else {
1513 bail!("Incorrect extern type.")
1514 };
1515 match inner
1516 .component
1517 .0
1518 .generated_trampolines
1519 .get(x)
1520 .context("Could not find exported trampoline.")?
1521 {
1522 GeneratedTrampoline::ImportedFunction(component_import) => {
1523 let expected = crate::types::FuncType::from_component(
1524 &component_import.func,
1525 &inner.component.0,
1526 Some(resource_map),
1527 )?;
1528 let func = Self::get_component_import(component_import, linker)?;
1529 ensure!(
1530 func.ty() == expected,
1531 "Function import {} had type {}, but expected {expected}",
1532 component_import.name,
1533 func.ty()
1534 );
1535 let guest_options = Self::import_function(
1536 inner,
1537 &ctx,
1538 &component_import.options,
1539 &component_import.func,
1540 );
1541
1542 let ty = ty.with_name(component_import.name.clone());
1545
1546 Ok(Extern::Func(wasm_runtime_layer::Func::new(
1547 ctx.as_context_mut().inner,
1548 ty,
1549 move |ctx, args, results| {
1550 let ctx = StoreContextMut { inner: ctx };
1551 func.call_from_guest(ctx, &guest_options, args, results)
1552 },
1553 )))
1554 }
1555 GeneratedTrampoline::ResourceNew(x) => {
1556 let x = x.as_u32();
1557 let tables = inner.state_table.clone();
1558 let ty = ty.with_name(format!("resource-new-{}", x));
1559 Ok(Extern::Func(wasm_runtime_layer::Func::new(
1560 ctx.as_context_mut().inner,
1561 ty,
1562 move |_ctx, args, results| {
1563 let rep =
1564 require_matches!(args[0], wasm_runtime_layer::Value::I32(x), x);
1565 let mut table_array = tables
1566 .resource_tables
1567 .try_lock()
1568 .expect("Could not get mutual reference to table.");
1569 results[0] = wasm_runtime_layer::Value::I32(
1570 table_array[x as usize].add(HandleElement {
1571 rep,
1572 own: true,
1573 lend_count: 0,
1574 }),
1575 );
1576 Ok(())
1577 },
1578 )))
1579 }
1580 GeneratedTrampoline::ResourceRep(x) => {
1581 let x = x.as_u32();
1582 let tables = inner.state_table.clone();
1583 let ty = ty.with_name(format!("resource-rep-{}", x));
1584 Ok(Extern::Func(wasm_runtime_layer::Func::new(
1585 ctx.as_context_mut().inner,
1586 ty,
1587 move |_ctx, args, results| {
1588 let idx =
1589 require_matches!(args[0], wasm_runtime_layer::Value::I32(x), x);
1590 let table_array = tables
1591 .resource_tables
1592 .try_lock()
1593 .expect("Could not get mutual reference to table.");
1594 results[0] = wasm_runtime_layer::Value::I32(
1595 table_array[x as usize].get(idx)?.rep,
1596 );
1597 Ok(())
1598 },
1599 )))
1600 }
1601 GeneratedTrampoline::ResourceDrop(y, _) => {
1602 destructors.push(*x);
1603 let x = y.as_u32();
1604 let tables = inner.state_table.clone();
1605 let ty = ty.with_name(format!("resource-drop-{}", x));
1606 Ok(Extern::Func(wasm_runtime_layer::Func::new(
1607 ctx.as_context_mut().inner,
1608 ty,
1609 move |ctx, args, _results| {
1610 let idx =
1611 require_matches!(args[0], wasm_runtime_layer::Value::I32(x), x);
1612 let mut table_array = tables
1613 .resource_tables
1614 .try_lock()
1615 .expect("Could not get mutual reference to table.");
1616 let current_table = &mut table_array[x as usize];
1617
1618 let elem_borrow = current_table.get(idx)?;
1619
1620 if elem_borrow.own {
1621 ensure!(
1622 elem_borrow.lend_count == 0,
1623 "Attempted to drop loaned resource."
1624 );
1625 let elem = current_table.remove(idx)?;
1626 if let Some(destructor) =
1627 table_array[x as usize].destructor().cloned()
1628 {
1629 drop(table_array);
1630 destructor.call(
1631 ctx,
1632 &[wasm_runtime_layer::Value::I32(elem.rep)],
1633 &mut [],
1634 )?;
1635 }
1636 }
1637 Ok(())
1638 },
1639 )))
1640 }
1641 }
1642 }
1643 CoreDef::InstanceFlags(i) => Ok(Extern::Global(inner.instance_flags[*i].clone())),
1644 }
1645 }
1646
1647 fn core_export<T: Copy + Into<wasmtime_environ::EntityIndex>>(
1649 inner: &InstanceInner,
1650 ctx: impl AsContext,
1651 export: &CoreExport<T>,
1652 ) -> Option<Extern> {
1653 let name = match &export.item {
1654 ExportItem::Index(idx) => {
1655 &inner.component.0.export_mapping
1656 [&inner.component.0.instance_modules[export.instance]][&(*idx).into()]
1657 }
1658 ExportItem::Name(s) => s,
1659 };
1660
1661 inner.instances[export.instance].get_export(&ctx.as_context().inner, name)
1662 }
1663
1664 fn global_initialize(
1666 mut inner: InstanceInner,
1667 mut ctx: impl AsContextMut,
1668 linker: &Linker,
1669 resource_map: &FxHashMap<ResourceType, ResourceType>,
1670 ) -> Result<InstanceInner> {
1671 let mut destructors = Vec::new();
1672 for initializer in &inner.component.0.translation.component.initializers {
1673 match initializer {
1674 GlobalInitializer::InstantiateModule(InstantiateModule::Static(idx, def)) => {
1675 let module = &inner.component.0.modules[idx];
1676 let imports = Self::generate_imports(
1677 &inner,
1678 &mut ctx,
1679 linker,
1680 module,
1681 def,
1682 &mut destructors,
1683 resource_map,
1684 )?;
1685 let instance = wasm_runtime_layer::Instance::new(
1686 &mut ctx.as_context_mut().inner,
1687 &module.module,
1688 &imports,
1689 )?;
1690 inner.instances.push(instance);
1691 }
1692 GlobalInitializer::ExtractMemory(_) => {}
1693 GlobalInitializer::ExtractRealloc(_) => {}
1694 GlobalInitializer::ExtractPostReturn(_) => {}
1695 GlobalInitializer::LowerImport { .. } => {}
1696 GlobalInitializer::Resource(_) => {}
1697 _ => bail!("Not yet implemented {initializer:?}."),
1698 }
1699 }
1700
1701 Self::fill_destructors(inner, ctx, destructors, resource_map)
1702 }
1703
1704 fn generate_imports(
1706 inner: &InstanceInner,
1707 mut store: impl AsContextMut,
1708 linker: &Linker,
1709 module: &ModuleTranslation,
1710 defs: &[CoreDef],
1711 destructors: &mut Vec<TrampolineIndex>,
1712 resource_map: &FxHashMap<ResourceType, ResourceType>,
1713 ) -> Result<Imports> {
1714 let mut import_ty_map = FxHashMap::default();
1715
1716 let engine = store.as_context().engine().clone();
1717 for import in module.module.imports(&engine) {
1718 import_ty_map.insert((import.module, import.name), import.ty.clone());
1719 }
1720
1721 let mut imports = Imports::default();
1722
1723 for (host, name, def) in module
1724 .translation
1725 .imports()
1726 .zip(defs)
1727 .map(|((module, name, _), arg)| (module, name, arg))
1728 {
1729 let ty = import_ty_map
1730 .get(&(host, name))
1731 .context("Unrecognized import.")?
1732 .clone();
1733 imports.define(
1734 host,
1735 name,
1736 Self::core_import(
1737 inner,
1738 &mut store,
1739 def,
1740 linker,
1741 ty,
1742 destructors,
1743 resource_map,
1744 )?,
1745 );
1746 }
1747
1748 Ok(imports)
1749 }
1750
1751 fn get_component_import(
1753 import: &ComponentImport,
1754 linker: &Linker,
1755 ) -> Result<crate::func::Func> {
1756 let inst = if let Some(name) = &import.instance {
1757 linker
1758 .instance(name)
1759 .ok_or_else(|| Error::msg(format!("Could not find imported interface {name:?}")))?
1760 } else {
1761 linker.root()
1762 };
1763
1764 inst.func(&import.name)
1765 .ok_or_else(|| Error::msg(format!("Could not find function import {}", import.name)))
1766 }
1767
1768 fn fill_destructors(
1770 inner: InstanceInner,
1771 ctx: impl AsContext,
1772 destructors: Vec<TrampolineIndex>,
1773 resource_map: &FxHashMap<ResourceType, ResourceType>,
1774 ) -> Result<InstanceInner> {
1775 let mut tables = inner
1776 .state_table
1777 .resource_tables
1778 .try_lock()
1779 .expect("Could not get access to resource tables.");
1780
1781 for index in destructors {
1782 let (x, def) = require_matches!(
1783 &inner.component.0.generated_trampolines[&index],
1784 GeneratedTrampoline::ResourceDrop(x, def),
1785 (x, def)
1786 );
1787 if let Some(def) = def {
1788 let export = require_matches!(def, CoreDef::Export(x), x);
1789 tables[x.as_u32() as usize].set_destructor(Some(require_matches!(
1790 Self::core_export(&inner, &ctx, export),
1791 Some(Extern::Func(x)),
1792 x
1793 )));
1794 }
1795 }
1796
1797 for (id, idx) in inner.component.0.resolve.types.iter().filter_map(|(i, _)| {
1798 let val = inner.component.0.resource_map[i.index()];
1799 (val.as_u32() < u32::MAX - 1).then_some((i, val))
1800 }) {
1801 let res = ResourceType::from_resolve(
1802 inner.component.0.type_identifiers[id.index()].clone(),
1803 id,
1804 &inner.component.0,
1805 Some(resource_map),
1806 )?;
1807 match res.host_destructor() {
1808 Some(Some(func)) => tables[idx.as_u32() as usize].set_destructor(Some(func)),
1809 Some(None) => tables[idx.as_u32() as usize]
1810 .set_destructor(ctx.as_context().inner.data().drop_host_resource.clone()),
1811 _ => {}
1812 }
1813 }
1814
1815 drop(tables);
1816
1817 Ok(inner)
1818 }
1819}
1820
1821#[derive(Debug)]
1823pub struct Exports {
1824 root: ExportInstance,
1826 instances: FxHashMap<InterfaceIdentifier, ExportInstance>,
1828}
1829
1830impl Exports {
1831 pub(crate) fn new() -> Self {
1833 Self {
1834 root: ExportInstance::new(),
1835 instances: FxHashMap::default(),
1836 }
1837 }
1838
1839 pub fn root(&self) -> &ExportInstance {
1841 &self.root
1842 }
1843
1844 pub fn instance(&self, name: &InterfaceIdentifier) -> Option<&ExportInstance> {
1846 self.instances.get(name)
1847 }
1848
1849 pub fn instances(&self) -> impl Iterator<Item = (&'_ InterfaceIdentifier, &'_ ExportInstance)> {
1851 self.instances.iter()
1852 }
1853}
1854
1855#[derive(Debug)]
1857pub struct ExportInstance {
1858 functions: FxHashMap<Arc<str>, crate::func::Func>,
1860 resources: FxHashMap<Arc<str>, ResourceType>,
1862 instance: Weak<InstanceInner>,
1864}
1865
1866impl ExportInstance {
1867 pub(crate) fn new() -> Self {
1869 Self {
1870 functions: FxHashMap::default(),
1871 resources: FxHashMap::default(),
1872 instance: Weak::new(),
1873 }
1874 }
1875
1876 pub fn func(&self, name: impl AsRef<str>) -> Option<crate::func::Func> {
1878 self.functions.get(name.as_ref()).map(|x| {
1879 x.instantiate(Instance(
1880 self.instance.upgrade().expect("Instance did not exist."),
1881 ))
1882 })
1883 }
1884
1885 pub fn funcs(&self) -> impl Iterator<Item = (&'_ str, crate::func::Func)> {
1887 let inst = self.instance.upgrade().expect("Instance did not exist.");
1888 self.functions
1889 .iter()
1890 .map(move |(k, v)| (&**k, v.instantiate(Instance(inst.clone()))))
1891 }
1892
1893 pub fn resource(&self, name: impl AsRef<str>) -> Option<ResourceType> {
1895 self.resources.get(name.as_ref()).cloned()
1896 }
1897
1898 pub fn resources(&self) -> impl Iterator<Item = (&'_ str, ResourceType)> {
1900 self.resources.iter().map(|(k, v)| (&**k, v.clone()))
1901 }
1902}
1903
1904#[derive(Debug)]
1906struct InstanceInner {
1907 pub component: Component,
1909 pub exports: Exports,
1911 pub id: u64,
1913 pub instance_flags: wasmtime_environ::PrimaryMap<RuntimeComponentInstanceIndex, Global>,
1915 pub instances: wasmtime_environ::PrimaryMap<RuntimeInstanceIndex, wasm_runtime_layer::Instance>,
1917 pub state_table: Arc<StateTable>,
1919 pub types: Arc<[crate::types::ValueType]>,
1921 pub store_id: u64,
1923}
1924
1925#[derive(Debug)]
1927struct StateTable {
1928 pub dropped: AtomicBool,
1930 pub resource_tables: Mutex<Vec<HandleTable>>,
1932}
1933
1934#[derive(Clone, Debug)]
1936struct ComponentImport {
1937 pub instance: Option<InterfaceIdentifier>,
1939 pub name: Arc<str>,
1941 pub func: Function,
1943 pub options: CanonicalOptions,
1945}
1946
1947#[derive(Clone, Debug)]
1949struct ComponentExport {
1950 pub options: CanonicalOptions,
1952 pub func: Function,
1954 pub def: CoreExport<wasmtime_environ::EntityIndex>,
1956 pub ty: crate::types::FuncType,
1958}
1959
1960pub struct Store<T, E: backend::WasmEngine> {
1970 inner: wasm_runtime_layer::Store<StoreInner<T, E>, E>,
1972}
1973
1974impl<T, E: backend::WasmEngine> Store<T, E> {
1975 pub fn new(engine: &Engine<E>, data: T) -> Self {
1977 static ID_COUNTER: AtomicU64 = AtomicU64::new(0);
1979
1980 let mut inner = wasm_runtime_layer::Store::new(
1981 engine,
1982 StoreInner {
1983 id: ID_COUNTER.fetch_add(1, Ordering::AcqRel),
1984 data,
1985 host_functions: FuncVec::default(),
1986 host_resources: Slab::default(),
1987 drop_host_resource: None,
1988 },
1989 );
1990
1991 inner.data_mut().drop_host_resource = Some(wasm_runtime_layer::Func::new(
1992 &mut inner,
1993 wasm_runtime_layer::FuncType::new([wasm_runtime_layer::ValueType::I32], [])
1994 .with_name("drop-host-resources"),
1995 |mut ctx, args, _| {
1996 if let wasm_runtime_layer::Value::I32(index) = &args[0] {
1997 ctx.data_mut().host_resources.remove(*index as usize);
1998 Ok(())
1999 } else {
2000 bail!("Could not drop resource.");
2001 }
2002 },
2003 ));
2004
2005 Self { inner }
2006 }
2007
2008 pub fn engine(&self) -> &Engine<E> {
2010 self.inner.engine()
2011 }
2012
2013 pub fn data(&self) -> &T {
2015 &self.inner.data().data
2016 }
2017
2018 pub fn data_mut(&mut self) -> &mut T {
2020 &mut self.inner.data_mut().data
2021 }
2022
2023 pub fn into_data(self) -> T {
2025 self.inner.into_data().data
2026 }
2027}
2028
2029pub struct StoreContext<'a, T: 'a, E: backend::WasmEngine> {
2034 inner: wasm_runtime_layer::StoreContext<'a, StoreInner<T, E>, E>,
2036}
2037
2038impl<'a, T: 'a, E: backend::WasmEngine> StoreContext<'a, T, E> {
2039 pub fn engine(&self) -> &Engine<E> {
2041 self.inner.engine()
2042 }
2043
2044 pub fn data(&self) -> &T {
2048 &self.inner.data().data
2049 }
2050}
2051
2052pub struct StoreContextMut<'a, T: 'a, E: backend::WasmEngine> {
2057 inner: wasm_runtime_layer::StoreContextMut<'a, StoreInner<T, E>, E>,
2059}
2060
2061impl<'a, T: 'a, E: backend::WasmEngine> StoreContextMut<'a, T, E> {
2062 pub fn engine(&self) -> &Engine<E> {
2064 self.inner.engine()
2065 }
2066
2067 pub fn data(&self) -> &T {
2071 &self.inner.data().data
2072 }
2073
2074 pub fn data_mut(&mut self) -> &mut T {
2078 &mut self.inner.data_mut().data
2079 }
2080}
2081
2082pub trait AsContext {
2084 type Engine: backend::WasmEngine;
2086
2087 type UserState;
2089
2090 fn as_context(&self) -> StoreContext<Self::UserState, Self::Engine>;
2092}
2093
2094pub trait AsContextMut: AsContext {
2096 fn as_context_mut(&mut self) -> StoreContextMut<Self::UserState, Self::Engine>;
2098}
2099
2100impl<T, E: backend::WasmEngine> AsContext for Store<T, E> {
2101 type Engine = E;
2102
2103 type UserState = T;
2104
2105 fn as_context(&self) -> StoreContext<Self::UserState, Self::Engine> {
2106 StoreContext {
2107 inner: wasm_runtime_layer::AsContext::as_context(&self.inner),
2108 }
2109 }
2110}
2111
2112impl<T, E: backend::WasmEngine> AsContextMut for Store<T, E> {
2113 fn as_context_mut(&mut self) -> StoreContextMut<Self::UserState, Self::Engine> {
2114 StoreContextMut {
2115 inner: wasm_runtime_layer::AsContextMut::as_context_mut(&mut self.inner),
2116 }
2117 }
2118}
2119
2120impl<T: AsContext> AsContext for &T {
2121 type Engine = T::Engine;
2122
2123 type UserState = T::UserState;
2124
2125 fn as_context(&self) -> StoreContext<Self::UserState, Self::Engine> {
2126 (**self).as_context()
2127 }
2128}
2129
2130impl<T: AsContext> AsContext for &mut T {
2131 type Engine = T::Engine;
2132
2133 type UserState = T::UserState;
2134
2135 fn as_context(&self) -> StoreContext<Self::UserState, Self::Engine> {
2136 (**self).as_context()
2137 }
2138}
2139
2140impl<T: AsContextMut> AsContextMut for &mut T {
2141 fn as_context_mut(&mut self) -> StoreContextMut<Self::UserState, Self::Engine> {
2142 (**self).as_context_mut()
2143 }
2144}
2145
2146impl<'a, T: 'a, E: backend::WasmEngine> AsContext for StoreContext<'a, T, E> {
2147 type Engine = E;
2148
2149 type UserState = T;
2150
2151 fn as_context(&self) -> StoreContext<Self::UserState, Self::Engine> {
2152 StoreContext {
2153 inner: wasm_runtime_layer::AsContext::as_context(&self.inner),
2154 }
2155 }
2156}
2157
2158impl<'a, T: 'a, E: backend::WasmEngine> AsContext for StoreContextMut<'a, T, E> {
2159 type Engine = E;
2160
2161 type UserState = T;
2162
2163 fn as_context(&self) -> StoreContext<Self::UserState, Self::Engine> {
2164 StoreContext {
2165 inner: wasm_runtime_layer::AsContext::as_context(&self.inner),
2166 }
2167 }
2168}
2169
2170impl<'a, T: 'a, E: backend::WasmEngine> AsContextMut for StoreContextMut<'a, T, E> {
2171 fn as_context_mut(&mut self) -> StoreContextMut<Self::UserState, Self::Engine> {
2172 StoreContextMut {
2173 inner: wasm_runtime_layer::AsContextMut::as_context_mut(&mut self.inner),
2174 }
2175 }
2176}
2177
2178struct StoreInner<T, E: backend::WasmEngine> {
2180 pub id: u64,
2182 pub data: T,
2184 pub host_functions: FuncVec<T, E>,
2186 pub host_resources: Slab<Box<dyn Any + Send + Sync>>,
2188 pub drop_host_resource: Option<wasm_runtime_layer::Func>,
2190}
2191
2192#[allow(clippy::large_enum_variant)]
2194#[derive(Clone, Debug)]
2195enum GeneratedTrampoline {
2196 ImportedFunction(ComponentImport),
2198 ResourceNew(TypeResourceTableIndex),
2200 ResourceRep(TypeResourceTableIndex),
2202 ResourceDrop(TypeResourceTableIndex, Option<CoreDef>),
2204}
2205
2206#[derive(Copy, Clone, Debug, Default)]
2208struct HandleElement {
2209 pub rep: i32,
2211 pub own: bool,
2213 pub lend_count: i32,
2215}
2216
2217#[derive(Clone, Debug, Default)]
2219struct HandleTable {
2220 array: Slab<HandleElement>,
2222 destructor: Option<wasm_runtime_layer::Func>,
2224}
2225
2226impl HandleTable {
2227 pub fn destructor(&self) -> Option<&wasm_runtime_layer::Func> {
2229 self.destructor.as_ref()
2230 }
2231
2232 pub fn set_destructor(&mut self, destructor: Option<wasm_runtime_layer::Func>) {
2234 self.destructor = destructor;
2235 }
2236
2237 pub fn get(&self, i: i32) -> Result<&HandleElement> {
2239 self.array.get(i as usize).context("Invalid handle index.")
2240 }
2241
2242 pub fn set(&mut self, i: i32, element: HandleElement) {
2245 *self
2246 .array
2247 .get_mut(i as usize)
2248 .expect("Invalid handle index.") = element;
2249 }
2250
2251 pub fn add(&mut self, handle: HandleElement) -> i32 {
2253 self.array.insert(handle) as i32
2254 }
2255
2256 pub fn remove(&mut self, i: i32) -> Result<HandleElement> {
2259 Ok(self.array.remove(i as usize))
2260 }
2261}