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