Prepares the compiler to branch to the given destination frame. This process involves: Balancing the machine stack pointer and value stack by popping it to match the destination branch. Updating the reachability state. Marking the destination frame as a destination target.
(
&mut self,
dest: &mut ControlStackFrame,
masm: &mut M,
mut maybe_pop_results: F,
)
| 664 | /// * Updating the reachability state. |
| 665 | /// * Marking the destination frame as a destination target. |
| 666 | pub fn br<M, F, B>( |
| 667 | &mut self, |
| 668 | dest: &mut ControlStackFrame, |
| 669 | masm: &mut M, |
| 670 | mut maybe_pop_results: F, |
| 671 | ) -> Result<()> |
| 672 | where |
| 673 | M: MacroAssembler, |
| 674 | F: FnMut(&mut M, &mut Self, &mut ControlStackFrame) -> Result<()>, |
| 675 | B: BranchState, |
| 676 | { |
| 677 | let state = dest.stack_state(); |
| 678 | let target_offset = state.target_offset; |
| 679 | let base_offset = state.base_offset; |
| 680 | let results_size = dest.results::<M>()?.size(); |
| 681 | |
| 682 | maybe_pop_results(masm, self, dest)?; |
| 683 | // After calling `maybe_pop_results`, the stack pointer plus |
| 684 | // any result space needed, must be greater or equal to the |
| 685 | // destination frame base stack pointer offset. |
| 686 | // |
| 687 | // We check |
| 688 | // current_sp + results >= base_offset |
| 689 | // as opposed to |
| 690 | // current_sp >= base_offset |
| 691 | // |
| 692 | // To: |
| 693 | // - Verify that `maybe_pop_results` popped exactly the right |
| 694 | // amount relative to the base offset. |
| 695 | // - Accommodate for multi-branch cases (i.e., `br_table`) in which |
| 696 | // result handling happens only once and _could_ happen outside of |
| 697 | // `maybe_pop_results` callback. |
| 698 | // |
| 699 | // |
| 700 | // Ensuring that the current stack pointer offset plus any |
| 701 | // result space is equal to or greater than the target branch |
| 702 | // base offset is the the most deterministic check at branch |
| 703 | // emission time since we can be certain that the base offset |
| 704 | // is the value recorded when a new control frame was pushed, |
| 705 | // upon which the expected target offset is calculated. |
| 706 | ensure!( |
| 707 | (masm.sp_offset()?.as_u32() + results_size) >= base_offset.as_u32(), |
| 708 | CodeGenError::invalid_sp_offset() |
| 709 | ); |
| 710 | |
| 711 | // At jump sites, the machine stack might be left unbalanced, |
| 712 | // due to register spills. |
| 713 | // The following snippet, pops the stack pointer to ensure |
| 714 | // that it is correctly placed according to the expectations |
| 715 | // of the destination branch. |
| 716 | // |
| 717 | // Note that in most branch cases (`return`, ` br`) the stack |
| 718 | // pointer will be already balanced, by virtue of calling |
| 719 | // [`ControlStackFrame::pop_abi_results`] through the |
| 720 | // callback. |
| 721 | // |
| 722 | // More generally speaking the current stack pointer will be |
| 723 | // less than the destination frame stack pointer offset in |
nothing calls this directly
no test coverage detected