| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 int commit_page_size = static_cast<int>(OS::CommitPageSize()); | 148 int commit_page_size = static_cast<int>(OS::CommitPageSize()); |
| 149 int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) / | 149 int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) / |
| 150 commit_page_size) + 1; | 150 commit_page_size) + 1; |
| 151 return static_cast<size_t>(commit_page_size * page_count); | 151 return static_cast<size_t>(commit_page_size * page_count); |
| 152 } | 152 } |
| 153 | 153 |
| 154 | 154 |
| 155 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) { | 155 Deoptimizer* Deoptimizer::Grab(Isolate* isolate) { |
| 156 Deoptimizer* result = isolate->deoptimizer_data()->current_; | 156 Deoptimizer* result = isolate->deoptimizer_data()->current_; |
| 157 ASSERT(result != NULL); | 157 ASSERT(result != NULL); |
| 158 if (isolate->optimized_handler_patch_buffer() != NULL) { |
| 159 ASSERT(result->bailout_type_ == LAZY); |
| 160 // Before allowing allocation, patch the optimized code back. The |
| 161 // patched code has relocation info that does not agree with the code, |
| 162 // so the patched code should not be seen by the garbage collector. |
| 163 Code* code = result->compiled_code_; |
| 164 DeoptimizationInputData* deopt_data = |
| 165 DeoptimizationInputData::cast(code->deoptimization_data()); |
| 166 int deopt_index = isolate->optimized_handler_deopt_index(); |
| 167 byte* patch_address = |
| 168 code->instruction_start() + deopt_data->Pc(deopt_index)->value(); |
| 169 memcpy(patch_address, isolate->optimized_handler_patch_buffer(), |
| 170 patch_size()); |
| 171 // FIXME(mmassi): why doesn't it clear immediately also the patch buffer? |
| 172 isolate->ClearOptimizedHandlerByDeopt(code); |
| 173 } |
| 158 result->DeleteFrameDescriptions(); | 174 result->DeleteFrameDescriptions(); |
| 159 isolate->deoptimizer_data()->current_ = NULL; | 175 isolate->deoptimizer_data()->current_ = NULL; |
| 160 return result; | 176 return result; |
| 161 } | 177 } |
| 162 | 178 |
| 163 | 179 |
| 164 int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) { | 180 int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) { |
| 165 if (jsframe_index == 0) return 0; | 181 if (jsframe_index == 0) return 0; |
| 166 | 182 |
| 167 int frame_index = 0; | 183 int frame_index = 0; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 188 // Get the function and code from the frame. | 204 // Get the function and code from the frame. |
| 189 JSFunction* function = JSFunction::cast(frame->function()); | 205 JSFunction* function = JSFunction::cast(frame->function()); |
| 190 Code* code = frame->LookupCode(); | 206 Code* code = frame->LookupCode(); |
| 191 | 207 |
| 192 // Locate the deoptimization point in the code. As we are at a call the | 208 // Locate the deoptimization point in the code. As we are at a call the |
| 193 // return address must be at a place in the code with deoptimization support. | 209 // return address must be at a place in the code with deoptimization support. |
| 194 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc()); | 210 SafepointEntry safepoint_entry = code->GetSafepointEntry(frame->pc()); |
| 195 int deoptimization_index = safepoint_entry.deoptimization_index(); | 211 int deoptimization_index = safepoint_entry.deoptimization_index(); |
| 196 ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex); | 212 ASSERT(deoptimization_index != Safepoint::kNoDeoptimizationIndex); |
| 197 | 213 |
| 214 // Find the size of exception handlers. |
| 215 DeoptimizationInputData* deoptimization_data = |
| 216 DeoptimizationInputData::cast(code->deoptimization_data()); |
| 217 unsigned handler_count = |
| 218 deoptimization_data->HandlerCount(deoptimization_index)->value(); |
| 219 unsigned handler_size = handler_count * StackHandlerConstants::kSize; |
| 220 |
| 198 // Always use the actual stack slots when calculating the fp to sp | 221 // Always use the actual stack slots when calculating the fp to sp |
| 199 // delta adding two for the function and context. | 222 // delta adding two for the function and context. |
| 200 unsigned stack_slots = code->stack_slots(); | 223 unsigned stack_slots = code->stack_slots(); |
| 201 unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize); | 224 unsigned fp_to_sp_delta = ((stack_slots + 2) * kPointerSize) + handler_size; |
| 202 | 225 |
| 203 Deoptimizer* deoptimizer = new Deoptimizer(isolate, | 226 Deoptimizer* deoptimizer = new Deoptimizer(isolate, |
| 204 function, | 227 function, |
| 205 Deoptimizer::DEBUGGER, | 228 Deoptimizer::DEBUGGER, |
| 206 deoptimization_index, | 229 deoptimization_index, |
| 207 frame->pc(), | 230 frame->pc(), |
| 208 fp_to_sp_delta, | 231 fp_to_sp_delta, |
| 209 code); | 232 code); |
| 210 Address tos = frame->fp() - fp_to_sp_delta; | 233 Address tos = frame->fp() - fp_to_sp_delta; |
| 211 deoptimizer->FillInputFrame(tos, frame); | 234 deoptimizer->FillInputFrame(tos, frame); |
| (...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 TranslationIterator iterator(translations, translation_index); | 763 TranslationIterator iterator(translations, translation_index); |
| 741 Translation::Opcode opcode = | 764 Translation::Opcode opcode = |
| 742 static_cast<Translation::Opcode>(iterator.Next()); | 765 static_cast<Translation::Opcode>(iterator.Next()); |
| 743 ASSERT(Translation::BEGIN == opcode); | 766 ASSERT(Translation::BEGIN == opcode); |
| 744 USE(opcode); | 767 USE(opcode); |
| 745 // Read the number of output frames and allocate an array for their | 768 // Read the number of output frames and allocate an array for their |
| 746 // descriptions. | 769 // descriptions. |
| 747 int count = iterator.Next(); | 770 int count = iterator.Next(); |
| 748 iterator.Next(); // Drop JS frames count. | 771 iterator.Next(); // Drop JS frames count. |
| 749 ASSERT(output_ == NULL); | 772 ASSERT(output_ == NULL); |
| 773 |
| 774 // If this deoptimization is needed to transfer control to a catch clause |
| 775 // only the first frame is relevant. |
| 776 if (isolate_->optimized_handler_patch_buffer() != NULL) { |
| 777 count = 1; |
| 778 } |
| 779 |
| 750 output_ = new FrameDescription*[count]; | 780 output_ = new FrameDescription*[count]; |
| 751 for (int i = 0; i < count; ++i) { | 781 for (int i = 0; i < count; ++i) { |
| 752 output_[i] = NULL; | 782 output_[i] = NULL; |
| 753 } | 783 } |
| 754 output_count_ = count; | 784 output_count_ = count; |
| 755 | 785 |
| 756 // Translate each output frame. | 786 // Translate each output frame. |
| 757 for (int i = 0; i < count; ++i) { | 787 for (int i = 0; i < count; ++i) { |
| 758 // Read the ast node id, function, and frame height for this output frame. | 788 // Read the ast node id, function, and frame height for this output frame. |
| 759 Translation::Opcode opcode = | 789 Translation::Opcode opcode = |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 824 BailoutId node_id = BailoutId(iterator->Next()); | 854 BailoutId node_id = BailoutId(iterator->Next()); |
| 825 JSFunction* function; | 855 JSFunction* function; |
| 826 if (frame_index != 0) { | 856 if (frame_index != 0) { |
| 827 function = JSFunction::cast(ComputeLiteral(iterator->Next())); | 857 function = JSFunction::cast(ComputeLiteral(iterator->Next())); |
| 828 } else { | 858 } else { |
| 829 int closure_id = iterator->Next(); | 859 int closure_id = iterator->Next(); |
| 830 USE(closure_id); | 860 USE(closure_id); |
| 831 ASSERT_EQ(Translation::kSelfLiteralId, closure_id); | 861 ASSERT_EQ(Translation::kSelfLiteralId, closure_id); |
| 832 function = function_; | 862 function = function_; |
| 833 } | 863 } |
| 864 Code* non_optimized_code = function->shared()->code(); |
| 834 unsigned height = iterator->Next(); | 865 unsigned height = iterator->Next(); |
| 835 unsigned height_in_bytes = height * kPointerSize; | 866 unsigned height_in_bytes = height * kPointerSize; |
| 836 if (trace_) { | 867 int handler_count = iterator->Next(); |
| 837 PrintF(" translating "); | 868 // If we are doing lazy deoptimization for catching in an optimized frame, |
| 838 function->PrintName(); | 869 // one of the handlers in the frame description has already been dropped |
| 839 PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes); | 870 // by throwing to it. |
| 871 if (isolate_->optimized_handler_patch_buffer() != NULL) { |
| 872 ASSERT(frame_index == 0 && output_count_ == 1); |
| 873 ASSERT(bailout_type_ == LAZY); |
| 874 ASSERT(handler_count > 0); |
| 875 --handler_count; |
| 840 } | 876 } |
| 877 int handlers_size = handler_count * StackHandlerConstants::kSize; |
| 841 | 878 |
| 842 // The 'fixed' part of the frame consists of the incoming parameters and | 879 // The 'fixed' part of the frame consists of the incoming parameters and |
| 843 // the part described by JavaScriptFrameConstants. | 880 // the part described by JavaScriptFrameConstants. |
| 844 unsigned fixed_frame_size = ComputeFixedSize(function); | 881 unsigned fixed_frame_size = ComputeFixedSize(function); |
| 845 unsigned input_frame_size = input_->GetFrameSize(); | 882 //TODO(mmassi): what's this for? |
| 883 //unsigned input_frame_size = input_->GetFrameSize(); |
| 846 unsigned output_frame_size = height_in_bytes + fixed_frame_size; | 884 unsigned output_frame_size = height_in_bytes + fixed_frame_size; |
| 885 if (FLAG_trace_deopt) { |
| 886 PrintF(" translating "); |
| 887 function->PrintName(); |
| 888 PrintF(" => node=%d, height=%d\n", |
| 889 node_id.ToInt(), height_in_bytes + handlers_size); |
| 890 } |
| 891 |
| 847 | 892 |
| 848 // Allocate and store the output frame description. | 893 // Allocate and store the output frame description. |
| 849 FrameDescription* output_frame = | 894 FrameDescription* output_frame = |
| 850 new(output_frame_size) FrameDescription(output_frame_size, function); | 895 new(output_frame_size) FrameDescription(output_frame_size, function); |
| 851 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT); | 896 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT); |
| 852 | 897 |
| 853 bool is_bottommost = (0 == frame_index); | 898 bool is_bottommost = (0 == frame_index); |
| 899 ASSERT(is_bottommost || handler_count == 0); // We do not inline try-catch. |
| 854 bool is_topmost = (output_count_ - 1 == frame_index); | 900 bool is_topmost = (output_count_ - 1 == frame_index); |
| 855 ASSERT(frame_index >= 0 && frame_index < output_count_); | 901 ASSERT(frame_index >= 0 && frame_index < output_count_); |
| 856 ASSERT(output_[frame_index] == NULL); | 902 ASSERT(output_[frame_index] == NULL); |
| 857 output_[frame_index] = output_frame; | 903 output_[frame_index] = output_frame; |
| 858 | 904 |
| 859 // The top address for the bottommost output frame can be computed from | 905 // The top address for the bottommost output frame can be computed from |
| 860 // the input frame pointer and the output frame's height. For all | 906 // the input frame pointer and the output frame's height. For all |
| 861 // subsequent output frames, it can be computed from the previous one's | 907 // subsequent output frames, it can be computed from the previous one's |
| 862 // top address and the current frame's size. | 908 // top address and the current frame's size. |
| 863 Register fp_reg = JavaScriptFrame::fp_register(); | 909 Register fp_reg = JavaScriptFrame::fp_register(); |
| 864 intptr_t top_address; | 910 intptr_t top_address; |
| 865 if (is_bottommost) { | 911 if (is_bottommost) { |
| 866 // Determine whether the input frame contains alignment padding. | 912 // Determine whether the input frame contains alignment padding. |
| 867 has_alignment_padding_ = HasAlignmentPadding(function) ? 1 : 0; | 913 has_alignment_padding_ = HasAlignmentPadding(function) ? 1 : 0; |
| 868 // 2 = context and function in the frame. | 914 // 2 = context and function in the frame. |
| 869 // If the optimized frame had alignment padding, adjust the frame pointer | 915 // If the optimized frame had alignment padding, adjust the frame pointer |
| 870 // to point to the new position of the old frame pointer after padding | 916 // to point to the new position of the old frame pointer after padding |
| 871 // is removed. Subtract 2 * kPointerSize for the context and function slots. | 917 // is removed. Subtract 2 * kPointerSize for the context and function slots. |
| 872 top_address = input_->GetRegister(fp_reg.code()) - (2 * kPointerSize) - | 918 top_address = input_->GetRegister(fp_reg.code()) - (2 * kPointerSize) - |
| 873 height_in_bytes + has_alignment_padding_ * kPointerSize; | 919 height_in_bytes + has_alignment_padding_ * kPointerSize; |
| 920 //TODO(mmassi): Is height_in_bytes the right value? |
| 874 } else { | 921 } else { |
| 875 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; | 922 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; |
| 876 } | 923 } |
| 877 output_frame->SetTop(top_address); | 924 output_frame->SetTop(top_address); |
| 878 | 925 |
| 879 // Compute the incoming parameter translation. | 926 // Compute the incoming parameter translation. |
| 880 int parameter_count = function->shared()->formal_parameter_count() + 1; | 927 int parameter_count = function->shared()->formal_parameter_count() + 1; |
| 881 unsigned output_offset = output_frame_size; | 928 unsigned output_offset = output_frame_size; |
| 882 unsigned input_offset = input_frame_size; | 929 unsigned input_offset = input_->GetFrameSize(); |
| 883 for (int i = 0; i < parameter_count; ++i) { | 930 for (int i = 0; i < parameter_count; ++i) { |
| 884 output_offset -= kPointerSize; | 931 output_offset -= kPointerSize; |
| 885 DoTranslateCommand(iterator, frame_index, output_offset); | 932 DoTranslateCommand(iterator, frame_index, output_offset); |
| 886 } | 933 } |
| 887 input_offset -= (parameter_count * kPointerSize); | 934 input_offset -= (parameter_count * kPointerSize); |
| 888 | 935 |
| 889 // There are no translation commands for the caller's pc and fp, the | 936 // There are no translation commands for the caller's pc and fp, the |
| 890 // context, and the function. Synthesize their values and set them up | 937 // context, and the function. Synthesize their values and set them up |
| 891 // explicitly. | 938 // explicitly. |
| 892 // | 939 // |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 961 // The function for the bottommost output frame should also agree with the | 1008 // The function for the bottommost output frame should also agree with the |
| 962 // input frame. | 1009 // input frame. |
| 963 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); | 1010 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); |
| 964 output_frame->SetFrameSlot(output_offset, value); | 1011 output_frame->SetFrameSlot(output_offset, value); |
| 965 if (trace_) { | 1012 if (trace_) { |
| 966 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" | 1013 PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08" |
| 967 V8PRIxPTR "; function\n", | 1014 V8PRIxPTR "; function\n", |
| 968 top_address + output_offset, output_offset, value); | 1015 top_address + output_offset, output_offset, value); |
| 969 } | 1016 } |
| 970 | 1017 |
| 1018 // Translate the stack-allocated locals. |
| 1019 int stack_slot_count = function->shared()->scope_info()->StackSlotCount(); |
| 1020 for (int i = 0; i < stack_slot_count; ++i) { |
| 1021 output_offset -= kPointerSize; |
| 1022 DoTranslateCommand(iterator, frame_index, output_offset); |
| 1023 } |
| 1024 |
| 1025 // If there are any exception handlers, translate them. |
| 1026 if (handler_count > 0) { |
| 1027 // Translate the handler blocks. The output frame needs: |
| 1028 // |
| 1029 // incoming args | fixed part | locals | handlers | expression stack |
| 1030 // |
| 1031 // because try occurs as a statement, i.e., with the expression stack |
| 1032 // empty. The input frame has: |
| 1033 // |
| 1034 // incoming args | fixed part | spill slots | handlers | outgoing args |
| 1035 // |
| 1036 // also because try is a statement, i.e., there is no pending call to |
| 1037 // interleave handlers and args. This would change if we began inlining |
| 1038 // functions containing try/catch. |
| 1039 // |
| 1040 // TODO(kmillikin): Begin inlining functions containing try/catch. |
| 1041 input_offset = ComputeOutgoingArgumentSize() + ComputeHandlersSize(); |
| 1042 intptr_t next_handler = 0; |
| 1043 for (int i = 0; i < handler_count; ++i) { |
| 1044 // The first two fields (fp and context) are invariant under |
| 1045 // deoptimization. |
| 1046 output_offset -= kPointerSize; |
| 1047 input_offset -= kPointerSize; |
| 1048 value = input_->GetFrameSlot(input_offset); |
| 1049 ASSERT(value == fp_value); |
| 1050 output_frame->SetFrameSlot(output_offset, value); |
| 1051 if (FLAG_trace_deopt) { |
| 1052 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] fp\n", |
| 1053 top_address + output_offset, output_offset, value, i); |
| 1054 } |
| 1055 |
| 1056 output_offset -= kPointerSize; |
| 1057 input_offset -= kPointerSize; |
| 1058 value = input_->GetFrameSlot(input_offset); |
| 1059 output_frame->SetFrameSlot(output_offset, value); |
| 1060 if (FLAG_trace_deopt) { |
| 1061 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] context\n", |
| 1062 top_address + output_offset, output_offset, value, i); |
| 1063 } |
| 1064 |
| 1065 // The state is the same except that the kind is unoptimized. |
| 1066 output_offset -= kPointerSize; |
| 1067 input_offset -= kPointerSize; |
| 1068 value = |
| 1069 input_->GetFrameSlot(input_offset) & ~StackHandler::kIsOptimizedMask; |
| 1070 output_frame->SetFrameSlot(output_offset, value); |
| 1071 if (FLAG_trace_deopt) { |
| 1072 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] index + kind\n", |
| 1073 top_address + output_offset, output_offset, value, i); |
| 1074 } |
| 1075 |
| 1076 // For all handlers in the frame, the code is the unoptimized code. |
| 1077 output_offset -= kPointerSize; |
| 1078 input_offset -= kPointerSize; |
| 1079 value = reinterpret_cast<uint32_t>(non_optimized_code); |
| 1080 output_frame->SetFrameSlot(output_offset, value); |
| 1081 if (FLAG_trace_deopt) { |
| 1082 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] code\n", |
| 1083 top_address + output_offset, output_offset, value, i); |
| 1084 } |
| 1085 |
| 1086 output_offset -= kPointerSize; |
| 1087 input_offset -= kPointerSize; |
| 1088 if (i == 0) { |
| 1089 // Bottommost handler's next link is deoptimization invariant. |
| 1090 value = input_->GetFrameSlot(input_offset); |
| 1091 } else { |
| 1092 value = next_handler; |
| 1093 } |
| 1094 output_frame->SetFrameSlot(output_offset, value); |
| 1095 next_handler = top_address + output_offset; |
| 1096 if (FLAG_trace_deopt) { |
| 1097 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] next\n", |
| 1098 top_address + output_offset, output_offset, value, i); |
| 1099 } |
| 1100 } |
| 1101 *reinterpret_cast<intptr_t*>(isolate_->handler_address()) = next_handler; |
| 1102 } |
| 1103 |
| 971 // Translate the rest of the frame. | 1104 // Translate the rest of the frame. |
| 972 for (unsigned i = 0; i < height; ++i) { | 1105 while (output_offset > 0) { |
| 973 output_offset -= kPointerSize; | 1106 output_offset -= kPointerSize; |
| 974 DoTranslateCommand(iterator, frame_index, output_offset); | 1107 DoTranslateCommand(iterator, frame_index, output_offset); |
| 975 } | 1108 } |
| 976 ASSERT(0 == output_offset); | 1109 ASSERT(0 == output_offset); |
| 977 | 1110 |
| 978 // Compute this frame's PC, state, and continuation. | 1111 // Compute this frame's PC, state, and continuation. |
| 979 Code* non_optimized_code = function->shared()->code(); | 1112 //TODO(mmassi): Where is non_optimized_code needed? |
| 980 FixedArray* raw_data = non_optimized_code->deoptimization_data(); | 1113 //Code* non_optimized_code = function->shared()->code(); |
| 981 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); | 1114 int pc_offset; |
| 982 Address start = non_optimized_code->instruction_start(); | 1115 FullCodeGenerator::State state; |
| 983 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); | 1116 Builtins::Name continuation; |
| 984 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); | 1117 if (isolate_->optimized_handler_patch_buffer() != NULL) { |
| 985 intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset); | 1118 ASSERT(frame_index == 0 && output_count_ == 1); |
| 986 output_frame->SetPc(pc_value); | 1119 // Catching in optimized code. Deopt to the corresponding unoptimized |
| 987 | 1120 // catch handler (not to the instruction following the one that threw). |
| 988 FullCodeGenerator::State state = | 1121 FixedArray* handler_table = non_optimized_code->handler_table(); |
| 989 FullCodeGenerator::StateField::decode(pc_and_state); | 1122 int handler_index = isolate_->optimized_handler_handler_index(); |
| 1123 pc_offset = Smi::cast(handler_table->get(handler_index))->value(); |
| 1124 state = FullCodeGenerator::NO_REGISTERS; |
| 1125 continuation = Builtins::kNotifyLazyDeoptimized; |
| 1126 // The exception value is needed in eax. |
| 1127 output_frame->SetRegister( |
| 1128 eax.code(), |
| 1129 reinterpret_cast<intptr_t>(isolate_->optimized_pending_exception())); |
| 1130 isolate_->clear_optimized_pending_exception(); |
| 1131 } else { |
| 1132 FixedArray* raw_data = non_optimized_code->deoptimization_data(); |
| 1133 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); |
| 1134 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); |
| 1135 pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); |
| 1136 state = FullCodeGenerator::StateField::decode(pc_and_state); |
| 1137 continuation = (bailout_type_ == EAGER) |
| 1138 ? Builtins::kNotifyDeoptimized |
| 1139 : Builtins::kNotifyLazyDeoptimized; |
| 1140 // For lazy deopt we preserve eax in the stack. Ensure that it is not |
| 1141 // the zap value (a probably-invalid HeapObject*). |
| 1142 // TODO(mmassi): According to Kevin the test should be "!= EAGER"... |
| 1143 if (bailout_type_ == EAGER && is_topmost) { |
| 1144 output_frame->SetRegister(eax.code(), |
| 1145 reinterpret_cast<intptr_t>(Smi::FromInt(0))); |
| 1146 } |
| 1147 } |
| 1148 byte* code_start = non_optimized_code->instruction_start(); |
| 1149 output_frame->SetPc(reinterpret_cast<uint32_t>(code_start + pc_offset)); |
| 1150 |
| 990 output_frame->SetState(Smi::FromInt(state)); | 1151 output_frame->SetState(Smi::FromInt(state)); |
| 991 | 1152 |
| 992 // Set the continuation for the topmost frame. | 1153 // Set the continuation for the topmost frame. |
| 993 if (is_topmost && bailout_type_ != DEBUGGER) { | 1154 if (is_topmost && bailout_type_ != DEBUGGER) { |
| 994 Builtins* builtins = isolate_->builtins(); | 1155 Builtins* builtins = isolate_->builtins(); |
| 995 Code* continuation = builtins->builtin(Builtins::kNotifyDeoptimized); | 1156 byte* entry = builtins->builtin(continuation)->entry(); |
| 996 if (bailout_type_ == LAZY) { | 1157 output_frame->SetContinuation(reinterpret_cast<uint32_t>(entry)); |
| 997 continuation = builtins->builtin(Builtins::kNotifyLazyDeoptimized); | |
| 998 } else if (bailout_type_ == SOFT) { | |
| 999 continuation = builtins->builtin(Builtins::kNotifySoftDeoptimized); | |
| 1000 } else { | |
| 1001 ASSERT(bailout_type_ == EAGER); | |
| 1002 } | |
| 1003 output_frame->SetContinuation( | |
| 1004 reinterpret_cast<intptr_t>(continuation->entry())); | |
| 1005 } | 1158 } |
| 1006 } | 1159 } |
| 1007 | 1160 |
| 1008 | 1161 |
| 1009 void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, | 1162 void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, |
| 1010 int frame_index) { | 1163 int frame_index) { |
| 1011 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); | 1164 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); |
| 1012 unsigned height = iterator->Next(); | 1165 unsigned height = iterator->Next(); |
| 1013 unsigned height_in_bytes = height * kPointerSize; | 1166 unsigned height_in_bytes = height * kPointerSize; |
| 1014 if (trace_) { | 1167 if (trace_) { |
| (...skipping 1025 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2040 // We save the untagged value on the side and store a GC-safe | 2193 // We save the untagged value on the side and store a GC-safe |
| 2041 // temporary placeholder in the frame. | 2194 // temporary placeholder in the frame. |
| 2042 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value); | 2195 AddDoubleValue(output_[frame_index]->GetTop() + output_offset, value); |
| 2043 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); | 2196 output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder); |
| 2044 return; | 2197 return; |
| 2045 } | 2198 } |
| 2046 | 2199 |
| 2047 case Translation::STACK_SLOT: { | 2200 case Translation::STACK_SLOT: { |
| 2048 int input_slot_index = iterator->Next(); | 2201 int input_slot_index = iterator->Next(); |
| 2049 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index); | 2202 unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index); |
| 2050 intptr_t input_value = input_->GetFrameSlot(input_offset); | 2203 intptr_t input_value; |
| 2204 if (isolate_->optimized_handler_patch_buffer() != NULL && |
| 2205 input_offset >= input_->frame_size()) { |
| 2206 // Skip stack slots that were above the handler (they must be |
| 2207 // arguments that must be thrown away because try is a statement). |
| 2208 input_value = static_cast<intptr_t>(NULL); |
| 2209 if (FLAG_trace_deopt) { |
| 2210 PrintF(" SKIPPING SLOT ABOVE HANDLER (ARGUMENT)\n"); |
| 2211 } |
| 2212 } else { |
| 2213 input_value = input_->GetFrameSlot(input_offset); |
| 2214 } |
| 2051 if (trace_) { | 2215 if (trace_) { |
| 2052 PrintF(" 0x%08" V8PRIxPTR ": ", | 2216 PrintF(" 0x%08" V8PRIxPTR ": ", |
| 2053 output_[frame_index]->GetTop() + output_offset); | 2217 output_[frame_index]->GetTop() + output_offset); |
| 2054 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ", | 2218 PrintF("[top + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ", |
| 2055 output_offset, | 2219 output_offset, |
| 2056 input_value, | 2220 input_value, |
| 2057 input_offset); | 2221 input_offset); |
| 2058 reinterpret_cast<Object*>(input_value)->ShortPrint(); | 2222 reinterpret_cast<Object*>(input_value)->ShortPrint(); |
| 2059 PrintF("\n"); | 2223 PrintF("\n"); |
| 2060 } | 2224 } |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2205 switch (opcode) { | 2369 switch (opcode) { |
| 2206 case Translation::BEGIN: | 2370 case Translation::BEGIN: |
| 2207 case Translation::JS_FRAME: | 2371 case Translation::JS_FRAME: |
| 2208 case Translation::ARGUMENTS_ADAPTOR_FRAME: | 2372 case Translation::ARGUMENTS_ADAPTOR_FRAME: |
| 2209 case Translation::CONSTRUCT_STUB_FRAME: | 2373 case Translation::CONSTRUCT_STUB_FRAME: |
| 2210 case Translation::GETTER_STUB_FRAME: | 2374 case Translation::GETTER_STUB_FRAME: |
| 2211 case Translation::SETTER_STUB_FRAME: | 2375 case Translation::SETTER_STUB_FRAME: |
| 2212 case Translation::COMPILED_STUB_FRAME: | 2376 case Translation::COMPILED_STUB_FRAME: |
| 2213 case Translation::DUPLICATE: | 2377 case Translation::DUPLICATE: |
| 2214 UNREACHABLE(); // Malformed input. | 2378 UNREACHABLE(); // Malformed input. |
| 2215 return false; | 2379 return false; |
| 2216 | 2380 |
| 2217 case Translation::REGISTER: { | 2381 case Translation::REGISTER: { |
| 2218 int output_reg = iterator->Next(); | 2382 int output_reg = iterator->Next(); |
| 2219 if (FLAG_trace_osr) { | 2383 if (FLAG_trace_osr) { |
| 2220 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n", | 2384 PrintF(" %s <- 0x%08" V8PRIxPTR " ; [sp + %d]\n", |
| 2221 converter.NameOfCPURegister(output_reg), | 2385 converter.NameOfCPURegister(output_reg), |
| 2222 input_value, | 2386 input_value, |
| 2223 *input_offset); | 2387 *input_offset); |
| 2224 } | 2388 } |
| 2225 output->SetRegister(output_reg, input_value); | 2389 output->SetRegister(output_reg, input_value); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2461 pc_after, | 2625 pc_after, |
| 2462 interrupt_code, | 2626 interrupt_code, |
| 2463 replacement_code)); | 2627 replacement_code)); |
| 2464 back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize; | 2628 back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize; |
| 2465 } | 2629 } |
| 2466 } | 2630 } |
| 2467 #endif // DEBUG | 2631 #endif // DEBUG |
| 2468 | 2632 |
| 2469 | 2633 |
| 2470 unsigned Deoptimizer::ComputeInputFrameSize() const { | 2634 unsigned Deoptimizer::ComputeInputFrameSize() const { |
| 2635 // This is the size of the frame that is the same for both optimized and |
| 2636 // unoptimized frames---the incoming parameters and the fixed part of the |
| 2637 // frame. |
| 2471 unsigned fixed_size = ComputeFixedSize(function_); | 2638 unsigned fixed_size = ComputeFixedSize(function_); |
| 2639 |
| 2472 // The fp-to-sp delta already takes the context and the function | 2640 // The fp-to-sp delta already takes the context and the function |
| 2473 // into account so we have to avoid double counting them (-2). | 2641 // into account so we have to avoid double counting them (-2). |
| 2474 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize); | 2642 unsigned result = fixed_size + fp_to_sp_delta_ - (2 * kPointerSize); |
| 2643 |
| 2475 #ifdef DEBUG | 2644 #ifdef DEBUG |
| 2476 if (bailout_type_ == OSR) { | 2645 if (bailout_type_ == OSR) { |
| 2477 // TODO(kasperl): It would be nice if we could verify that the | 2646 // TODO(kasperl): It would be nice if we could verify that the |
| 2478 // size matches with the stack height we can compute based on the | 2647 // size matches with the stack height we can compute based on the |
| 2479 // environment at the OSR entry. The code for that his built into | 2648 // environment at the OSR entry. The code for that his built into |
| 2480 // the DoComputeOsrOutputFrame function for now. | 2649 // the DoComputeOsrOutputFrame function for now. |
| 2481 } else if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) { | 2650 } else if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) { |
| 2482 unsigned stack_slots = compiled_code_->stack_slots(); | 2651 // Verify the actual frame size matches the expected (fixed part + |
| 2483 unsigned outgoing_size = ComputeOutgoingArgumentSize(); | 2652 // spill slots + exception handlers + outgoing arguments). |
| 2484 ASSERT(result == fixed_size + (stack_slots * kPointerSize) + outgoing_size); | 2653 unsigned spill_slots_size = compiled_code_->stack_slots() * kPointerSize; |
| 2654 unsigned handlers_size = ComputeHandlersSize(); |
| 2655 // If we are doing lazy deoptimization for catching in an optimized |
| 2656 // frame, one of the handlers in the frame description has already been |
| 2657 // dropped by throwing to it. |
| 2658 if (isolate_->optimized_handler_patch_buffer() != NULL) { |
| 2659 ASSERT(bailout_type_ == LAZY); |
| 2660 ASSERT(static_cast<int>(handlers_size) >= StackHandlerConstants::kSize); |
| 2661 handlers_size -= StackHandlerConstants::kSize; |
| 2662 } |
| 2663 unsigned outgoing_arg_size = ComputeOutgoingArgumentSize(); |
| 2664 ASSERT(result == |
| 2665 fixed_size + spill_slots_size + handlers_size + outgoing_arg_size); |
| 2485 } | 2666 } |
| 2486 #endif | 2667 #endif |
| 2487 return result; | 2668 return result; |
| 2488 } | 2669 } |
| 2489 | 2670 |
| 2490 | 2671 |
| 2491 unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const { | 2672 unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const { |
| 2492 // The fixed part of the frame consists of the return address, frame | 2673 // The fixed part of the frame consists of the return address, frame |
| 2493 // pointer, function, context, and all the incoming arguments. | 2674 // pointer, function, context, and all the incoming arguments. |
| 2494 return ComputeIncomingArgumentSize(function) + | 2675 return ComputeIncomingArgumentSize(function) + |
| 2495 StandardFrameConstants::kFixedFrameSize; | 2676 StandardFrameConstants::kFixedFrameSize; |
| 2496 } | 2677 } |
| 2497 | 2678 |
| 2498 | 2679 |
| 2499 unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const { | 2680 unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const { |
| 2500 // The incoming arguments is the values for formal parameters and | 2681 // The incoming arguments is the values for formal parameters and |
| 2501 // the receiver. Every slot contains a pointer. | 2682 // the receiver. Every slot contains a pointer. |
| 2502 if (function->IsSmi()) { | 2683 if (function->IsSmi()) { |
| 2503 ASSERT(Smi::cast(function) == Smi::FromInt(StackFrame::STUB)); | 2684 ASSERT(Smi::cast(function) == Smi::FromInt(StackFrame::STUB)); |
| 2504 return 0; | 2685 return 0; |
| 2505 } | 2686 } |
| 2506 unsigned arguments = function->shared()->formal_parameter_count() + 1; | 2687 unsigned arguments = function->shared()->formal_parameter_count() + 1; |
| 2507 return arguments * kPointerSize; | 2688 return arguments * kPointerSize; |
| 2508 } | 2689 } |
| 2509 | 2690 |
| 2510 | 2691 |
| 2511 unsigned Deoptimizer::ComputeOutgoingArgumentSize() const { | 2692 unsigned Deoptimizer::ComputeOutgoingArgumentSize() const { |
| 2693 // Since try is a statement there will not be arguments left on the stack |
| 2694 // once we have popped the handler. |
| 2695 if (isolate_->optimized_handler_patch_buffer() != NULL) { |
| 2696 return 0; |
| 2697 } |
| 2698 |
| 2512 DeoptimizationInputData* data = DeoptimizationInputData::cast( | 2699 DeoptimizationInputData* data = DeoptimizationInputData::cast( |
| 2513 compiled_code_->deoptimization_data()); | 2700 compiled_code_->deoptimization_data()); |
| 2514 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value(); | 2701 unsigned height = data->ArgumentsStackHeight(bailout_id_)->value(); |
| 2515 return height * kPointerSize; | 2702 return height * kPointerSize; |
| 2516 } | 2703 } |
| 2517 | 2704 |
| 2518 | 2705 |
| 2706 unsigned Deoptimizer::ComputeHandlersSize() const { |
| 2707 DeoptimizationInputData* data = DeoptimizationInputData::cast( |
| 2708 compiled_code_->deoptimization_data()); |
| 2709 unsigned handler_count = data->HandlerCount(bailout_id_)->value(); |
| 2710 return handler_count * StackHandlerConstants::kSize; |
| 2711 } |
| 2712 |
| 2713 |
| 2519 Object* Deoptimizer::ComputeLiteral(int index) const { | 2714 Object* Deoptimizer::ComputeLiteral(int index) const { |
| 2520 DeoptimizationInputData* data = DeoptimizationInputData::cast( | 2715 DeoptimizationInputData* data = DeoptimizationInputData::cast( |
| 2521 compiled_code_->deoptimization_data()); | 2716 compiled_code_->deoptimization_data()); |
| 2522 FixedArray* literals = data->LiteralArray(); | 2717 FixedArray* literals = data->LiteralArray(); |
| 2523 return literals->get(index); | 2718 return literals->get(index); |
| 2524 } | 2719 } |
| 2525 | 2720 |
| 2526 | 2721 |
| 2527 void Deoptimizer::AddObjectStart(intptr_t slot_address, int length) { | 2722 void Deoptimizer::AddObjectStart(intptr_t slot_address, int length) { |
| 2528 ObjectMaterializationDescriptor object_desc( | 2723 ObjectMaterializationDescriptor object_desc( |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2743 | 2938 |
| 2744 void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) { | 2939 void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) { |
| 2745 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone()); | 2940 buffer_->Add(ARGUMENTS_ADAPTOR_FRAME, zone()); |
| 2746 buffer_->Add(literal_id, zone()); | 2941 buffer_->Add(literal_id, zone()); |
| 2747 buffer_->Add(height, zone()); | 2942 buffer_->Add(height, zone()); |
| 2748 } | 2943 } |
| 2749 | 2944 |
| 2750 | 2945 |
| 2751 void Translation::BeginJSFrame(BailoutId node_id, | 2946 void Translation::BeginJSFrame(BailoutId node_id, |
| 2752 int literal_id, | 2947 int literal_id, |
| 2753 unsigned height) { | 2948 unsigned height, |
| 2949 int handler_count) { |
| 2754 buffer_->Add(JS_FRAME, zone()); | 2950 buffer_->Add(JS_FRAME, zone()); |
| 2755 buffer_->Add(node_id.ToInt(), zone()); | 2951 buffer_->Add(node_id.ToInt(), zone()); |
| 2756 buffer_->Add(literal_id, zone()); | 2952 buffer_->Add(literal_id, zone()); |
| 2757 buffer_->Add(height, zone()); | 2953 buffer_->Add(height, zone()); |
| 2954 buffer_->Add(handler_count, zone()); |
| 2758 } | 2955 } |
| 2759 | 2956 |
| 2760 | 2957 |
| 2761 void Translation::BeginCompiledStubFrame() { | 2958 void Translation::BeginCompiledStubFrame() { |
| 2762 buffer_->Add(COMPILED_STUB_FRAME, zone()); | 2959 buffer_->Add(COMPILED_STUB_FRAME, zone()); |
| 2763 } | 2960 } |
| 2764 | 2961 |
| 2765 | 2962 |
| 2766 void Translation::BeginArgumentsObject(int args_length) { | 2963 void Translation::BeginArgumentsObject(int args_length) { |
| 2767 buffer_->Add(ARGUMENTS_OBJECT, zone()); | 2964 buffer_->Add(ARGUMENTS_OBJECT, zone()); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2844 case UINT32_STACK_SLOT: | 3041 case UINT32_STACK_SLOT: |
| 2845 case DOUBLE_STACK_SLOT: | 3042 case DOUBLE_STACK_SLOT: |
| 2846 case LITERAL: | 3043 case LITERAL: |
| 2847 case COMPILED_STUB_FRAME: | 3044 case COMPILED_STUB_FRAME: |
| 2848 return 1; | 3045 return 1; |
| 2849 case BEGIN: | 3046 case BEGIN: |
| 2850 case ARGUMENTS_ADAPTOR_FRAME: | 3047 case ARGUMENTS_ADAPTOR_FRAME: |
| 2851 case CONSTRUCT_STUB_FRAME: | 3048 case CONSTRUCT_STUB_FRAME: |
| 2852 return 2; | 3049 return 2; |
| 2853 case JS_FRAME: | 3050 case JS_FRAME: |
| 2854 return 3; | 3051 return 4; |
| 2855 } | 3052 } |
| 2856 UNREACHABLE(); | 3053 UNREACHABLE(); |
| 2857 return -1; | 3054 return -1; |
| 2858 } | 3055 } |
| 2859 | 3056 |
| 2860 | 3057 |
| 2861 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) | 3058 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) |
| 2862 | 3059 |
| 2863 const char* Translation::StringFor(Opcode opcode) { | 3060 const char* Translation::StringFor(Opcode opcode) { |
| 2864 switch (opcode) { | 3061 switch (opcode) { |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3111 | 3308 |
| 3112 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { | 3309 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { |
| 3113 v->VisitPointer(BitCast<Object**>(&function_)); | 3310 v->VisitPointer(BitCast<Object**>(&function_)); |
| 3114 v->VisitPointers(parameters_, parameters_ + parameters_count_); | 3311 v->VisitPointers(parameters_, parameters_ + parameters_count_); |
| 3115 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); | 3312 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); |
| 3116 } | 3313 } |
| 3117 | 3314 |
| 3118 #endif // ENABLE_DEBUGGER_SUPPORT | 3315 #endif // ENABLE_DEBUGGER_SUPPORT |
| 3119 | 3316 |
| 3120 } } // namespace v8::internal | 3317 } } // namespace v8::internal |
| OLD | NEW |