Issue #2898 - Don't unroll to large stack probe loops.

Resolves #2898
This commit is contained in:
Moonchild 2026-01-09 15:08:10 +01:00 committed by OwnedByWuigi
commit 6e4c40c648
3 changed files with 56 additions and 11 deletions

View file

@ -425,13 +425,32 @@ MacroAssembler::subFromStackPtr(Imm32 imm32)
// Ion frame data for a piece of code is very large. To handle this special case,
// for frames over 1k in size we allocate memory on the stack incrementally, touching
// it as we go.
//
// When the amount is quite large, which it can be, we emit an actual loop, in order
// to keep the function prologue compact. Compactness is a requirement for e.g.
// Wasm's CodeRange data structure, which can encode only 8-bit offsets.
uint32_t amountLeft = imm32.value;
while (amountLeft > 4096) {
uint32_t fullPages = amountLeft / 4096;
if (fullPages <= 8) {
while (amountLeft > 4096) {
subq(Imm32(4096), StackPointer);
store32(Imm32(0), Address(StackPointer, 0));
amountLeft -= 4096;
}
subq(Imm32(amountLeft), StackPointer);
} else {
ScratchRegisterScope scratch(*this);
Label top;
move32(Imm32(fullPages), scratch);
bind(&top);
subq(Imm32(4096), StackPointer);
store32(Imm32(0), Address(StackPointer, 0));
amountLeft -= 4096;
subl(Imm32(1), scratch);
j(Assembler::NonZero, &top);
amountLeft -= fullPages * 4096;
if (amountLeft)
subq(Imm32(amountLeft), StackPointer);
}
subq(Imm32(amountLeft), StackPointer);
}
}

View file

@ -339,13 +339,39 @@ MacroAssembler::subFromStackPtr(Imm32 imm32)
// Ion frame data for a piece of code is very large. To handle this special case,
// for frames over 1k in size we allocate memory on the stack incrementally, touching
// it as we go.
//
// When the amount is quite large, which it can be, we emit an actual loop, in order
// to keep the function prologue compact. Compactness is a requirement for e.g.
// Wasm's CodeRange data structure, which can encode only 8-bit offsets.
uint32_t amountLeft = imm32.value;
while (amountLeft > 4096) {
uint32_t fullPages = amountLeft / 4096;
if (fullPages <= 8) {
while (amountLeft > 4096) {
subl(Imm32(4096), StackPointer);
store32(Imm32(0), Address(StackPointer, 0));
amountLeft -= 4096;
}
subl(Imm32(amountLeft), StackPointer);
} else {
// Save scratch register.
push(eax);
amountLeft -= 4;
fullPages = amountLeft / 4096;
Label top;
move32(Imm32(fullPages), eax);
bind(&top);
subl(Imm32(4096), StackPointer);
store32(Imm32(0), Address(StackPointer, 0));
amountLeft -= 4096;
subl(Imm32(1), eax);
j(Assembler::NonZero, &top);
amountLeft -= fullPages * 4096;
if (amountLeft)
subl(Imm32(amountLeft), StackPointer);
// Restore scratch register.
movl(Operand(StackPointer, uint32_t(imm32.value) - 4), eax);
}
subl(Imm32(amountLeft), StackPointer);
}
}

View file

@ -400,11 +400,11 @@ CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode, FuncOffset
{
MOZ_ASSERT(begin_ < profilingReturn_);
MOZ_ASSERT(profilingReturn_ < end_);
MOZ_ASSERT(funcBeginToTableEntry_ == offsets.tableEntry - begin_);
MOZ_ASSERT(funcBeginToTableProfilingJump_ == offsets.tableProfilingJump - begin_);
MOZ_ASSERT(funcBeginToNonProfilingEntry_ == offsets.nonProfilingEntry - begin_);
MOZ_ASSERT(funcProfilingJumpToProfilingReturn_ == profilingReturn_ - offsets.profilingJump);
MOZ_ASSERT(funcProfilingEpilogueToProfilingReturn_ == profilingReturn_ - offsets.profilingEpilogue);
MOZ_ASSERT(offsets.tableEntry - begin_ <= UINT8_MAX);
MOZ_ASSERT(offsets.tableProfilingJump - begin_ <= UINT8_MAX);
MOZ_ASSERT(offsets.nonProfilingEntry - begin_ <= UINT8_MAX);
MOZ_ASSERT(profilingReturn_ - offsets.profilingJump <= UINT8_MAX);
MOZ_ASSERT(profilingReturn_ - offsets.profilingEpilogue <= UINT8_MAX);
}
static size_t