Reimplement dynamic frame alignment for frames that are compiled via OSR or have more than 2 double spill slots.
The first spill slot is now reserved on all optimized frames to distinguish frames that were aligned. Review URL: https://chromiumcodereview.appspot.com/10532066 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11772 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e6f2eab7f6
commit
75ca3e3395
10
src/debug.cc
10
src/debug.cc
@ -1451,7 +1451,7 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
|
|||||||
// Remember source position and frame to handle step next.
|
// Remember source position and frame to handle step next.
|
||||||
thread_local_.last_statement_position_ =
|
thread_local_.last_statement_position_ =
|
||||||
debug_info->code()->SourceStatementPosition(frame->pc());
|
debug_info->code()->SourceStatementPosition(frame->pc());
|
||||||
thread_local_.last_fp_ = frame->fp();
|
thread_local_.last_fp_ = frame->UnpaddedFP();
|
||||||
} else {
|
} else {
|
||||||
// If there's restarter frame on top of the stack, just get the pointer
|
// If there's restarter frame on top of the stack, just get the pointer
|
||||||
// to function which is going to be restarted.
|
// to function which is going to be restarted.
|
||||||
@ -1520,7 +1520,7 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
|
|||||||
// propagated on the next Debug::Break.
|
// propagated on the next Debug::Break.
|
||||||
thread_local_.last_statement_position_ =
|
thread_local_.last_statement_position_ =
|
||||||
debug_info->code()->SourceStatementPosition(frame->pc());
|
debug_info->code()->SourceStatementPosition(frame->pc());
|
||||||
thread_local_.last_fp_ = frame->fp();
|
thread_local_.last_fp_ = frame->UnpaddedFP();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step in or Step in min
|
// Step in or Step in min
|
||||||
@ -1555,7 +1555,7 @@ bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
|
|||||||
// Continue if we are still on the same frame and in the same statement.
|
// Continue if we are still on the same frame and in the same statement.
|
||||||
int current_statement_position =
|
int current_statement_position =
|
||||||
break_location_iterator->code()->SourceStatementPosition(frame->pc());
|
break_location_iterator->code()->SourceStatementPosition(frame->pc());
|
||||||
return thread_local_.last_fp_ == frame->fp() &&
|
return thread_local_.last_fp_ == frame->UnpaddedFP() &&
|
||||||
thread_local_.last_statement_position_ == current_statement_position;
|
thread_local_.last_statement_position_ == current_statement_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1756,7 +1756,7 @@ void Debug::ClearOneShot() {
|
|||||||
|
|
||||||
void Debug::ActivateStepIn(StackFrame* frame) {
|
void Debug::ActivateStepIn(StackFrame* frame) {
|
||||||
ASSERT(!StepOutActive());
|
ASSERT(!StepOutActive());
|
||||||
thread_local_.step_into_fp_ = frame->fp();
|
thread_local_.step_into_fp_ = frame->UnpaddedFP();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1767,7 +1767,7 @@ void Debug::ClearStepIn() {
|
|||||||
|
|
||||||
void Debug::ActivateStepOut(StackFrame* frame) {
|
void Debug::ActivateStepOut(StackFrame* frame) {
|
||||||
ASSERT(!StepInActive());
|
ASSERT(!StepInActive());
|
||||||
thread_local_.step_out_fp_ = frame->fp();
|
thread_local_.step_out_fp_ = frame->UnpaddedFP();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -354,6 +354,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
|
|||||||
bailout_type_(type),
|
bailout_type_(type),
|
||||||
from_(from),
|
from_(from),
|
||||||
fp_to_sp_delta_(fp_to_sp_delta),
|
fp_to_sp_delta_(fp_to_sp_delta),
|
||||||
|
has_alignment_padding_(0),
|
||||||
input_(NULL),
|
input_(NULL),
|
||||||
output_count_(0),
|
output_count_(0),
|
||||||
jsframe_count_(0),
|
jsframe_count_(0),
|
||||||
@ -594,12 +595,14 @@ void Deoptimizer::DoComputeOutputFrames() {
|
|||||||
PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
|
PrintF("[deoptimizing: end 0x%08" V8PRIxPTR " ",
|
||||||
reinterpret_cast<intptr_t>(function));
|
reinterpret_cast<intptr_t>(function));
|
||||||
function->PrintName();
|
function->PrintName();
|
||||||
PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, took %0.3f ms]\n",
|
PrintF(" => node=%u, pc=0x%08" V8PRIxPTR ", state=%s, alignment=%s,"
|
||||||
|
" took %0.3f ms]\n",
|
||||||
node_id,
|
node_id,
|
||||||
output_[index]->GetPc(),
|
output_[index]->GetPc(),
|
||||||
FullCodeGenerator::State2String(
|
FullCodeGenerator::State2String(
|
||||||
static_cast<FullCodeGenerator::State>(
|
static_cast<FullCodeGenerator::State>(
|
||||||
output_[index]->GetState()->value())),
|
output_[index]->GetState()->value())),
|
||||||
|
has_alignment_padding_ ? "with padding" : "no padding",
|
||||||
ms);
|
ms);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -770,7 +773,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
|||||||
if (FLAG_trace_deopt) {
|
if (FLAG_trace_deopt) {
|
||||||
PrintF(" 0x%08" V8PRIxPTR ": ",
|
PrintF(" 0x%08" V8PRIxPTR ": ",
|
||||||
output_[frame_index]->GetTop() + output_offset);
|
output_[frame_index]->GetTop() + output_offset);
|
||||||
PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [esp + %d] ",
|
PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ",
|
||||||
output_offset,
|
output_offset,
|
||||||
input_value,
|
input_value,
|
||||||
input_offset);
|
input_offset);
|
||||||
@ -790,7 +793,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
|||||||
if (FLAG_trace_deopt) {
|
if (FLAG_trace_deopt) {
|
||||||
PrintF(" 0x%08" V8PRIxPTR ": ",
|
PrintF(" 0x%08" V8PRIxPTR ": ",
|
||||||
output_[frame_index]->GetTop() + output_offset);
|
output_[frame_index]->GetTop() + output_offset);
|
||||||
PrintF("[top + %d] <- %" V8PRIdPTR " ; [esp + %d] (%s)\n",
|
PrintF("[top + %d] <- %" V8PRIdPTR " ; [sp + %d] (%s)\n",
|
||||||
output_offset,
|
output_offset,
|
||||||
value,
|
value,
|
||||||
input_offset,
|
input_offset,
|
||||||
@ -816,7 +819,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
|||||||
input_->GetOffsetFromSlotIndex(input_slot_index);
|
input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||||
double value = input_->GetDoubleFrameSlot(input_offset);
|
double value = input_->GetDoubleFrameSlot(input_offset);
|
||||||
if (FLAG_trace_deopt) {
|
if (FLAG_trace_deopt) {
|
||||||
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n",
|
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
|
||||||
output_[frame_index]->GetTop() + output_offset,
|
output_[frame_index]->GetTop() + output_offset,
|
||||||
output_offset,
|
output_offset,
|
||||||
value,
|
value,
|
||||||
|
@ -221,6 +221,10 @@ class Deoptimizer : public Malloced {
|
|||||||
}
|
}
|
||||||
static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
|
static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
|
||||||
|
|
||||||
|
static int has_alignment_padding_offset() {
|
||||||
|
return OFFSET_OF(Deoptimizer, has_alignment_padding_);
|
||||||
|
}
|
||||||
|
|
||||||
static int GetDeoptimizedCodeCount(Isolate* isolate);
|
static int GetDeoptimizedCodeCount(Isolate* isolate);
|
||||||
|
|
||||||
static const int kNotDeoptimizationEntry = -1;
|
static const int kNotDeoptimizationEntry = -1;
|
||||||
@ -322,6 +326,7 @@ class Deoptimizer : public Malloced {
|
|||||||
BailoutType bailout_type_;
|
BailoutType bailout_type_;
|
||||||
Address from_;
|
Address from_;
|
||||||
int fp_to_sp_delta_;
|
int fp_to_sp_delta_;
|
||||||
|
int has_alignment_padding_;
|
||||||
|
|
||||||
// Input frame description.
|
// Input frame description.
|
||||||
FrameDescription* input_;
|
FrameDescription* input_;
|
||||||
|
@ -469,6 +469,20 @@ StackFrame::Type StackFrame::GetCallerState(State* state) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Address StackFrame::UnpaddedFP() const {
|
||||||
|
#if defined(V8_TARGET_ARCH_IA32) || defined(V8_HOST_ARCH_IA32)
|
||||||
|
if (!is_optimized()) return fp();
|
||||||
|
int32_t alignment_state = Memory::int32_at(
|
||||||
|
fp() + JavaScriptFrameConstants::kDynamicAlignmentStateOffset);
|
||||||
|
|
||||||
|
return (alignment_state == kAlignmentPaddingPushed) ?
|
||||||
|
(fp() + kPointerSize) : fp();
|
||||||
|
#else
|
||||||
|
return fp();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Code* EntryFrame::unchecked_code() const {
|
Code* EntryFrame::unchecked_code() const {
|
||||||
return HEAP->raw_unchecked_js_entry_code();
|
return HEAP->raw_unchecked_js_entry_code();
|
||||||
}
|
}
|
||||||
|
@ -206,6 +206,11 @@ class StackFrame BASE_EMBEDDED {
|
|||||||
Address fp() const { return state_.fp; }
|
Address fp() const { return state_.fp; }
|
||||||
Address caller_sp() const { return GetCallerStackPointer(); }
|
Address caller_sp() const { return GetCallerStackPointer(); }
|
||||||
|
|
||||||
|
// If this frame is optimized and was dynamically aligned return its old
|
||||||
|
// unaligned frame pointer. When the frame is deoptimized its FP will shift
|
||||||
|
// up one word and become unaligned.
|
||||||
|
Address UnpaddedFP() const;
|
||||||
|
|
||||||
Address pc() const { return *pc_address(); }
|
Address pc() const { return *pc_address(); }
|
||||||
void set_pc(Address pc) { *pc_address() = pc; }
|
void set_pc(Address pc) { *pc_address() = pc; }
|
||||||
|
|
||||||
|
@ -681,7 +681,8 @@ HGraph::HGraph(CompilationInfo* info, Zone* zone)
|
|||||||
blocks_(8, zone),
|
blocks_(8, zone),
|
||||||
values_(16, zone),
|
values_(16, zone),
|
||||||
phi_list_(NULL),
|
phi_list_(NULL),
|
||||||
zone_(zone) {
|
zone_(zone),
|
||||||
|
is_recursive_(false) {
|
||||||
start_environment_ =
|
start_environment_ =
|
||||||
new(zone) HEnvironment(NULL, info->scope(), info->closure(), zone);
|
new(zone) HEnvironment(NULL, info->scope(), info->closure(), zone);
|
||||||
start_environment_->set_ast_id(AstNode::kFunctionEntryId);
|
start_environment_->set_ast_id(AstNode::kFunctionEntryId);
|
||||||
@ -6927,6 +6928,11 @@ void HGraphBuilder::VisitCall(Call* expr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (TryInlineCall(expr)) return;
|
if (TryInlineCall(expr)) return;
|
||||||
|
|
||||||
|
if (expr->target().is_identical_to(info()->closure())) {
|
||||||
|
graph()->MarkRecursive();
|
||||||
|
}
|
||||||
|
|
||||||
call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(),
|
call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(),
|
||||||
argument_count));
|
argument_count));
|
||||||
} else {
|
} else {
|
||||||
|
@ -336,6 +336,14 @@ class HGraph: public ZoneObject {
|
|||||||
osr_values_.set(values);
|
osr_values_.set(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkRecursive() {
|
||||||
|
is_recursive_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_recursive() const {
|
||||||
|
return is_recursive_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Postorder(HBasicBlock* block,
|
void Postorder(HBasicBlock* block,
|
||||||
BitVector* visited,
|
BitVector* visited,
|
||||||
@ -382,6 +390,8 @@ class HGraph: public ZoneObject {
|
|||||||
|
|
||||||
Zone* zone_;
|
Zone* zone_;
|
||||||
|
|
||||||
|
bool is_recursive_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(HGraph);
|
DISALLOW_COPY_AND_ASSIGN(HGraph);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -351,10 +351,12 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
|
|||||||
PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
|
PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
|
||||||
reinterpret_cast<intptr_t>(function_));
|
reinterpret_cast<intptr_t>(function_));
|
||||||
function_->PrintName();
|
function_->PrintName();
|
||||||
PrintF(" => node=%u, frame=%d->%d]\n",
|
PrintF(" => node=%u, frame=%d->%d, ebp:esp=0x%08x:0x%08x]\n",
|
||||||
ast_id,
|
ast_id,
|
||||||
input_frame_size,
|
input_frame_size,
|
||||||
output_frame_size);
|
output_frame_size,
|
||||||
|
input_->GetRegister(ebp.code()),
|
||||||
|
input_->GetRegister(esp.code()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's only one output frame in the OSR case.
|
// There's only one output frame in the OSR case.
|
||||||
@ -404,7 +406,7 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
|
|||||||
name = "function";
|
name = "function";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PrintF(" [esp + %d] <- 0x%08x ; [esp + %d] (fixed part - %s)\n",
|
PrintF(" [sp + %d] <- 0x%08x ; [sp + %d] (fixed part - %s)\n",
|
||||||
output_offset,
|
output_offset,
|
||||||
input_value,
|
input_value,
|
||||||
input_offset,
|
input_offset,
|
||||||
@ -415,6 +417,24 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
|
|||||||
output_offset -= kPointerSize;
|
output_offset -= kPointerSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// All OSR stack frames are dynamically aligned to an 8-byte boundary.
|
||||||
|
int frame_pointer = input_->GetRegister(ebp.code());
|
||||||
|
if ((frame_pointer & kPointerSize) != 0) {
|
||||||
|
frame_pointer -= kPointerSize;
|
||||||
|
has_alignment_padding_ = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t alignment_state = (has_alignment_padding_ == 1) ?
|
||||||
|
kAlignmentPaddingPushed :
|
||||||
|
kNoAlignmentPadding;
|
||||||
|
if (FLAG_trace_osr) {
|
||||||
|
PrintF(" [sp + %d] <- 0x%08x ; (alignment state)\n",
|
||||||
|
output_offset,
|
||||||
|
alignment_state);
|
||||||
|
}
|
||||||
|
output_[0]->SetFrameSlot(output_offset, alignment_state);
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
|
||||||
// Translate the rest of the frame.
|
// Translate the rest of the frame.
|
||||||
while (ok && input_offset >= 0) {
|
while (ok && input_offset >= 0) {
|
||||||
ok = DoOsrTranslateCommand(&iterator, &input_offset);
|
ok = DoOsrTranslateCommand(&iterator, &input_offset);
|
||||||
@ -427,7 +447,7 @@ void Deoptimizer::DoComputeOsrOutputFrame() {
|
|||||||
output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
|
output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
|
||||||
} else {
|
} else {
|
||||||
// Set up the frame pointer and the context pointer.
|
// Set up the frame pointer and the context pointer.
|
||||||
output_[0]->SetRegister(ebp.code(), input_->GetRegister(ebp.code()));
|
output_[0]->SetRegister(ebp.code(), frame_pointer);
|
||||||
output_[0]->SetRegister(esi.code(), input_->GetRegister(esi.code()));
|
output_[0]->SetRegister(esi.code(), input_->GetRegister(esi.code()));
|
||||||
|
|
||||||
unsigned pc_offset = data->OsrPcOffset()->value();
|
unsigned pc_offset = data->OsrPcOffset()->value();
|
||||||
@ -688,24 +708,38 @@ void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
|||||||
ASSERT(output_[frame_index] == NULL);
|
ASSERT(output_[frame_index] == NULL);
|
||||||
output_[frame_index] = output_frame;
|
output_[frame_index] = output_frame;
|
||||||
|
|
||||||
|
// Compute the incoming parameter translation.
|
||||||
|
int parameter_count = function->shared()->formal_parameter_count() + 1;
|
||||||
|
unsigned output_offset = output_frame_size;
|
||||||
|
unsigned input_offset = input_frame_size;
|
||||||
|
|
||||||
|
unsigned alignment_state_offset =
|
||||||
|
input_offset - parameter_count * kPointerSize -
|
||||||
|
StandardFrameConstants::kFixedFrameSize -
|
||||||
|
kPointerSize;
|
||||||
|
ASSERT(JavaScriptFrameConstants::kDynamicAlignmentStateOffset ==
|
||||||
|
JavaScriptFrameConstants::kLocal0Offset);
|
||||||
|
|
||||||
// The top address for the bottommost output frame can be computed from
|
// The top address for the bottommost output frame can be computed from
|
||||||
// the input frame pointer and the output frame's height. For all
|
// the input frame pointer and the output frame's height. For all
|
||||||
// subsequent output frames, it can be computed from the previous one's
|
// subsequent output frames, it can be computed from the previous one's
|
||||||
// top address and the current frame's size.
|
// top address and the current frame's size.
|
||||||
uint32_t top_address;
|
uint32_t top_address;
|
||||||
if (is_bottommost) {
|
if (is_bottommost) {
|
||||||
|
int32_t alignment_state = input_->GetFrameSlot(alignment_state_offset);
|
||||||
|
has_alignment_padding_ =
|
||||||
|
(alignment_state == kAlignmentPaddingPushed) ? 1 : 0;
|
||||||
// 2 = context and function in the frame.
|
// 2 = context and function in the frame.
|
||||||
top_address =
|
// If the optimized frame had alignment padding, adjust the frame pointer
|
||||||
input_->GetRegister(ebp.code()) - (2 * kPointerSize) - height_in_bytes;
|
// to point to the new position of the old frame pointer after padding
|
||||||
|
// is removed. Subtract 2 * kPointerSize for the context and function slots.
|
||||||
|
top_address = input_->GetRegister(ebp.code()) - (2 * kPointerSize) -
|
||||||
|
height_in_bytes + has_alignment_padding_ * kPointerSize;
|
||||||
} else {
|
} else {
|
||||||
top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
|
top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
|
||||||
}
|
}
|
||||||
output_frame->SetTop(top_address);
|
output_frame->SetTop(top_address);
|
||||||
|
|
||||||
// Compute the incoming parameter translation.
|
|
||||||
int parameter_count = function->shared()->formal_parameter_count() + 1;
|
|
||||||
unsigned output_offset = output_frame_size;
|
|
||||||
unsigned input_offset = input_frame_size;
|
|
||||||
for (int i = 0; i < parameter_count; ++i) {
|
for (int i = 0; i < parameter_count; ++i) {
|
||||||
output_offset -= kPointerSize;
|
output_offset -= kPointerSize;
|
||||||
DoTranslateCommand(iterator, frame_index, output_offset);
|
DoTranslateCommand(iterator, frame_index, output_offset);
|
||||||
@ -747,13 +781,17 @@ void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
|||||||
}
|
}
|
||||||
output_frame->SetFrameSlot(output_offset, value);
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
intptr_t fp_value = top_address + output_offset;
|
intptr_t fp_value = top_address + output_offset;
|
||||||
ASSERT(!is_bottommost || input_->GetRegister(ebp.code()) == fp_value);
|
ASSERT(!is_bottommost ||
|
||||||
|
(input_->GetRegister(ebp.code()) + has_alignment_padding_ * kPointerSize) ==
|
||||||
|
fp_value);
|
||||||
output_frame->SetFp(fp_value);
|
output_frame->SetFp(fp_value);
|
||||||
if (is_topmost) output_frame->SetRegister(ebp.code(), fp_value);
|
if (is_topmost) output_frame->SetRegister(ebp.code(), fp_value);
|
||||||
if (FLAG_trace_deopt) {
|
if (FLAG_trace_deopt) {
|
||||||
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
|
||||||
fp_value, output_offset, value);
|
fp_value, output_offset, value);
|
||||||
}
|
}
|
||||||
|
ASSERT(!is_bottommost || !has_alignment_padding_ ||
|
||||||
|
(fp_value & kPointerSize) != 0);
|
||||||
|
|
||||||
// For the bottommost output frame the context can be gotten from the input
|
// For the bottommost output frame the context can be gotten from the input
|
||||||
// frame. For all subsequent output frames it can be gotten from the function
|
// frame. For all subsequent output frames it can be gotten from the function
|
||||||
@ -948,6 +986,28 @@ void Deoptimizer::EntryGenerator::Generate() {
|
|||||||
}
|
}
|
||||||
__ pop(eax);
|
__ pop(eax);
|
||||||
|
|
||||||
|
if (type() != OSR) {
|
||||||
|
// If frame was dynamically aligned, pop padding.
|
||||||
|
Label no_padding;
|
||||||
|
__ cmp(Operand(eax, Deoptimizer::has_alignment_padding_offset()),
|
||||||
|
Immediate(0));
|
||||||
|
__ j(equal, &no_padding);
|
||||||
|
__ pop(ecx);
|
||||||
|
if (FLAG_debug_code) {
|
||||||
|
__ cmp(ecx, Immediate(kAlignmentZapValue));
|
||||||
|
__ Assert(equal, "alignment marker expected");
|
||||||
|
}
|
||||||
|
__ bind(&no_padding);
|
||||||
|
} else {
|
||||||
|
// If frame needs dynamic alignment push padding.
|
||||||
|
Label no_padding;
|
||||||
|
__ cmp(Operand(eax, Deoptimizer::has_alignment_padding_offset()),
|
||||||
|
Immediate(0));
|
||||||
|
__ j(equal, &no_padding);
|
||||||
|
__ push(Immediate(kAlignmentZapValue));
|
||||||
|
__ bind(&no_padding);
|
||||||
|
}
|
||||||
|
|
||||||
// Replace the current frame with the output frames.
|
// Replace the current frame with the output frames.
|
||||||
Label outer_push_loop, inner_push_loop;
|
Label outer_push_loop, inner_push_loop;
|
||||||
// Outer loop state: eax = current FrameDescription**, edx = one past the
|
// Outer loop state: eax = current FrameDescription**, edx = one past the
|
||||||
|
@ -53,6 +53,10 @@ typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
|
|||||||
// Number of registers for which space is reserved in safepoints.
|
// Number of registers for which space is reserved in safepoints.
|
||||||
const int kNumSafepointRegisters = 8;
|
const int kNumSafepointRegisters = 8;
|
||||||
|
|
||||||
|
const int kNoAlignmentPadding = 0;
|
||||||
|
const int kAlignmentPaddingPushed = 2;
|
||||||
|
const int kAlignmentZapValue = 0x12345678; // Not heap object tagged.
|
||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@ -119,6 +123,8 @@ class JavaScriptFrameConstants : public AllStatic {
|
|||||||
// Caller SP-relative.
|
// Caller SP-relative.
|
||||||
static const int kParam0Offset = -2 * kPointerSize;
|
static const int kParam0Offset = -2 * kPointerSize;
|
||||||
static const int kReceiverOffset = -1 * kPointerSize;
|
static const int kReceiverOffset = -1 * kPointerSize;
|
||||||
|
|
||||||
|
static const int kDynamicAlignmentStateOffset = kLocal0Offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,6 +79,10 @@ bool LCodeGen::GenerateCode() {
|
|||||||
// the frame (that is done in GeneratePrologue).
|
// the frame (that is done in GeneratePrologue).
|
||||||
FrameScope frame_scope(masm_, StackFrame::MANUAL);
|
FrameScope frame_scope(masm_, StackFrame::MANUAL);
|
||||||
|
|
||||||
|
dynamic_frame_alignment_ = (chunk()->num_double_slots() > 2 &&
|
||||||
|
!chunk()->graph()->is_recursive()) ||
|
||||||
|
info()->osr_ast_id() != AstNode::kNoNumber;
|
||||||
|
|
||||||
return GeneratePrologue() &&
|
return GeneratePrologue() &&
|
||||||
GenerateBody() &&
|
GenerateBody() &&
|
||||||
GenerateDeferredCode() &&
|
GenerateDeferredCode() &&
|
||||||
@ -153,14 +157,52 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
__ bind(&ok);
|
__ bind(&ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (dynamic_frame_alignment_) {
|
||||||
|
// Move state of dynamic frame alignment into edx.
|
||||||
|
__ mov(edx, Immediate(kNoAlignmentPadding));
|
||||||
|
|
||||||
|
Label do_not_pad, align_loop;
|
||||||
|
STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
|
||||||
|
// Align esp + 4 to a multiple of 2 * kPointerSize.
|
||||||
|
__ test(esp, Immediate(kPointerSize));
|
||||||
|
__ j(not_zero, &do_not_pad, Label::kNear);
|
||||||
|
__ push(Immediate(0));
|
||||||
|
__ mov(ebx, esp);
|
||||||
|
__ mov(edx, Immediate(kAlignmentPaddingPushed));
|
||||||
|
// Copy arguments, receiver, and return address.
|
||||||
|
__ mov(ecx, Immediate(scope()->num_parameters() + 2));
|
||||||
|
|
||||||
|
__ bind(&align_loop);
|
||||||
|
__ mov(eax, Operand(ebx, 1 * kPointerSize));
|
||||||
|
__ mov(Operand(ebx, 0), eax);
|
||||||
|
__ add(Operand(ebx), Immediate(kPointerSize));
|
||||||
|
__ dec(ecx);
|
||||||
|
__ j(not_zero, &align_loop, Label::kNear);
|
||||||
|
__ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
|
||||||
|
__ bind(&do_not_pad);
|
||||||
|
}
|
||||||
|
|
||||||
__ push(ebp); // Caller's frame pointer.
|
__ push(ebp); // Caller's frame pointer.
|
||||||
__ mov(ebp, esp);
|
__ mov(ebp, esp);
|
||||||
__ push(esi); // Callee's context.
|
__ push(esi); // Callee's context.
|
||||||
__ push(edi); // Callee's JS function.
|
__ push(edi); // Callee's JS function.
|
||||||
|
|
||||||
|
if (dynamic_frame_alignment_ && FLAG_debug_code) {
|
||||||
|
__ test(esp, Immediate(kPointerSize));
|
||||||
|
__ Assert(zero, "frame is expected to be aligned");
|
||||||
|
}
|
||||||
|
|
||||||
// Reserve space for the stack slots needed by the code.
|
// Reserve space for the stack slots needed by the code.
|
||||||
int slots = GetStackSlotCount();
|
int slots = GetStackSlotCount();
|
||||||
if (slots > 0) {
|
ASSERT_GE(slots, 1);
|
||||||
|
if (slots == 1) {
|
||||||
|
if (dynamic_frame_alignment_) {
|
||||||
|
__ push(edx);
|
||||||
|
} else {
|
||||||
|
__ push(Immediate(kNoAlignmentPadding));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (FLAG_debug_code) {
|
if (FLAG_debug_code) {
|
||||||
__ mov(Operand(eax), Immediate(slots));
|
__ mov(Operand(eax), Immediate(slots));
|
||||||
Label loop;
|
Label loop;
|
||||||
@ -182,6 +224,17 @@ bool LCodeGen::GeneratePrologue() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store dynamic frame alignment state in the first local.
|
||||||
|
if (dynamic_frame_alignment_) {
|
||||||
|
__ mov(Operand(ebp,
|
||||||
|
JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
|
||||||
|
edx);
|
||||||
|
} else {
|
||||||
|
__ mov(Operand(ebp,
|
||||||
|
JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
|
||||||
|
Immediate(kNoAlignmentPadding));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Possibly allocate a local context.
|
// Possibly allocate a local context.
|
||||||
@ -2101,8 +2154,25 @@ void LCodeGen::DoReturn(LReturn* instr) {
|
|||||||
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
||||||
__ CallRuntime(Runtime::kTraceExit, 1);
|
__ CallRuntime(Runtime::kTraceExit, 1);
|
||||||
}
|
}
|
||||||
|
if (dynamic_frame_alignment_) {
|
||||||
|
// Fetch the state of the dynamic frame alignment.
|
||||||
|
__ mov(edx, Operand(ebp,
|
||||||
|
JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
|
||||||
|
}
|
||||||
__ mov(esp, ebp);
|
__ mov(esp, ebp);
|
||||||
__ pop(ebp);
|
__ pop(ebp);
|
||||||
|
if (dynamic_frame_alignment_) {
|
||||||
|
Label no_padding;
|
||||||
|
__ cmp(edx, Immediate(kNoAlignmentPadding));
|
||||||
|
__ j(equal, &no_padding);
|
||||||
|
if (FLAG_debug_code) {
|
||||||
|
__ cmp(Operand(esp, (GetParameterCount() + 2) * kPointerSize),
|
||||||
|
Immediate(kAlignmentZapValue));
|
||||||
|
__ Assert(equal, "expected alignment marker");
|
||||||
|
}
|
||||||
|
__ Ret((GetParameterCount() + 2) * kPointerSize, ecx);
|
||||||
|
__ bind(&no_padding);
|
||||||
|
}
|
||||||
__ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
|
__ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
status_(UNUSED),
|
status_(UNUSED),
|
||||||
translations_(zone),
|
translations_(zone),
|
||||||
deferred_(8, zone),
|
deferred_(8, zone),
|
||||||
|
dynamic_frame_alignment_(false),
|
||||||
osr_pc_offset_(-1),
|
osr_pc_offset_(-1),
|
||||||
last_lazy_deopt_pc_(0),
|
last_lazy_deopt_pc_(0),
|
||||||
safepoints_(zone),
|
safepoints_(zone),
|
||||||
@ -342,6 +343,7 @@ class LCodeGen BASE_EMBEDDED {
|
|||||||
Status status_;
|
Status status_;
|
||||||
TranslationBuffer translations_;
|
TranslationBuffer translations_;
|
||||||
ZoneList<LDeferredCode*> deferred_;
|
ZoneList<LDeferredCode*> deferred_;
|
||||||
|
bool dynamic_frame_alignment_;
|
||||||
int osr_pc_offset_;
|
int osr_pc_offset_;
|
||||||
int last_lazy_deopt_pc_;
|
int last_lazy_deopt_pc_;
|
||||||
|
|
||||||
|
@ -368,7 +368,11 @@ void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
|
|||||||
|
|
||||||
int LChunk::GetNextSpillIndex(bool is_double) {
|
int LChunk::GetNextSpillIndex(bool is_double) {
|
||||||
// Skip a slot if for a double-width slot.
|
// Skip a slot if for a double-width slot.
|
||||||
if (is_double) spill_slot_count_++;
|
if (is_double) {
|
||||||
|
spill_slot_count_++;
|
||||||
|
spill_slot_count_ |= 1;
|
||||||
|
num_double_slots_++;
|
||||||
|
}
|
||||||
return spill_slot_count_++;
|
return spill_slot_count_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,6 +554,12 @@ LChunk* LChunkBuilder::Build() {
|
|||||||
chunk_ = new(zone()) LChunk(info(), graph());
|
chunk_ = new(zone()) LChunk(info(), graph());
|
||||||
HPhase phase("L_Building chunk", chunk_);
|
HPhase phase("L_Building chunk", chunk_);
|
||||||
status_ = BUILDING;
|
status_ = BUILDING;
|
||||||
|
|
||||||
|
// Reserve the first spill slot for the state of dynamic alignment.
|
||||||
|
int alignment_state_index = chunk_->GetNextSpillIndex(false);
|
||||||
|
ASSERT_EQ(alignment_state_index, 0);
|
||||||
|
USE(alignment_state_index);
|
||||||
|
|
||||||
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
|
const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
|
||||||
for (int i = 0; i < blocks->length(); i++) {
|
for (int i = 0; i < blocks->length(); i++) {
|
||||||
HBasicBlock* next = NULL;
|
HBasicBlock* next = NULL;
|
||||||
|
@ -2307,6 +2307,7 @@ class LChunk: public ZoneObject {
|
|||||||
public:
|
public:
|
||||||
LChunk(CompilationInfo* info, HGraph* graph)
|
LChunk(CompilationInfo* info, HGraph* graph)
|
||||||
: spill_slot_count_(0),
|
: spill_slot_count_(0),
|
||||||
|
num_double_slots_(0),
|
||||||
info_(info),
|
info_(info),
|
||||||
graph_(graph),
|
graph_(graph),
|
||||||
instructions_(32, graph->zone()),
|
instructions_(32, graph->zone()),
|
||||||
@ -2324,6 +2325,7 @@ class LChunk: public ZoneObject {
|
|||||||
int ParameterAt(int index);
|
int ParameterAt(int index);
|
||||||
int GetParameterStackSlot(int index) const;
|
int GetParameterStackSlot(int index) const;
|
||||||
int spill_slot_count() const { return spill_slot_count_; }
|
int spill_slot_count() const { return spill_slot_count_; }
|
||||||
|
int num_double_slots() const { return num_double_slots_; }
|
||||||
CompilationInfo* info() const { return info_; }
|
CompilationInfo* info() const { return info_; }
|
||||||
HGraph* graph() const { return graph_; }
|
HGraph* graph() const { return graph_; }
|
||||||
const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
|
const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
|
||||||
@ -2363,6 +2365,7 @@ class LChunk: public ZoneObject {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
int spill_slot_count_;
|
int spill_slot_count_;
|
||||||
|
int num_double_slots_;
|
||||||
CompilationInfo* info_;
|
CompilationInfo* info_;
|
||||||
HGraph* const graph_;
|
HGraph* const graph_;
|
||||||
ZoneList<LInstruction*> instructions_;
|
ZoneList<LInstruction*> instructions_;
|
||||||
|
Loading…
Reference in New Issue
Block a user