wasmparser/
features.rs

1macro_rules! define_wasm_features {
2    (
3        $(#[$outer:meta])*
4        pub struct WasmFeatures: $repr:ty {
5            $(
6                $(#[$inner:ident $($args:tt)*])*
7                pub $field:ident: $const:ident($flag:expr) = $default:expr;
8            )*
9        }
10    ) => {
11        #[cfg(feature = "features")]
12        bitflags::bitflags! {
13            $(#[$outer])*
14            pub struct WasmFeatures: $repr {
15                $(
16                    $(#[$inner $($args)*])*
17                    #[doc = "\nDefaults to `"]
18                    #[doc = stringify!($default)]
19                    #[doc = "`.\n"]
20                    const $const = $flag;
21                )*
22            }
23        }
24
25        /// Enabled WebAssembly proposals and features.
26        ///
27        /// This is the disabled zero-size version of this structure because the
28        /// `features` feature was disabled at compile time of this crate.
29        #[cfg(not(feature = "features"))]
30        #[derive(Clone, Debug, Default, Hash, Copy)]
31        pub struct WasmFeatures {
32            _priv: (),
33        }
34
35        #[cfg(feature = "features")]
36        impl Default for WasmFeatures {
37            #[inline]
38            fn default() -> Self {
39                let mut features = WasmFeatures::empty();
40                $(
41                    features.set(WasmFeatures::$const, $default);
42                )*
43                features
44            }
45        }
46
47        impl WasmFeatures {
48            /// Construct a bit-packed `WasmFeatures` from the inflated struct version.
49            #[inline]
50            #[cfg(feature = "features")]
51            pub fn from_inflated(inflated: WasmFeaturesInflated) -> Self {
52                let mut features = WasmFeatures::empty();
53                $(
54                    features.set(WasmFeatures::$const, inflated.$field);
55                )*
56                features
57            }
58
59            /// Inflate these bit-packed features into a struct with a field per
60            /// feature.
61            ///
62            /// Although the inflated struct takes up much more memory than the
63            /// bit-packed version, its fields can be exhaustively matched
64            /// upon. This makes it useful for temporarily checking against,
65            /// while keeping the bit-packed version as the method of storing
66            /// the features for longer periods of time.
67            #[inline]
68            #[cfg(feature = "features")]
69            pub fn inflate(&self) -> WasmFeaturesInflated {
70                WasmFeaturesInflated {
71                    $(
72                        $field: self.$field(),
73                    )*
74                }
75            }
76
77            $(
78                /// Returns whether this feature is enabled in this feature set.
79                #[inline]
80                pub fn $field(&self) -> bool {
81                    #[cfg(feature = "features")]
82                    { self.contains(WasmFeatures::$const) }
83                    #[cfg(not(feature = "features"))]
84                    { $default }
85                }
86            )*
87        }
88
89        /// Inflated version of [`WasmFeatures`][crate::WasmFeatures] that
90        /// allows for exhaustive matching on fields.
91        #[cfg(feature = "features")]
92        pub struct WasmFeaturesInflated {
93            $(
94                $(#[$inner $($args)*])*
95                #[doc = "\nDefaults to `"]
96                #[doc = stringify!($default)]
97                #[doc = "`.\n"]
98                pub $field: bool,
99            )*
100        }
101
102        macro_rules! foreach_wasm_feature {
103            ($f:ident) => {
104                $($f!($field = $default);)*
105            }
106        }
107        pub(crate) use foreach_wasm_feature;
108    };
109}
110
111define_wasm_features! {
112    /// Flags for features that are enabled for validation.
113    ///
114    /// This type controls the set of WebAssembly proposals and features that
115    /// are active during validation and parsing of WebAssembly binaries. This
116    /// is used in conjunction with
117    /// [`Validator::new_with_features`](crate::Validator::new_with_features)
118    /// for example.
119    ///
120    /// The [`Default`] implementation for this structure returns the set of
121    /// supported WebAssembly proposals this crate implements. All features are
122    /// required to be in Phase 4 or above in the WebAssembly standardization
123    /// process.
124    ///
125    /// Enabled/disabled features can affect both parsing and validation at this
126    /// time. When decoding a WebAssembly binary it's generally recommended if
127    /// possible to enable all features, as is the default with
128    /// [`BinaryReader::new`](crate::BinaryReader::new). If strict conformance
129    /// with historical versions of the specification are required then
130    /// [`BinaryReader::new_features`](crate::BinaryReader::new_features) or
131    /// [`BinaryReader::set_features`](crate::BinaryReader::set_features) can be
132    /// used.
133    ///
134    /// This crate additionally has a compile-time Cargo feature called
135    /// `features` which can be used to enable/disable most of this type at
136    /// compile time. This crate feature is turned on by default and enables
137    /// this bitflags-representation of this structure. When the `features`
138    /// feature is disabled then this is a zero-sized structure and no longer
139    /// has any associated constants. When `features` are disabled all values
140    /// for proposals are fixed at compile time to their defaults.
141    #[derive(Hash, Debug, Copy, Clone, Eq, PartialEq)]
142    pub struct WasmFeatures: u64 {
143        /// The WebAssembly `mutable-global` proposal.
144        pub mutable_global: MUTABLE_GLOBAL(1) = true;
145        /// The WebAssembly `saturating-float-to-int` proposal.
146        pub saturating_float_to_int: SATURATING_FLOAT_TO_INT(1 << 1) = true;
147        /// The WebAssembly `sign-extension-ops` proposal.
148        pub sign_extension: SIGN_EXTENSION(1 << 2) = true;
149        /// The WebAssembly reference types proposal.
150        pub reference_types: REFERENCE_TYPES(1 << 3) = true;
151        /// The WebAssembly multi-value proposal.
152        pub multi_value: MULTI_VALUE(1 << 4) = true;
153        /// The WebAssembly bulk memory operations proposal.
154        pub bulk_memory: BULK_MEMORY(1 << 5) = true;
155        /// The WebAssembly SIMD proposal.
156        pub simd: SIMD(1 << 6) = true;
157        /// The WebAssembly Relaxed SIMD proposal.
158        pub relaxed_simd: RELAXED_SIMD(1 << 7) = true;
159        /// The WebAssembly threads proposal.
160        pub threads: THREADS(1 << 8) = true;
161        /// The WebAssembly shared-everything-threads proposal; includes new
162        /// component model built-ins.
163        pub shared_everything_threads: SHARED_EVERYTHING_THREADS(1 << 9) = false;
164        /// The WebAssembly tail-call proposal.
165        pub tail_call: TAIL_CALL(1 << 10) = true;
166        /// Whether or not floating-point instructions are enabled.
167        ///
168        /// This is enabled by default can be used to disallow floating-point
169        /// operators and types.
170        ///
171        /// This does not correspond to a WebAssembly proposal but is instead
172        /// intended for embeddings which have stricter-than-usual requirements
173        /// about execution. Floats in WebAssembly can have different NaN patterns
174        /// across hosts which can lead to host-dependent execution which some
175        /// runtimes may not desire.
176        pub floats: FLOATS(1 << 11) = true;
177        /// The WebAssembly multi memory proposal.
178        pub multi_memory: MULTI_MEMORY(1 << 12) = true;
179        /// The WebAssembly exception handling proposal.
180        pub exceptions: EXCEPTIONS(1 << 13) = true;
181        /// The WebAssembly memory64 proposal.
182        pub memory64: MEMORY64(1 << 14) = true;
183        /// The WebAssembly extended_const proposal.
184        pub extended_const: EXTENDED_CONST(1 << 15) = true;
185        /// The WebAssembly component model proposal.
186        pub component_model: COMPONENT_MODEL(1 << 16) = true;
187        /// The WebAssembly typed function references proposal.
188        pub function_references: FUNCTION_REFERENCES(1 << 17) = true;
189        /// The WebAssembly memory control proposal.
190        pub memory_control: MEMORY_CONTROL(1 << 18) = false;
191        /// The WebAssembly gc proposal.
192        pub gc: GC(1 << 19) = true;
193        /// The WebAssembly [custom-page-sizes
194        /// proposal](https://github.com/WebAssembly/custom-page-sizes).
195        pub custom_page_sizes: CUSTOM_PAGE_SIZES(1 << 20) = false;
196        /// The WebAssembly legacy exception handling proposal (phase 1)
197        ///
198        /// # Note
199        ///
200        /// Support this feature as long as all leading browsers also support it
201        /// <https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md>
202        pub legacy_exceptions: LEGACY_EXCEPTIONS(1 << 23) = false;
203        /// Whether or not gc types are enabled.
204        ///
205        /// This feature does not correspond to any WebAssembly proposal nor
206        /// concept in the specification itself. This is intended to assist
207        /// embedders in disabling support for GC types at validation time. For
208        /// example if an engine wants to support all of WebAssembly except
209        /// a runtime garbage collector it could disable this feature.
210        ///
211        /// This features is enabled by default and is used to gate types such
212        /// as `externref` or `anyref`. Note that the requisite WebAssembly
213        /// proposal must also be enabled for types like `externref`, meaning
214        /// that it requires both `REFERENCE_TYPES` and `GC_TYPE` to be enabled.
215        ///
216        /// Note that the `funcref` and `exnref` types are not gated by this
217        /// feature. Those are expected to not require a full garbage collector
218        /// so are not gated by this.
219        pub gc_types: GC_TYPES(1 << 24) = true;
220        /// The WebAssembly [stack-switching proposal](https://github.com/WebAssembly/stack-switching).
221        pub stack_switching: STACK_SWITCHING(1 << 25) = false;
222        /// The WebAssembly [wide-arithmetic proposal](https://github.com/WebAssembly/wide-arithmetic).
223        pub wide_arithmetic: WIDE_ARITHMETIC(1 << 26) = false;
224
225        /// Support for the `value` type in the component model proposal.
226        ///
227        /// Corresponds to the 🪙 character in
228        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
229        pub cm_values: CM_VALUES(1 << 21) = false;
230        /// Support for the nested namespaces and projects in component model names.
231        ///
232        /// Corresponds to the 🪺 character in
233        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
234        pub cm_nested_names: CM_NESTED_NAMES(1 << 22) = false;
235        /// Support for component model async lift/lower ABI, as well as streams, futures, and errors.
236        ///
237        /// Corresponds to the 🔀 character in
238        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
239        pub cm_async: CM_ASYNC(1 << 27) = false;
240        /// Gates the "stackful ABI" in the component model async proposal.
241        ///
242        /// Corresponds to the 🚟 character in
243        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
244        pub cm_async_stackful: CM_ASYNC_STACKFUL(1 << 28) = false;
245        /// Gates some intrinsics being marked with `async` in the component
246        /// model async proposal.
247        ///
248        /// Corresponds to the 🚝 character in
249        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
250        pub cm_async_builtins: CM_ASYNC_BUILTINS(1 << 29) = false;
251        /// Gates some intrinsics being marked with `error-context` in the component
252        /// model async proposal.
253        ///
254        /// Corresponds to the 📝 character in
255        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
256        pub cm_error_context: CM_ERROR_CONTEXT(1 << 30) = false;
257        /// Support for fixed size lists
258        ///
259        /// Corresponds to the 🔧 character in
260        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
261        pub cm_fixed_size_list: CM_FIXED_SIZE_LIST(1 << 31) = false;
262        /// Support for Wasm GC in the component model proposal.
263        ///
264        /// Corresponds to the 🛸 character in
265        /// <https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md>.
266        pub cm_gc: CM_GC(1 << 32) = false;
267    }
268}
269
270impl WasmFeatures {
271    /// The feature set associated with the MVP release of WebAssembly (its
272    /// first release).
273    //
274    // Note that the features listed here are the wasmparser-specific built-in
275    // features such as "floats" and "gc-types". These don't actually correspond
276    // to any wasm proposals themselves and instead just gate constructs in
277    // wasm. They're listed here so they otherwise don't have to be listed
278    // below, but for example wasm with `externref` will be rejected due to lack
279    // of `externref` first.
280    #[cfg(feature = "features")]
281    pub const MVP: WasmFeatures = WasmFeatures::FLOATS.union(WasmFeatures::GC_TYPES);
282
283    /// The feature set associated with the 1.0 version of the
284    /// WebAssembly specification circa 2017.
285    ///
286    /// <https://webassembly.github.io/spec/versions/core/WebAssembly-1.0.pdf>
287    #[cfg(feature = "features")]
288    pub const WASM1: WasmFeatures = WasmFeatures::MVP.union(WasmFeatures::MUTABLE_GLOBAL);
289
290    /// The feature set associated with the 2.0 version of the
291    /// WebAssembly specification circa 2022.
292    ///
293    /// <https://webassembly.github.io/spec/versions/core/WebAssembly-2.0.pdf>
294    #[cfg(feature = "features")]
295    pub const WASM2: WasmFeatures = WasmFeatures::WASM1
296        .union(WasmFeatures::BULK_MEMORY)
297        .union(WasmFeatures::REFERENCE_TYPES)
298        .union(WasmFeatures::SIGN_EXTENSION)
299        .union(WasmFeatures::SATURATING_FLOAT_TO_INT)
300        .union(WasmFeatures::MULTI_VALUE)
301        .union(WasmFeatures::SIMD);
302
303    /// The feature set associated with the 3.0 version of the
304    /// WebAssembly specification.
305    ///
306    /// Note that as of the time of this writing the 3.0 version of the
307    /// specification is not yet published. The precise set of features set
308    /// here may change as that continues to evolve.
309    ///
310    /// (draft)
311    /// <https://webassembly.github.io/spec/versions/core/WebAssembly-3.0-draft.pdf>
312    #[cfg(feature = "features")]
313    pub const WASM3: WasmFeatures = WasmFeatures::WASM2
314        .union(WasmFeatures::GC)
315        .union(WasmFeatures::TAIL_CALL)
316        .union(WasmFeatures::EXTENDED_CONST)
317        .union(WasmFeatures::FUNCTION_REFERENCES)
318        .union(WasmFeatures::MULTI_MEMORY)
319        .union(WasmFeatures::RELAXED_SIMD)
320        .union(WasmFeatures::THREADS)
321        .union(WasmFeatures::EXCEPTIONS)
322        .union(WasmFeatures::MEMORY64);
323}
324
325#[cfg(feature = "features")]
326impl From<WasmFeaturesInflated> for WasmFeatures {
327    #[inline]
328    fn from(inflated: WasmFeaturesInflated) -> Self {
329        Self::from_inflated(inflated)
330    }
331}
332
333#[cfg(feature = "features")]
334impl From<WasmFeatures> for WasmFeaturesInflated {
335    #[inline]
336    fn from(features: WasmFeatures) -> Self {
337        features.inflate()
338    }
339}
340
341impl WasmFeatures {
342    /// Returns whether any types considered valid with this set of
343    /// `WasmFeatures` requires any type canonicalization/interning internally.
344    #[cfg(feature = "validate")]
345    pub(crate) fn needs_type_canonicalization(&self) -> bool {
346        #[cfg(feature = "features")]
347        {
348            // Types from the function-references proposal and beyond (namely
349            // GC) need type canonicalization for inter-type references and for
350            // rec-groups to work. Prior proposals have no such inter-type
351            // references structurally and as such can hit various fast paths in
352            // the validator to do a bit less work when processing the type
353            // section.
354            //
355            // None of these proposals below support inter-type references. If
356            // `self` contains any proposal outside of this set then it requires
357            // type canonicalization.
358            const FAST_VALIDATION_FEATURES: WasmFeatures = WasmFeatures::WASM2
359                .union(WasmFeatures::CUSTOM_PAGE_SIZES)
360                .union(WasmFeatures::EXTENDED_CONST)
361                .union(WasmFeatures::MEMORY64)
362                .union(WasmFeatures::MULTI_MEMORY)
363                .union(WasmFeatures::RELAXED_SIMD)
364                .union(WasmFeatures::TAIL_CALL)
365                .union(WasmFeatures::THREADS)
366                .union(WasmFeatures::WIDE_ARITHMETIC);
367            !FAST_VALIDATION_FEATURES.contains(*self)
368        }
369        #[cfg(not(feature = "features"))]
370        {
371            // GC/function-references are enabled by default, so
372            // canonicalization is required if feature flags aren't enabled at
373            // runtime.
374            true
375        }
376    }
377}