summaryrefslogtreecommitdiff
path: root/crates/parser/src/module.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/module.rs')
-rw-r--r--crates/parser/src/module.rs237
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(&section_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;
}