@@ -35,6 +35,10 @@ mod macros;
3535mod module;
3636mod optimize;
3737mod visit;
38+
39+ #[ cfg( parallel_parser) ]
40+ mod parallel;
41+
3842pub use error:: * ;
3943use module:: ModuleReader ;
4044use wasmparser:: { Validator , WasmFeatures } ;
@@ -51,11 +55,27 @@ pub struct ParserOptions {
5155 pub optimize_rewrite : bool ,
5256 /// Whether to remove `Nop` and `MergeBarrier` instructions after rewriting.
5357 pub optimize_remove_nop : bool ,
58+
59+ #[ cfg( parallel_parser) ]
60+ /// Number of threads to use for parallel parsing.
61+ ///
62+ /// Requires the `parallel` feature. Ignored when the feature is disabled.
63+ ///
64+ /// - `None`: auto-detect based on available parallelism
65+ /// - `Some(1)`: force single-threaded
66+ /// - `Some(n)`: use up to `n` workers
67+ pub parser_threads : Option < usize > ,
5468}
5569
5670impl Default for ParserOptions {
5771 fn default ( ) -> Self {
58- Self { optimize_local_memory_allocation : true , optimize_rewrite : true , optimize_remove_nop : true }
72+ Self {
73+ optimize_local_memory_allocation : true ,
74+ optimize_rewrite : true ,
75+ optimize_remove_nop : true ,
76+ #[ cfg( parallel_parser) ]
77+ parser_threads : None ,
78+ }
5979 }
6080}
6181
@@ -92,6 +112,21 @@ impl ParserOptions {
92112 pub const fn optimize_remove_nop ( & self ) -> bool {
93113 self . optimize_remove_nop
94114 }
115+
116+ #[ cfg( parallel_parser) ]
117+ /// Set the number of threads for parallel parsing.
118+ ///
119+ /// Requires the `parallel` feature to have any effect.
120+ pub const fn with_parser_threads ( mut self , threads : usize ) -> Self {
121+ self . parser_threads = Some ( threads) ;
122+ self
123+ }
124+
125+ #[ cfg( parallel_parser) ]
126+ /// Returns the configured parser thread count, or `None` for auto-detect.
127+ pub const fn parser_threads ( & self ) -> Option < usize > {
128+ self . parser_threads
129+ }
95130}
96131
97132/// A WebAssembly parser
@@ -139,20 +174,40 @@ impl Parser {
139174 Validator :: new_with_features ( features)
140175 }
141176
177+ #[ cfg( feature = "std" ) ]
178+ fn read_more ( stream : & mut impl std:: io:: Read , buffer : & mut alloc:: vec:: Vec < u8 > , hint : usize ) -> Result < usize > {
179+ let len = buffer. len ( ) ;
180+ buffer. extend ( ( 0 ..hint) . map ( |_| 0u8 ) ) ;
181+ let read_bytes = stream
182+ . read ( & mut buffer[ len..] )
183+ . map_err ( |e| ParseError :: Other ( alloc:: format!( "Error reading from stream: {e}" ) ) ) ?;
184+ buffer. truncate ( len + read_bytes) ;
185+ Ok ( read_bytes)
186+ }
187+
142188 /// Parse a [`Module`] from bytes
143189 pub fn parse_module_bytes ( & self , wasm : impl AsRef < [ u8 ] > ) -> Result < Module > {
144190 let wasm = wasm. as_ref ( ) ;
145191 let mut validator = Self :: create_validator ( self . options . clone ( ) ) ;
146192 let mut reader = ModuleReader :: default ( ) ;
147193
148194 for payload in wasmparser:: Parser :: new ( 0 ) . parse_all ( wasm) {
149- reader. process_payload ( payload?, & mut validator) ?;
195+ match payload? {
196+ wasmparser:: Payload :: CodeSectionStart { count, range, size } => {
197+ reader. begin_code_section ( count, range, size, & mut validator, & self . options ) ?;
198+ }
199+ wasmparser:: Payload :: CodeSectionEntry ( function) => {
200+ reader. process_borrowed_code_section_entry ( function, & mut validator, & self . options ) ?;
201+ }
202+ payload => reader. process_payload ( payload, & mut validator) ?,
203+ }
150204 }
151205
152206 if !reader. end_reached {
153207 return Err ( ParseError :: EndNotReached ) ;
154208 }
155209
210+ reader. process_pending_functions ( & self . options ) ?;
156211 reader. into_module ( & self . options )
157212 }
158213
@@ -176,18 +231,60 @@ impl Parser {
176231 loop {
177232 match parser. parse ( & buffer, eof) ? {
178233 wasmparser:: Chunk :: NeedMoreData ( hint) => {
179- let len = buffer. len ( ) ;
180- buffer. extend ( ( 0 ..hint) . map ( |_| 0u8 ) ) ;
181- let read_bytes = stream
182- . read ( & mut buffer[ len..] )
183- . map_err ( |e| ParseError :: Other ( alloc:: format!( "Error reading from stream: {e}" ) ) ) ?;
184- buffer. truncate ( len + read_bytes) ;
234+ let read_bytes = Self :: read_more ( & mut stream, & mut buffer, hint as usize ) ?;
185235 eof = read_bytes == 0 ;
186236 }
187237 wasmparser:: Chunk :: Parsed { consumed, payload } => {
188- reader. process_payload ( payload, & mut validator) ?;
189- buffer. drain ( ..consumed) ;
238+ #[ cfg( parallel_parser) ]
239+ let mut deferred_code_section = None ;
240+
241+ match payload {
242+ wasmparser:: Payload :: CodeSectionStart { count, range, size } => {
243+ let defer =
244+ reader. begin_code_section ( count, range. clone ( ) , size, & mut validator, & self . options ) ?;
245+
246+ #[ cfg( parallel_parser) ]
247+ if defer {
248+ deferred_code_section = Some ( ( count, range. end - size as usize , size as usize ) ) ;
249+ }
250+
251+ #[ cfg( not( parallel_parser) ) ]
252+ let _ = defer;
253+
254+ buffer. drain ( ..consumed) ;
255+ }
256+ wasmparser:: Payload :: CodeSectionEntry ( function) => {
257+ reader. process_inline_code_section_entry ( function, & mut validator, & self . options ) ?;
258+ buffer. drain ( ..consumed) ;
259+ }
260+ payload => {
261+ reader. process_payload ( payload, & mut validator) ?;
262+ buffer. drain ( ..consumed) ;
263+ }
264+ }
265+
266+ #[ cfg( parallel_parser) ]
267+ if let Some ( ( count, body_offset, section_size) ) = deferred_code_section {
268+ while buffer. len ( ) < section_size {
269+ let remaining = section_size - buffer. len ( ) ;
270+ let read_bytes = Self :: read_more ( & mut stream, & mut buffer, remaining) ?;
271+ if read_bytes == 0 {
272+ return Err ( ParseError :: ParseError {
273+ message : "unexpected end-of-file" . into ( ) ,
274+ offset : body_offset + buffer. len ( ) ,
275+ } ) ;
276+ }
277+ }
278+
279+ let section_bytes = alloc:: sync:: Arc :: < [ u8 ] > :: from ( buffer[ ..section_size] . to_vec ( ) ) ;
280+ reader. queue_owned_code_section ( count, body_offset, section_bytes, & mut validator) ?;
281+ parser. skip_section ( ) ;
282+ buffer. drain ( ..section_size) ;
283+ continue ;
284+ }
285+
190286 if eof || reader. end_reached {
287+ reader. process_pending_functions ( & self . options ) ?;
191288 return reader. into_module ( & self . options ) ;
192289 }
193290 }
@@ -196,10 +293,10 @@ impl Parser {
196293 }
197294}
198295
199- impl TryFrom < ModuleReader > for Module {
296+ impl TryFrom < ModuleReader < ' _ > > for Module {
200297 type Error = ParseError ;
201298
202- fn try_from ( reader : ModuleReader ) -> Result < Self > {
299+ fn try_from ( reader : ModuleReader < ' _ > ) -> Result < Self > {
203300 reader. into_module ( & ParserOptions :: default ( ) )
204301 }
205302}
0 commit comments