Commit 5a505fc0 authored by Junliang Yan's avatar Junliang Yan Committed by V8 LUCI CQ

ppc/s390: [liftoff][arm] Add explicit stack check for large frames

Port edc349db

Bug: v8:11235
Change-Id: I53538b1a18d778c4580683d300bc380ee1041c40
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3194874Reviewed-by: 's avatarMilad Fa <mfarazma@redhat.com>
Commit-Queue: Junliang Yan <junyan@redhat.com>
Cr-Commit-Position: refs/heads/main@{#77150}
parent 4b6ee115
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "src/heap/memory-chunk.h" #include "src/heap/memory-chunk.h"
#include "src/wasm/baseline/liftoff-assembler.h" #include "src/wasm/baseline/liftoff-assembler.h"
#include "src/wasm/simd-shuffle.h" #include "src/wasm/simd-shuffle.h"
#include "src/wasm/wasm-objects.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -131,30 +132,81 @@ void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params, ...@@ -131,30 +132,81 @@ void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params,
void LiftoffAssembler::AlignFrameSize() {} void LiftoffAssembler::AlignFrameSize() {}
void LiftoffAssembler::PatchPrepareStackFrame(int offset, void LiftoffAssembler::PatchPrepareStackFrame(
SafepointTableBuilder*) { int offset, SafepointTableBuilder* safepoint_table_builder) {
int frame_size = int frame_size =
GetTotalFrameSize() - GetTotalFrameSize() -
(FLAG_enable_embedded_constant_pool ? 3 : 2) * kSystemPointerSize; (FLAG_enable_embedded_constant_pool ? 3 : 2) * kSystemPointerSize;
#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
if (!is_int16(-frame_size)) {
bailout(kOtherReason, "PPC subi overflow");
return;
}
Assembler patching_assembler( Assembler patching_assembler(
AssemblerOptions{}, AssemblerOptions{},
ExternalAssemblerBuffer(buffer_start_ + offset, kInstrSize + kGap)); ExternalAssemblerBuffer(buffer_start_ + offset, kInstrSize + kGap));
if (V8_LIKELY(frame_size < 4 * KB)) {
patching_assembler.addi(sp, sp, Operand(-frame_size)); patching_assembler.addi(sp, sp, Operand(-frame_size));
return;
}
// 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()}).
int jump_offset = pc_offset() - offset;
if (!is_int26(jump_offset)) {
bailout(kUnsupportedArchitecture, "branch offset overflow");
return;
}
patching_assembler.b(jump_offset, LeaveLK);
// 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.
RecordComment("OOL: stack check for large frame");
Label continuation;
if (frame_size < FLAG_stack_size * 1024) {
Register stack_limit = ip;
LoadU64(stack_limit,
FieldMemOperand(kWasmInstanceRegister,
WasmInstanceObject::kRealStackLimitAddressOffset),
r0);
LoadU64(stack_limit, MemOperand(stack_limit), r0);
AddS64(stack_limit, stack_limit, Operand(frame_size), r0);
CmpU64(sp, stack_limit);
bge(&continuation);
}
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) stop();
bind(&continuation);
// Now allocate the stack space. Note that this might do more than just
// decrementing the SP; consult {TurboAssembler::AllocateStackSpace}.
SubS64(sp, sp, Operand(frame_size), r0);
// 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).
jump_offset = offset - pc_offset() + kInstrSize;
if (!is_int26(jump_offset)) {
bailout(kUnsupportedArchitecture, "branch offset overflow");
return;
}
b(jump_offset, LeaveLK);
} }
void LiftoffAssembler::FinishCode() { EmitConstantPool(); } void LiftoffAssembler::FinishCode() { EmitConstantPool(); }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "src/heap/memory-chunk.h" #include "src/heap/memory-chunk.h"
#include "src/wasm/baseline/liftoff-assembler.h" #include "src/wasm/baseline/liftoff-assembler.h"
#include "src/wasm/simd-shuffle.h" #include "src/wasm/simd-shuffle.h"
#include "src/wasm/wasm-objects.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -122,26 +123,72 @@ void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params, ...@@ -122,26 +123,72 @@ void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params,
void LiftoffAssembler::AlignFrameSize() {} void LiftoffAssembler::AlignFrameSize() {}
void LiftoffAssembler::PatchPrepareStackFrame(int offset, void LiftoffAssembler::PatchPrepareStackFrame(
SafepointTableBuilder*) { int offset, SafepointTableBuilder* safepoint_table_builder) {
int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize; int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize;
constexpr int LayInstrSize = 6; constexpr int LayInstrSize = 6;
#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
Assembler patching_assembler( Assembler patching_assembler(
AssemblerOptions{}, AssemblerOptions{},
ExternalAssemblerBuffer(buffer_start_ + offset, LayInstrSize + kGap)); ExternalAssemblerBuffer(buffer_start_ + offset, LayInstrSize + kGap));
if (V8_LIKELY(frame_size < 4 * KB)) {
patching_assembler.lay(sp, MemOperand(sp, -frame_size)); patching_assembler.lay(sp, MemOperand(sp, -frame_size));
return;
}
// 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()}).
int jump_offset = pc_offset() - offset;
patching_assembler.branchOnCond(al, jump_offset, true, true);
// 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.
RecordComment("OOL: stack check for large frame");
Label continuation;
if (frame_size < FLAG_stack_size * 1024) {
Register stack_limit = ip;
LoadU64(stack_limit,
FieldMemOperand(kWasmInstanceRegister,
WasmInstanceObject::kRealStackLimitAddressOffset),
r0);
LoadU64(stack_limit, MemOperand(stack_limit), r0);
AddU64(stack_limit, Operand(frame_size));
CmpU64(sp, stack_limit);
bge(&continuation);
}
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) stop();
bind(&continuation);
// Now allocate the stack space. Note that this might do more than just
// decrementing the SP; consult {TurboAssembler::AllocateStackSpace}.
lay(sp, MemOperand(sp, -frame_size));
// 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).
jump_offset = offset - pc_offset() + 6;
branchOnCond(al, jump_offset, true);
} }
void LiftoffAssembler::FinishCode() {} void LiftoffAssembler::FinishCode() {}
......
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