Skip to content

Commit 5b46a26

Browse files
Support optimizing feature checks at compile time (#1733)
* Support optimizing feature checks at compile time Something I've long wanted for `wasmparser` is the ability to constant-propagate decisions about feature selection instead of requiring runtime checks to do so. This should be a performance win for proposals as they become standardized and more and more of wasm is gated behind some feature or another. The goal with this is to enable a mode of `wasmparser` which doesn't require runtime checks of booleans/bits to see whether a proposal is enabled or not. In lieu of not redesigning everything too much (e.g. adding `F: WasmFeatures` everywhere) this commit adds a new compile time Cargo feature to the crate called `features` which, when disabled, makes `WasmFeatures` a zero-sized type that represent the default active features for `wasmparser`. This enables const-propagating decisions about features throughout the codebase and should help optimize the validator/decoder in niche situations. * Add required feature * Update crates/wasmparser/src/features.rs Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> --------- Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com>
1 parent bf41228 commit 5b46a26

File tree

38 files changed

+271
-175
lines changed

38 files changed

+271
-175
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ jobs:
233233
- run: cargo check --no-default-features -p wasmparser --target x86_64-unknown-none --features validate,serde,no-hash-maps
234234
- run: cargo check --no-default-features -p wasmparser --features std
235235
- run: cargo check --no-default-features -p wasmparser --features validate
236+
- run: cargo check --no-default-features -p wasmparser --features features
237+
- run: cargo check --no-default-features -p wasmparser --features features,validate
236238
- run: cargo check --no-default-features -p wasmparser --features no-hash-maps
237239
- run: cargo check --no-default-features -p wasmparser --features serde
238240
- run: cargo check --no-default-features -p wasmparser --features serde,no-hash-maps

Cargo.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ wat = { workspace = true, features = ['dwarf'] }
122122
termcolor = { workspace = true }
123123

124124
# Dependencies of `validate`
125-
wasmparser = { workspace = true, optional = true, features = ['validate'] }
125+
wasmparser = { workspace = true, optional = true }
126126
rayon = { workspace = true, optional = true }
127127
bitflags = { workspace = true, optional = true }
128128

@@ -211,7 +211,15 @@ default = [
211211
]
212212

213213
# Each subcommand is gated behind a feature and lists the dependencies it needs
214-
validate = ['dep:wasmparser', 'rayon', 'dep:addr2line', 'dep:gimli', 'dep:bitflags']
214+
validate = [
215+
'dep:wasmparser',
216+
'rayon',
217+
'dep:addr2line',
218+
'dep:gimli',
219+
'dep:bitflags',
220+
'wasmparser/validate',
221+
'wasmparser/features',
222+
]
215223
print = []
216224
parse = []
217225
smith = ['wasm-smith', 'arbitrary', 'dep:serde', 'dep:serde_derive', 'dep:serde_json']

crates/wasm-compose/src/graph.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use wasmparser::{
1717
ResourceId, SubtypeCx, Types, TypesRef,
1818
},
1919
Chunk, ComponentExternalKind, ComponentTypeRef, Encoding, Parser, Payload, ValidPayload,
20-
Validator, WasmFeatures,
20+
Validator,
2121
};
2222

2323
pub(crate) fn type_desc(item: ComponentEntityType) -> &'static str {
@@ -98,8 +98,7 @@ impl<'a> Component<'a> {
9898
fn parse(name: String, path: Option<PathBuf>, bytes: Cow<'a, [u8]>) -> Result<Self> {
9999
let mut parser = Parser::new(0);
100100
let mut parsers = Vec::new();
101-
let mut validator =
102-
Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL);
101+
let mut validator = Validator::new();
103102
let mut imports = IndexMap::new();
104103
let mut exports = IndexMap::new();
105104

@@ -990,7 +989,7 @@ impl<'a> CompositionGraph<'a> {
990989
let bytes = CompositionGraphEncoder::new(options, self).encode()?;
991990

992991
if options.validate {
993-
Validator::new_with_features(WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL)
992+
Validator::new()
994993
.validate_all(&bytes)
995994
.context("failed to validate encoded graph bytes")?;
996995
}

crates/wasm-encoder/src/core/code.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@ impl CodeSection {
8383
/// into a new code section encoder:
8484
///
8585
/// ```
86-
/// # use wasmparser::{BinaryReader, WasmFeatures, CodeSectionReader};
86+
/// # use wasmparser::{BinaryReader, CodeSectionReader};
8787
/// // id, size, # entries, entry
8888
/// let code_section = [10, 6, 1, 4, 0, 65, 0, 11];
8989
///
9090
/// // Parse the code section.
91-
/// let reader = BinaryReader::new(&code_section, 0, WasmFeatures::all());
91+
/// let reader = BinaryReader::new(&code_section, 0);
9292
/// let reader = CodeSectionReader::new(reader).unwrap();
9393
/// let body = reader.into_iter().next().unwrap().unwrap();
9494
/// let body_range = body.range();

crates/wasm-metadata/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::ops::Range;
1010
use wasm_encoder::{ComponentSection as _, ComponentSectionId, Encode, Section};
1111
use wasmparser::{
1212
BinaryReader, ComponentNameSectionReader, KnownCustom, NameSectionReader, Parser, Payload::*,
13-
ProducersSectionReader, WasmFeatures,
13+
ProducersSectionReader,
1414
};
1515

1616
/// A representation of a WebAssembly producers section.
@@ -64,7 +64,7 @@ impl Producers {
6464
}
6565
/// Read the producers section from a Wasm binary.
6666
pub fn from_bytes(bytes: &[u8], offset: usize) -> Result<Self> {
67-
let reader = BinaryReader::new(bytes, offset, WasmFeatures::all());
67+
let reader = BinaryReader::new(bytes, offset);
6868
let section = ProducersSectionReader::new(reader)?;
6969
let mut fields = IndexMap::new();
7070
for field in section.into_iter() {
@@ -604,7 +604,7 @@ impl<'a> ModuleNames<'a> {
604604
/// Read a name section from a WebAssembly binary. Records the module name, and all other
605605
/// contents of name section, for later serialization.
606606
pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result<ModuleNames<'a>> {
607-
let reader = BinaryReader::new(bytes, offset, WasmFeatures::all());
607+
let reader = BinaryReader::new(bytes, offset);
608608
let section = NameSectionReader::new(reader);
609609
let mut s = Self::empty();
610610
for name in section.into_iter() {
@@ -690,7 +690,7 @@ impl<'a> ComponentNames<'a> {
690690
/// Read a component-name section from a WebAssembly binary. Records the component name, as
691691
/// well as all other component name fields for later serialization.
692692
pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result<ComponentNames<'a>> {
693-
let reader = BinaryReader::new(bytes, offset, WasmFeatures::all());
693+
let reader = BinaryReader::new(bytes, offset);
694694
let section = ComponentNameSectionReader::new(reader);
695695
let mut s = Self::empty();
696696
for name in section.into_iter() {

crates/wasm-mutate/src/info.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
use std::collections::HashSet;
66
use std::ops::Range;
77
use wasm_encoder::{RawSection, SectionId};
8-
use wasmparser::{BinaryReader, Chunk, Parser, Payload, WasmFeatures};
8+
use wasmparser::{BinaryReader, Chunk, Parser, Payload};
99

1010
/// Provides module information for future usage during mutation
1111
/// an instance of ModuleInfo could be user to determine which mutation could be applied
@@ -220,7 +220,7 @@ impl<'a> ModuleInfo<'a> {
220220
pub fn has_nonempty_code(&self) -> bool {
221221
if let Some(section) = self.code {
222222
let section_data = self.raw_sections[section].data;
223-
let reader = BinaryReader::new(section_data, 0, WasmFeatures::all());
223+
let reader = BinaryReader::new(section_data, 0);
224224
wasmparser::CodeSectionReader::new(reader)
225225
.map(|r| r.count() != 0)
226226
.unwrap_or(false)
@@ -253,7 +253,7 @@ impl<'a> ModuleInfo<'a> {
253253
}
254254

255255
pub fn get_binary_reader(&self, i: usize) -> wasmparser::BinaryReader<'a> {
256-
BinaryReader::new(self.raw_sections[i].data, 0, WasmFeatures::all())
256+
BinaryReader::new(self.raw_sections[i].data, 0)
257257
}
258258

259259
pub fn has_exports(&self) -> bool {

crates/wasm-mutate/src/mutators/remove_section.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub enum RemoveSection {
1616

1717
fn is_empty_section(section: &wasm_encoder::RawSection) -> bool {
1818
use wasmparser::*;
19-
let reader = BinaryReader::new(section.data, 0, WasmFeatures::all());
19+
let reader = BinaryReader::new(section.data, 0);
2020
crate::module::match_section_id! {
2121
match section.id;
2222
Custom => Ok(section.data.is_empty()),

crates/wasm-shrink/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ log = { workspace = true }
2121
rand = { workspace = true }
2222
clap = { workspace = true, optional = true }
2323
wasm-mutate = { workspace = true }
24-
wasmparser = { workspace = true, features = ['validate'] }
24+
wasmparser = { workspace = true, features = ['validate', 'features'] }
2525

2626
[dev-dependencies]
2727
env_logger = { workspace = true }

crates/wasm-shrink/src/lib.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
//!
44
//! See the [`WasmShrink`] type for details.
55
6-
use std::collections::HashSet;
7-
86
use anyhow::{Context, Result};
97
use rand::{rngs::SmallRng, Rng, SeedableRng};
8+
use std::collections::HashSet;
109
use wasm_mutate::WasmMutate;
1110
use wasmparser::WasmFeatures;
1211

@@ -217,25 +216,7 @@ impl ShrinkRun {
217216
}
218217

219218
fn validate_wasm(&self, wasm: &[u8]) -> Result<()> {
220-
let mut validator = wasmparser::Validator::new_with_features(
221-
WasmFeatures::REFERENCE_TYPES
222-
| WasmFeatures::MULTI_VALUE
223-
| WasmFeatures::BULK_MEMORY
224-
| WasmFeatures::SIMD
225-
| WasmFeatures::THREADS
226-
| WasmFeatures::TAIL_CALL
227-
| WasmFeatures::MULTI_MEMORY
228-
| WasmFeatures::EXCEPTIONS
229-
| WasmFeatures::MEMORY64
230-
| WasmFeatures::RELAXED_SIMD
231-
| WasmFeatures::EXTENDED_CONST
232-
| WasmFeatures::MUTABLE_GLOBAL
233-
| WasmFeatures::SATURATING_FLOAT_TO_INT
234-
| WasmFeatures::SIGN_EXTENSION
235-
| WasmFeatures::FLOATS
236-
| WasmFeatures::MEMORY_CONTROL,
237-
);
238-
219+
let mut validator = wasmparser::Validator::new_with_features(WasmFeatures::all());
239220
validator.validate_all(wasm)?;
240221
Ok(())
241222
}

crates/wasm-smith/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ wat = { workspace = true, optional = true }
3535
[dev-dependencies]
3636
criterion = { workspace = true }
3737
rand = { workspace = true }
38-
wasmparser = { workspace = true, features = ["validate"] }
38+
wasmparser = { workspace = true, features = ["validate", "features"] }
3939
wasmprinter = { path = "../wasmprinter" }
4040
wat = { path = "../wat" }
4141

0 commit comments

Comments
 (0)