[Liftoff] Add function-entry stack checks
Refactor out-of-line code to represent either traps or stack checks, and add function-entry stack checks. R=ahaas@chromium.org Bug: v8:6600 Change-Id: I467ccc2016f67da5562a576aeaeceba002cd04ca Reviewed-on: https://chromium-review.googlesource.com/834208 Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#50266}
This commit is contained in:
parent
bd1f8050b0
commit
88a9495c51
@ -73,10 +73,18 @@ void LiftoffAssembler::emit_jump(Label* label) {}
|
||||
|
||||
void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label) {}
|
||||
|
||||
void LiftoffAssembler::StackCheck(Label* ool_code) {}
|
||||
|
||||
void LiftoffAssembler::CallTrapCallbackForTesting() {}
|
||||
|
||||
void LiftoffAssembler::AssertUnreachable(BailoutReason reason) {}
|
||||
|
||||
void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -73,10 +73,18 @@ void LiftoffAssembler::emit_jump(Label* label) {}
|
||||
|
||||
void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label) {}
|
||||
|
||||
void LiftoffAssembler::StackCheck(Label* ool_code) {}
|
||||
|
||||
void LiftoffAssembler::CallTrapCallbackForTesting() {}
|
||||
|
||||
void LiftoffAssembler::AssertUnreachable(BailoutReason reason) {}
|
||||
|
||||
void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -19,9 +19,9 @@ namespace liftoff {
|
||||
inline Operand GetStackSlot(uint32_t index) {
|
||||
// ebp-8 holds the stack marker, ebp-16 is the wasm context, first stack slot
|
||||
// is located at ebp-24.
|
||||
constexpr int32_t kStackSlotSize = 8;
|
||||
constexpr int32_t kFirstStackSlotOffset = -24;
|
||||
return Operand(ebp, kFirstStackSlotOffset - index * kStackSlotSize);
|
||||
return Operand(
|
||||
ebp, kFirstStackSlotOffset - index * LiftoffAssembler::kStackSlotSize);
|
||||
}
|
||||
|
||||
// TODO(clemensh): Make this a constexpr variable once Operand is constexpr.
|
||||
@ -134,8 +134,7 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
|
||||
|
||||
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
uint32_t caller_slot_idx) {
|
||||
constexpr int32_t kStackSlotSize = 4;
|
||||
Operand src(ebp, kStackSlotSize * (caller_slot_idx + 1));
|
||||
Operand src(ebp, kPointerSize * (caller_slot_idx + 1));
|
||||
// TODO(clemensh): Handle different sizes here.
|
||||
if (dst.is_gp()) {
|
||||
mov(dst.gp(), src);
|
||||
@ -308,6 +307,13 @@ void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label) {
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::StackCheck(Label* ool_code) {
|
||||
Register limit = GetUnusedRegister(kGpReg).gp();
|
||||
mov(limit, Immediate(ExternalReference::address_of_stack_limit(isolate())));
|
||||
cmp(esp, Operand(limit, 0));
|
||||
j(below_equal, ool_code);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::CallTrapCallbackForTesting() {
|
||||
PrepareCallCFunction(0, GetUnusedRegister(kGpReg).gp());
|
||||
CallCFunction(
|
||||
@ -318,6 +324,51 @@ void LiftoffAssembler::AssertUnreachable(BailoutReason reason) {
|
||||
TurboAssembler::AssertUnreachable(reason);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {
|
||||
LiftoffRegList gp_regs = regs & kGpCacheRegList;
|
||||
while (!gp_regs.is_empty()) {
|
||||
LiftoffRegister reg = gp_regs.GetFirstRegSet();
|
||||
push(reg.gp());
|
||||
gp_regs.clear(reg);
|
||||
}
|
||||
LiftoffRegList fp_regs = regs & kFpCacheRegList;
|
||||
unsigned num_fp_regs = fp_regs.GetNumRegsSet();
|
||||
if (num_fp_regs) {
|
||||
sub(esp, Immediate(num_fp_regs * kStackSlotSize));
|
||||
unsigned offset = 0;
|
||||
while (!fp_regs.is_empty()) {
|
||||
LiftoffRegister reg = fp_regs.GetFirstRegSet();
|
||||
movsd(Operand(esp, offset), reg.fp());
|
||||
fp_regs.clear(reg);
|
||||
offset += sizeof(double);
|
||||
}
|
||||
DCHECK_EQ(offset, num_fp_regs * sizeof(double));
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {
|
||||
LiftoffRegList fp_regs = regs & kFpCacheRegList;
|
||||
unsigned fp_offset = 0;
|
||||
while (!fp_regs.is_empty()) {
|
||||
LiftoffRegister reg = fp_regs.GetFirstRegSet();
|
||||
movsd(reg.fp(), Operand(esp, fp_offset));
|
||||
fp_regs.clear(reg);
|
||||
fp_offset += sizeof(double);
|
||||
}
|
||||
if (fp_offset) add(esp, Immediate(fp_offset));
|
||||
LiftoffRegList gp_regs = regs & kGpCacheRegList;
|
||||
while (!gp_regs.is_empty()) {
|
||||
LiftoffRegister reg = gp_regs.GetLastRegSet();
|
||||
pop(reg.gp());
|
||||
gp_regs.clear(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {
|
||||
DCHECK_LT(num_stack_slots, (1 << 16) / kPointerSize); // 16 bit immediate
|
||||
ret(static_cast<int>(num_stack_slots * kPointerSize));
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -32,6 +32,9 @@ class LiftoffAssembler : public TurboAssembler {
|
||||
// needed.
|
||||
static constexpr int kMaxValueStackHeight = 8;
|
||||
|
||||
// Each slot in our stack frame currently has exactly 8 bytes.
|
||||
static constexpr uint32_t kStackSlotSize = 8;
|
||||
|
||||
class VarState {
|
||||
public:
|
||||
enum Location : uint8_t { kStack, kRegister, kConstant };
|
||||
@ -286,10 +289,17 @@ class LiftoffAssembler : public TurboAssembler {
|
||||
inline void emit_jump(Label*);
|
||||
inline void emit_cond_jump(Condition, Label*);
|
||||
|
||||
inline void StackCheck(Label* ool_code);
|
||||
|
||||
inline void CallTrapCallbackForTesting();
|
||||
|
||||
inline void AssertUnreachable(BailoutReason reason);
|
||||
|
||||
inline void PushRegisters(LiftoffRegList);
|
||||
inline void PopRegisters(LiftoffRegList);
|
||||
|
||||
inline void DropStackSlotsAndRet(uint32_t num_stack_slots);
|
||||
|
||||
////////////////////////////////////
|
||||
// End of platform-specific part. //
|
||||
////////////////////////////////////
|
||||
|
@ -37,9 +37,13 @@ namespace {
|
||||
class MovableLabel {
|
||||
public:
|
||||
Label* get() { return label_.get(); }
|
||||
MovableLabel() : MovableLabel(new Label()) {}
|
||||
|
||||
static MovableLabel None() { return MovableLabel(nullptr); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Label> label_ = base::make_unique<Label>();
|
||||
std::unique_ptr<Label> label_;
|
||||
explicit MovableLabel(Label* label) : label_(label) {}
|
||||
};
|
||||
#else
|
||||
// On all other platforms, just store the Label directly.
|
||||
@ -47,6 +51,8 @@ class MovableLabel {
|
||||
public:
|
||||
Label* get() { return &label_; }
|
||||
|
||||
static MovableLabel None() { return MovableLabel(); }
|
||||
|
||||
private:
|
||||
Label label_;
|
||||
};
|
||||
@ -71,6 +77,23 @@ class LiftoffCompiler {
|
||||
|
||||
using Decoder = WasmFullDecoder<validate, LiftoffCompiler>;
|
||||
|
||||
struct OutOfLineCode {
|
||||
MovableLabel label;
|
||||
MovableLabel continuation;
|
||||
Builtins::Name builtin;
|
||||
wasm::WasmCodePosition position;
|
||||
LiftoffRegList regs_to_save;
|
||||
|
||||
// Named constructors:
|
||||
static OutOfLineCode Trap(Builtins::Name b, wasm::WasmCodePosition pos) {
|
||||
return {{}, {}, b, pos, {}};
|
||||
}
|
||||
static OutOfLineCode StackCheck(wasm::WasmCodePosition pos,
|
||||
LiftoffRegList regs) {
|
||||
return {{}, MovableLabel::None(), Builtins::kWasmStackGuard, pos, regs};
|
||||
}
|
||||
};
|
||||
|
||||
LiftoffCompiler(LiftoffAssembler* liftoff_asm,
|
||||
compiler::CallDescriptor* call_desc, compiler::ModuleEnv* env,
|
||||
compiler::RuntimeExceptionSupport runtime_exception_support,
|
||||
@ -116,8 +139,8 @@ class LiftoffCompiler {
|
||||
Label* label = decoder->control_at(i)->label.get();
|
||||
if (!label->is_bound()) __ bind(label);
|
||||
}
|
||||
for (auto& trap : trap_ool_code_) {
|
||||
if (!trap.label.get()->is_bound()) __ bind(trap.label.get());
|
||||
for (auto& ool : out_of_line_code_) {
|
||||
if (!ool.label.get()->is_bound()) __ bind(ool.label.get());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -171,6 +194,15 @@ class LiftoffCompiler {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void StackCheck(wasm::WasmCodePosition position) {
|
||||
if (FLAG_wasm_no_stack_checks || !runtime_exception_support_) return;
|
||||
out_of_line_code_.push_back(
|
||||
OutOfLineCode::StackCheck(position, __ cache_state()->used_registers));
|
||||
OutOfLineCode& ool = out_of_line_code_.back();
|
||||
__ StackCheck(ool.label.get());
|
||||
__ bind(ool.continuation.get());
|
||||
}
|
||||
|
||||
void StartFunctionBody(Decoder* decoder, Control* block) {
|
||||
if (!kLiftoffAssemblerImplementedOnThisPlatform) {
|
||||
unsupported(decoder, "platform");
|
||||
@ -178,7 +210,8 @@ class LiftoffCompiler {
|
||||
}
|
||||
__ EnterFrame(StackFrame::WASM_COMPILED);
|
||||
__ set_has_frame(true);
|
||||
__ ReserveStackSpace(kPointerSize * __ GetTotalFrameSlotCount());
|
||||
__ ReserveStackSpace(LiftoffAssembler::kStackSlotSize *
|
||||
__ GetTotalFrameSlotCount());
|
||||
// Parameter 0 is the wasm context.
|
||||
uint32_t num_params =
|
||||
static_cast<uint32_t>(call_desc_->ParameterCount()) - 1;
|
||||
@ -236,48 +269,50 @@ class LiftoffCompiler {
|
||||
}
|
||||
}
|
||||
block->label_state.stack_base = __ num_locals();
|
||||
|
||||
// The function-prologue stack check is associated with position 0, which
|
||||
// is never a position of any instruction in the function.
|
||||
StackCheck(0);
|
||||
|
||||
DCHECK_EQ(__ num_locals(), param_idx);
|
||||
DCHECK_EQ(__ num_locals(), __ cache_state()->stack_height());
|
||||
CheckStackSizeLimit(decoder);
|
||||
}
|
||||
|
||||
static Builtins::Name GetBuiltinIdForTrap(wasm::TrapReason reason) {
|
||||
switch (reason) {
|
||||
#define TRAPREASON_TO_MESSAGE(name) \
|
||||
case wasm::k##name: \
|
||||
return Builtins::kThrowWasm##name;
|
||||
FOREACH_WASM_TRAPREASON(TRAPREASON_TO_MESSAGE)
|
||||
#undef TRAPREASON_TO_MESSAGE
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateTrap(wasm::TrapReason reason, wasm::WasmCodePosition position) {
|
||||
void GenerateOutOfLineCode(OutOfLineCode& ool) {
|
||||
__ bind(ool.label.get());
|
||||
const bool is_stack_check = ool.builtin == Builtins::kWasmStackGuard;
|
||||
if (!runtime_exception_support_) {
|
||||
// We cannot test calls to the runtime in cctest/test-run-wasm.
|
||||
// Therefore we emit a call to C here instead of a call to the runtime.
|
||||
// In this mode, we never generate stack checks.
|
||||
DCHECK(!is_stack_check);
|
||||
__ CallTrapCallbackForTesting();
|
||||
__ LeaveFrame(StackFrame::WASM_COMPILED);
|
||||
__ Ret();
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK(runtime_exception_support_);
|
||||
if (!ool.regs_to_save.is_empty()) __ PushRegisters(ool.regs_to_save);
|
||||
|
||||
source_position_table_builder_->AddPosition(
|
||||
__ pc_offset(), SourcePosition(position), false);
|
||||
__ pc_offset(), SourcePosition(ool.position), false);
|
||||
__ Call(__ isolate()->builtins()->builtin_handle(ool.builtin),
|
||||
RelocInfo::CODE_TARGET);
|
||||
safepoint_table_builder_.DefineSafepoint(asm_, Safepoint::kSimple, 0,
|
||||
Safepoint::kNoLazyDeopt);
|
||||
Builtins::Name trap_id = GetBuiltinIdForTrap(reason);
|
||||
__ Call(__ isolate()->builtins()->builtin_handle(trap_id),
|
||||
RelocInfo::CODE_TARGET);
|
||||
__ AssertUnreachable(kUnexpectedReturnFromWasmTrap);
|
||||
DCHECK_EQ(ool.continuation.get()->is_bound(), is_stack_check);
|
||||
if (!ool.regs_to_save.is_empty()) __ PopRegisters(ool.regs_to_save);
|
||||
if (is_stack_check) {
|
||||
__ emit_jump(ool.continuation.get());
|
||||
} else {
|
||||
__ AssertUnreachable(kUnexpectedReturnFromWasmTrap);
|
||||
}
|
||||
}
|
||||
|
||||
void FinishFunction(Decoder* decoder) {
|
||||
for (auto& trap : trap_ool_code_) {
|
||||
__ bind(trap.label.get());
|
||||
GenerateTrap(trap.reason, trap.position);
|
||||
for (OutOfLineCode& ool : out_of_line_code_) {
|
||||
GenerateOutOfLineCode(ool);
|
||||
}
|
||||
safepoint_table_builder_.Emit(asm_, __ GetTotalFrameSlotCount());
|
||||
}
|
||||
@ -431,7 +466,8 @@ class LiftoffCompiler {
|
||||
__ MoveToReturnRegister(reg);
|
||||
}
|
||||
__ LeaveFrame(StackFrame::WASM_COMPILED);
|
||||
__ Ret();
|
||||
__ DropStackSlotsAndRet(
|
||||
static_cast<uint32_t>(call_desc_->StackParameterCount()));
|
||||
}
|
||||
|
||||
void GetLocal(Decoder* decoder, Value* result,
|
||||
@ -588,7 +624,9 @@ class LiftoffCompiler {
|
||||
if (FLAG_wasm_no_bounds_checks) return;
|
||||
|
||||
// Add OOL code.
|
||||
Label* trap_label = AddTrapCode(kTrapMemOutOfBounds, position);
|
||||
out_of_line_code_.push_back(
|
||||
OutOfLineCode::Trap(Builtins::kThrowWasmTrapMemOutOfBounds, position));
|
||||
Label* trap_label = out_of_line_code_.back().label.get();
|
||||
|
||||
if (access_size > max_size_ || offset > max_size_ - access_size) {
|
||||
// The access will be out of bounds, even for the largest memory.
|
||||
@ -714,14 +752,6 @@ class LiftoffCompiler {
|
||||
}
|
||||
|
||||
private:
|
||||
struct TrapOolCode {
|
||||
MovableLabel label;
|
||||
wasm::TrapReason reason;
|
||||
wasm::WasmCodePosition position;
|
||||
TrapOolCode(wasm::TrapReason r, wasm::WasmCodePosition pos)
|
||||
: reason(r), position(pos) {}
|
||||
};
|
||||
|
||||
LiftoffAssembler* const asm_;
|
||||
compiler::CallDescriptor* const call_desc_;
|
||||
compiler::ModuleEnv* const env_;
|
||||
@ -730,7 +760,7 @@ class LiftoffCompiler {
|
||||
const uint32_t max_size_;
|
||||
const compiler::RuntimeExceptionSupport runtime_exception_support_;
|
||||
bool ok_ = true;
|
||||
std::vector<TrapOolCode> trap_ool_code_;
|
||||
std::vector<OutOfLineCode> out_of_line_code_;
|
||||
SourcePositionTableBuilder* const source_position_table_builder_;
|
||||
// Zone used to store information during compilation. The result will be
|
||||
// stored independently, such that this zone can die together with the
|
||||
@ -772,11 +802,6 @@ class LiftoffCompiler {
|
||||
PrintF("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
Label* AddTrapCode(wasm::TrapReason reason, wasm::WasmCodePosition pos) {
|
||||
trap_ool_code_.emplace_back(reason, pos);
|
||||
return trap_ool_code_.back().label.get();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -142,6 +142,8 @@ class LiftoffRegList {
|
||||
|
||||
bool is_empty() const { return regs_ == 0; }
|
||||
|
||||
unsigned GetNumRegsSet() const { return base::bits::CountPopulation(regs_); }
|
||||
|
||||
LiftoffRegList operator&(LiftoffRegList other) const {
|
||||
return FromBits(regs_ & other.regs_);
|
||||
}
|
||||
@ -151,11 +153,18 @@ class LiftoffRegList {
|
||||
}
|
||||
|
||||
LiftoffRegister GetFirstRegSet() const {
|
||||
DCHECK_NE(0, regs_);
|
||||
DCHECK(!is_empty());
|
||||
unsigned first_code = base::bits::CountTrailingZeros(regs_);
|
||||
return LiftoffRegister::from_liftoff_code(first_code);
|
||||
}
|
||||
|
||||
LiftoffRegister GetLastRegSet() const {
|
||||
DCHECK(!is_empty());
|
||||
unsigned last_code =
|
||||
8 * sizeof(regs_) - 1 - base::bits::CountLeadingZeros(regs_);
|
||||
return LiftoffRegister::from_liftoff_code(last_code);
|
||||
}
|
||||
|
||||
LiftoffRegList MaskOut(storage_t mask) const {
|
||||
// Masking out is guaranteed to return a correct reg list, hence no checks
|
||||
// needed.
|
||||
|
@ -73,10 +73,18 @@ void LiftoffAssembler::emit_jump(Label* label) {}
|
||||
|
||||
void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label) {}
|
||||
|
||||
void LiftoffAssembler::StackCheck(Label* ool_code) {}
|
||||
|
||||
void LiftoffAssembler::CallTrapCallbackForTesting() {}
|
||||
|
||||
void LiftoffAssembler::AssertUnreachable(BailoutReason reason) {}
|
||||
|
||||
void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -73,10 +73,18 @@ void LiftoffAssembler::emit_jump(Label* label) {}
|
||||
|
||||
void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label) {}
|
||||
|
||||
void LiftoffAssembler::StackCheck(Label* ool_code) {}
|
||||
|
||||
void LiftoffAssembler::CallTrapCallbackForTesting() {}
|
||||
|
||||
void LiftoffAssembler::AssertUnreachable(BailoutReason reason) {}
|
||||
|
||||
void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -73,10 +73,18 @@ void LiftoffAssembler::emit_jump(Label* label) {}
|
||||
|
||||
void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label) {}
|
||||
|
||||
void LiftoffAssembler::StackCheck(Label* ool_code) {}
|
||||
|
||||
void LiftoffAssembler::CallTrapCallbackForTesting() {}
|
||||
|
||||
void LiftoffAssembler::AssertUnreachable(BailoutReason reason) {}
|
||||
|
||||
void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -73,10 +73,18 @@ void LiftoffAssembler::emit_jump(Label* label) {}
|
||||
|
||||
void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label) {}
|
||||
|
||||
void LiftoffAssembler::StackCheck(Label* ool_code) {}
|
||||
|
||||
void LiftoffAssembler::CallTrapCallbackForTesting() {}
|
||||
|
||||
void LiftoffAssembler::AssertUnreachable(BailoutReason reason) {}
|
||||
|
||||
void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {}
|
||||
|
||||
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -19,9 +19,9 @@ namespace liftoff {
|
||||
inline Operand GetStackSlot(uint32_t index) {
|
||||
// rbp-8 holds the stack marker, rbp-16 is the wasm context, first stack slot
|
||||
// is located at rbp-24.
|
||||
constexpr int32_t kStackSlotSize = 8;
|
||||
constexpr int32_t kFirstStackSlotOffset = -24;
|
||||
return Operand(rbp, kFirstStackSlotOffset - index * kStackSlotSize);
|
||||
return Operand(
|
||||
rbp, kFirstStackSlotOffset - index * LiftoffAssembler::kStackSlotSize);
|
||||
}
|
||||
|
||||
// TODO(clemensh): Make this a constexpr variable once Operand is constexpr.
|
||||
@ -30,6 +30,7 @@ inline Operand GetContextOperand() { return Operand(rbp, -16); }
|
||||
} // namespace liftoff
|
||||
|
||||
void LiftoffAssembler::ReserveStackSpace(uint32_t bytes) {
|
||||
DCHECK_LE(bytes, kMaxInt);
|
||||
subp(rsp, Immediate(bytes));
|
||||
}
|
||||
|
||||
@ -142,8 +143,7 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg,
|
||||
|
||||
void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
uint32_t caller_slot_idx) {
|
||||
constexpr int32_t kStackSlotSize = 8;
|
||||
Operand src(rbp, kStackSlotSize * (caller_slot_idx + 1));
|
||||
Operand src(rbp, kPointerSize * (caller_slot_idx + 1));
|
||||
// TODO(clemensh): Handle different sizes here.
|
||||
if (dst.is_gp()) {
|
||||
movq(dst.gp(), src);
|
||||
@ -320,6 +320,13 @@ void LiftoffAssembler::emit_cond_jump(Condition cond, Label* label) {
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::StackCheck(Label* ool_code) {
|
||||
Register limit = GetUnusedRegister(kGpReg).gp();
|
||||
LoadAddress(limit, ExternalReference::address_of_stack_limit(isolate()));
|
||||
cmpp(rsp, Operand(limit, 0));
|
||||
j(below_equal, ool_code);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::CallTrapCallbackForTesting() {
|
||||
PrepareCallCFunction(0);
|
||||
CallCFunction(
|
||||
@ -330,6 +337,51 @@ void LiftoffAssembler::AssertUnreachable(BailoutReason reason) {
|
||||
TurboAssembler::AssertUnreachable(reason);
|
||||
}
|
||||
|
||||
void LiftoffAssembler::PushRegisters(LiftoffRegList regs) {
|
||||
LiftoffRegList gp_regs = regs & kGpCacheRegList;
|
||||
while (!gp_regs.is_empty()) {
|
||||
LiftoffRegister reg = gp_regs.GetFirstRegSet();
|
||||
pushq(reg.gp());
|
||||
gp_regs.clear(reg);
|
||||
}
|
||||
LiftoffRegList fp_regs = regs & kFpCacheRegList;
|
||||
unsigned num_fp_regs = fp_regs.GetNumRegsSet();
|
||||
if (num_fp_regs) {
|
||||
subp(rsp, Immediate(num_fp_regs * kStackSlotSize));
|
||||
unsigned offset = 0;
|
||||
while (!fp_regs.is_empty()) {
|
||||
LiftoffRegister reg = fp_regs.GetFirstRegSet();
|
||||
movsd(Operand(rsp, offset), reg.fp());
|
||||
fp_regs.clear(reg);
|
||||
offset += sizeof(double);
|
||||
}
|
||||
DCHECK_EQ(offset, num_fp_regs * sizeof(double));
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::PopRegisters(LiftoffRegList regs) {
|
||||
LiftoffRegList fp_regs = regs & kFpCacheRegList;
|
||||
unsigned fp_offset = 0;
|
||||
while (!fp_regs.is_empty()) {
|
||||
LiftoffRegister reg = fp_regs.GetFirstRegSet();
|
||||
movsd(reg.fp(), Operand(rsp, fp_offset));
|
||||
fp_regs.clear(reg);
|
||||
fp_offset += sizeof(double);
|
||||
}
|
||||
if (fp_offset) addp(rsp, Immediate(fp_offset));
|
||||
LiftoffRegList gp_regs = regs & kGpCacheRegList;
|
||||
while (!gp_regs.is_empty()) {
|
||||
LiftoffRegister reg = gp_regs.GetLastRegSet();
|
||||
popq(reg.gp());
|
||||
gp_regs.clear(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::DropStackSlotsAndRet(uint32_t num_stack_slots) {
|
||||
DCHECK_LT(num_stack_slots, (1 << 16) / kPointerSize); // 16 bit immediate
|
||||
ret(static_cast<int>(num_stack_slots * kPointerSize));
|
||||
}
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user