Commit 9670cff3 authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

[liftoff][arm64] Add explicit stack check for large frames

Handle large frames by doing an explicit check to see if there is enough
remaining stack space before the stack limit.
The bailout which can be removed then is being triggered on more than 1
percent of all functions, so this is expected to improve compile time by
several percent, because we avoid the costly TurboFan compilation for
those >1%.

The code follows the same pattern as on arm, see
https://crrev.com/c/3046180.

R=ahaas@chromium.org

Bug: v8:11235
Change-Id: I0d359ae5fe0126da7ade860f596cfc108e7fd1d0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3054114Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75925}
parent 4440d7a5
......@@ -546,8 +546,8 @@ void LiftoffAssembler::PatchPrepareStackFrame(
AllocateStackSpace(frame_size);
// Jump back to the start of the function, from {pc_offset()} to
// right after the reserved space for the {sub_sp_32} (which is a branch
// now).
// right after the reserved space for the {__ sub(sp, sp, framesize)} (which
// is a branch now).
int func_start_offset =
offset + liftoff::kPatchInstructionsRequired * kInstrSize;
b(func_start_offset - pc_offset() - Instruction::kPcLoadDelta);
......
......@@ -8,6 +8,7 @@
#include "src/base/platform/wrappers.h"
#include "src/heap/memory-chunk.h"
#include "src/wasm/baseline/liftoff-assembler.h"
#include "src/wasm/wasm-objects.h"
namespace v8 {
namespace internal {
......@@ -303,8 +304,8 @@ void LiftoffAssembler::AlignFrameSize() {
}
}
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
SafepointTableBuilder*) {
void LiftoffAssembler::PatchPrepareStackFrame(
int offset, SafepointTableBuilder* safepoint_table_builder) {
// The frame_size includes the frame marker. The frame marker has already been
// pushed on the stack though, so we don't need to allocate memory for it
// anymore.
......@@ -315,39 +316,68 @@ void LiftoffAssembler::PatchPrepareStackFrame(int offset,
DCHECK_EQ(frame_size, RoundUp(frame_size, kQuadWordSizeInBytes));
DCHECK(IsImmAddSub(frame_size));
#ifdef USE_SIMULATOR
// When using the simulator, deal with Liftoff which allocates the stack
// before checking it.
// TODO(arm): Remove this when the stack check mechanism will be updated.
if (frame_size > KB / 2) {
bailout(kOtherReason,
"Stack limited to 512 bytes to avoid a bug in StackCheck");
return;
}
#endif
PatchingAssembler patching_assembler(AssemblerOptions{},
buffer_start_ + offset, 1);
#if V8_TARGET_OS_WIN
if (frame_size > kStackPageSize) {
// Generate OOL code (at the end of the function, where the current
// assembler is pointing) to do the explicit stack limit check (see
// https://docs.microsoft.com/en-us/previous-versions/visualstudio/
// visual-studio-6.0/aa227153(v=vs.60)).
// At the function start, emit a jump to that OOL code (from {offset} to
// {pc_offset()}).
int ool_offset = pc_offset() - offset;
patching_assembler.b(ool_offset >> kInstrSizeLog2);
// Now generate the OOL code.
Claim(frame_size, 1);
// Jump back to the start of the function (from {pc_offset()} to {offset +
// kInstrSize}).
int func_start_offset = offset + kInstrSize - pc_offset();
b(func_start_offset >> kInstrSizeLog2);
if (V8_LIKELY(frame_size < 4 * KB)) {
// This is the standard case for small frames: just subtract from SP and be
// done with it.
patching_assembler.PatchSubSp(frame_size);
return;
}
#endif
patching_assembler.PatchSubSp(frame_size);
// The frame size is bigger than 4KB, so we might overflow the available stack
// space if we first allocate the frame and then do the stack check (we will
// need some remaining stack space for throwing the exception). That's why we
// check the available stack space before we allocate the frame. To do this we
// replace the {__ sub(sp, sp, framesize)} with a jump to OOL code that does
// this "extended stack check".
//
// The OOL code can simply be generated here with the normal assembler,
// because all other code generation, including OOL code, has already finished
// when {PatchPrepareStackFrame} is called. The function prologue then jumps
// to the current {pc_offset()} to execute the OOL code for allocating the
// large frame.
// Emit the unconditional branch in the function prologue (from {offset} to
// {pc_offset()}).
patching_assembler.b((pc_offset() - offset) >> kInstrSizeLog2);
// If the frame is bigger than the stack, we throw the stack overflow
// exception unconditionally. Thereby we can avoid the integer overflow
// check in the condition code.
Label continuation;
if (frame_size < FLAG_stack_size * 1024) {
UseScratchRegisterScope temps(this);
Register stack_limit = temps.AcquireX();
Ldr(stack_limit,
FieldMemOperand(kWasmInstanceRegister,
WasmInstanceObject::kRealStackLimitAddressOffset));
Ldr(stack_limit, MemOperand(stack_limit));
Add(stack_limit, stack_limit, Operand(frame_size));
Cmp(sp, stack_limit);
B(hs /* higher or same */, &continuation);
}
// The instance was not written to the frame yet, but the slot was already
// reserved in {EnterFrame}. The runtime call expects it, thus spill it now.
SpillInstance(kWasmInstanceRegister);
Call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL);
// The call will not return; just define an empty safepoint.
safepoint_table_builder->DefineSafepoint(this);
if (FLAG_debug_code) Brk(0);
bind(&continuation);
// Now allocate the stack space. Note that this might do more than just
// decrementing the SP; consult {TurboAssembler::Claim}.
Claim(frame_size, 1);
// Jump back to the start of the function, from {pc_offset()} to
// right after the reserved space for the {__ sub(sp, sp, framesize)} (which
// is a branch now).
int func_start_offset = offset + kInstrSize;
b((func_start_offset - pc_offset()) >> kInstrSizeLog2);
}
void LiftoffAssembler::FinishCode() { ForceConstantPoolEmissionWithoutJump(); }
......
......@@ -310,12 +310,6 @@ void CheckBailoutAllowed(LiftoffBailoutReason reason, const char* detail,
return;
#endif
// TODO(11235): On arm64 there is still a limit on the size of supported stack
// frames.
#if V8_TARGET_ARCH_ARM64
if (strstr(detail, "Stack limited to 512 bytes")) return;
#endif
#define LIST_FEATURE(name, ...) kFeature_##name,
constexpr WasmFeatures kExperimentalFeatures{
FOREACH_WASM_EXPERIMENTAL_FEATURE_FLAG(LIST_FEATURE)};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment