| 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 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 switch (type) { | 506 switch (type) { |
| 507 case EAGER: return "eager"; | 507 case EAGER: return "eager"; |
| 508 case SOFT: return "soft"; | 508 case SOFT: return "soft"; |
| 509 case LAZY: return "lazy"; | 509 case LAZY: return "lazy"; |
| 510 case DEBUGGER: return "debugger"; | 510 case DEBUGGER: return "debugger"; |
| 511 } | 511 } |
| 512 FATAL("Unsupported deopt type"); | 512 FATAL("Unsupported deopt type"); |
| 513 return NULL; | 513 return NULL; |
| 514 } | 514 } |
| 515 | 515 |
| 516 | |
| 517 Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function, | 516 Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function, |
| 518 BailoutType type, unsigned bailout_id, Address from, | 517 BailoutType type, unsigned bailout_id, Address from, |
| 519 int fp_to_sp_delta, Code* optimized_code) | 518 int fp_to_sp_delta, Code* optimized_code) |
| 520 : isolate_(isolate), | 519 : isolate_(isolate), |
| 521 function_(function), | 520 function_(function), |
| 522 bailout_id_(bailout_id), | 521 bailout_id_(bailout_id), |
| 523 bailout_type_(type), | 522 bailout_type_(type), |
| 524 from_(from), | 523 from_(from), |
| 525 fp_to_sp_delta_(fp_to_sp_delta), | 524 fp_to_sp_delta_(fp_to_sp_delta), |
| 526 has_alignment_padding_(0), | 525 has_alignment_padding_(0), |
| 526 deoptimizing_throw_(false), |
| 527 catch_handler_data_(-1), |
| 528 catch_handler_pc_offset_(-1), |
| 527 input_(nullptr), | 529 input_(nullptr), |
| 528 output_count_(0), | 530 output_count_(0), |
| 529 jsframe_count_(0), | 531 jsframe_count_(0), |
| 530 output_(nullptr), | 532 output_(nullptr), |
| 531 trace_scope_(nullptr) { | 533 trace_scope_(nullptr) { |
| 534 if (isolate->deoptimizer_lazy_throw()) { |
| 535 isolate->set_deoptimizer_lazy_throw(false); |
| 536 deoptimizing_throw_ = true; |
| 537 } |
| 538 |
| 532 // For COMPILED_STUBs called from builtins, the function pointer is a SMI | 539 // For COMPILED_STUBs called from builtins, the function pointer is a SMI |
| 533 // indicating an internal frame. | 540 // indicating an internal frame. |
| 534 if (function->IsSmi()) { | 541 if (function->IsSmi()) { |
| 535 function = nullptr; | 542 function = nullptr; |
| 536 } | 543 } |
| 537 DCHECK(from != nullptr); | 544 DCHECK(from != nullptr); |
| 538 if (function != nullptr && function->IsOptimized()) { | 545 if (function != nullptr && function->IsOptimized()) { |
| 539 function->shared()->increment_deopt_count(); | 546 function->shared()->increment_deopt_count(); |
| 540 if (bailout_type_ == Deoptimizer::SOFT) { | 547 if (bailout_type_ == Deoptimizer::SOFT) { |
| 541 isolate->counters()->soft_deopts_executed()->Increment(); | 548 isolate->counters()->soft_deopts_executed()->Increment(); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 695 Code* code = Code::cast(element); | 702 Code* code = Code::cast(element); |
| 696 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION); | 703 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION); |
| 697 length++; | 704 length++; |
| 698 element = code->next_code_link(); | 705 element = code->next_code_link(); |
| 699 } | 706 } |
| 700 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 707 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
| 701 } | 708 } |
| 702 return length; | 709 return length; |
| 703 } | 710 } |
| 704 | 711 |
| 712 namespace { |
| 713 |
| 714 int LookupCatchHandler(TranslatedFrame* translated_frame, int* data_out) { |
| 715 switch (translated_frame->kind()) { |
| 716 case TranslatedFrame::kFunction: { |
| 717 BailoutId node_id = translated_frame->node_id(); |
| 718 JSFunction* function = |
| 719 JSFunction::cast(translated_frame->begin()->GetRawValue()); |
| 720 Code* non_optimized_code = function->shared()->code(); |
| 721 FixedArray* raw_data = non_optimized_code->deoptimization_data(); |
| 722 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); |
| 723 unsigned pc_and_state = |
| 724 Deoptimizer::GetOutputInfo(data, node_id, function->shared()); |
| 725 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); |
| 726 HandlerTable* table = |
| 727 HandlerTable::cast(non_optimized_code->handler_table()); |
| 728 HandlerTable::CatchPrediction prediction; |
| 729 return table->LookupRange(pc_offset, data_out, &prediction); |
| 730 } |
| 731 case TranslatedFrame::kInterpretedFunction: { |
| 732 int bytecode_offset = translated_frame->node_id().ToInt(); |
| 733 JSFunction* function = |
| 734 JSFunction::cast(translated_frame->begin()->GetRawValue()); |
| 735 BytecodeArray* bytecode = function->shared()->bytecode_array(); |
| 736 HandlerTable* table = HandlerTable::cast(bytecode->handler_table()); |
| 737 HandlerTable::CatchPrediction prediction; |
| 738 return table->LookupRange(bytecode_offset, data_out, &prediction); |
| 739 } |
| 740 default: |
| 741 break; |
| 742 } |
| 743 return -1; |
| 744 } |
| 745 |
| 746 } // namespace |
| 705 | 747 |
| 706 // We rely on this function not causing a GC. It is called from generated code | 748 // We rely on this function not causing a GC. It is called from generated code |
| 707 // without having a real stack frame in place. | 749 // without having a real stack frame in place. |
| 708 void Deoptimizer::DoComputeOutputFrames() { | 750 void Deoptimizer::DoComputeOutputFrames() { |
| 709 base::ElapsedTimer timer; | 751 base::ElapsedTimer timer; |
| 710 | 752 |
| 711 // Determine basic deoptimization information. The optimized frame is | 753 // Determine basic deoptimization information. The optimized frame is |
| 712 // described by the input data. | 754 // described by the input data. |
| 713 DeoptimizationInputData* input_data = | 755 DeoptimizationInputData* input_data = |
| 714 DeoptimizationInputData::cast(compiled_code_->deoptimization_data()); | 756 DeoptimizationInputData::cast(compiled_code_->deoptimization_data()); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 735 input_data->TranslationIndex(bailout_id_)->value(); | 777 input_data->TranslationIndex(bailout_id_)->value(); |
| 736 | 778 |
| 737 TranslationIterator state_iterator(translations, translation_index); | 779 TranslationIterator state_iterator(translations, translation_index); |
| 738 translated_state_.Init( | 780 translated_state_.Init( |
| 739 input_->GetFramePointerAddress(), &state_iterator, | 781 input_->GetFramePointerAddress(), &state_iterator, |
| 740 input_data->LiteralArray(), input_->GetRegisterValues(), | 782 input_data->LiteralArray(), input_->GetRegisterValues(), |
| 741 trace_scope_ == nullptr ? nullptr : trace_scope_->file()); | 783 trace_scope_ == nullptr ? nullptr : trace_scope_->file()); |
| 742 | 784 |
| 743 // Do the input frame to output frame(s) translation. | 785 // Do the input frame to output frame(s) translation. |
| 744 size_t count = translated_state_.frames().size(); | 786 size_t count = translated_state_.frames().size(); |
| 787 // If we are supposed to go to the catch handler, find the catching frame |
| 788 // for the catch and make sure we only deoptimize upto that frame. |
| 789 if (deoptimizing_throw_) { |
| 790 size_t catch_handler_frame_index = count; |
| 791 for (size_t i = count; i-- > 0;) { |
| 792 catch_handler_pc_offset_ = LookupCatchHandler( |
| 793 &(translated_state_.frames()[i]), &catch_handler_data_); |
| 794 if (catch_handler_pc_offset_ >= 0) { |
| 795 catch_handler_frame_index = i; |
| 796 break; |
| 797 } |
| 798 } |
| 799 CHECK_LT(catch_handler_frame_index, count); |
| 800 count = catch_handler_frame_index + 1; |
| 801 } |
| 802 |
| 745 DCHECK(output_ == NULL); | 803 DCHECK(output_ == NULL); |
| 746 output_ = new FrameDescription*[count]; | 804 output_ = new FrameDescription*[count]; |
| 747 for (size_t i = 0; i < count; ++i) { | 805 for (size_t i = 0; i < count; ++i) { |
| 748 output_[i] = NULL; | 806 output_[i] = NULL; |
| 749 } | 807 } |
| 750 output_count_ = static_cast<int>(count); | 808 output_count_ = static_cast<int>(count); |
| 751 | 809 |
| 752 Register fp_reg = JavaScriptFrame::fp_register(); | 810 Register fp_reg = JavaScriptFrame::fp_register(); |
| 753 stack_fp_ = reinterpret_cast<Address>( | 811 stack_fp_ = reinterpret_cast<Address>( |
| 754 input_->GetRegister(fp_reg.code()) + | 812 input_->GetRegister(fp_reg.code()) + |
| 755 has_alignment_padding_ * kPointerSize); | 813 has_alignment_padding_ * kPointerSize); |
| 756 | 814 |
| 757 // Translate each output frame. | 815 // Translate each output frame. |
| 758 for (size_t i = 0; i < count; ++i) { | 816 for (size_t i = 0; i < count; ++i) { |
| 759 // Read the ast node id, function, and frame height for this output frame. | 817 // Read the ast node id, function, and frame height for this output frame. |
| 760 int frame_index = static_cast<int>(i); | 818 int frame_index = static_cast<int>(i); |
| 761 switch (translated_state_.frames()[i].kind()) { | 819 switch (translated_state_.frames()[i].kind()) { |
| 762 case TranslatedFrame::kFunction: | 820 case TranslatedFrame::kFunction: |
| 763 DoComputeJSFrame(frame_index); | 821 DoComputeJSFrame(frame_index, deoptimizing_throw_ && i == count - 1); |
| 764 jsframe_count_++; | 822 jsframe_count_++; |
| 765 break; | 823 break; |
| 766 case TranslatedFrame::kInterpretedFunction: | 824 case TranslatedFrame::kInterpretedFunction: |
| 767 DoComputeInterpretedFrame(frame_index); | 825 DoComputeInterpretedFrame(frame_index, |
| 826 deoptimizing_throw_ && i == count - 1); |
| 768 jsframe_count_++; | 827 jsframe_count_++; |
| 769 break; | 828 break; |
| 770 case TranslatedFrame::kArgumentsAdaptor: | 829 case TranslatedFrame::kArgumentsAdaptor: |
| 771 DoComputeArgumentsAdaptorFrame(frame_index); | 830 DoComputeArgumentsAdaptorFrame(frame_index); |
| 772 break; | 831 break; |
| 773 case TranslatedFrame::kConstructStub: | 832 case TranslatedFrame::kConstructStub: |
| 774 DoComputeConstructStubFrame(frame_index); | 833 DoComputeConstructStubFrame(frame_index); |
| 775 break; | 834 break; |
| 776 case TranslatedFrame::kGetter: | 835 case TranslatedFrame::kGetter: |
| 777 DoComputeAccessorStubFrame(frame_index, false); | 836 DoComputeAccessorStubFrame(frame_index, false); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 802 node_id.ToInt(), | 861 node_id.ToInt(), |
| 803 output_[index]->GetPc(), | 862 output_[index]->GetPc(), |
| 804 FullCodeGenerator::State2String( | 863 FullCodeGenerator::State2String( |
| 805 static_cast<FullCodeGenerator::State>( | 864 static_cast<FullCodeGenerator::State>( |
| 806 output_[index]->GetState()->value())), | 865 output_[index]->GetState()->value())), |
| 807 has_alignment_padding_ ? "with padding" : "no padding", | 866 has_alignment_padding_ ? "with padding" : "no padding", |
| 808 ms); | 867 ms); |
| 809 } | 868 } |
| 810 } | 869 } |
| 811 | 870 |
| 812 | 871 void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) { |
| 813 void Deoptimizer::DoComputeJSFrame(int frame_index) { | |
| 814 TranslatedFrame* translated_frame = | 872 TranslatedFrame* translated_frame = |
| 815 &(translated_state_.frames()[frame_index]); | 873 &(translated_state_.frames()[frame_index]); |
| 816 TranslatedFrame::iterator value_iterator = translated_frame->begin(); | 874 TranslatedFrame::iterator value_iterator = translated_frame->begin(); |
| 875 bool is_bottommost = (0 == frame_index); |
| 876 bool is_topmost = (output_count_ - 1 == frame_index); |
| 817 int input_index = 0; | 877 int input_index = 0; |
| 818 | 878 |
| 819 BailoutId node_id = translated_frame->node_id(); | 879 BailoutId node_id = translated_frame->node_id(); |
| 820 unsigned height = | 880 unsigned height = |
| 821 translated_frame->height() - 1; // Do not count the context. | 881 translated_frame->height() - 1; // Do not count the context. |
| 822 unsigned height_in_bytes = height * kPointerSize; | 882 unsigned height_in_bytes = height * kPointerSize; |
| 883 if (goto_catch_handler) { |
| 884 // Take the stack height from the handler table. |
| 885 height = catch_handler_data_; |
| 886 // We also make space for the exception itself. |
| 887 height_in_bytes = (height + 1) * kPointerSize; |
| 888 DCHECK(is_topmost); |
| 889 } |
| 890 |
| 823 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); | 891 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); |
| 824 value_iterator++; | 892 value_iterator++; |
| 825 input_index++; | 893 input_index++; |
| 826 if (trace_scope_ != NULL) { | 894 if (trace_scope_ != NULL) { |
| 827 PrintF(trace_scope_->file(), " translating frame "); | 895 PrintF(trace_scope_->file(), " translating frame "); |
| 828 function->PrintName(trace_scope_->file()); | 896 function->PrintName(trace_scope_->file()); |
| 829 PrintF(trace_scope_->file(), | 897 PrintF(trace_scope_->file(), " => node=%d, height=%d%s\n", node_id.ToInt(), |
| 830 " => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes); | 898 height_in_bytes, goto_catch_handler ? " (throw)" : ""); |
| 831 } | 899 } |
| 832 | 900 |
| 833 // The 'fixed' part of the frame consists of the incoming parameters and | 901 // The 'fixed' part of the frame consists of the incoming parameters and |
| 834 // the part described by JavaScriptFrameConstants. | 902 // the part described by JavaScriptFrameConstants. |
| 835 unsigned fixed_frame_size = ComputeJavascriptFixedSize(function); | 903 unsigned fixed_frame_size = ComputeJavascriptFixedSize(function); |
| 836 unsigned input_frame_size = input_->GetFrameSize(); | 904 unsigned input_frame_size = input_->GetFrameSize(); |
| 837 unsigned output_frame_size = height_in_bytes + fixed_frame_size; | 905 unsigned output_frame_size = height_in_bytes + fixed_frame_size; |
| 838 | 906 |
| 839 // Allocate and store the output frame description. | 907 // Allocate and store the output frame description. |
| 840 FrameDescription* output_frame = | 908 FrameDescription* output_frame = |
| 841 new(output_frame_size) FrameDescription(output_frame_size, function); | 909 new(output_frame_size) FrameDescription(output_frame_size, function); |
| 842 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT); | 910 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT); |
| 843 | 911 |
| 844 bool is_bottommost = (0 == frame_index); | |
| 845 bool is_topmost = (output_count_ - 1 == frame_index); | |
| 846 CHECK(frame_index >= 0 && frame_index < output_count_); | 912 CHECK(frame_index >= 0 && frame_index < output_count_); |
| 847 CHECK_NULL(output_[frame_index]); | 913 CHECK_NULL(output_[frame_index]); |
| 848 output_[frame_index] = output_frame; | 914 output_[frame_index] = output_frame; |
| 849 | 915 |
| 850 // The top address for the bottommost output frame can be computed from | 916 // The top address for the bottommost output frame can be computed from |
| 851 // the input frame pointer and the output frame's height. For all | 917 // the input frame pointer and the output frame's height. For all |
| 852 // subsequent output frames, it can be computed from the previous one's | 918 // subsequent output frames, it can be computed from the previous one's |
| 853 // top address and the current frame's size. | 919 // top address and the current frame's size. |
| 854 Register fp_reg = JavaScriptFrame::fp_register(); | 920 Register fp_reg = JavaScriptFrame::fp_register(); |
| 855 intptr_t top_address; | 921 intptr_t top_address; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 938 DebugPrintOutputSlot(value, frame_index, output_offset, | 1004 DebugPrintOutputSlot(value, frame_index, output_offset, |
| 939 "caller's constant_pool\n"); | 1005 "caller's constant_pool\n"); |
| 940 } | 1006 } |
| 941 | 1007 |
| 942 // For the bottommost output frame the context can be gotten from the input | 1008 // For the bottommost output frame the context can be gotten from the input |
| 943 // frame. For all subsequent output frames it can be gotten from the function | 1009 // frame. For all subsequent output frames it can be gotten from the function |
| 944 // so long as we don't inline functions that need local contexts. | 1010 // so long as we don't inline functions that need local contexts. |
| 945 Register context_reg = JavaScriptFrame::context_register(); | 1011 Register context_reg = JavaScriptFrame::context_register(); |
| 946 output_offset -= kPointerSize; | 1012 output_offset -= kPointerSize; |
| 947 input_offset -= kPointerSize; | 1013 input_offset -= kPointerSize; |
| 1014 |
| 1015 TranslatedFrame::iterator context_pos = value_iterator; |
| 1016 int context_input_index = input_index; |
| 1017 // When deoptimizing into a catch block, we need to take the context |
| 1018 // from just above the top of the operand stack (we push the context |
| 1019 // at the entry of the try block). |
| 1020 if (goto_catch_handler) { |
| 1021 for (unsigned i = 0; i < height + 1; ++i) { |
| 1022 context_pos++; |
| 1023 context_input_index++; |
| 1024 } |
| 1025 } |
| 948 // Read the context from the translations. | 1026 // Read the context from the translations. |
| 949 Object* context = value_iterator->GetRawValue(); | 1027 Object* context = context_pos->GetRawValue(); |
| 950 if (context == isolate_->heap()->undefined_value()) { | 1028 if (context == isolate_->heap()->undefined_value()) { |
| 951 // If the context was optimized away, just use the context from | 1029 // If the context was optimized away, just use the context from |
| 952 // the activation. This should only apply to Crankshaft code. | 1030 // the activation. This should only apply to Crankshaft code. |
| 953 CHECK(!compiled_code_->is_turbofanned()); | 1031 CHECK(!compiled_code_->is_turbofanned()); |
| 954 context = | 1032 context = |
| 955 is_bottommost | 1033 is_bottommost |
| 956 ? reinterpret_cast<Object*>(input_->GetFrameSlot(input_offset)) | 1034 ? reinterpret_cast<Object*>(input_->GetFrameSlot(input_offset)) |
| 957 : function->context(); | 1035 : function->context(); |
| 958 } | 1036 } |
| 959 value = reinterpret_cast<intptr_t>(context); | 1037 value = reinterpret_cast<intptr_t>(context); |
| 960 output_frame->SetContext(value); | 1038 output_frame->SetContext(value); |
| 961 if (is_topmost) output_frame->SetRegister(context_reg.code(), value); | 1039 if (is_topmost) output_frame->SetRegister(context_reg.code(), value); |
| 962 WriteValueToOutput(context, input_index, frame_index, output_offset, | 1040 WriteValueToOutput(context, context_input_index, frame_index, output_offset, |
| 963 "context "); | 1041 "context "); |
| 964 if (context == isolate_->heap()->arguments_marker()) { | 1042 if (context == isolate_->heap()->arguments_marker()) { |
| 965 Address output_address = | 1043 Address output_address = |
| 966 reinterpret_cast<Address>(output_[frame_index]->GetTop()) + | 1044 reinterpret_cast<Address>(output_[frame_index]->GetTop()) + |
| 967 output_offset; | 1045 output_offset; |
| 968 values_to_materialize_.push_back({output_address, value_iterator}); | 1046 values_to_materialize_.push_back({output_address, context_pos}); |
| 969 } | 1047 } |
| 970 value_iterator++; | 1048 value_iterator++; |
| 971 input_index++; | 1049 input_index++; |
| 972 | 1050 |
| 973 // The function was mentioned explicitly in the BEGIN_FRAME. | 1051 // The function was mentioned explicitly in the BEGIN_FRAME. |
| 974 output_offset -= kPointerSize; | 1052 output_offset -= kPointerSize; |
| 975 input_offset -= kPointerSize; | 1053 input_offset -= kPointerSize; |
| 976 value = reinterpret_cast<intptr_t>(function); | 1054 value = reinterpret_cast<intptr_t>(function); |
| 977 // The function for the bottommost output frame should also agree with the | 1055 // The function for the bottommost output frame should also agree with the |
| 978 // input frame. | 1056 // input frame. |
| 979 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value); | 1057 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value); |
| 980 WriteValueToOutput(function, 0, frame_index, output_offset, "function "); | 1058 WriteValueToOutput(function, 0, frame_index, output_offset, "function "); |
| 981 | 1059 |
| 982 // Translate the rest of the frame. | 1060 // Translate the rest of the frame. |
| 983 for (unsigned i = 0; i < height; ++i) { | 1061 for (unsigned i = 0; i < height; ++i) { |
| 984 output_offset -= kPointerSize; | 1062 output_offset -= kPointerSize; |
| 985 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, | 1063 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, |
| 986 output_offset); | 1064 output_offset); |
| 987 } | 1065 } |
| 1066 if (goto_catch_handler) { |
| 1067 // Write out the exception for the catch handler. |
| 1068 output_offset -= kPointerSize; |
| 1069 Object* exception_obj = reinterpret_cast<Object*>( |
| 1070 input_->GetRegister(FullCodeGenerator::result_register().code())); |
| 1071 WriteValueToOutput(exception_obj, input_index, frame_index, output_offset, |
| 1072 "exception "); |
| 1073 input_index++; |
| 1074 } |
| 988 CHECK_EQ(0u, output_offset); | 1075 CHECK_EQ(0u, output_offset); |
| 989 | 1076 |
| 990 // Compute this frame's PC, state, and continuation. | |
| 991 Code* non_optimized_code = function->shared()->code(); | 1077 Code* non_optimized_code = function->shared()->code(); |
| 992 FixedArray* raw_data = non_optimized_code->deoptimization_data(); | |
| 993 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); | |
| 994 Address start = non_optimized_code->instruction_start(); | |
| 995 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); | |
| 996 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); | |
| 997 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset); | |
| 998 output_frame->SetPc(pc_value); | |
| 999 | 1078 |
| 1000 // Update constant pool. | 1079 // Update constant pool. |
| 1001 if (FLAG_enable_embedded_constant_pool) { | 1080 if (FLAG_enable_embedded_constant_pool) { |
| 1002 intptr_t constant_pool_value = | 1081 intptr_t constant_pool_value = |
| 1003 reinterpret_cast<intptr_t>(non_optimized_code->constant_pool()); | 1082 reinterpret_cast<intptr_t>(non_optimized_code->constant_pool()); |
| 1004 output_frame->SetConstantPool(constant_pool_value); | 1083 output_frame->SetConstantPool(constant_pool_value); |
| 1005 if (is_topmost) { | 1084 if (is_topmost) { |
| 1006 Register constant_pool_reg = | 1085 Register constant_pool_reg = |
| 1007 JavaScriptFrame::constant_pool_pointer_register(); | 1086 JavaScriptFrame::constant_pool_pointer_register(); |
| 1008 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); | 1087 output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); |
| 1009 } | 1088 } |
| 1010 } | 1089 } |
| 1011 | 1090 |
| 1091 // Compute this frame's PC, state, and continuation. |
| 1092 FixedArray* raw_data = non_optimized_code->deoptimization_data(); |
| 1093 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); |
| 1094 Address start = non_optimized_code->instruction_start(); |
| 1095 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); |
| 1096 unsigned pc_offset = goto_catch_handler |
| 1097 ? catch_handler_pc_offset_ |
| 1098 : FullCodeGenerator::PcField::decode(pc_and_state); |
| 1099 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset); |
| 1100 output_frame->SetPc(pc_value); |
| 1101 |
| 1102 // If we are going to the catch handler, then the exception lives in |
| 1103 // the accumulator. |
| 1012 FullCodeGenerator::State state = | 1104 FullCodeGenerator::State state = |
| 1013 FullCodeGenerator::StateField::decode(pc_and_state); | 1105 goto_catch_handler ? FullCodeGenerator::TOS_REG |
| 1106 : FullCodeGenerator::StateField::decode(pc_and_state); |
| 1014 output_frame->SetState(Smi::FromInt(state)); | 1107 output_frame->SetState(Smi::FromInt(state)); |
| 1015 | 1108 |
| 1016 // Set the continuation for the topmost frame. | 1109 // Set the continuation for the topmost frame. |
| 1017 if (is_topmost && bailout_type_ != DEBUGGER) { | 1110 if (is_topmost && bailout_type_ != DEBUGGER) { |
| 1018 Builtins* builtins = isolate_->builtins(); | 1111 Builtins* builtins = isolate_->builtins(); |
| 1019 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized); | 1112 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized); |
| 1020 if (bailout_type_ == LAZY) { | 1113 if (bailout_type_ == LAZY) { |
| 1021 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); | 1114 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); |
| 1022 } else if (bailout_type_ == SOFT) { | 1115 } else if (bailout_type_ == SOFT) { |
| 1023 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized); | 1116 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized); |
| 1024 } else { | 1117 } else { |
| 1025 CHECK_EQ(bailout_type_, EAGER); | 1118 CHECK_EQ(bailout_type_, EAGER); |
| 1026 } | 1119 } |
| 1027 output_frame->SetContinuation( | 1120 output_frame->SetContinuation( |
| 1028 reinterpret_cast<intptr_t>(continuation->entry())); | 1121 reinterpret_cast<intptr_t>(continuation->entry())); |
| 1029 } | 1122 } |
| 1030 } | 1123 } |
| 1031 | 1124 |
| 1032 | 1125 void Deoptimizer::DoComputeInterpretedFrame(int frame_index, |
| 1033 void Deoptimizer::DoComputeInterpretedFrame(int frame_index) { | 1126 bool goto_catch_handler) { |
| 1034 TranslatedFrame* translated_frame = | 1127 TranslatedFrame* translated_frame = |
| 1035 &(translated_state_.frames()[frame_index]); | 1128 &(translated_state_.frames()[frame_index]); |
| 1036 TranslatedFrame::iterator value_iterator = translated_frame->begin(); | 1129 TranslatedFrame::iterator value_iterator = translated_frame->begin(); |
| 1037 int input_index = 0; | 1130 int input_index = 0; |
| 1038 | 1131 |
| 1039 BailoutId bytecode_offset = translated_frame->node_id(); | 1132 int bytecode_offset = translated_frame->node_id().ToInt(); |
| 1040 unsigned height = translated_frame->height(); | 1133 unsigned height = translated_frame->height(); |
| 1041 unsigned height_in_bytes = height * kPointerSize; | 1134 unsigned height_in_bytes = height * kPointerSize; |
| 1042 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); | 1135 JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); |
| 1043 value_iterator++; | 1136 value_iterator++; |
| 1044 input_index++; | 1137 input_index++; |
| 1045 if (trace_scope_ != NULL) { | 1138 if (trace_scope_ != NULL) { |
| 1046 PrintF(trace_scope_->file(), " translating interpreted frame "); | 1139 PrintF(trace_scope_->file(), " translating interpreted frame "); |
| 1047 function->PrintName(trace_scope_->file()); | 1140 function->PrintName(trace_scope_->file()); |
| 1048 PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d\n", | 1141 PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d%s\n", |
| 1049 bytecode_offset.ToInt(), height_in_bytes); | 1142 bytecode_offset, height_in_bytes, |
| 1143 goto_catch_handler ? " (throw)" : ""); |
| 1144 } |
| 1145 if (goto_catch_handler) { |
| 1146 bytecode_offset = catch_handler_pc_offset_; |
| 1050 } | 1147 } |
| 1051 | 1148 |
| 1052 // The 'fixed' part of the frame consists of the incoming parameters and | 1149 // The 'fixed' part of the frame consists of the incoming parameters and |
| 1053 // the part described by InterpreterFrameConstants. | 1150 // the part described by InterpreterFrameConstants. |
| 1054 unsigned fixed_frame_size = ComputeInterpretedFixedSize(function); | 1151 unsigned fixed_frame_size = ComputeInterpretedFixedSize(function); |
| 1055 unsigned input_frame_size = input_->GetFrameSize(); | 1152 unsigned input_frame_size = input_->GetFrameSize(); |
| 1056 unsigned output_frame_size = height_in_bytes + fixed_frame_size; | 1153 unsigned output_frame_size = height_in_bytes + fixed_frame_size; |
| 1057 | 1154 |
| 1058 // Allocate and store the output frame description. | 1155 // Allocate and store the output frame description. |
| 1059 FrameDescription* output_frame = | 1156 FrameDescription* output_frame = |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1152 DebugPrintOutputSlot(value, frame_index, output_offset, | 1249 DebugPrintOutputSlot(value, frame_index, output_offset, |
| 1153 "caller's constant_pool\n"); | 1250 "caller's constant_pool\n"); |
| 1154 } | 1251 } |
| 1155 | 1252 |
| 1156 // For the bottommost output frame the context can be gotten from the input | 1253 // For the bottommost output frame the context can be gotten from the input |
| 1157 // frame. For all subsequent output frames it can be gotten from the function | 1254 // frame. For all subsequent output frames it can be gotten from the function |
| 1158 // so long as we don't inline functions that need local contexts. | 1255 // so long as we don't inline functions that need local contexts. |
| 1159 Register context_reg = InterpretedFrame::context_register(); | 1256 Register context_reg = InterpretedFrame::context_register(); |
| 1160 output_offset -= kPointerSize; | 1257 output_offset -= kPointerSize; |
| 1161 input_offset -= kPointerSize; | 1258 input_offset -= kPointerSize; |
| 1259 |
| 1260 // When deoptimizing into a catch block, we need to take the context |
| 1261 // from a register that was specified in the handler table. |
| 1262 TranslatedFrame::iterator context_pos = value_iterator; |
| 1263 int context_input_index = input_index; |
| 1264 if (goto_catch_handler) { |
| 1265 // Skip to the translated value of the register specified |
| 1266 // in the handler table. |
| 1267 for (int i = 0; i < catch_handler_data_ + 1; ++i) { |
| 1268 context_pos++; |
| 1269 context_input_index++; |
| 1270 } |
| 1271 } |
| 1162 // Read the context from the translations. | 1272 // Read the context from the translations. |
| 1163 Object* context = value_iterator->GetRawValue(); | 1273 Object* context = context_pos->GetRawValue(); |
| 1164 // The context should not be a placeholder for a materialized object. | 1274 // The context should not be a placeholder for a materialized object. |
| 1165 CHECK(context != isolate_->heap()->arguments_marker()); | 1275 CHECK(context != isolate_->heap()->arguments_marker()); |
| 1166 value = reinterpret_cast<intptr_t>(context); | 1276 value = reinterpret_cast<intptr_t>(context); |
| 1167 output_frame->SetContext(value); | 1277 output_frame->SetContext(value); |
| 1168 if (is_topmost) output_frame->SetRegister(context_reg.code(), value); | 1278 if (is_topmost) output_frame->SetRegister(context_reg.code(), value); |
| 1169 WriteValueToOutput(context, input_index, frame_index, output_offset, | 1279 WriteValueToOutput(context, context_input_index, frame_index, output_offset, |
| 1170 "context "); | 1280 "context "); |
| 1171 value_iterator++; | 1281 value_iterator++; |
| 1172 input_index++; | 1282 input_index++; |
| 1173 | 1283 |
| 1174 // The function was mentioned explicitly in the BEGIN_FRAME. | 1284 // The function was mentioned explicitly in the BEGIN_FRAME. |
| 1175 output_offset -= kPointerSize; | 1285 output_offset -= kPointerSize; |
| 1176 input_offset -= kPointerSize; | 1286 input_offset -= kPointerSize; |
| 1177 value = reinterpret_cast<intptr_t>(function); | 1287 value = reinterpret_cast<intptr_t>(function); |
| 1178 // The function for the bottommost output frame should also agree with the | 1288 // The function for the bottommost output frame should also agree with the |
| 1179 // input frame. | 1289 // input frame. |
| 1180 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value); | 1290 DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value); |
| 1181 WriteValueToOutput(function, 0, frame_index, output_offset, "function "); | 1291 WriteValueToOutput(function, 0, frame_index, output_offset, "function "); |
| 1182 | 1292 |
| 1183 // TODO(rmcilroy): Deal with new.target correctly - currently just set it to | 1293 // TODO(rmcilroy): Deal with new.target correctly - currently just set it to |
| 1184 // undefined. | 1294 // undefined. |
| 1185 output_offset -= kPointerSize; | 1295 output_offset -= kPointerSize; |
| 1186 input_offset -= kPointerSize; | 1296 input_offset -= kPointerSize; |
| 1187 Object* new_target = isolate_->heap()->undefined_value(); | 1297 Object* new_target = isolate_->heap()->undefined_value(); |
| 1188 WriteValueToOutput(new_target, 0, frame_index, output_offset, "new_target "); | 1298 WriteValueToOutput(new_target, 0, frame_index, output_offset, "new_target "); |
| 1189 | 1299 |
| 1190 // The bytecode offset was mentioned explicitly in the BEGIN_FRAME. | 1300 // The bytecode offset was mentioned explicitly in the BEGIN_FRAME. |
| 1191 output_offset -= kPointerSize; | 1301 output_offset -= kPointerSize; |
| 1192 input_offset -= kPointerSize; | 1302 input_offset -= kPointerSize; |
| 1193 int raw_bytecode_offset = | 1303 int raw_bytecode_offset = |
| 1194 BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset.ToInt(); | 1304 BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset; |
| 1195 Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset); | 1305 Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset); |
| 1196 WriteValueToOutput(smi_bytecode_offset, 0, frame_index, output_offset, | 1306 WriteValueToOutput(smi_bytecode_offset, 0, frame_index, output_offset, |
| 1197 "bytecode offset "); | 1307 "bytecode offset "); |
| 1198 | 1308 |
| 1199 // Translate the rest of the interpreter registers in the frame. | 1309 // Translate the rest of the interpreter registers in the frame. |
| 1200 for (unsigned i = 0; i < height; ++i) { | 1310 for (unsigned i = 0; i < height; ++i) { |
| 1201 output_offset -= kPointerSize; | 1311 output_offset -= kPointerSize; |
| 1202 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, | 1312 WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, |
| 1203 output_offset); | 1313 output_offset); |
| 1204 } | 1314 } |
| 1205 CHECK_EQ(0u, output_offset); | 1315 CHECK_EQ(0u, output_offset); |
| 1206 | 1316 |
| 1207 // Set the accumulator register. | 1317 // Set the accumulator register. If we are lazy deopting to a catch handler, |
| 1208 output_frame->SetRegister( | 1318 // we set the accumulator to the exception (which lives in the result |
| 1209 kInterpreterAccumulatorRegister.code(), | 1319 // register). |
| 1210 reinterpret_cast<intptr_t>(value_iterator->GetRawValue())); | 1320 intptr_t accumulator_value = |
| 1321 goto_catch_handler |
| 1322 ? input_->GetRegister(FullCodeGenerator::result_register().code()) |
| 1323 : reinterpret_cast<intptr_t>(value_iterator->GetRawValue()); |
| 1324 output_frame->SetRegister(kInterpreterAccumulatorRegister.code(), |
| 1325 accumulator_value); |
| 1211 value_iterator++; | 1326 value_iterator++; |
| 1212 | 1327 |
| 1213 Builtins* builtins = isolate_->builtins(); | 1328 Builtins* builtins = isolate_->builtins(); |
| 1214 Code* dispatch_builtin = | 1329 Code* dispatch_builtin = |
| 1215 builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch); | 1330 builtins->builtin(Builtins::kInterpreterEnterBytecodeDispatch); |
| 1216 output_frame->SetPc(reinterpret_cast<intptr_t>(dispatch_builtin->entry())); | 1331 output_frame->SetPc(reinterpret_cast<intptr_t>(dispatch_builtin->entry())); |
| 1217 output_frame->SetState(0); | 1332 output_frame->SetState(0); |
| 1218 | 1333 |
| 1219 // Update constant pool. | 1334 // Update constant pool. |
| 1220 if (FLAG_enable_embedded_constant_pool) { | 1335 if (FLAG_enable_embedded_constant_pool) { |
| (...skipping 2490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3711 DCHECK(value_info->IsMaterializedObject()); | 3826 DCHECK(value_info->IsMaterializedObject()); |
| 3712 | 3827 |
| 3713 value_info->value_ = | 3828 value_info->value_ = |
| 3714 Handle<Object>(previously_materialized_objects->get(i), isolate_); | 3829 Handle<Object>(previously_materialized_objects->get(i), isolate_); |
| 3715 } | 3830 } |
| 3716 } | 3831 } |
| 3717 } | 3832 } |
| 3718 | 3833 |
| 3719 } // namespace internal | 3834 } // namespace internal |
| 3720 } // namespace v8 | 3835 } // namespace v8 |
| OLD | NEW |