tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit bba78a6469c9c8563a2f480e182dfcbaa080eaf6
parent 9001885200b03a20aebf747727688a6637fb13a9
Author: Rong "Mantle" Bao <webmaster@csmantle.top>
Date:   Thu, 27 Nov 2025 11:57:06 +0000

Bug 1996840 - [riscv64] Part 4: Supply good maxInsts in no-pool area size calculation. r=nbp

This patch supplies maxInst calculated with padding in mind to
BlockTrampolinePoolScope. New deadlines inserted within the no-pool area
are also considered before entering to prevent pool overrun.

Differential Revision: https://phabricator.services.mozilla.com/D271918

Diffstat:
Mjs/src/jit/riscv64/Assembler-riscv64.h | 9++++++---
Mjs/src/jit/riscv64/MacroAssembler-riscv64.cpp | 23+++++++++++++++--------
Mjs/src/jit/shared/IonAssemblerBufferWithConstantPools.h | 41++++++++++++++++++++++++++++++++++++-----
3 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/js/src/jit/riscv64/Assembler-riscv64.h b/js/src/jit/riscv64/Assembler-riscv64.h @@ -203,7 +203,9 @@ class Assembler : public AssemblerShared, MOZ_ASSERT(!isFinished); isFinished = true; } - void enterNoPool(size_t maxInst) { m_buffer.enterNoPool(maxInst); } + void enterNoPool(size_t maxInst, size_t maxNewDeadlines = 0) { + m_buffer.enterNoPool(maxInst, maxNewDeadlines); + } void leaveNoPool() { m_buffer.leaveNoPool(); } bool swapBuffer(wasm::Bytes& bytes); // Size of the instruction stream, in bytes. @@ -563,9 +565,10 @@ class ABIArgGenerator : public ABIArgGeneratorShared { // will assert. class BlockTrampolinePoolScope { public: - explicit BlockTrampolinePoolScope(Assembler* assem, int margin) + explicit BlockTrampolinePoolScope(Assembler* assem, size_t margin, + size_t maxBranches = 0) : assem_(assem) { - assem_->enterNoPool(margin); + assem_->enterNoPool(margin, maxBranches); } ~BlockTrampolinePoolScope() { assem_->leaveNoPool(); } diff --git a/js/src/jit/riscv64/MacroAssembler-riscv64.cpp b/js/src/jit/riscv64/MacroAssembler-riscv64.cpp @@ -635,7 +635,7 @@ template <typename F> void MacroAssemblerRiscv64::RoundHelper(FPURegister dst, FPURegister src, FPURegister fpu_scratch, FPURoundingMode frm) { - BlockTrampolinePoolScope block_trampoline_pool(this, 20); + BlockTrampolinePoolScope block_trampoline_pool(this, 20, 2); UseScratchRegisterScope temps(this); Register scratch2 = temps.Acquire(); @@ -2623,7 +2623,9 @@ static void AtomicExchange(MacroAssembler& masm, if (nbytes == 4) { masm.memoryBarrierBefore(sync); masm.bind(&again); - BlockTrampolinePoolScope block_trampoline_pool(&masm, 5); + BlockTrampolinePoolScope block_trampoline_pool(&masm, + /* 1 + 1 + 1 + 4 + 1 = */ 8, + 1); if (access) { masm.append(*access, wasm::TrapMachineInsn::Atomic, FaultingCodeOffset(masm.currentOffset())); @@ -2660,7 +2662,8 @@ static void AtomicExchange(MacroAssembler& masm, masm.bind(&again); - BlockTrampolinePoolScope block_trampoline_pool(&masm, 10); + BlockTrampolinePoolScope block_trampoline_pool( + &masm, /* 1 + 1 + 1 + 1 + 4 + 1 + 2 + 1 = */ 12, 1); if (access) { masm.append(*access, wasm::TrapMachineInsn::Atomic, FaultingCodeOffset(masm.currentOffset())); @@ -2713,7 +2716,9 @@ static void AtomicExchange64(MacroAssembler& masm, masm.memoryBarrierBefore(sync); masm.bind(&tryAgain); - BlockTrampolinePoolScope block_trampoline_pool(&masm, 5); + BlockTrampolinePoolScope block_trampoline_pool(&masm, + /* 1 + 1 + 1 + 4 + 1 = */ 8, + 1); if (access) { masm.append(*access, js::wasm::TrapMachineInsn::Load64, FaultingCodeOffset(masm.currentOffset())); @@ -2743,7 +2748,9 @@ static void AtomicFetchOp64(MacroAssembler& masm, masm.memoryBarrierBefore(sync); masm.bind(&tryAgain); - BlockTrampolinePoolScope block_trampoline_pool(&masm, 5); + BlockTrampolinePoolScope block_trampoline_pool(&masm, + /* 1 + 1 + 1 + 4 + 1 = */ 8, + 1); if (access) { masm.append(*access, js::wasm::TrapMachineInsn::Load64, FaultingCodeOffset(masm.currentOffset())); @@ -4821,7 +4828,7 @@ bool MacroAssemblerRiscv64::CalculateOffset(Label* L, int32_t* offset, void MacroAssemblerRiscv64::BranchShortHelper(int32_t offset, Label* L) { MOZ_ASSERT(L == nullptr || offset == 0); - BlockTrampolinePoolScope block_trampoline_pool(this, 2); + BlockTrampolinePoolScope block_trampoline_pool(this, 2, 1); offset = GetOffset(offset, L, OffsetSize::kOffset21); Assembler::j(offset); } @@ -4845,7 +4852,7 @@ bool MacroAssemblerRiscv64::BranchShortHelper(int32_t offset, Label* L, scratch = rt.rm(); } { - BlockTrampolinePoolScope block_trampoline_pool(this, 2); + BlockTrampolinePoolScope block_trampoline_pool(this, 2, 1); switch (cond) { case Always: if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false; @@ -6913,7 +6920,7 @@ void MacroAssemblerRiscv64::GenPCRelativeJumpAndLink(Register rd, CodeOffset MacroAssemblerRiscv64::BranchAndLinkShortHelper(int32_t offset, Label* L) { MOZ_ASSERT(L == nullptr || offset == 0); - BlockTrampolinePoolScope block_trampoline_pool(this, 2); + BlockTrampolinePoolScope block_trampoline_pool(this, 2, 1); offset = GetOffset(offset, L, OffsetSize::kOffset21); return jal(offset); } diff --git a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h @@ -620,6 +620,11 @@ struct AssemblerBufferWithConstantPools // The maximum number of word sized instructions declared for the outermost // nesting level no-pool region. Set to zero when invalid. size_t inhibitPoolsMaxInst_; + // The maximum number of new deadlines that are allowed to register in the + // no-pool region. + size_t inhibitPoolsMaxNewDeadlines_; + // The actual number of new deadlines registered in the no-pool region. + size_t inhibitPoolsActualNewDeadlines_; #endif // Instruction to use for alignment fill. @@ -660,6 +665,8 @@ struct AssemblerBufferWithConstantPools #ifdef DEBUG inhibitPoolsStartOffset_(~size_t(0) /*"invalid"*/), inhibitPoolsMaxInst_(0), + inhibitPoolsMaxNewDeadlines_(0), + inhibitPoolsActualNewDeadlines_(0), #endif alignFillInst_(alignFillInst), nopFillInst_(nopFillInst), @@ -703,7 +710,8 @@ struct AssemblerBufferWithConstantPools // Check if it is possible to add numInst instructions and numPoolEntries // constant pool entries without needing to flush the current pool. - bool hasSpaceForInsts(unsigned numInsts, unsigned numPoolEntries) const { + bool hasSpaceForInsts(unsigned numInsts, unsigned numPoolEntries, + unsigned numNewDeadlines = 0) const { size_t nextOffset = sizeExcludingCurrentPool(); // Earliest starting offset for the current pool after adding numInsts. // This is the beginning of the pool entries proper, after inserting a @@ -748,7 +756,8 @@ struct AssemblerBufferWithConstantPools // Total pending secondary range veneer size. size_t secondaryVeneers = guardSize_ * - (branchDeadlines_.size() - branchDeadlines_.maxRangeSize()) * + (branchDeadlines_.size() - branchDeadlines_.maxRangeSize() + + numNewDeadlines) * InstSize; if (deadline < poolEnd + secondaryVeneers) { @@ -919,6 +928,13 @@ struct AssemblerBufferWithConstantPools if (!this->oom() && !branchDeadlines_.addDeadline(rangeIdx, deadline)) { this->fail_oom(); } +#ifdef DEBUG + if (inhibitPools_ > 0) { + inhibitPoolsActualNewDeadlines_++; + MOZ_ASSERT(inhibitPoolsActualNewDeadlines_ <= + inhibitPoolsMaxNewDeadlines_); + } +#endif } // Un-register a short-range branch deadline. @@ -932,6 +948,12 @@ struct AssemblerBufferWithConstantPools if (!this->oom()) { branchDeadlines_.removeDeadline(rangeIdx, deadline); } +#ifdef DEBUG + if (inhibitPools_ > 0) { + MOZ_ASSERT(inhibitPoolsMaxNewDeadlines_ > 0); + inhibitPoolsActualNewDeadlines_--; + } +#endif } private: @@ -1056,7 +1078,7 @@ struct AssemblerBufferWithConstantPools finishPool(SIZE_MAX); } - void enterNoPool(size_t maxInst) { + void enterNoPool(size_t maxInst, size_t maxNewDeadlines = 0) { // Calling this with a zero arg is pointless. MOZ_ASSERT(maxInst > 0); @@ -1077,6 +1099,8 @@ struct AssemblerBufferWithConstantPools inhibitPoolsStartOffset_); MOZ_ASSERT(size_t(this->nextOffset().getOffset()) + maxInst * InstSize <= inhibitPoolsStartOffset_ + inhibitPoolsMaxInst_ * InstSize); + MOZ_ASSERT(inhibitPoolsActualNewDeadlines_ + maxNewDeadlines <= + inhibitPoolsMaxNewDeadlines_); inhibitPools_++; return; } @@ -1085,6 +1109,8 @@ struct AssemblerBufferWithConstantPools MOZ_ASSERT(inhibitPools_ == 0); MOZ_ASSERT(inhibitPoolsStartOffset_ == ~size_t(0)); MOZ_ASSERT(inhibitPoolsMaxInst_ == 0); + MOZ_ASSERT(inhibitPoolsMaxNewDeadlines_ == 0); + MOZ_ASSERT(inhibitPoolsActualNewDeadlines_ == 0); insertNopFill(); @@ -1092,14 +1118,14 @@ struct AssemblerBufferWithConstantPools // so then finish the pool before entering the no-pool region. It is // assumed that no pool entries are allocated in a no-pool region and // this is asserted when allocating entries. - if (!hasSpaceForInsts(maxInst, 0)) { + if (!hasSpaceForInsts(maxInst, 0, maxNewDeadlines)) { JitSpew(JitSpew_Pools, "No-Pool instruction(%zu) caused a spill.", sizeExcludingCurrentPool()); finishPool(maxInst * InstSize); if (this->oom()) { return; } - MOZ_ASSERT(hasSpaceForInsts(maxInst, 0)); + MOZ_ASSERT(hasSpaceForInsts(maxInst, 0, maxNewDeadlines)); } #ifdef DEBUG @@ -1107,6 +1133,8 @@ struct AssemblerBufferWithConstantPools // the region. inhibitPoolsStartOffset_ = this->nextOffset().getOffset(); inhibitPoolsMaxInst_ = maxInst; + inhibitPoolsMaxNewDeadlines_ = maxNewDeadlines; + inhibitPoolsActualNewDeadlines_ = 0; MOZ_ASSERT(inhibitPoolsStartOffset_ != ~size_t(0)); #endif @@ -1136,10 +1164,13 @@ struct AssemblerBufferWithConstantPools // where we are leaving the outermost nesting level. MOZ_ASSERT(this->nextOffset().getOffset() - inhibitPoolsStartOffset_ <= inhibitPoolsMaxInst_ * InstSize); + MOZ_ASSERT(inhibitPoolsActualNewDeadlines_ <= inhibitPoolsMaxNewDeadlines_); #ifdef DEBUG inhibitPoolsStartOffset_ = ~size_t(0); inhibitPoolsMaxInst_ = 0; + inhibitPoolsMaxNewDeadlines_ = 0; + inhibitPoolsActualNewDeadlines_ = 0; #endif inhibitPools_ = 0;