1278656ceSAlex Crichton use crate::component::ComponentContext;
2278656ceSAlex Crichton use std::collections::hash_map::Entry;
3278656ceSAlex Crichton use wasmparser::{
4278656ceSAlex Crichton     CanonicalFunction, ComponentAlias, ComponentExternalKind, ComponentOuterAliasKind, Encoding,
5278656ceSAlex Crichton     Instance, Parser, Payload,
6278656ceSAlex Crichton };
7*228f448bSNick Fitzgerald use wasmtime::{Result, bail};
8278656ceSAlex Crichton 
9278656ceSAlex Crichton /// Parse the given Wasm bytes into a `ComponentContext` tree.
10278656ceSAlex Crichton ///
11278656ceSAlex Crichton /// This will parse the input component and build up metadata that Wizer needs
12278656ceSAlex Crichton /// to know about the component. At this time there are limitations to this
13278656ceSAlex Crichton /// parsing phase which in theory could be lifted in the future but serve as
14278656ceSAlex Crichton /// simplifying assumptions for now:
15278656ceSAlex Crichton ///
16155f8276SAlex Crichton /// * Nested components with modules are not supported.
17278656ceSAlex Crichton /// * Imported modules or components are not supported.
18278656ceSAlex Crichton /// * Instantiating a module twice is not supported.
19278656ceSAlex Crichton /// * Component-level start functions are not supported.
20278656ceSAlex Crichton ///
21278656ceSAlex Crichton /// Some of these restrictions are likely to be loosened over time, however.
parse<'a>(full_wasm: &'a [u8]) -> wasmtime::Result<ComponentContext<'a>>22*228f448bSNick Fitzgerald pub(crate) fn parse<'a>(full_wasm: &'a [u8]) -> wasmtime::Result<ComponentContext<'a>> {
23278656ceSAlex Crichton     let mut component = ComponentContext::default();
24155f8276SAlex Crichton     let parser = Parser::new(0).parse_all(full_wasm);
25155f8276SAlex Crichton     parse_into(Some(&mut component), full_wasm, parser)?;
26155f8276SAlex Crichton     Ok(component)
27155f8276SAlex Crichton }
28278656ceSAlex Crichton 
parse_into<'a>( mut cx: Option<&mut ComponentContext<'a>>, full_wasm: &'a [u8], mut iter: impl Iterator<Item = wasmparser::Result<Payload<'a>>>, ) -> wasmtime::Result<()>29155f8276SAlex Crichton fn parse_into<'a>(
30155f8276SAlex Crichton     mut cx: Option<&mut ComponentContext<'a>>,
31155f8276SAlex Crichton     full_wasm: &'a [u8],
32155f8276SAlex Crichton     mut iter: impl Iterator<Item = wasmparser::Result<Payload<'a>>>,
33*228f448bSNick Fitzgerald ) -> wasmtime::Result<()> {
34155f8276SAlex Crichton     let mut stack = Vec::new();
35155f8276SAlex Crichton     while let Some(payload) = iter.next() {
36278656ceSAlex Crichton         let payload = payload?;
37278656ceSAlex Crichton 
38278656ceSAlex Crichton         match &payload {
39278656ceSAlex Crichton             // Module sections get parsed with wizer's core wasm support.
40155f8276SAlex Crichton             Payload::ModuleSection { .. } => match &mut cx {
41155f8276SAlex Crichton                 Some(component) => {
42155f8276SAlex Crichton                     let info = crate::parse::parse_with(&full_wasm, &mut iter)?;
43278656ceSAlex Crichton                     component.push_module_section(info);
44278656ceSAlex Crichton                 }
45155f8276SAlex Crichton                 None => {
46155f8276SAlex Crichton                     bail!("nested components with modules not currently supported");
47155f8276SAlex Crichton                 }
48155f8276SAlex Crichton             },
49278656ceSAlex Crichton 
50278656ceSAlex Crichton             // All other sections get pushed raw as-is into the component.
51278656ceSAlex Crichton             _ => {
52155f8276SAlex Crichton                 if let Some((id, range)) = payload.as_section()
53155f8276SAlex Crichton                     && let Some(component) = &mut cx
54155f8276SAlex Crichton                 {
55278656ceSAlex Crichton                     component.push_raw_section(wasm_encoder::RawSection {
56278656ceSAlex Crichton                         id,
57278656ceSAlex Crichton                         data: &full_wasm[range],
58278656ceSAlex Crichton                     });
59278656ceSAlex Crichton                 }
60278656ceSAlex Crichton             }
61278656ceSAlex Crichton         }
62278656ceSAlex Crichton 
63278656ceSAlex Crichton         // Further validation/handling of each section, mostly about maintaining
64278656ceSAlex Crichton         // index spaces so we know what indices are used when the instrumented
65278656ceSAlex Crichton         // component is produced.
66278656ceSAlex Crichton         match payload {
67278656ceSAlex Crichton             Payload::Version {
68278656ceSAlex Crichton                 encoding: Encoding::Module,
69278656ceSAlex Crichton                 ..
70278656ceSAlex Crichton             } => {
71278656ceSAlex Crichton                 bail!("expected a component, found a core module");
72278656ceSAlex Crichton             }
73278656ceSAlex Crichton 
74278656ceSAlex Crichton             Payload::ComponentSection { .. } => {
75155f8276SAlex Crichton                 stack.push(cx.take());
76155f8276SAlex Crichton             }
77155f8276SAlex Crichton 
78155f8276SAlex Crichton             Payload::End(_) => {
79155f8276SAlex Crichton                 if stack.len() > 0 {
80155f8276SAlex Crichton                     cx = stack.pop().unwrap();
81155f8276SAlex Crichton                 }
82278656ceSAlex Crichton             }
83278656ceSAlex Crichton 
84278656ceSAlex Crichton             Payload::InstanceSection(reader) => {
85155f8276SAlex Crichton                 if let Some(component) = &mut cx {
86278656ceSAlex Crichton                     for instance in reader {
87278656ceSAlex Crichton                         let instance_index = component.inc_core_instances();
88278656ceSAlex Crichton 
89278656ceSAlex Crichton                         if let Instance::Instantiate { module_index, .. } = instance? {
90278656ceSAlex Crichton                             match component.core_instantiations.entry(module_index) {
91278656ceSAlex Crichton                                 Entry::Vacant(entry) => {
92278656ceSAlex Crichton                                     entry.insert(instance_index);
93278656ceSAlex Crichton                                 }
94155f8276SAlex Crichton                                 Entry::Occupied(_) => {
95155f8276SAlex Crichton                                     bail!("modules may be instantiated at most once")
96155f8276SAlex Crichton                                 }
97155f8276SAlex Crichton                             }
98278656ceSAlex Crichton                         }
99278656ceSAlex Crichton                     }
100278656ceSAlex Crichton                 }
101278656ceSAlex Crichton             }
102278656ceSAlex Crichton             Payload::ComponentInstanceSection(reader) => {
103155f8276SAlex Crichton                 if let Some(component) = &mut cx {
104278656ceSAlex Crichton                     for _ in reader {
105278656ceSAlex Crichton                         component.inc_instances();
106278656ceSAlex Crichton                     }
107278656ceSAlex Crichton                 }
108155f8276SAlex Crichton             }
109278656ceSAlex Crichton 
110278656ceSAlex Crichton             Payload::ComponentAliasSection(reader) => {
111278656ceSAlex Crichton                 for alias in reader {
112278656ceSAlex Crichton                     match alias? {
113278656ceSAlex Crichton                         ComponentAlias::CoreInstanceExport { kind, .. } => {
114155f8276SAlex Crichton                             if let Some(component) = &mut cx {
115278656ceSAlex Crichton                                 component.inc_core(kind);
116278656ceSAlex Crichton                             }
117155f8276SAlex Crichton                         }
118278656ceSAlex Crichton                         ComponentAlias::InstanceExport { kind, .. } => {
119278656ceSAlex Crichton                             validate_item_kind(kind, "aliases")?;
120155f8276SAlex Crichton                             if let Some(component) = &mut cx {
121278656ceSAlex Crichton                                 component.inc(kind);
122278656ceSAlex Crichton                             }
123155f8276SAlex Crichton                         }
124278656ceSAlex Crichton                         ComponentAlias::Outer { kind, .. } => match kind {
125278656ceSAlex Crichton                             ComponentOuterAliasKind::CoreType => {}
126278656ceSAlex Crichton                             ComponentOuterAliasKind::Type => {
127155f8276SAlex Crichton                                 if let Some(component) = &mut cx {
128278656ceSAlex Crichton                                     component.inc_types();
129278656ceSAlex Crichton                                 }
130155f8276SAlex Crichton                             }
131278656ceSAlex Crichton                             ComponentOuterAliasKind::CoreModule => {
132278656ceSAlex Crichton                                 bail!("wizer does not currently support module aliases");
133278656ceSAlex Crichton                             }
134278656ceSAlex Crichton                             ComponentOuterAliasKind::Component => {
135278656ceSAlex Crichton                                 bail!("wizer does not currently support component aliases");
136278656ceSAlex Crichton                             }
137278656ceSAlex Crichton                         },
138278656ceSAlex Crichton                     }
139278656ceSAlex Crichton                 }
140278656ceSAlex Crichton             }
141278656ceSAlex Crichton 
142278656ceSAlex Crichton             Payload::ComponentCanonicalSection(reader) => {
143278656ceSAlex Crichton                 for function in reader {
144278656ceSAlex Crichton                     match function? {
145278656ceSAlex Crichton                         CanonicalFunction::Lift { .. } => {
146155f8276SAlex Crichton                             if let Some(component) = &mut cx {
147278656ceSAlex Crichton                                 component.inc_funcs();
148278656ceSAlex Crichton                             }
149155f8276SAlex Crichton                         }
150278656ceSAlex Crichton                         _ => {
151155f8276SAlex Crichton                             if let Some(component) = &mut cx {
152278656ceSAlex Crichton                                 component.inc_core_funcs();
153278656ceSAlex Crichton                             }
154278656ceSAlex Crichton                         }
155278656ceSAlex Crichton                     }
156278656ceSAlex Crichton                 }
157155f8276SAlex Crichton             }
158278656ceSAlex Crichton 
159278656ceSAlex Crichton             Payload::ComponentImportSection(reader) => {
160278656ceSAlex Crichton                 for import in reader {
161278656ceSAlex Crichton                     let kind = import?.ty.kind();
162278656ceSAlex Crichton                     validate_item_kind(kind, "imports")?;
163155f8276SAlex Crichton                     if let Some(component) = &mut cx {
164278656ceSAlex Crichton                         component.inc(kind);
165278656ceSAlex Crichton                     }
166278656ceSAlex Crichton                 }
167155f8276SAlex Crichton             }
168278656ceSAlex Crichton 
169278656ceSAlex Crichton             Payload::ComponentExportSection(reader) => {
170278656ceSAlex Crichton                 for export in reader {
171278656ceSAlex Crichton                     let kind = export?.kind;
172278656ceSAlex Crichton                     validate_item_kind(kind, "exports")?;
173155f8276SAlex Crichton                     if let Some(component) = &mut cx {
174278656ceSAlex Crichton                         component.inc(kind);
175278656ceSAlex Crichton                     }
176278656ceSAlex Crichton                 }
177155f8276SAlex Crichton             }
178278656ceSAlex Crichton 
179278656ceSAlex Crichton             Payload::ComponentTypeSection(reader) => {
180278656ceSAlex Crichton                 for _ in reader {
181155f8276SAlex Crichton                     if let Some(component) = &mut cx {
182278656ceSAlex Crichton                         component.inc_types();
183278656ceSAlex Crichton                     }
184278656ceSAlex Crichton                 }
185155f8276SAlex Crichton             }
186278656ceSAlex Crichton 
187278656ceSAlex Crichton             // The `start` section for components is itself not stable, so not
188278656ceSAlex Crichton             // super urgent to handle. A simplifying assumption is made to just
189278656ceSAlex Crichton             // reject it outright for now if it shows up.
190278656ceSAlex Crichton             Payload::ComponentStartSection { .. } => {
191278656ceSAlex Crichton                 bail!("wizer does not currently support component start functions");
192278656ceSAlex Crichton             }
193278656ceSAlex Crichton 
194278656ceSAlex Crichton             _ => {}
195278656ceSAlex Crichton         }
196278656ceSAlex Crichton     }
197278656ceSAlex Crichton 
198155f8276SAlex Crichton     Ok(())
199278656ceSAlex Crichton }
200278656ceSAlex Crichton 
validate_item_kind(kind: ComponentExternalKind, msg: &str) -> Result<()>201278656ceSAlex Crichton fn validate_item_kind(kind: ComponentExternalKind, msg: &str) -> Result<()> {
202278656ceSAlex Crichton     match kind {
203278656ceSAlex Crichton         // Aliasing modules would require keeping track of where a module's
204278656ceSAlex Crichton         // original definition is. There's not much usage of this in the wild
205278656ceSAlex Crichton         // so reject it for now as a simplifying assumption.
206278656ceSAlex Crichton         ComponentExternalKind::Module => {
207278656ceSAlex Crichton             bail!("wizer does not currently support module {msg}");
208278656ceSAlex Crichton         }
209278656ceSAlex Crichton 
210278656ceSAlex Crichton         // Aliasing components deals with nested instantiations or similar,
211278656ceSAlex Crichton         // where a simplifying assumption is made to not worry about that for now.
212278656ceSAlex Crichton         ComponentExternalKind::Component => {
213278656ceSAlex Crichton             bail!("wizer does not currently support component {msg}");
214278656ceSAlex Crichton         }
215278656ceSAlex Crichton 
216278656ceSAlex Crichton         // Like start sections, support for this is just deferred to some other
217278656ceSAlex Crichton         // time, if ever.
218278656ceSAlex Crichton         ComponentExternalKind::Value => {
219278656ceSAlex Crichton             bail!("wizer does not currently support value {msg}");
220278656ceSAlex Crichton         }
221278656ceSAlex Crichton 
222278656ceSAlex Crichton         ComponentExternalKind::Func
223278656ceSAlex Crichton         | ComponentExternalKind::Type
224278656ceSAlex Crichton         | ComponentExternalKind::Instance => Ok(()),
225278656ceSAlex Crichton     }
226278656ceSAlex Crichton }
227