Skip to content

Commit 40fe970

Browse files
keithwalexcrichton
andauthored
wasmparser: improve visit_operator performance (#2228)
* wasmparser: improve visit_operator performance - The BinaryReader can visit_operator by itself again, with no need for OperatorsReader or extra state, when the visitor implements the FrameStack trait. Validation uses this to avoid duplicating the frame stack. - OperatorsReader keeps an internal FrameStack and can be created from its allocations (and turned back into them), avoiding the need to allocate a stack of frames. * Don't require handling OperatorsReaderAllocations Make it a non-default API that other various locations can optionally use but aren't required to do so. * More test fixes * Even more test fixes * Simplify some adapter definitions * Simplify definition of `OperatorFactory` * Minor doc updates * Fix doc link --------- Co-authored-by: Alex Crichton <[email protected]>
1 parent 641b571 commit 40fe970

File tree

11 files changed

+1536
-1336
lines changed

11 files changed

+1536
-1336
lines changed

crates/wasmparser/benches/benchmark.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ use anyhow::Result;
22
use criterion::{Criterion, criterion_group, criterion_main};
33
use once_cell::unsync::Lazy;
44
use std::fs;
5+
use std::mem;
56
use std::path::Path;
67
use std::path::PathBuf;
78
use wasmparser::VisitSimdOperator;
8-
use wasmparser::{DataKind, ElementKind, Parser, Payload, Validator, VisitOperator, WasmFeatures};
9+
use wasmparser::{
10+
BinaryReader, DataKind, ElementKind, OperatorsReader, Parser, Payload, Validator,
11+
VisitOperator, WasmFeatures,
12+
};
913

1014
/// A benchmark input.
1115
pub struct BenchmarkInput {
@@ -80,6 +84,17 @@ fn collect_test_files(path: &Path, list: &mut Vec<BenchmarkInput>) -> Result<()>
8084
/// so that we can report better errors in case of failures.
8185
fn read_all_wasm(wasm: &[u8]) -> Result<()> {
8286
use Payload::*;
87+
let mut allocs = wasmparser::OperatorsReaderAllocations::default();
88+
let mut read_expr = |reader: BinaryReader<'_>| -> Result<_> {
89+
let mut ops = OperatorsReader::new_with_allocs(reader, mem::take(&mut allocs));
90+
91+
while !ops.eof() {
92+
ops.visit_operator(&mut NopVisit)?;
93+
}
94+
ops.finish()?;
95+
allocs = ops.into_allocations();
96+
Ok(())
97+
};
8398
for item in Parser::new(0).parse_all(wasm) {
8499
match item? {
85100
TypeSection(s) => {
@@ -114,9 +129,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> {
114129
}
115130
GlobalSection(s) => {
116131
for item in s {
117-
for op in item?.init_expr.get_operators_reader() {
118-
op?;
119-
}
132+
read_expr(item?.init_expr.get_binary_reader())?;
120133
}
121134
}
122135
ExportSection(s) => {
@@ -128,9 +141,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> {
128141
for item in s {
129142
let item = item?;
130143
if let ElementKind::Active { offset_expr, .. } = item.kind {
131-
for op in offset_expr.get_operators_reader() {
132-
op?;
133-
}
144+
read_expr(offset_expr.get_binary_reader())?;
134145
}
135146
match item.items {
136147
wasmparser::ElementItems::Functions(r) => {
@@ -150,9 +161,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> {
150161
for item in s {
151162
let item = item?;
152163
if let DataKind::Active { offset_expr, .. } = item.kind {
153-
for op in offset_expr.get_operators_reader() {
154-
op?;
155-
}
164+
read_expr(offset_expr.get_binary_reader())?;
156165
}
157166
}
158167
}
@@ -161,11 +170,7 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> {
161170
for item in locals.by_ref() {
162171
let _ = item?;
163172
}
164-
let mut ops = locals.into_operators_reader();
165-
while !ops.eof() {
166-
ops.visit_operator(&mut NopVisit)?;
167-
}
168-
ops.finish()?;
173+
read_expr(locals.into_binary_reader_for_operators())?;
169174
}
170175

171176
// Component sections

crates/wasmparser/src/arity.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
use crate::prelude::*;
1717
use crate::{
18-
BinaryReaderError, BlockType, BrTable, CompositeInnerType, ContType, FrameKind, FuncType,
19-
Operator, OperatorsReader, RefType, Result, ResumeTable, SubType, TryTable, ValType,
18+
BlockType, BrTable, CompositeInnerType, ContType, FrameKind, FuncType, Operator, RefType,
19+
ResumeTable, SubType, TryTable, ValType,
2020
};
2121

2222
/// To compute the arity (param and result counts) of "variable-arity"
@@ -70,15 +70,6 @@ pub trait ModuleArity {
7070
}
7171
}
7272

73-
impl OperatorsReader<'_> {
74-
/// Read the next operator and compute its arity (param and result counts)
75-
pub fn operator_arity(&self, module: &impl ModuleArity) -> Result<(u32, u32)> {
76-
self.clone().read()?.operator_arity(module).ok_or_else(|| {
77-
BinaryReaderError::new("operator arity is unknown", self.original_position())
78-
})
79-
}
80-
}
81-
8273
impl Operator<'_> {
8374
/// Compute the arity (param and result counts) of the operator, given
8475
/// an impl ModuleArity, which stores the necessary module state.

0 commit comments

Comments
 (0)