Commit 601c2713 authored by Lu Yahan's avatar Lu Yahan Committed by V8 LUCI CQ

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

Port edc349db
Port 593fbb69

Bug: v8:11235
Change-Id: I19dd21a14f6475b0cf212728c4124f3b8f6c9c3b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3076770
Auto-Submit: Yahan Lu <yahan@iscas.ac.cn>
Commit-Queue: Yahan Lu <yahan@iscas.ac.cn>
Reviewed-by: 's avatarJi Qiu <qiuji@iscas.ac.cn>
Cr-Commit-Position: refs/heads/master@{#76156}
parent f888f48e
...@@ -3396,21 +3396,6 @@ void TurboAssembler::Ret(Condition cond, Register rs, const Operand& rt) { ...@@ -3396,21 +3396,6 @@ void TurboAssembler::Ret(Condition cond, Register rs, const Operand& rt) {
} }
} }
void TurboAssembler::GenPCRelativeJump(Register rd, int64_t imm32) {
DCHECK(is_int32(imm32));
int32_t Hi20 = (((int32_t)imm32 + 0x800) >> 12);
int32_t Lo12 = (int32_t)imm32 << 20 >> 20;
auipc(rd, Hi20); // Read PC + Hi20 into scratch.
jr(rd, Lo12); // jump PC + Hi20 + Lo12
}
void TurboAssembler::GenPCRelativeJumpAndLink(Register rd, int64_t imm32) {
DCHECK(is_int32(imm32));
int32_t Hi20 = (((int32_t)imm32 + 0x800) >> 12);
int32_t Lo12 = (int32_t)imm32 << 20 >> 20;
auipc(rd, Hi20); // Read PC + Hi20 into scratch.
jalr(rd, Lo12); // jump PC + Hi20 + Lo12
}
void TurboAssembler::BranchLong(Label* L) { void TurboAssembler::BranchLong(Label* L) {
// Generate position independent long branch. // Generate position independent long branch.
...@@ -4146,6 +4131,9 @@ void TurboAssembler::EnterFrame(StackFrame::Type type) { ...@@ -4146,6 +4131,9 @@ void TurboAssembler::EnterFrame(StackFrame::Type type) {
li(scratch, Operand(StackFrame::TypeToMarker(type))); li(scratch, Operand(StackFrame::TypeToMarker(type)));
Push(scratch); Push(scratch);
} }
#if V8_ENABLE_WEBASSEMBLY
if (type == StackFrame::WASM) Push(kWasmInstanceRegister);
#endif // V8_ENABLE_WEBASSEMBLY
} }
void TurboAssembler::LeaveFrame(StackFrame::Type type) { void TurboAssembler::LeaveFrame(StackFrame::Type type) {
......
...@@ -209,8 +209,21 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { ...@@ -209,8 +209,21 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void LoadRootRegisterOffset(Register destination, intptr_t offset) final; void LoadRootRegisterOffset(Register destination, intptr_t offset) final;
void LoadRootRelative(Register destination, int32_t offset) final; void LoadRootRelative(Register destination, int32_t offset) final;
inline void GenPCRelativeJump(Register rd, int64_t imm32); inline void GenPCRelativeJump(Register rd, int64_t imm32) {
inline void GenPCRelativeJumpAndLink(Register rd, int64_t imm32); DCHECK(is_int32(imm32));
int32_t Hi20 = (((int32_t)imm32 + 0x800) >> 12);
int32_t Lo12 = (int32_t)imm32 << 20 >> 20;
auipc(rd, Hi20); // Read PC + Hi20 into scratch.
jr(rd, Lo12); // jump PC + Hi20 + Lo12
}
inline void GenPCRelativeJumpAndLink(Register rd, int64_t imm32) {
DCHECK(is_int32(imm32));
int32_t Hi20 = (((int32_t)imm32 + 0x800) >> 12);
int32_t Lo12 = (int32_t)imm32 << 20 >> 20;
auipc(rd, Hi20); // Read PC + Hi20 into scratch.
jalr(rd, Lo12); // jump PC + Hi20 + Lo12
}
// Jump, Call, and Ret pseudo instructions implementing inter-working. // Jump, Call, and Ret pseudo instructions implementing inter-working.
#define COND_ARGS \ #define COND_ARGS \
Condition cond = al, Register rs = zero_reg, \ Condition cond = al, Register rs = zero_reg, \
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/base/platform/wrappers.h" #include "src/base/platform/wrappers.h"
#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/wasm-objects.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -277,10 +278,9 @@ inline void ChangeEndiannessStore(LiftoffAssembler* assm, LiftoffRegister src, ...@@ -277,10 +278,9 @@ inline void ChangeEndiannessStore(LiftoffAssembler* assm, LiftoffRegister src,
int LiftoffAssembler::PrepareStackFrame() { int LiftoffAssembler::PrepareStackFrame() {
int offset = pc_offset(); int offset = pc_offset();
// When constant that represents size of stack frame can't be represented // When the frame size is bigger than 4KB, we need two instructions for
// as 16bit we need three instructions to add it to sp, so we reserve space // stack checking, so we reserve space for this case.
// for this case. addi(sp, sp, 0);
Add64(sp, sp, Operand(0L));
nop(); nop();
nop(); nop();
return offset; return offset;
...@@ -311,19 +311,76 @@ void LiftoffAssembler::PrepareTailCall(int num_callee_stack_params, ...@@ -311,19 +311,76 @@ 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() - kSystemPointerSize; // The frame_size includes the frame marker and the instance slot. Both are
// pushed as part of frame construction, so we don't need to allocate memory
// for them anymore.
int frame_size = GetTotalFrameSize() - 2 * kSystemPointerSize;
// We can't run out of space, just pass anything big enough to not cause the // We can't run out of space, just pass anything big enough to not cause the
// assembler to try to grow the buffer. // assembler to try to grow the buffer.
constexpr int kAvailableSpace = 256; constexpr int kAvailableSpace = 256;
TurboAssembler patching_assembler( TurboAssembler patching_assembler(
nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
ExternalAssemblerBuffer(buffer_start_ + offset, kAvailableSpace)); ExternalAssemblerBuffer(buffer_start_ + offset, kAvailableSpace));
// If bytes can be represented as 16bit, addi will be generated and two
// nops will stay untouched. Otherwise, lui-ori sequence will load it to if (V8_LIKELY(frame_size < 4 * KB)) {
// register and, as third instruction, daddu will be generated. // This is the standard case for small frames: just subtract from SP and be
patching_assembler.Add64(sp, sp, Operand(-frame_size)); // done with it.
patching_assembler.Add64(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 {__ Daddu(sp, sp, -frame_size)} 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 imm32 = pc_offset() - offset;
patching_assembler.GenPCRelativeJump(kScratchReg, imm32);
// 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 = kScratchReg;
Ld(stack_limit,
FieldMemOperand(kWasmInstanceRegister,
WasmInstanceObject::kRealStackLimitAddressOffset));
Ld(stack_limit, MemOperand(stack_limit));
Add64(stack_limit, stack_limit, Operand(frame_size));
Branch(&continuation, uge, sp, Operand(stack_limit));
}
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;
Add64(sp, sp, Operand(-frame_size));
// Jump back to the start of the function, from {pc_offset()} to
// right after the reserved space for the {__ Daddu(sp, sp, -framesize)}
// (which is a Branch now).
int func_start_offset = offset + 2 * kInstrSize;
imm32 = func_start_offset - pc_offset();
GenPCRelativeJump(kScratchReg, imm32);
} }
void LiftoffAssembler::FinishCode() { ForceConstantPoolEmissionWithoutJump(); } void LiftoffAssembler::FinishCode() { ForceConstantPoolEmissionWithoutJump(); }
......
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