1 use wasmparser::ValType;
2
3 use crate::component::info::Accessor;
4 use crate::component::{ComponentContext, ComponentInstanceState, WIZER_INSTANCE};
5 use crate::snapshot::Snapshot;
6 use crate::{InstanceState, SnapshotVal};
7
8 /// Snapshot result of a component.
9 ///
10 /// Currently this only contains the state for instances found within the
11 /// component, and each instance's snapshot is defined as the same core wasm
12 /// snapshot state.
13 pub struct ComponentSnapshot {
14 /// List of snapshots for corresponding module indices.
15 ///
16 /// Note that modules don't get a snapshot if they aren't instantiated.
17 pub(crate) modules: Vec<(u32, Snapshot)>,
18 }
19
snapshot( component: &ComponentContext<'_>, ctx: &mut impl ComponentInstanceState, ) -> ComponentSnapshot20 pub async fn snapshot(
21 component: &ComponentContext<'_>,
22 ctx: &mut impl ComponentInstanceState,
23 ) -> ComponentSnapshot {
24 let mut modules = Vec::new();
25
26 for (module_index, module) in component.core_modules() {
27 // Ignore uninstantiated modules.
28 if !component.core_instantiations.contains_key(&module_index) {
29 continue;
30 }
31
32 // Use the core-level snapshotting routines to collect a
33 // snapshot of the module. Requests for core-level items are
34 // redirected through the component-level `ctx` provided.
35 let snapshot = crate::snapshot::snapshot(
36 module,
37 &mut ViaComponent {
38 ctx,
39 module_index,
40 component,
41 },
42 )
43 .await;
44 modules.push((module_index, snapshot));
45 }
46
47 ComponentSnapshot { modules }
48 }
49
50 /// Implementation of `InstanceState` via component model primitives.
51 struct ViaComponent<'a, 'b, S> {
52 ctx: &'a mut S,
53 component: &'a ComponentContext<'b>,
54 module_index: u32,
55 }
56
57 impl<'a, S> ViaComponent<'a, '_, S>
58 where
59 S: ComponentInstanceState,
60 {
get_accessor(&self, name: &str) -> &'a Accessor61 fn get_accessor(&self, name: &str) -> &'a Accessor {
62 let accessors = self.component.accessors.as_ref().unwrap();
63 accessors
64 .iter()
65 .find(|a| match a {
66 Accessor::Global {
67 module_index,
68 core_export_name,
69 ..
70 }
71 | Accessor::Memory {
72 module_index,
73 core_export_name,
74 ..
75 } => *module_index == self.module_index && core_export_name == name,
76 })
77 .unwrap()
78 }
79 }
80
81 impl<S> InstanceState for ViaComponent<'_, '_, S>
82 where
83 S: ComponentInstanceState,
84 {
global_get(&mut self, name: &str, _: ValType) -> SnapshotVal85 async fn global_get(&mut self, name: &str, _: ValType) -> SnapshotVal {
86 let Accessor::Global {
87 accessor_export_name,
88 ty,
89 ..
90 } = self.get_accessor(name)
91 else {
92 panic!("expected global accessor for {name}");
93 };
94 match ty {
95 wasmparser::ValType::I32 => SnapshotVal::I32(
96 self.ctx
97 .call_func_ret_s32(WIZER_INSTANCE, accessor_export_name)
98 .await,
99 ),
100 wasmparser::ValType::I64 => SnapshotVal::I64(
101 self.ctx
102 .call_func_ret_s64(WIZER_INSTANCE, accessor_export_name)
103 .await,
104 ),
105 wasmparser::ValType::F32 => SnapshotVal::F32(
106 self.ctx
107 .call_func_ret_f32(WIZER_INSTANCE, accessor_export_name)
108 .await,
109 ),
110 wasmparser::ValType::F64 => SnapshotVal::F64(
111 self.ctx
112 .call_func_ret_f64(WIZER_INSTANCE, accessor_export_name)
113 .await,
114 ),
115 wasmparser::ValType::V128 => todo!(),
116 wasmparser::ValType::Ref(_) => unreachable!(),
117 }
118 }
119
memory_contents(&mut self, name: &str, contents: impl FnOnce(&[u8]) + Send)120 async fn memory_contents(&mut self, name: &str, contents: impl FnOnce(&[u8]) + Send) {
121 let Accessor::Memory {
122 accessor_export_name,
123 ..
124 } = self.get_accessor(name)
125 else {
126 panic!("expected memory accessor for {name}");
127 };
128 self.ctx
129 .call_func_ret_list_u8(WIZER_INSTANCE, accessor_export_name, contents)
130 .await
131 }
132 }
133