Commit f52f66e5 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[Liftoff][win32] Emit explicit stack limit checks

On Windows (32-bit), we need to emit explicit stack limit checks for
stack frames bigger than one page (4kB). This CL implements this by
emitting corresponding code at the end of Liftoff functions if needed.

R=mstarzinger@chromium.org

Bug: v8:7908, v8:6600
Change-Id: Iacb3e7afdd433a4e68620d9230bd0ba473611da8
Reviewed-on: https://chromium-review.googlesource.com/1120175
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54141}
parent 406f4ffa
......@@ -1634,23 +1634,31 @@ void Assembler::call(CodeStub* stub) {
emit(Immediate::EmbeddedCode(stub));
}
void Assembler::jmp(Label* L, Label::Distance distance) {
void Assembler::jmp_rel(int offset) {
EnsureSpace ensure_space(this);
if (L->is_bound()) {
const int short_size = 2;
const int long_size = 5;
int offs = L->pos() - pc_offset();
DCHECK_LE(offs, 0);
if (is_int8(offs - short_size)) {
if (is_int8(offset - short_size)) {
// 1110 1011 #8-bit disp.
EMIT(0xEB);
EMIT((offs - short_size) & 0xFF);
EMIT((offset - short_size) & 0xFF);
} else {
// 1110 1001 #32-bit disp.
EMIT(0xE9);
emit(offs - long_size);
emit(offset - long_size);
}
} else if (distance == Label::kNear) {
}
void Assembler::jmp(Label* L, Label::Distance distance) {
if (L->is_bound()) {
int offset = L->pos() - pc_offset();
DCHECK_LE(offset, 0); // backward jump.
jmp_rel(offset);
return;
}
EnsureSpace ensure_space(this);
if (distance == Label::kNear) {
EMIT(0xEB);
emit_near_disp(L);
} else {
......
......@@ -865,6 +865,9 @@ class Assembler : public AssemblerBase {
void jmp(Register reg) { jmp(Operand(reg)); }
void jmp(Operand adr);
void jmp(Handle<Code> code, RelocInfo::Mode rmode);
// unconditionoal jump relative to the current address. Low-level rountine,
// use with caution!
void jmp_rel(int offset);
// Conditional jumps
void j(Condition cc,
......
......@@ -13,12 +13,12 @@ namespace v8 {
namespace internal {
namespace wasm {
uint32_t LiftoffAssembler::PrepareStackFrame() {
int LiftoffAssembler::PrepareStackFrame() {
BAILOUT("PrepareStackFrame");
return 0;
}
void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
uint32_t stack_slots) {
BAILOUT("PatchPrepareStackFrame");
}
......
......@@ -114,14 +114,14 @@ inline MemOperand GetMemOp(LiftoffAssembler* assm,
} // namespace liftoff
uint32_t LiftoffAssembler::PrepareStackFrame() {
uint32_t offset = static_cast<uint32_t>(pc_offset());
int LiftoffAssembler::PrepareStackFrame() {
int offset = pc_offset();
InstructionAccurateScope scope(this, 1);
sub(sp, sp, 0);
return offset;
}
void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
uint32_t stack_slots) {
static_assert(kStackSlotSize == kXRegSize,
"kStackSlotSize must equal kXRegSize");
......
......@@ -121,17 +121,20 @@ inline void SpillRegisters(LiftoffAssembler* assm, Regs... regs) {
}
}
} // namespace liftoff
constexpr DoubleRegister kScratchDoubleReg = xmm7;
constexpr int kSubSpSize = 6; // 6 bytes for "sub esp, <imm32>"
static constexpr DoubleRegister kScratchDoubleReg = xmm7;
} // namespace liftoff
uint32_t LiftoffAssembler::PrepareStackFrame() {
uint32_t offset = static_cast<uint32_t>(pc_offset());
int LiftoffAssembler::PrepareStackFrame() {
int offset = pc_offset();
sub_sp_32(0);
DCHECK_EQ(liftoff::kSubSpSize, pc_offset() - offset);
return offset;
}
void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
uint32_t stack_slots) {
uint32_t bytes = liftoff::kConstantStackSpace + kStackSlotSize * stack_slots;
DCHECK_LE(bytes, kMaxInt);
......@@ -140,7 +143,35 @@ void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
constexpr int kAvailableSpace = 64;
Assembler patching_assembler(Assembler::Options{}, buffer_ + offset,
kAvailableSpace);
#if V8_OS_WIN
constexpr int kPageSize = 4 * 1024;
if (bytes > kPageSize) {
// 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.jmp_rel(ool_offset);
DCHECK_GE(liftoff::kSubSpSize, patching_assembler.pc_offset());
patching_assembler.Nop(liftoff::kSubSpSize -
patching_assembler.pc_offset());
// Now generate the OOL code.
// Use {edi} as scratch register; it is not being used as parameter
// register (see wasm-linkage.h).
mov(edi, bytes);
AllocateStackFrame(edi);
// Jump back to the start of the function (from {pc_offset()} to {offset +
// kSubSpSize}).
int func_start_offset = offset + liftoff::kSubSpSize - pc_offset();
jmp_rel(func_start_offset);
return;
}
#endif
patching_assembler.sub_sp_32(bytes);
DCHECK_EQ(liftoff::kSubSpSize, patching_assembler.pc_offset());
}
void LiftoffAssembler::FinishCode() {}
......@@ -884,9 +915,9 @@ void LiftoffAssembler::emit_f32_sub(DoubleRegister dst, DoubleRegister lhs,
CpuFeatureScope scope(this, AVX);
vsubss(dst, lhs, rhs);
} else if (dst == rhs) {
movss(kScratchDoubleReg, rhs);
movss(liftoff::kScratchDoubleReg, rhs);
movss(dst, lhs);
subss(dst, kScratchDoubleReg);
subss(dst, liftoff::kScratchDoubleReg);
} else {
if (dst != lhs) movss(dst, lhs);
subss(dst, rhs);
......@@ -912,9 +943,9 @@ void LiftoffAssembler::emit_f32_div(DoubleRegister dst, DoubleRegister lhs,
CpuFeatureScope scope(this, AVX);
vdivss(dst, lhs, rhs);
} else if (dst == rhs) {
movss(kScratchDoubleReg, rhs);
movss(liftoff::kScratchDoubleReg, rhs);
movss(dst, lhs);
divss(dst, kScratchDoubleReg);
divss(dst, liftoff::kScratchDoubleReg);
} else {
if (dst != lhs) movss(dst, lhs);
divss(dst, rhs);
......@@ -997,8 +1028,8 @@ void LiftoffAssembler::emit_f32_max(DoubleRegister dst, DoubleRegister lhs,
void LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) {
static constexpr uint32_t kSignBit = uint32_t{1} << 31;
if (dst == src) {
TurboAssembler::Move(kScratchDoubleReg, kSignBit - 1);
Andps(dst, kScratchDoubleReg);
TurboAssembler::Move(liftoff::kScratchDoubleReg, kSignBit - 1);
Andps(dst, liftoff::kScratchDoubleReg);
} else {
TurboAssembler::Move(dst, kSignBit - 1);
Andps(dst, src);
......@@ -1008,8 +1039,8 @@ void LiftoffAssembler::emit_f32_abs(DoubleRegister dst, DoubleRegister src) {
void LiftoffAssembler::emit_f32_neg(DoubleRegister dst, DoubleRegister src) {
static constexpr uint32_t kSignBit = uint32_t{1} << 31;
if (dst == src) {
TurboAssembler::Move(kScratchDoubleReg, kSignBit);
Xorps(dst, kScratchDoubleReg);
TurboAssembler::Move(liftoff::kScratchDoubleReg, kSignBit);
Xorps(dst, liftoff::kScratchDoubleReg);
} else {
TurboAssembler::Move(dst, kSignBit);
Xorps(dst, src);
......@@ -1060,9 +1091,9 @@ void LiftoffAssembler::emit_f64_sub(DoubleRegister dst, DoubleRegister lhs,
CpuFeatureScope scope(this, AVX);
vsubsd(dst, lhs, rhs);
} else if (dst == rhs) {
movsd(kScratchDoubleReg, rhs);
movsd(liftoff::kScratchDoubleReg, rhs);
movsd(dst, lhs);
subsd(dst, kScratchDoubleReg);
subsd(dst, liftoff::kScratchDoubleReg);
} else {
if (dst != lhs) movsd(dst, lhs);
subsd(dst, rhs);
......@@ -1088,9 +1119,9 @@ void LiftoffAssembler::emit_f64_div(DoubleRegister dst, DoubleRegister lhs,
CpuFeatureScope scope(this, AVX);
vdivsd(dst, lhs, rhs);
} else if (dst == rhs) {
movsd(kScratchDoubleReg, rhs);
movsd(liftoff::kScratchDoubleReg, rhs);
movsd(dst, lhs);
divsd(dst, kScratchDoubleReg);
divsd(dst, liftoff::kScratchDoubleReg);
} else {
if (dst != lhs) movsd(dst, lhs);
divsd(dst, rhs);
......@@ -1112,8 +1143,8 @@ void LiftoffAssembler::emit_f64_max(DoubleRegister dst, DoubleRegister lhs,
void LiftoffAssembler::emit_f64_abs(DoubleRegister dst, DoubleRegister src) {
static constexpr uint64_t kSignBit = uint64_t{1} << 63;
if (dst == src) {
TurboAssembler::Move(kScratchDoubleReg, kSignBit - 1);
Andpd(dst, kScratchDoubleReg);
TurboAssembler::Move(liftoff::kScratchDoubleReg, kSignBit - 1);
Andpd(dst, liftoff::kScratchDoubleReg);
} else {
TurboAssembler::Move(dst, kSignBit - 1);
Andpd(dst, src);
......@@ -1123,8 +1154,8 @@ void LiftoffAssembler::emit_f64_abs(DoubleRegister dst, DoubleRegister src) {
void LiftoffAssembler::emit_f64_neg(DoubleRegister dst, DoubleRegister src) {
static constexpr uint64_t kSignBit = uint64_t{1} << 63;
if (dst == src) {
TurboAssembler::Move(kScratchDoubleReg, kSignBit);
Xorpd(dst, kScratchDoubleReg);
TurboAssembler::Move(liftoff::kScratchDoubleReg, kSignBit);
Xorpd(dst, liftoff::kScratchDoubleReg);
} else {
TurboAssembler::Move(dst, kSignBit);
Xorpd(dst, src);
......@@ -1173,7 +1204,7 @@ inline void ConvertFloatToIntAndBack(LiftoffAssembler* assm, Register dst,
assm->cvttsd2si(dst, src);
assm->Cvtsi2sd(converted_back, dst);
} else { // f64 -> u32
assm->Cvttsd2ui(dst, src, kScratchDoubleReg);
assm->Cvttsd2ui(dst, src, liftoff::kScratchDoubleReg);
assm->Cvtui2sd(converted_back, dst);
}
} else { // f32
......@@ -1181,7 +1212,7 @@ inline void ConvertFloatToIntAndBack(LiftoffAssembler* assm, Register dst,
assm->cvttss2si(dst, src);
assm->Cvtsi2ss(converted_back, dst);
} else { // f32 -> u32
assm->Cvttss2ui(dst, src, kScratchDoubleReg);
assm->Cvttss2ui(dst, src, liftoff::kScratchDoubleReg);
assm->Cvtui2ss(converted_back, dst,
assm->GetUnusedRegister(kGpReg, pinned).gp());
}
......
......@@ -487,7 +487,7 @@ void LiftoffAssembler::PrepareCall(wasm::FunctionSig* sig,
const int num_lowered_params = is_pair ? 2 : 1;
const uint32_t stack_idx = param_base + param;
const VarState& slot = cache_state_.stack_state[stack_idx];
// Process both halfs of register pair separately, because they are passed
// Process both halfs of a register pair separately, because they are passed
// as separate parameters. One or both of them could end up on the stack.
for (int lowered_idx = 0; lowered_idx < num_lowered_params; ++lowered_idx) {
const RegPairHalf half =
......
......@@ -344,8 +344,8 @@ class LiftoffAssembler : public TurboAssembler {
// size of the stack frame is known. It returns an offset in the machine code
// which can later be patched (via {PatchPrepareStackFrame)} when the size of
// the frame is known.
inline uint32_t PrepareStackFrame();
inline void PatchPrepareStackFrame(uint32_t offset, uint32_t stack_slots);
inline int PrepareStackFrame();
inline void PatchPrepareStackFrame(int offset, uint32_t stack_slots);
inline void FinishCode();
inline void AbortCompilation();
......
......@@ -417,10 +417,10 @@ class LiftoffCompiler {
for (OutOfLineCode& ool : out_of_line_code_) {
GenerateOutOfLineCode(ool);
}
__ FinishCode();
safepoint_table_builder_.Emit(asm_, __ GetTotalFrameSlotCount());
__ PatchPrepareStackFrame(pc_offset_stack_frame_construction_,
__ GetTotalFrameSlotCount());
__ FinishCode();
safepoint_table_builder_.Emit(asm_, __ GetTotalFrameSlotCount());
// The previous calls may have also generated a bailout.
DidAssemblerBailout(decoder);
}
......
......@@ -100,8 +100,8 @@ inline void push(LiftoffAssembler* assm, LiftoffRegister reg, ValueType type) {
} // namespace liftoff
uint32_t LiftoffAssembler::PrepareStackFrame() {
uint32_t offset = static_cast<uint32_t>(pc_offset());
int LiftoffAssembler::PrepareStackFrame() {
int offset = pc_offset();
// When constant that represents size of stack frame can't be represented
// as 16bit we need three instructions to add it to sp, so we reserve space
// for this case.
......@@ -111,7 +111,7 @@ uint32_t LiftoffAssembler::PrepareStackFrame() {
return offset;
}
void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
uint32_t stack_slots) {
uint32_t bytes = liftoff::kConstantStackSpace + kStackSlotSize * stack_slots;
DCHECK_LE(bytes, kMaxInt);
......
......@@ -90,8 +90,8 @@ inline void push(LiftoffAssembler* assm, LiftoffRegister reg, ValueType type) {
} // namespace liftoff
uint32_t LiftoffAssembler::PrepareStackFrame() {
uint32_t offset = static_cast<uint32_t>(pc_offset());
int LiftoffAssembler::PrepareStackFrame() {
int offset = pc_offset();
// When constant that represents size of stack frame can't be represented
// as 16bit we need three instructions to add it to sp, so we reserve space
// for this case.
......@@ -101,7 +101,7 @@ uint32_t LiftoffAssembler::PrepareStackFrame() {
return offset;
}
void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
uint32_t stack_slots) {
uint64_t bytes = liftoff::kConstantStackSpace + kStackSlotSize * stack_slots;
DCHECK_LE(bytes, kMaxInt);
......
......@@ -13,12 +13,12 @@ namespace v8 {
namespace internal {
namespace wasm {
uint32_t LiftoffAssembler::PrepareStackFrame() {
int LiftoffAssembler::PrepareStackFrame() {
BAILOUT("PrepareStackFrame");
return 0;
}
void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
uint32_t stack_slots) {
BAILOUT("PatchPrepareStackFrame");
}
......
......@@ -13,12 +13,12 @@ namespace v8 {
namespace internal {
namespace wasm {
uint32_t LiftoffAssembler::PrepareStackFrame() {
int LiftoffAssembler::PrepareStackFrame() {
BAILOUT("PrepareStackFrame");
return 0;
}
void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
uint32_t stack_slots) {
BAILOUT("PatchPrepareStackFrame");
}
......
......@@ -115,13 +115,13 @@ inline void SpillRegisters(LiftoffAssembler* assm, Regs... regs) {
} // namespace liftoff
uint32_t LiftoffAssembler::PrepareStackFrame() {
uint32_t offset = static_cast<uint32_t>(pc_offset());
int LiftoffAssembler::PrepareStackFrame() {
int offset = pc_offset();
sub_sp_32(0);
return offset;
}
void LiftoffAssembler::PatchPrepareStackFrame(uint32_t offset,
void LiftoffAssembler::PatchPrepareStackFrame(int offset,
uint32_t stack_slots) {
uint32_t bytes = liftoff::kConstantStackSpace + kStackSlotSize * stack_slots;
DCHECK_LE(bytes, kMaxInt);
......
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