diff options
Diffstat (limited to 'crates/parser/src/module.rs')
| -rw-r--r-- | crates/parser/src/module.rs | 237 |
1 files changed, 154 insertions, 83 deletions
diff --git a/crates/parser/src/module.rs b/crates/parser/src/module.rs index 4030a72..9273d44 100644 --- a/crates/parser/src/module.rs +++ b/crates/parser/src/module.rs @@ -13,21 +13,13 @@ pub(crate) struct FunctionCode { pub uses_local_memory: bool, } -pub(crate) fn imported_func_count(imports: &[Import]) -> usize { - imports.iter().filter(|i| matches!(&i.kind, ImportKind::Function(_))).count() -} - -pub(crate) fn imported_memory_count(imports: &[Import]) -> u32 { - imports.iter().filter(|i| matches!(&i.kind, ImportKind::Memory(_))).count() as u32 -} - pub(crate) fn optimize_function_code( mut code: FunctionCode, options: &ParserOptions, function_results: ValueCounts, self_func_addr: u32, imported_memory_count: u32, -) -> FunctionCode { +) -> Result<FunctionCode> { let optimized = optimize::optimize_instructions( code.instructions, &mut code.data, @@ -35,17 +27,18 @@ pub(crate) fn optimize_function_code( function_results, self_func_addr, imported_memory_count, - ); + )?; code.instructions = optimized.instructions; code.uses_local_memory = optimized.uses_local_memory; - code + Ok(code) } #[derive(Default)] pub(crate) struct ModuleReader<'a> { func_validator_allocations: Option<FuncValidatorAllocations>, operators_reader_allocations: Option<OperatorsReaderAllocations>, + translation_metadata: Option<Arc<crate::visit::ModuleMetadata>>, has_code_section: bool, marker: PhantomData<&'a [u8]>, @@ -54,6 +47,7 @@ pub(crate) struct ModuleReader<'a> { pub(crate) start_func: Option<u32>, pub(crate) func_types: Arc<[Arc<FuncType>]>, pub(crate) code_type_addrs: Box<[u32]>, + code_results: Box<[ValueCounts]>, pub(crate) exports: Arc<[Export]>, pub(crate) code: Vec<FunctionCode>, pub(crate) globals: Box<[Global]>, @@ -63,19 +57,33 @@ pub(crate) struct ModuleReader<'a> { pub(crate) data: Box<[Data]>, pub(crate) elements: Box<[Element]>, pub(crate) end_reached: bool, + imported_func_count: usize, + imported_memory_count: u32, #[cfg(parallel_parser)] pending_functions: Option<Vec<crate::parallel::PendingFunction<'a>>>, } impl<'a> ModuleReader<'a> { - fn function_results(&self, ordinal: usize) -> ValueCounts { - let ty_idx = self.code_type_addrs[ordinal]; - let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug"); - ValueCounts::from_iter(ty.results()) + fn translation_metadata(&mut self) -> &crate::visit::ModuleMetadata { + if self.translation_metadata.is_none() { + self.translation_metadata = Some(Arc::new(crate::visit::ModuleMetadata::new( + &self.func_types, + &self.code_type_addrs, + &self.imports, + &self.globals, + &self.memory_types, + &self.table_types, + ))); + } + self.translation_metadata.as_deref().unwrap() } - pub(crate) fn process_payload(&mut self, payload: Payload<'_>, validator: &mut Validator) -> Result<()> { + pub(crate) fn process_payload( + &mut self, + payload: Payload<'_>, + mut validator: Option<&mut Validator>, + ) -> Result<()> { fn check_section(section: &str, duplicate: bool) -> Result<()> { debug!("found {section} section"); if duplicate { @@ -86,7 +94,9 @@ impl<'a> ModuleReader<'a> { match payload { Payload::Version { num, encoding, range } => { - validator.version(num, encoding, &range)?; + if let Some(validator) = validator.as_mut() { + validator.version(num, encoding, &range)?; + } self.version = Some(num); if let wasmparser::Encoding::Component = encoding { return Err(ParseError::InvalidEncoding(encoding)); @@ -94,40 +104,54 @@ impl<'a> ModuleReader<'a> { } Payload::StartSection { func, range } => { check_section("start", self.start_func.is_some())?; - validator.start_section(func, &range)?; + if let Some(validator) = validator.as_mut() { + validator.start_section(func, &range)?; + } self.start_func = Some(func); } Payload::TypeSection(reader) => { check_section("type", !self.func_types.is_empty())?; - validator.type_section(&reader)?; + if let Some(validator) = validator.as_mut() { + validator.type_section(&reader)?; + } self.func_types = reader.into_iter().map(|t| convert_module_type(t?)).collect::<Result<_>>()?; } Payload::GlobalSection(reader) => { check_section("global", !self.globals.is_empty())?; - validator.global_section(&reader)?; + if let Some(validator) = validator.as_mut() { + validator.global_section(&reader)?; + } self.globals = convert_module_globals(reader)?; } Payload::TableSection(reader) => { check_section("table", !self.table_types.is_empty())?; - validator.table_section(&reader)?; + if let Some(validator) = validator.as_mut() { + validator.table_section(&reader)?; + } self.table_types = reader.into_iter().map(|table| convert_module_table(table?)).collect::<Result<_>>()?; } Payload::MemorySection(reader) => { check_section("memory", !self.memory_types.is_empty())?; - validator.memory_section(&reader)?; + if let Some(validator) = validator.as_mut() { + validator.memory_section(&reader)?; + } self.memory_types = reader.into_iter().map(|memory| Ok(convert_module_memory(memory?))).collect::<Result<_>>()?; } Payload::ElementSection(reader) => { debug!("Found element section"); - validator.element_section(&reader)?; + if let Some(validator) = validator.as_mut() { + validator.element_section(&reader)?; + } self.elements = reader.into_iter().map(|element| convert_module_element(element?)).collect::<Result<_>>()?; } Payload::DataSection(reader) => { check_section("data", !self.data.is_empty())?; - validator.data_section(&reader)?; + if let Some(validator) = validator.as_mut() { + validator.data_section(&reader)?; + } self.data = reader.into_iter().map(|data| convert_module_data(data?)).collect::<Result<_>>()?; } Payload::DataCountSection { count, range } => { @@ -135,22 +159,51 @@ impl<'a> ModuleReader<'a> { if !self.data.is_empty() { return Err(ParseError::UnsupportedSection("Data count section after data section".into())); } - validator.data_count_section(count, &range)?; + if let Some(validator) = validator.as_mut() { + validator.data_count_section(count, &range)?; + } } Payload::FunctionSection(reader) => { check_section("function", !self.code_type_addrs.is_empty())?; - validator.function_section(&reader)?; - self.code_type_addrs = reader.into_iter().map(|f| Ok(f?)).collect::<Result<_>>()?; + if let Some(validator) = validator.as_mut() { + validator.function_section(&reader)?; + } + let mut type_addrs = Vec::with_capacity(reader.count() as usize); + let mut results = Vec::with_capacity(reader.count() as usize); + for ty_idx in reader { + let ty_idx = ty_idx?; + let ty = self + .func_types + .get(ty_idx as usize) + .ok_or_else(|| ParseError::Other(format!("function type index out of bounds: {ty_idx}")))?; + type_addrs.push(ty_idx); + results.push(ValueCounts::from_iter(ty.results())); + } + self.code_type_addrs = type_addrs.into_boxed_slice(); + self.code_results = results.into_boxed_slice(); } Payload::ImportSection(reader) => { check_section("import", !self.imports.is_empty())?; - validator.import_section(&reader)?; - self.imports = - reader.into_imports().map(|import| convert_module_import(import?)).collect::<Result<_>>()?; + if let Some(validator) = validator.as_mut() { + validator.import_section(&reader)?; + } + let mut imports = Vec::with_capacity(reader.count() as usize); + for import in reader.into_imports() { + let import = convert_module_import(import?)?; + match import.kind { + ImportKind::Function(_) => self.imported_func_count += 1, + ImportKind::Memory(_) => self.imported_memory_count += 1, + _ => {} + } + imports.push(import); + } + self.imports = imports.into_boxed_slice(); } Payload::ExportSection(reader) => { check_section("export", !self.exports.is_empty())?; - validator.export_section(&reader)?; + if let Some(validator) = validator.as_mut() { + validator.export_section(&reader)?; + } self.exports = reader.into_iter().map(|e| convert_module_export(e?)).collect::<Result<_>>()?; } Payload::End(offset) => { @@ -159,7 +212,9 @@ impl<'a> ModuleReader<'a> { return Err(ParseError::DuplicateSection("End section".into())); } - validator.end(offset)?; + if let Some(validator) = validator.as_mut() { + validator.end(offset)?; + } self.end_reached = true; } Payload::CustomSection(_reader) => { @@ -181,7 +236,7 @@ impl<'a> ModuleReader<'a> { count: u32, range: Range<usize>, size: u32, - validator: &mut Validator, + validator: Option<&mut Validator>, options: &ParserOptions, ) -> Result<bool> { debug!("Found code section ({count} functions)"); @@ -191,7 +246,9 @@ impl<'a> ModuleReader<'a> { self.has_code_section = true; self.code.reserve(count as usize); - validator.code_section_start(&range)?; + if let Some(validator) = validator { + validator.code_section_start(&range)?; + } #[cfg(parallel_parser)] { @@ -213,29 +270,38 @@ impl<'a> ModuleReader<'a> { pub(crate) fn process_inline_code_section_entry( &mut self, function: wasmparser::FunctionBody<'_>, - validator: &mut Validator, + validator: Option<&mut Validator>, options: &ParserOptions, ) -> Result<()> { debug!("Found code section entry"); - let func_validator_allocs = self.func_validator_allocations.take().unwrap_or_default(); + let func_validator_allocs = self.func_validator_allocations.take(); let operators_reader_allocs = self.operators_reader_allocations.take().unwrap_or_default(); - let func_to_validate = validator.code_section_entry(&function)?; - let func_validator = func_to_validate.into_validator(func_validator_allocs); + let func_validator = validator + .map(|validator| validator.code_section_entry(&function)) + .transpose()? + .map(|func| func.into_validator(func_validator_allocs.unwrap_or_default())); + + let ordinal = self.code.len(); + let ty_idx = *self + .code_type_addrs + .get(ordinal) + .ok_or_else(|| ParseError::Other("code entry has no function signature".into()))?; + let metadata = self.translation_metadata(); let (code, func_validator_allocs, operators_reader_allocs) = - convert_module_code(function, func_validator, operators_reader_allocs)?; + convert_module_code(function, func_validator, operators_reader_allocs, metadata, ty_idx)?; self.code.push(optimize_function_code( code, options, - self.function_results(self.code.len()), - (imported_func_count(&self.imports) + self.code.len()) as u32, - imported_memory_count(&self.imports), - )); + self.code_results[self.code.len()], + (self.imported_func_count + self.code.len()) as u32, + self.imported_memory_count, + )?); - self.func_validator_allocations = Some(func_validator_allocs); + self.func_validator_allocations = func_validator_allocs; self.operators_reader_allocations = Some(operators_reader_allocs); Ok(()) } @@ -243,23 +309,15 @@ impl<'a> ModuleReader<'a> { pub(crate) fn process_borrowed_code_section_entry( &mut self, function: wasmparser::FunctionBody<'a>, - validator: &mut Validator, + validator: Option<&mut Validator>, options: &ParserOptions, ) -> Result<()> { debug!("Found code section entry"); #[cfg(parallel_parser)] - if let Some(pending) = self.pending_functions.as_mut() { - let func_to_validate = validator.code_section_entry(&function)?; - let ordinal = self.code.len() + pending.len(); - let ty_idx = self.code_type_addrs[ordinal]; - pending.push(crate::parallel::PendingFunction { - ordinal, - ty_idx, - func_to_validate, - body: crate::parallel::FunctionBodyInput::Borrowed(function), - }); - return Ok(()); + if self.pending_functions.is_some() { + let func_to_validate = validator.map(|validator| validator.code_section_entry(&function)).transpose()?; + return self.queue_function(crate::parallel::FunctionBodyInput::Borrowed(function), func_to_validate); } self.process_inline_code_section_entry(function, validator, options) @@ -271,32 +329,23 @@ impl<'a> ModuleReader<'a> { count: u32, body_offset: usize, section_bytes: Arc<[u8]>, - validator: &mut Validator, + mut validator: Option<&mut Validator>, ) -> Result<()> { - let code_len = self.code.len(); - let pending = self - .pending_functions - .as_mut() - .ok_or_else(|| ParseError::Other("owned code section queued without pending storage".into()))?; - let mut reader = wasmparser::BinaryReader::new(§ion_bytes, body_offset); for _ in 0..count { let body_reader = reader.read_reader()?; let body_range = body_reader.range(); let function = wasmparser::FunctionBody::new(body_reader); - let func_to_validate = validator.code_section_entry(&function)?; - let ordinal = code_len + pending.len(); - let ty_idx = self.code_type_addrs[ordinal]; - pending.push(crate::parallel::PendingFunction { - ordinal, - ty_idx, - func_to_validate, - body: crate::parallel::FunctionBodyInput::Owned(crate::parallel::OwnedFunctionBody { + let func_to_validate = + validator.as_mut().map(|validator| validator.code_section_entry(&function)).transpose()?; + self.queue_function( + crate::parallel::FunctionBodyInput::Owned(crate::parallel::OwnedFunctionBody { section_bytes: section_bytes.clone(), body_range: (body_range.start - body_offset)..(body_range.end - body_offset), body_offset: body_range.start, }), - }); + func_to_validate, + )?; } if reader.bytes_remaining() != 0 { @@ -310,18 +359,40 @@ impl<'a> ModuleReader<'a> { } #[cfg(parallel_parser)] + fn queue_function( + &mut self, + body: crate::parallel::FunctionBodyInput<'a>, + func_to_validate: Option<wasmparser::FuncToValidate<wasmparser::ValidatorResources>>, + ) -> Result<()> { + let ordinal = self.code.len() + self.pending_functions.as_ref().map_or(0, Vec::len); + let results = *self + .code_results + .get(ordinal) + .ok_or_else(|| ParseError::Other("code entry has no function signature".into()))?; + let ty_idx = *self + .code_type_addrs + .get(ordinal) + .ok_or_else(|| ParseError::Other("code entry has no function signature".into()))?; + let job = crate::parallel::PendingFunction { ordinal, results, func_to_validate, ty_idx, body }; + self.pending_functions + .as_mut() + .ok_or_else(|| ParseError::Other("function queued without pending storage".into()))? + .push(job); + Ok(()) + } + + #[cfg(parallel_parser)] pub(crate) fn process_pending_functions(&mut self, options: &ParserOptions) -> Result<()> { let Some(pending) = self.pending_functions.take().filter(|pending| !pending.is_empty()) else { return Ok(()); }; - self.code.extend(crate::parallel::process_pending( - pending, - options, - &self.func_types, - imported_func_count(&self.imports), - imported_memory_count(&self.imports), - )?); + let imported_func_count = self.imported_func_count; + let imported_memory_count = self.imported_memory_count; + let metadata = self.translation_metadata(); + let code = + crate::parallel::process_pending(pending, metadata, options, imported_func_count, imported_memory_count)?; + self.code.extend(code); Ok(()) } @@ -339,7 +410,7 @@ impl<'a> ModuleReader<'a> { return Err(ParseError::Other("Code and code type address count mismatch".to_string())); } - let import_mem_count = imported_memory_count(&self.imports); + let import_mem_count = self.imported_memory_count; let has_local_mem_export = self.exports.iter().any(|export| export.kind == ExternalKind::Memory && export.index >= import_mem_count); let has_active_data_segment_on_local_memory = self.data.iter().any(|data| match &data.kind { @@ -371,10 +442,10 @@ impl<'a> ModuleReader<'a> { .code .into_iter() .zip(self.code_type_addrs) - .map(|(code, ty_idx)| { - let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone(); + .zip(self.code_results) + .map(|((code, ty_idx), results)| { + let ty = self.func_types.get(ty_idx as usize).expect("function type was checked while parsing").clone(); let params = ValueCounts::from_iter(ty.params()); - let results = ValueCounts::from_iter(ty.results()); if code.uses_local_memory { local_memory_allocation = LocalMemoryAllocation::Eager; } |
