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