@@ -26,10 +26,12 @@ use cranelift_frontend::Variable;
2626use cranelift_frontend:: { FuncInstBuilder , FunctionBuilder } ;
2727use smallvec:: { SmallVec , smallvec} ;
2828use std:: mem;
29- use wasmparser:: { FuncValidator , Operator , WasmFeatures , WasmModuleResources } ;
29+ use wasmparser:: {
30+ BranchHint , FuncValidator , Operator , SectionLimitedIntoIter , WasmFeatures , WasmModuleResources ,
31+ } ;
3032use wasmtime_core:: math:: f64_cvt_to_int_bounds;
3133use wasmtime_environ:: {
32- BranchHint , BuiltinFunctionIndex , ComponentPC , DataIndex , DefinedFuncIndex , ElemIndex ,
34+ BuiltinFunctionIndex , ComponentPC , DataIndex , DefinedFuncIndex , ElemIndex ,
3335 EngineOrModuleTypeIndex , FrameStateSlotBuilder , FrameValType , FuncIndex , FuncKey ,
3436 GlobalConstValue , GlobalIndex , IndexType , Memory , MemoryIndex , MemoryTunables , Module ,
3537 ModuleInternedTypeIndex , ModuleTranslation , ModuleTypesBuilder , PtrSize , Table , TableIndex ,
@@ -233,11 +235,12 @@ pub struct FuncEnvironment<'module_environment> {
233235 /// to e.g. record the return-address of a callsite for debuginfo.
234236 pub ( crate ) next_srcloc : ir:: SourceLoc ,
235237
236- /// Branch hints for the current function, consumed in program-counter order
237- /// by `take_branch_hint`.
238- branch_hints : & ' module_environment [ BranchHint ] ,
239- /// Forward cursor into `branch_hints`.
240- branch_hint_cursor : usize ,
238+ /// Lazily-decoded branch hints for the current function, in ascending
239+ /// `func_offset` order (as the proposal requires). `None` once exhausted or
240+ /// when the function carries no hints.
241+ branch_hints : Option < SectionLimitedIntoIter < ' module_environment , BranchHint > > ,
242+ /// One-item lookahead into `branch_hints`, consumed by `take_branch_hint`.
243+ peeked_hint : Option < BranchHint > ,
241244 /// Module-relative byte offset of the current function body's start.
242245 func_body_offset : usize ,
243246}
@@ -249,10 +252,19 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
249252 types : & ' module_environment ModuleTypesBuilder ,
250253 wasm_func_ty : & ' module_environment WasmFuncType ,
251254 key : FuncKey ,
255+ func_index : FuncIndex ,
256+ func_body_offset : usize ,
252257 ) -> Self {
253258 let tunables = compiler. tunables ( ) ;
254259 let builtin_functions = BuiltinFunctions :: new ( compiler) ;
255260
261+ // Resolve the lazy branch-hint decoder for this function, if any.
262+ // `func_body_offset` lets `take_branch_hint` convert source locations to
263+ // the function-body-relative offsets the hints use.
264+ let branch_hints = translation
265+ . branch_hints ( func_index)
266+ . map ( |reader| reader. into_iter ( ) ) ;
267+
256268 // This isn't used during translation, so squash the warning about this
257269 // being unused from the compiler.
258270 let _ = BuiltinFunctions :: raise;
@@ -303,46 +315,48 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
303315 next_srcloc : ir:: SourceLoc :: default ( ) ,
304316 wasm_module_offset : translation. wasm_module_offset ,
305317
306- branch_hints : & [ ] ,
307- branch_hint_cursor : 0 ,
308- func_body_offset : 0 ,
318+ branch_hints,
319+ peeked_hint : None ,
320+ func_body_offset,
309321 }
310322 }
311323
312- /// Set the branch hints and the module-relative start offset for the
313- /// function about to be translated. Hints are expected in ascending
314- /// `func_offset` order (as the proposal requires); `take_branch_hint`
315- /// simply skips any that are out of order.
316- pub ( crate ) fn set_branch_hints (
317- & mut self ,
318- hints : & ' module_environment [ BranchHint ] ,
319- func_body_offset : usize ,
320- ) {
321- self . branch_hints = hints;
322- self . branch_hint_cursor = 0 ;
323- self . func_body_offset = func_body_offset;
324- }
325-
326324 /// Consume the branch hint for the instruction at module-relative `offset`
327- /// (i.e. `builder.srcloc().bits()`), if any; `Some(true)` means likely
328- /// taken. The cursor only advances, making this O(n) over a function body.
329- pub ( crate ) fn take_branch_hint ( & mut self , offset : usize ) -> Option < bool > {
330- if self . branch_hints . is_empty ( ) {
325+ /// (i.e. `builder.srcloc().bits()`), if any. The lazy decoder only moves
326+ /// forward, making this O(n) over a function body.
327+ pub ( crate ) fn take_branch_hint ( & mut self , offset : usize ) -> Option < BranchHint > {
328+ // Fast path for the common case of a function with no hints (always so
329+ // when the proposal is disabled): this is called for every `if`/`br_if`.
330+ if self . branch_hints . is_none ( ) {
331331 return None ;
332332 }
333333 let rel = u32:: try_from ( offset. checked_sub ( self . func_body_offset ) ?) . ok ( ) ?;
334- // Skip hints that don't line up with this (or a later) branch.
335- while matches ! (
336- self . branch_hints. get( self . branch_hint_cursor) ,
337- Some ( h) if h. func_offset < rel,
338- ) {
339- self . branch_hint_cursor += 1 ;
334+ loop {
335+ // Refill the one-item lookahead from the lazy decoder.
336+ if self . peeked_hint . is_none ( ) {
337+ self . peeked_hint = self . next_branch_hint ( ) ;
338+ }
339+ let hint = self . peeked_hint ?;
340+ if hint. func_offset < rel {
341+ // Hint precedes this branch (or never lined up); drop it.
342+ self . peeked_hint = None ;
343+ continue ;
344+ }
345+ if hint. func_offset == rel {
346+ self . peeked_hint = None ;
347+ return Some ( hint) ;
348+ }
349+ // The next hint is for a later offset; nothing for this branch.
350+ return None ;
340351 }
341- let hint = self . branch_hints . get ( self . branch_hint_cursor ) ?;
342- ( hint. func_offset == rel) . then ( || {
343- self . branch_hint_cursor += 1 ;
344- hint. taken
345- } )
352+ }
353+
354+ /// Decode the next hint for the current function, if any.
355+ fn next_branch_hint ( & mut self ) -> Option < BranchHint > {
356+ // These bytes were already validated when the section was decoded into
357+ // per-function readers, so this re-decode cannot fail; defensively treat
358+ // an unexpected error as the end of the hints.
359+ self . branch_hints . as_mut ( ) ?. next ( ) ?. ok ( )
346360 }
347361
348362 pub ( crate ) fn pointer_type ( & self ) -> ir:: Type {
0 commit comments