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