| 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 |