| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/deoptimizer.h" | 5 #include "src/deoptimizer.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
| 8 #include "src/ast/prettyprinter.h" | 8 #include "src/ast/prettyprinter.h" |
| 9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 10 #include "src/disasm.h" | 10 #include "src/disasm.h" |
| (...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 834 if (trace_scope_ != NULL) { | 834 if (trace_scope_ != NULL) { |
| 835 double ms = timer.Elapsed().InMillisecondsF(); | 835 double ms = timer.Elapsed().InMillisecondsF(); |
| 836 int index = output_count_ - 1; // Index of the topmost frame. | 836 int index = output_count_ - 1; // Index of the topmost frame. |
| 837 PrintF(trace_scope_->file(), "[deoptimizing (%s): end ", | 837 PrintF(trace_scope_->file(), "[deoptimizing (%s): end ", |
| 838 MessageFor(bailout_type_)); | 838 MessageFor(bailout_type_)); |
| 839 PrintFunctionName(); | 839 PrintFunctionName(); |
| 840 PrintF(trace_scope_->file(), | 840 PrintF(trace_scope_->file(), |
| 841 " @%d => node=%d, pc=0x%08" V8PRIxPTR ", caller sp=0x%08" V8PRIxPTR | 841 " @%d => node=%d, pc=0x%08" V8PRIxPTR ", caller sp=0x%08" V8PRIxPTR |
| 842 ", state=%s, took %0.3f ms]\n", | 842 ", state=%s, took %0.3f ms]\n", |
| 843 bailout_id_, node_id.ToInt(), output_[index]->GetPc(), | 843 bailout_id_, node_id.ToInt(), output_[index]->GetPc(), |
| 844 caller_frame_top_, FullCodeGenerator::State2String( | 844 caller_frame_top_, BailoutStateToString(static_cast<BailoutState>( |
| 845 static_cast<FullCodeGenerator::State>( | 845 output_[index]->GetState()->value())), |
| 846 output_[index]->GetState()->value())), | |
| 847 ms); | 846 ms); |
| 848 } | 847 } |
| 849 } | 848 } |
| 850 | 849 |
| 851 void Deoptimizer::DoComputeJSFrame(TranslatedFrame* translated_frame, | 850 void Deoptimizer::DoComputeJSFrame(TranslatedFrame* translated_frame, |
| 852 int frame_index, bool goto_catch_handler) { | 851 int frame_index, bool goto_catch_handler) { |
| 853 SharedFunctionInfo* shared = translated_frame->raw_shared_info(); | 852 SharedFunctionInfo* shared = translated_frame->raw_shared_info(); |
| 854 | 853 |
| 855 TranslatedFrame::iterator value_iterator = translated_frame->begin(); | 854 TranslatedFrame::iterator value_iterator = translated_frame->begin(); |
| 856 bool is_bottommost = (0 == frame_index); | 855 bool is_bottommost = (0 == frame_index); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1048 Address start = non_optimized_code->instruction_start(); | 1047 Address start = non_optimized_code->instruction_start(); |
| 1049 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); | 1048 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); |
| 1050 unsigned pc_offset = goto_catch_handler | 1049 unsigned pc_offset = goto_catch_handler |
| 1051 ? catch_handler_pc_offset_ | 1050 ? catch_handler_pc_offset_ |
| 1052 : FullCodeGenerator::PcField::decode(pc_and_state); | 1051 : FullCodeGenerator::PcField::decode(pc_and_state); |
| 1053 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset); | 1052 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset); |
| 1054 output_frame->SetPc(pc_value); | 1053 output_frame->SetPc(pc_value); |
| 1055 | 1054 |
| 1056 // If we are going to the catch handler, then the exception lives in | 1055 // If we are going to the catch handler, then the exception lives in |
| 1057 // the accumulator. | 1056 // the accumulator. |
| 1058 FullCodeGenerator::State state = | 1057 BailoutState state = |
| 1059 goto_catch_handler ? FullCodeGenerator::TOS_REG | 1058 goto_catch_handler |
| 1060 : FullCodeGenerator::StateField::decode(pc_and_state); | 1059 ? BailoutState::TOS_REGISTER |
| 1061 output_frame->SetState(Smi::FromInt(state)); | 1060 : FullCodeGenerator::BailoutStateField::decode(pc_and_state); |
| 1061 output_frame->SetState(Smi::FromInt(static_cast<int>(state))); |
| 1062 | 1062 |
| 1063 // Set the continuation for the topmost frame. | 1063 // Set the continuation for the topmost frame. |
| 1064 if (is_topmost) { | 1064 if (is_topmost) { |
| 1065 Builtins* builtins = isolate_->builtins(); | 1065 Builtins* builtins = isolate_->builtins(); |
| 1066 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized); | 1066 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized); |
| 1067 if (bailout_type_ == LAZY) { | 1067 if (bailout_type_ == LAZY) { |
| 1068 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); | 1068 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); |
| 1069 } else if (bailout_type_ == SOFT) { | 1069 } else if (bailout_type_ == SOFT) { |
| 1070 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized); | 1070 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized); |
| 1071 } else { | 1071 } else { |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1267 } else { | 1267 } else { |
| 1268 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, | 1268 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, |
| 1269 output_offset); | 1269 output_offset); |
| 1270 } | 1270 } |
| 1271 CHECK_EQ(0u, output_offset); | 1271 CHECK_EQ(0u, output_offset); |
| 1272 | 1272 |
| 1273 Builtins* builtins = isolate_->builtins(); | 1273 Builtins* builtins = isolate_->builtins(); |
| 1274 Code* dispatch_builtin = | 1274 Code* dispatch_builtin = |
| 1275 builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch); | 1275 builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch); |
| 1276 output_frame->SetPc(reinterpret_cast<intptr_t>(dispatch_builtin->entry())); | 1276 output_frame->SetPc(reinterpret_cast<intptr_t>(dispatch_builtin->entry())); |
| 1277 output_frame->SetState(0); | 1277 // Restore accumulator (TOS) register. |
| 1278 output_frame->SetState( |
| 1279 Smi::FromInt(static_cast<int>(BailoutState::TOS_REGISTER))); |
| 1278 | 1280 |
| 1279 // Update constant pool. | 1281 // Update constant pool. |
| 1280 if (FLAG_enable_embedded_constant_pool) { | 1282 if (FLAG_enable_embedded_constant_pool) { |
| 1281 intptr_t constant_pool_value = | 1283 intptr_t constant_pool_value = |
| 1282 reinterpret_cast<intptr_t>(dispatch_builtin->constant_pool()); | 1284 reinterpret_cast<intptr_t>(dispatch_builtin->constant_pool()); |
| 1283 output_frame->SetConstantPool(constant_pool_value); | 1285 output_frame->SetConstantPool(constant_pool_value); |
| 1284 if (is_topmost) { | 1286 if (is_topmost) { |
| 1285 Register constant_pool_reg = | 1287 Register constant_pool_reg = |
| 1286 InterpretedFrame::constant_pool_pointer_register(); | 1288 InterpretedFrame::constant_pool_pointer_register(); |
| 1287 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); | 1289 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); |
| 1288 } | 1290 } |
| 1289 } | 1291 } |
| 1290 | 1292 |
| 1291 // Set the continuation for the topmost frame. | 1293 // Set the continuation for the topmost frame. |
| 1292 if (is_topmost) { | 1294 if (is_topmost) { |
| 1293 Code* continuation = | 1295 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized); |
| 1294 builtins->builtin(Builtins::kInterpreterNotifyDeoptimized); | |
| 1295 if (bailout_type_ == LAZY) { | 1296 if (bailout_type_ == LAZY) { |
| 1296 continuation = | 1297 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); |
| 1297 builtins->builtin(Builtins::kInterpreterNotifyLazyDeoptimized); | |
| 1298 } else if (bailout_type_ == SOFT) { | 1298 } else if (bailout_type_ == SOFT) { |
| 1299 continuation = | 1299 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized); |
| 1300 builtins->builtin(Builtins::kInterpreterNotifySoftDeoptimized); | |
| 1301 } else { | 1300 } else { |
| 1302 CHECK_EQ(bailout_type_, EAGER); | 1301 CHECK_EQ(bailout_type_, EAGER); |
| 1303 } | 1302 } |
| 1304 output_frame->SetContinuation( | 1303 output_frame->SetContinuation( |
| 1305 reinterpret_cast<intptr_t>(continuation->entry())); | 1304 reinterpret_cast<intptr_t>(continuation->entry())); |
| 1306 } | 1305 } |
| 1307 } | 1306 } |
| 1308 | 1307 |
| 1309 void Deoptimizer::DoComputeArgumentsAdaptorFrame( | 1308 void Deoptimizer::DoComputeArgumentsAdaptorFrame( |
| 1310 TranslatedFrame* translated_frame, int frame_index) { | 1309 TranslatedFrame* translated_frame, int frame_index) { |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1504 | 1503 |
| 1505 Builtins* builtins = isolate_->builtins(); | 1504 Builtins* builtins = isolate_->builtins(); |
| 1506 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); | 1505 Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric); |
| 1507 unsigned height = translated_frame->height(); | 1506 unsigned height = translated_frame->height(); |
| 1508 unsigned height_in_bytes = height * kPointerSize; | 1507 unsigned height_in_bytes = height * kPointerSize; |
| 1509 | 1508 |
| 1510 // If the construct frame appears to be topmost we should ensure that the | 1509 // If the construct frame appears to be topmost we should ensure that the |
| 1511 // value of result register is preserved during continuation execution. | 1510 // value of result register is preserved during continuation execution. |
| 1512 // We do this here by "pushing" the result of the constructor function to the | 1511 // We do this here by "pushing" the result of the constructor function to the |
| 1513 // top of the reconstructed stack and then using the | 1512 // top of the reconstructed stack and then using the |
| 1514 // FullCodeGenerator::TOS_REG machinery. | 1513 // BailoutState::TOS_REGISTER machinery. |
| 1515 if (is_topmost) { | 1514 if (is_topmost) { |
| 1516 height_in_bytes += kPointerSize; | 1515 height_in_bytes += kPointerSize; |
| 1517 } | 1516 } |
| 1518 | 1517 |
| 1519 // Skip function. | 1518 // Skip function. |
| 1520 value_iterator++; | 1519 value_iterator++; |
| 1521 input_index++; | 1520 input_index++; |
| 1522 if (trace_scope_ != NULL) { | 1521 if (trace_scope_ != NULL) { |
| 1523 PrintF(trace_scope_->file(), | 1522 PrintF(trace_scope_->file(), |
| 1524 " translating construct stub => height=%d\n", height_in_bytes); | 1523 " translating construct stub => height=%d\n", height_in_bytes); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1625 | 1624 |
| 1626 if (is_topmost) { | 1625 if (is_topmost) { |
| 1627 // Ensure the result is restored back when we return to the stub. | 1626 // Ensure the result is restored back when we return to the stub. |
| 1628 output_offset -= kPointerSize; | 1627 output_offset -= kPointerSize; |
| 1629 Register result_reg = FullCodeGenerator::result_register(); | 1628 Register result_reg = FullCodeGenerator::result_register(); |
| 1630 value = input_->GetRegister(result_reg.code()); | 1629 value = input_->GetRegister(result_reg.code()); |
| 1631 output_frame->SetFrameSlot(output_offset, value); | 1630 output_frame->SetFrameSlot(output_offset, value); |
| 1632 DebugPrintOutputSlot(value, frame_index, output_offset, | 1631 DebugPrintOutputSlot(value, frame_index, output_offset, |
| 1633 "constructor result\n"); | 1632 "constructor result\n"); |
| 1634 | 1633 |
| 1635 output_frame->SetState(Smi::FromInt(FullCodeGenerator::TOS_REG)); | 1634 output_frame->SetState( |
| 1635 Smi::FromInt(static_cast<int>(BailoutState::TOS_REGISTER))); |
| 1636 } | 1636 } |
| 1637 | 1637 |
| 1638 CHECK_EQ(0u, output_offset); | 1638 CHECK_EQ(0u, output_offset); |
| 1639 | 1639 |
| 1640 intptr_t pc = reinterpret_cast<intptr_t>( | 1640 intptr_t pc = reinterpret_cast<intptr_t>( |
| 1641 construct_stub->instruction_start() + | 1641 construct_stub->instruction_start() + |
| 1642 isolate_->heap()->construct_stub_deopt_pc_offset()->value()); | 1642 isolate_->heap()->construct_stub_deopt_pc_offset()->value()); |
| 1643 output_frame->SetPc(pc); | 1643 output_frame->SetPc(pc); |
| 1644 if (FLAG_enable_embedded_constant_pool) { | 1644 if (FLAG_enable_embedded_constant_pool) { |
| 1645 intptr_t constant_pool_value = | 1645 intptr_t constant_pool_value = |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1679 // The receiver (and the implicit return value, if any) are expected in | 1679 // The receiver (and the implicit return value, if any) are expected in |
| 1680 // registers by the LoadIC/StoreIC, so they don't belong to the output stack | 1680 // registers by the LoadIC/StoreIC, so they don't belong to the output stack |
| 1681 // frame. This means that we have to use a height of 0. | 1681 // frame. This means that we have to use a height of 0. |
| 1682 unsigned height = 0; | 1682 unsigned height = 0; |
| 1683 unsigned height_in_bytes = height * kPointerSize; | 1683 unsigned height_in_bytes = height * kPointerSize; |
| 1684 | 1684 |
| 1685 // If the accessor frame appears to be topmost we should ensure that the | 1685 // If the accessor frame appears to be topmost we should ensure that the |
| 1686 // value of result register is preserved during continuation execution. | 1686 // value of result register is preserved during continuation execution. |
| 1687 // We do this here by "pushing" the result of the accessor function to the | 1687 // We do this here by "pushing" the result of the accessor function to the |
| 1688 // top of the reconstructed stack and then using the | 1688 // top of the reconstructed stack and then using the |
| 1689 // FullCodeGenerator::TOS_REG machinery. | 1689 // BailoutState::TOS_REGISTER machinery. |
| 1690 // We don't need to restore the result in case of a setter call because we | 1690 // We don't need to restore the result in case of a setter call because we |
| 1691 // have to return the stored value but not the result of the setter function. | 1691 // have to return the stored value but not the result of the setter function. |
| 1692 bool should_preserve_result = is_topmost && !is_setter_stub_frame; | 1692 bool should_preserve_result = is_topmost && !is_setter_stub_frame; |
| 1693 if (should_preserve_result) { | 1693 if (should_preserve_result) { |
| 1694 height_in_bytes += kPointerSize; | 1694 height_in_bytes += kPointerSize; |
| 1695 } | 1695 } |
| 1696 | 1696 |
| 1697 const char* kind = is_setter_stub_frame ? "setter" : "getter"; | 1697 const char* kind = is_setter_stub_frame ? "setter" : "getter"; |
| 1698 if (trace_scope_ != NULL) { | 1698 if (trace_scope_ != NULL) { |
| 1699 PrintF(trace_scope_->file(), | 1699 PrintF(trace_scope_->file(), |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1798 | 1798 |
| 1799 if (should_preserve_result) { | 1799 if (should_preserve_result) { |
| 1800 // Ensure the result is restored back when we return to the stub. | 1800 // Ensure the result is restored back when we return to the stub. |
| 1801 output_offset -= kPointerSize; | 1801 output_offset -= kPointerSize; |
| 1802 Register result_reg = FullCodeGenerator::result_register(); | 1802 Register result_reg = FullCodeGenerator::result_register(); |
| 1803 value = input_->GetRegister(result_reg.code()); | 1803 value = input_->GetRegister(result_reg.code()); |
| 1804 output_frame->SetFrameSlot(output_offset, value); | 1804 output_frame->SetFrameSlot(output_offset, value); |
| 1805 DebugPrintOutputSlot(value, frame_index, output_offset, | 1805 DebugPrintOutputSlot(value, frame_index, output_offset, |
| 1806 "accessor result\n"); | 1806 "accessor result\n"); |
| 1807 | 1807 |
| 1808 output_frame->SetState(Smi::FromInt(FullCodeGenerator::TOS_REG)); | 1808 output_frame->SetState( |
| 1809 Smi::FromInt(static_cast<int>(BailoutState::TOS_REGISTER))); |
| 1809 } else { | 1810 } else { |
| 1810 output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS)); | 1811 output_frame->SetState( |
| 1812 Smi::FromInt(static_cast<int>(BailoutState::NO_REGISTERS))); |
| 1811 } | 1813 } |
| 1812 | 1814 |
| 1813 CHECK_EQ(0u, output_offset); | 1815 CHECK_EQ(0u, output_offset); |
| 1814 | 1816 |
| 1815 Smi* offset = is_setter_stub_frame ? | 1817 Smi* offset = is_setter_stub_frame ? |
| 1816 isolate_->heap()->setter_stub_deopt_pc_offset() : | 1818 isolate_->heap()->setter_stub_deopt_pc_offset() : |
| 1817 isolate_->heap()->getter_stub_deopt_pc_offset(); | 1819 isolate_->heap()->getter_stub_deopt_pc_offset(); |
| 1818 intptr_t pc = reinterpret_cast<intptr_t>( | 1820 intptr_t pc = reinterpret_cast<intptr_t>( |
| 1819 accessor_stub->instruction_start() + offset->value()); | 1821 accessor_stub->instruction_start() + offset->value()); |
| 1820 output_frame->SetPc(pc); | 1822 output_frame->SetPc(pc); |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2055 output_frame->SetPc(reinterpret_cast<intptr_t>( | 2057 output_frame->SetPc(reinterpret_cast<intptr_t>( |
| 2056 trampoline->instruction_start())); | 2058 trampoline->instruction_start())); |
| 2057 if (FLAG_enable_embedded_constant_pool) { | 2059 if (FLAG_enable_embedded_constant_pool) { |
| 2058 Register constant_pool_reg = | 2060 Register constant_pool_reg = |
| 2059 StubFailureTrampolineFrame::constant_pool_pointer_register(); | 2061 StubFailureTrampolineFrame::constant_pool_pointer_register(); |
| 2060 intptr_t constant_pool_value = | 2062 intptr_t constant_pool_value = |
| 2061 reinterpret_cast<intptr_t>(trampoline->constant_pool()); | 2063 reinterpret_cast<intptr_t>(trampoline->constant_pool()); |
| 2062 output_frame->SetConstantPool(constant_pool_value); | 2064 output_frame->SetConstantPool(constant_pool_value); |
| 2063 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); | 2065 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); |
| 2064 } | 2066 } |
| 2065 output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS)); | 2067 output_frame->SetState( |
| 2068 Smi::FromInt(static_cast<int>(BailoutState::NO_REGISTERS))); |
| 2066 Code* notify_failure = | 2069 Code* notify_failure = |
| 2067 isolate_->builtins()->builtin(Builtins::kNotifyStubFailureSaveDoubles); | 2070 isolate_->builtins()->builtin(Builtins::kNotifyStubFailureSaveDoubles); |
| 2068 output_frame->SetContinuation( | 2071 output_frame->SetContinuation( |
| 2069 reinterpret_cast<intptr_t>(notify_failure->entry())); | 2072 reinterpret_cast<intptr_t>(notify_failure->entry())); |
| 2070 } | 2073 } |
| 2071 | 2074 |
| 2072 | 2075 |
| 2073 void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) { | 2076 void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) { |
| 2074 // Walk to the last JavaScript output frame to find out if it has | 2077 // Walk to the last JavaScript output frame to find out if it has |
| 2075 // adapted arguments. | 2078 // adapted arguments. |
| (...skipping 1847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3923 CHECK(value_info->IsMaterializedObject()); | 3926 CHECK(value_info->IsMaterializedObject()); |
| 3924 | 3927 |
| 3925 value_info->value_ = | 3928 value_info->value_ = |
| 3926 Handle<Object>(previously_materialized_objects->get(i), isolate_); | 3929 Handle<Object>(previously_materialized_objects->get(i), isolate_); |
| 3927 } | 3930 } |
| 3928 } | 3931 } |
| 3929 } | 3932 } |
| 3930 | 3933 |
| 3931 } // namespace internal | 3934 } // namespace internal |
| 3932 } // namespace v8 | 3935 } // namespace v8 |
| OLD | NEW |