1 use crate::component::ComponentContext; 2 use anyhow::{Result, bail}; 3 use std::collections::hash_map::Entry; 4 use wasmparser::{ 5 CanonicalFunction, ComponentAlias, ComponentExternalKind, ComponentOuterAliasKind, Encoding, 6 Instance, Parser, Payload, 7 }; 8 9 /// Parse the given Wasm bytes into a `ComponentContext` tree. 10 /// 11 /// This will parse the input component and build up metadata that Wizer needs 12 /// to know about the component. At this time there are limitations to this 13 /// parsing phase which in theory could be lifted in the future but serve as 14 /// simplifying assumptions for now: 15 /// 16 /// * Nested components are not supported. 17 /// * Imported modules or components are not supported. 18 /// * Instantiating a module twice is not supported. 19 /// * Component-level start functions are not supported. 20 /// 21 /// Some of these restrictions are likely to be loosened over time, however. 22 pub(crate) fn parse<'a>(full_wasm: &'a [u8]) -> anyhow::Result<ComponentContext<'a>> { 23 let mut component = ComponentContext::default(); 24 let mut parser = Parser::new(0).parse_all(full_wasm); 25 26 while let Some(payload) = parser.next() { 27 let payload = payload?; 28 29 match &payload { 30 // Module sections get parsed with wizer's core wasm support. 31 Payload::ModuleSection { .. } => { 32 let info = crate::parse::parse_with(&full_wasm, &mut parser)?; 33 component.push_module_section(info); 34 } 35 36 // All other sections get pushed raw as-is into the component. 37 _ => { 38 if let Some((id, range)) = payload.as_section() { 39 component.push_raw_section(wasm_encoder::RawSection { 40 id, 41 data: &full_wasm[range], 42 }); 43 } 44 } 45 } 46 47 // Further validation/handling of each section, mostly about maintaining 48 // index spaces so we know what indices are used when the instrumented 49 // component is produced. 50 match payload { 51 Payload::Version { 52 encoding: Encoding::Module, 53 .. 54 } => { 55 bail!("expected a component, found a core module"); 56 } 57 58 Payload::ComponentSection { .. } => { 59 bail!("wizer does not currently support nested components"); 60 } 61 62 Payload::InstanceSection(reader) => { 63 for instance in reader { 64 let instance_index = component.inc_core_instances(); 65 66 if let Instance::Instantiate { module_index, .. } = instance? { 67 match component.core_instantiations.entry(module_index) { 68 Entry::Vacant(entry) => { 69 entry.insert(instance_index); 70 } 71 Entry::Occupied(_) => bail!("modules may be instantiated at most once"), 72 } 73 } 74 } 75 } 76 Payload::ComponentInstanceSection(reader) => { 77 for _ in reader { 78 component.inc_instances(); 79 } 80 } 81 82 Payload::ComponentAliasSection(reader) => { 83 for alias in reader { 84 match alias? { 85 ComponentAlias::CoreInstanceExport { kind, .. } => { 86 component.inc_core(kind); 87 } 88 ComponentAlias::InstanceExport { kind, .. } => { 89 validate_item_kind(kind, "aliases")?; 90 component.inc(kind); 91 } 92 ComponentAlias::Outer { kind, .. } => match kind { 93 ComponentOuterAliasKind::CoreType => {} 94 ComponentOuterAliasKind::Type => { 95 component.inc_types(); 96 } 97 ComponentOuterAliasKind::CoreModule => { 98 bail!("wizer does not currently support module aliases"); 99 } 100 ComponentOuterAliasKind::Component => { 101 bail!("wizer does not currently support component aliases"); 102 } 103 }, 104 } 105 } 106 } 107 108 Payload::ComponentCanonicalSection(reader) => { 109 for function in reader { 110 match function? { 111 CanonicalFunction::Lift { .. } => { 112 component.inc_funcs(); 113 } 114 _ => { 115 component.inc_core_funcs(); 116 } 117 } 118 } 119 } 120 121 Payload::ComponentImportSection(reader) => { 122 for import in reader { 123 let kind = import?.ty.kind(); 124 validate_item_kind(kind, "imports")?; 125 component.inc(kind); 126 } 127 } 128 129 Payload::ComponentExportSection(reader) => { 130 for export in reader { 131 let kind = export?.kind; 132 validate_item_kind(kind, "exports")?; 133 component.inc(kind); 134 } 135 } 136 137 Payload::ComponentTypeSection(reader) => { 138 for _ in reader { 139 component.inc_types(); 140 } 141 } 142 143 // The `start` section for components is itself not stable, so not 144 // super urgent to handle. A simplifying assumption is made to just 145 // reject it outright for now if it shows up. 146 Payload::ComponentStartSection { .. } => { 147 bail!("wizer does not currently support component start functions"); 148 } 149 150 _ => {} 151 } 152 } 153 154 Ok(component) 155 } 156 157 fn validate_item_kind(kind: ComponentExternalKind, msg: &str) -> Result<()> { 158 match kind { 159 // Aliasing modules would require keeping track of where a module's 160 // original definition is. There's not much usage of this in the wild 161 // so reject it for now as a simplifying assumption. 162 ComponentExternalKind::Module => { 163 bail!("wizer does not currently support module {msg}"); 164 } 165 166 // Aliasing components deals with nested instantiations or similar, 167 // where a simplifying assumption is made to not worry about that for now. 168 ComponentExternalKind::Component => { 169 bail!("wizer does not currently support component {msg}"); 170 } 171 172 // Like start sections, support for this is just deferred to some other 173 // time, if ever. 174 ComponentExternalKind::Value => { 175 bail!("wizer does not currently support value {msg}"); 176 } 177 178 ComponentExternalKind::Func 179 | ComponentExternalKind::Type 180 | ComponentExternalKind::Instance => Ok(()), 181 } 182 } 183