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:
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;