Index: src/deoptimizer.cc |
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc |
index 3e699922de9f1ed0b4d802b7b9bebe3777b3ae88..f1c21663ca3d07cc34fdfd182a8dca7b553682cf 100644 |
--- a/src/deoptimizer.cc |
+++ b/src/deoptimizer.cc |
@@ -968,7 +968,6 @@ void Deoptimizer::DoComputeJSFrame(TranslatedFrame* translated_frame, |
// 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 |
// so long as we don't inline functions that need local contexts. |
- Register context_reg = JavaScriptFrame::context_register(); |
output_offset -= kPointerSize; |
TranslatedFrame::iterator context_pos = value_iterator; |
@@ -993,7 +992,10 @@ void Deoptimizer::DoComputeJSFrame(TranslatedFrame* translated_frame, |
} |
value = reinterpret_cast<intptr_t>(context); |
output_frame->SetContext(value); |
- if (is_topmost) output_frame->SetRegister(context_reg.code(), value); |
+ if (is_topmost) { |
+ Register context_reg = JavaScriptFrame::context_register(); |
+ output_frame->SetRegister(context_reg.code(), value); |
+ } |
WriteValueToOutput(context, context_input_index, frame_index, output_offset, |
"context "); |
if (context == isolate_->heap()->arguments_marker()) { |
@@ -1493,12 +1495,27 @@ void Deoptimizer::DoComputeTailCallerFrame(TranslatedFrame* translated_frame, |
void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame, |
int frame_index) { |
TranslatedFrame::iterator value_iterator = translated_frame->begin(); |
+ bool is_topmost = (output_count_ - 1 == frame_index); |
+ // The construct frame could become topmost only if we inlined a constructor |
+ // call which does a tail call (otherwise the tail callee's frame would be |
+ // the topmost one). So it could only be the LAZY case. |
+ CHECK(!is_topmost || bailout_type_ == LAZY); |
int input_index = 0; |
Builtins* builtins = isolate_->builtins(); |
Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); |
unsigned height = translated_frame->height(); |
unsigned height_in_bytes = height * kPointerSize; |
+ |
+ // If the construct frame appears to be topmost we should ensure that the |
+ // value of result register is preserved during continuation execution. |
+ // We do this here by "pushing" the result of the constructor function to the |
+ // top of the reconstructed stack and then using the |
+ // FullCodeGenerator::TOS_REG machinery. |
+ if (is_topmost) { |
+ height_in_bytes += kPointerSize; |
+ } |
+ |
// Skip function. |
value_iterator++; |
input_index++; |
@@ -1515,8 +1532,8 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame, |
new (output_frame_size) FrameDescription(output_frame_size); |
output_frame->SetFrameType(StackFrame::CONSTRUCT); |
- // Construct stub can not be topmost or bottommost. |
- DCHECK(frame_index > 0 && frame_index < output_count_ - 1); |
+ // Construct stub can not be topmost. |
+ DCHECK(frame_index > 0 && frame_index < output_count_); |
DCHECK(output_[frame_index] == NULL); |
output_[frame_index] = output_frame; |
@@ -1551,6 +1568,10 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame, |
output_frame->SetCallerFp(output_offset, value); |
intptr_t fp_value = top_address + output_offset; |
output_frame->SetFp(fp_value); |
+ if (is_topmost) { |
+ Register fp_reg = JavaScriptFrame::fp_register(); |
+ output_frame->SetRegister(fp_reg.code(), fp_value); |
+ } |
DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n"); |
if (FLAG_enable_embedded_constant_pool) { |
@@ -1573,6 +1594,10 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame, |
output_offset -= kPointerSize; |
value = output_[frame_index - 1]->GetContext(); |
output_frame->SetFrameSlot(output_offset, value); |
+ if (is_topmost) { |
+ Register context_reg = JavaScriptFrame::context_register(); |
+ output_frame->SetRegister(context_reg.code(), value); |
+ } |
DebugPrintOutputSlot(value, frame_index, output_offset, "context\n"); |
// The allocation site. |
@@ -1598,6 +1623,18 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame, |
DebugPrintOutputSlot(value, frame_index, output_offset, |
"allocated receiver\n"); |
+ if (is_topmost) { |
+ // Ensure the result is restored back when we return to the stub. |
+ output_offset -= kPointerSize; |
+ Register result_reg = FullCodeGenerator::result_register(); |
+ value = input_->GetRegister(result_reg.code()); |
+ output_frame->SetFrameSlot(output_offset, value); |
+ DebugPrintOutputSlot(value, frame_index, output_offset, |
+ "constructor result\n"); |
+ |
+ output_frame->SetState(Smi::FromInt(FullCodeGenerator::TOS_REG)); |
+ } |
+ |
CHECK_EQ(0u, output_offset); |
intptr_t pc = reinterpret_cast<intptr_t>( |
@@ -1608,6 +1645,20 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame, |
intptr_t constant_pool_value = |
reinterpret_cast<intptr_t>(construct_stub->constant_pool()); |
output_frame->SetConstantPool(constant_pool_value); |
+ if (is_topmost) { |
+ Register constant_pool_reg = |
+ JavaScriptFrame::constant_pool_pointer_register(); |
+ output_frame->SetRegister(constant_pool_reg.code(), fp_value); |
+ } |
+ } |
+ |
+ // Set the continuation for the topmost frame. |
+ if (is_topmost) { |
+ Builtins* builtins = isolate_->builtins(); |
+ DCHECK_EQ(LAZY, bailout_type_); |
+ Code* continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); |
+ output_frame->SetContinuation( |
+ reinterpret_cast<intptr_t>(continuation->entry())); |
} |
} |
@@ -1615,6 +1666,11 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame, |
int frame_index, |
bool is_setter_stub_frame) { |
TranslatedFrame::iterator value_iterator = translated_frame->begin(); |
+ bool is_topmost = (output_count_ - 1 == frame_index); |
+ // The accessor frame could become topmost only if we inlined an accessor |
+ // call which does a tail call (otherwise the tail callee's frame would be |
+ // the topmost one). So it could only be the LAZY case. |
+ CHECK(!is_topmost || bailout_type_ == LAZY); |
int input_index = 0; |
// Skip accessor. |
@@ -1625,6 +1681,19 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame, |
// frame. This means that we have to use a height of 0. |
unsigned height = 0; |
unsigned height_in_bytes = height * kPointerSize; |
+ |
+ // If the accessor frame appears to be topmost we should ensure that the |
+ // value of result register is preserved during continuation execution. |
+ // We do this here by "pushing" the result of the accessor function to the |
+ // top of the reconstructed stack and then using the |
+ // FullCodeGenerator::TOS_REG machinery. |
+ // We don't need to restore the result in case of a setter call because we |
+ // have to return the stored value but not the result of the setter function. |
+ bool should_preserve_result = is_topmost && !is_setter_stub_frame; |
+ if (should_preserve_result) { |
+ height_in_bytes += kPointerSize; |
+ } |
+ |
const char* kind = is_setter_stub_frame ? "setter" : "getter"; |
if (trace_scope_ != NULL) { |
PrintF(trace_scope_->file(), |
@@ -1647,8 +1716,8 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame, |
new (output_frame_size) FrameDescription(output_frame_size); |
output_frame->SetFrameType(StackFrame::INTERNAL); |
- // A frame for an accessor stub can not be the topmost or bottommost one. |
- CHECK(frame_index > 0 && frame_index < output_count_ - 1); |
+ // A frame for an accessor stub can not be bottommost. |
+ CHECK(frame_index > 0 && frame_index < output_count_); |
CHECK_NULL(output_[frame_index]); |
output_[frame_index] = output_frame; |
@@ -1671,6 +1740,10 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame, |
output_frame->SetCallerFp(output_offset, value); |
intptr_t fp_value = top_address + output_offset; |
output_frame->SetFp(fp_value); |
+ if (is_topmost) { |
+ Register fp_reg = JavaScriptFrame::fp_register(); |
+ output_frame->SetRegister(fp_reg.code(), fp_value); |
+ } |
DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n"); |
if (FLAG_enable_embedded_constant_pool) { |
@@ -1705,6 +1778,10 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame, |
output_offset -= kPointerSize; |
value = output_[frame_index - 1]->GetContext(); |
output_frame->SetFrameSlot(output_offset, value); |
+ if (is_topmost) { |
+ Register context_reg = JavaScriptFrame::context_register(); |
+ output_frame->SetRegister(context_reg.code(), value); |
+ } |
DebugPrintOutputSlot(value, frame_index, output_offset, "context\n"); |
// Skip receiver. |
@@ -1719,6 +1796,20 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame, |
output_offset); |
} |
+ if (should_preserve_result) { |
+ // Ensure the result is restored back when we return to the stub. |
+ output_offset -= kPointerSize; |
+ Register result_reg = FullCodeGenerator::result_register(); |
+ value = input_->GetRegister(result_reg.code()); |
+ output_frame->SetFrameSlot(output_offset, value); |
+ DebugPrintOutputSlot(value, frame_index, output_offset, |
+ "accessor result\n"); |
+ |
+ output_frame->SetState(Smi::FromInt(FullCodeGenerator::TOS_REG)); |
+ } else { |
+ output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS)); |
+ } |
+ |
CHECK_EQ(0u, output_offset); |
Smi* offset = is_setter_stub_frame ? |
@@ -1731,6 +1822,20 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame, |
intptr_t constant_pool_value = |
reinterpret_cast<intptr_t>(accessor_stub->constant_pool()); |
output_frame->SetConstantPool(constant_pool_value); |
+ if (is_topmost) { |
+ Register constant_pool_reg = |
+ JavaScriptFrame::constant_pool_pointer_register(); |
+ output_frame->SetRegister(constant_pool_reg.code(), fp_value); |
+ } |
+ } |
+ |
+ // Set the continuation for the topmost frame. |
+ if (is_topmost) { |
+ Builtins* builtins = isolate_->builtins(); |
+ DCHECK_EQ(LAZY, bailout_type_); |
+ Code* continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); |
+ output_frame->SetContinuation( |
+ reinterpret_cast<intptr_t>(continuation->entry())); |
} |
} |