Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(827)

Side by Side Diff: src/ia32/deoptimizer-ia32.cc

Issue 10910161: Partial ia32 implementation of optimized try/catch (by Kevin Millikin) (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fixed build. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/builtins-ia32.cc ('k') | src/ia32/lithium-codegen-ia32.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 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 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 ASSERT(Translation::JS_FRAME == opcode); 344 ASSERT(Translation::JS_FRAME == opcode);
345 unsigned node_id = iterator.Next(); 345 unsigned node_id = iterator.Next();
346 USE(node_id); 346 USE(node_id);
347 ASSERT(node_id == ast_id); 347 ASSERT(node_id == ast_id);
348 int closure_id = iterator.Next(); 348 int closure_id = iterator.Next();
349 USE(closure_id); 349 USE(closure_id);
350 ASSERT_EQ(Translation::kSelfLiteralId, closure_id); 350 ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
351 unsigned height = iterator.Next(); 351 unsigned height = iterator.Next();
352 unsigned height_in_bytes = height * kPointerSize; 352 unsigned height_in_bytes = height * kPointerSize;
353 USE(height_in_bytes); 353 USE(height_in_bytes);
354 int handler_count = iterator.Next();
355 USE(handler_count);
354 356
355 unsigned fixed_size = ComputeFixedSize(function_); 357 unsigned fixed_size = ComputeFixedSize(function_);
356 unsigned input_frame_size = input_->GetFrameSize(); 358 unsigned input_frame_size = input_->GetFrameSize();
357 ASSERT(fixed_size + height_in_bytes == input_frame_size); 359 ASSERT(fixed_size + height_in_bytes == input_frame_size);
358 360
359 unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize; 361 unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize;
360 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value(); 362 unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
361 unsigned outgoing_size = outgoing_height * kPointerSize; 363 unsigned outgoing_size = outgoing_height * kPointerSize;
362 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size; 364 unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
363 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call. 365 ASSERT(outgoing_size == 0); // OSR does not happen in the middle of a call.
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 Code* continuation = 475 Code* continuation =
474 function_->GetIsolate()->builtins()->builtin(Builtins::kNotifyOSR); 476 function_->GetIsolate()->builtins()->builtin(Builtins::kNotifyOSR);
475 output_[0]->SetContinuation( 477 output_[0]->SetContinuation(
476 reinterpret_cast<uint32_t>(continuation->entry())); 478 reinterpret_cast<uint32_t>(continuation->entry()));
477 479
478 if (FLAG_trace_osr) { 480 if (FLAG_trace_osr) {
479 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ", 481 PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
480 ok ? "finished" : "aborted", 482 ok ? "finished" : "aborted",
481 reinterpret_cast<intptr_t>(function_)); 483 reinterpret_cast<intptr_t>(function_));
482 function_->PrintName(); 484 function_->PrintName();
483 PrintF(" => pc=0x%0x]\n", output_[0]->GetPc()); 485 PrintF(" => pc=0x%08x]\n", output_[0]->GetPc());
484 } 486 }
485 } 487 }
486 488
487 489
488 void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, 490 void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
489 int frame_index) { 491 int frame_index) {
490 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next())); 492 JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
491 unsigned height = iterator->Next(); 493 unsigned height = iterator->Next();
492 unsigned height_in_bytes = height * kPointerSize; 494 unsigned height_in_bytes = height * kPointerSize;
493 if (FLAG_trace_deopt) { 495 if (FLAG_trace_deopt) {
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
818 BailoutId node_id = BailoutId(iterator->Next()); 820 BailoutId node_id = BailoutId(iterator->Next());
819 JSFunction* function; 821 JSFunction* function;
820 if (frame_index != 0) { 822 if (frame_index != 0) {
821 function = JSFunction::cast(ComputeLiteral(iterator->Next())); 823 function = JSFunction::cast(ComputeLiteral(iterator->Next()));
822 } else { 824 } else {
823 int closure_id = iterator->Next(); 825 int closure_id = iterator->Next();
824 USE(closure_id); 826 USE(closure_id);
825 ASSERT_EQ(Translation::kSelfLiteralId, closure_id); 827 ASSERT_EQ(Translation::kSelfLiteralId, closure_id);
826 function = function_; 828 function = function_;
827 } 829 }
830 Code* non_optimized_code = function->shared()->code();
828 unsigned height = iterator->Next(); 831 unsigned height = iterator->Next();
829 unsigned height_in_bytes = height * kPointerSize; 832 unsigned height_in_bytes = height * kPointerSize;
830 if (FLAG_trace_deopt) { 833 int handler_count = iterator->Next();
831 PrintF(" translating "); 834 // If we are doing lazy deoptimization for catching in an optimized frame,
832 function->PrintName(); 835 // one of the handlers in the frame description has already been dropped
833 PrintF(" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes); 836 // by throwing to it.
837 if (isolate_->optimized_handler_patch_buffer() != NULL) {
838 ASSERT(frame_index == 0 && output_count_ == 1);
839 ASSERT(bailout_type_ == LAZY);
840 ASSERT(handler_count > 0);
841 --handler_count;
834 } 842 }
843 int handlers_size = handler_count * StackHandlerConstants::kSize;
835 844
836 // The 'fixed' part of the frame consists of the incoming parameters and 845 // The 'fixed' part of the frame consists of the incoming parameters and
837 // the part described by JavaScriptFrameConstants. 846 // the part described by JavaScriptFrameConstants.
838 unsigned fixed_frame_size = ComputeFixedSize(function); 847 unsigned fixed_frame_size = ComputeFixedSize(function);
839 unsigned input_frame_size = input_->GetFrameSize(); 848 unsigned varying_frame_size = height_in_bytes + handlers_size;
840 unsigned output_frame_size = height_in_bytes + fixed_frame_size; 849 unsigned output_frame_size = fixed_frame_size + varying_frame_size;
850 if (FLAG_trace_deopt) {
851 PrintF(" translating ");
852 function->PrintName();
853 PrintF(" => node=%d, height=%d\n",
854 node_id.ToInt(), height_in_bytes + handlers_size);
855 }
841 856
842 // Allocate and store the output frame description. 857 // Allocate and store the output frame description.
843 FrameDescription* output_frame = 858 FrameDescription* output_frame =
844 new(output_frame_size) FrameDescription(output_frame_size, function); 859 new(output_frame_size) FrameDescription(output_frame_size, function);
845 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT); 860 output_frame->SetFrameType(StackFrame::JAVA_SCRIPT);
846 861
847 bool is_bottommost = (0 == frame_index); 862 bool is_bottommost = (0 == frame_index);
863 ASSERT(is_bottommost || handler_count == 0); // We do not inline try-catch.
848 bool is_topmost = (output_count_ - 1 == frame_index); 864 bool is_topmost = (output_count_ - 1 == frame_index);
849 ASSERT(frame_index >= 0 && frame_index < output_count_); 865 ASSERT(frame_index >= 0 && frame_index < output_count_);
850 ASSERT(output_[frame_index] == NULL); 866 ASSERT(output_[frame_index] == NULL);
851 output_[frame_index] = output_frame; 867 output_[frame_index] = output_frame;
852 868
853 // Compute the incoming parameter translation. 869 // Compute the incoming parameter translation.
854 int parameter_count = function->shared()->formal_parameter_count() + 1; 870 int parameter_count = function->shared()->formal_parameter_count() + 1;
855 unsigned output_offset = output_frame_size; 871 unsigned output_offset = output_frame_size;
856 unsigned input_offset = input_frame_size; 872 unsigned input_offset = input_->GetFrameSize();
857 873
858 unsigned alignment_state_offset = 874 unsigned alignment_state_offset =
859 input_offset - parameter_count * kPointerSize - 875 input_offset - parameter_count * kPointerSize -
860 StandardFrameConstants::kFixedFrameSize - 876 StandardFrameConstants::kFixedFrameSize -
861 kPointerSize; 877 kPointerSize;
862 ASSERT(JavaScriptFrameConstants::kDynamicAlignmentStateOffset == 878 ASSERT(JavaScriptFrameConstants::kDynamicAlignmentStateOffset ==
863 JavaScriptFrameConstants::kLocal0Offset); 879 JavaScriptFrameConstants::kLocal0Offset);
864 880
865 // The top address for the bottommost output frame can be computed from 881 // The top address for the bottommost output frame can be computed from
866 // the input frame pointer and the output frame's height. For all 882 // the input frame pointer and the output frame's height. For all
867 // subsequent output frames, it can be computed from the previous one's 883 // subsequent output frames, it can be computed from the previous one's
868 // top address and the current frame's size. 884 // top address and the current frame's size.
869 uint32_t top_address; 885 uint32_t top_address;
870 if (is_bottommost) { 886 if (is_bottommost) {
871 int32_t alignment_state = input_->GetFrameSlot(alignment_state_offset); 887 int32_t alignment_state = input_->GetFrameSlot(alignment_state_offset);
872 has_alignment_padding_ = 888 has_alignment_padding_ =
873 (alignment_state == kAlignmentPaddingPushed) ? 1 : 0; 889 (alignment_state == kAlignmentPaddingPushed) ? 1 : 0;
874 // 2 = context and function in the frame. 890 // 2 = context and function in the frame.
875 // If the optimized frame had alignment padding, adjust the frame pointer 891 // If the optimized frame had alignment padding, adjust the frame pointer
876 // to point to the new position of the old frame pointer after padding 892 // to point to the new position of the old frame pointer after padding
877 // is removed. Subtract 2 * kPointerSize for the context and function slots. 893 // is removed. Subtract 2 * kPointerSize for the context and function slots.
878 top_address = input_->GetRegister(ebp.code()) - (2 * kPointerSize) - 894 top_address = input_->GetRegister(ebp.code()) - (2 * kPointerSize) -
879 height_in_bytes + has_alignment_padding_ * kPointerSize; 895 varying_frame_size + has_alignment_padding_ * kPointerSize;
880 } else { 896 } else {
881 top_address = output_[frame_index - 1]->GetTop() - output_frame_size; 897 top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
882 } 898 }
883 output_frame->SetTop(top_address); 899 output_frame->SetTop(top_address);
884 900
885 for (int i = 0; i < parameter_count; ++i) { 901 for (int i = 0; i < parameter_count; ++i) {
886 output_offset -= kPointerSize; 902 output_offset -= kPointerSize;
887 DoTranslateCommand(iterator, frame_index, output_offset); 903 DoTranslateCommand(iterator, frame_index, output_offset);
888 } 904 }
889 input_offset -= (parameter_count * kPointerSize); 905 input_offset -= (parameter_count * kPointerSize);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 value = reinterpret_cast<uint32_t>(function); 975 value = reinterpret_cast<uint32_t>(function);
960 // The function for the bottommost output frame should also agree with the 976 // The function for the bottommost output frame should also agree with the
961 // input frame. 977 // input frame.
962 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); 978 ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
963 output_frame->SetFrameSlot(output_offset, value); 979 output_frame->SetFrameSlot(output_offset, value);
964 if (FLAG_trace_deopt) { 980 if (FLAG_trace_deopt) {
965 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n", 981 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function\n",
966 top_address + output_offset, output_offset, value); 982 top_address + output_offset, output_offset, value);
967 } 983 }
968 984
969 // Translate the rest of the frame. 985
970 for (unsigned i = 0; i < height; ++i) { 986 // Translate the stack-allocated locals.
987 int stack_slot_count = function->shared()->scope_info()->StackSlotCount();
988 for (int i = 0; i < stack_slot_count; ++i) {
971 output_offset -= kPointerSize; 989 output_offset -= kPointerSize;
972 DoTranslateCommand(iterator, frame_index, output_offset); 990 DoTranslateCommand(iterator, frame_index, output_offset);
973 } 991 }
974 ASSERT(0 == output_offset); 992
993 // If there are any exception handlers, translate them.
994 if (handler_count > 0) {
995 // Translate the handler blocks. The output frame needs:
996 //
997 // incoming args | fixed part | locals | handlers | expression stack
998 //
999 // because try occurs as a statement, i.e., with the expression stack
1000 // empty. The input frame has:
1001 //
1002 // incoming args | fixed part | spill slots | handlers | outgoing args
1003 //
1004 // also because try is a statement, i.e., there is no pending call to
1005 // interleave handlers and args. This would change if we began inlining
1006 // functions containing try/catch.
1007 //
1008 // TODO(kmillikin): Begin inlining functions containing try/catch.
1009 input_offset = ComputeOutgoingArgumentSize() + ComputeHandlersSize();
1010 intptr_t next_handler = 0;
1011 for (int i = 0; i < handler_count; ++i) {
1012 // The first two fields (fp and context) are invariant under
1013 // deoptimization.
1014 output_offset -= kPointerSize;
1015 input_offset -= kPointerSize;
1016 value = input_->GetFrameSlot(input_offset);
1017 ASSERT(value == fp_value);
1018 output_frame->SetFrameSlot(output_offset, value);
1019 if (FLAG_trace_deopt) {
1020 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] fp\n",
1021 top_address + output_offset, output_offset, value, i);
1022 }
1023
1024 output_offset -= kPointerSize;
1025 input_offset -= kPointerSize;
1026 value = input_->GetFrameSlot(input_offset);
1027 output_frame->SetFrameSlot(output_offset, value);
1028 if (FLAG_trace_deopt) {
1029 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] context\n",
1030 top_address + output_offset, output_offset, value, i);
1031 }
1032
1033 // The state is the same except that the kind is unoptimized.
1034 output_offset -= kPointerSize;
1035 input_offset -= kPointerSize;
1036 value =
1037 input_->GetFrameSlot(input_offset) & ~StackHandler::kIsOptimizedMask;
1038 output_frame->SetFrameSlot(output_offset, value);
1039 if (FLAG_trace_deopt) {
1040 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] index + kind\n",
1041 top_address + output_offset, output_offset, value, i);
1042 }
1043
1044 // For all handlers in the frame, the code is the unoptimized code.
1045 output_offset -= kPointerSize;
1046 input_offset -= kPointerSize;
1047 value = reinterpret_cast<uint32_t>(non_optimized_code);
1048 output_frame->SetFrameSlot(output_offset, value);
1049 if (FLAG_trace_deopt) {
1050 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] code\n",
1051 top_address + output_offset, output_offset, value, i);
1052 }
1053
1054 output_offset -= kPointerSize;
1055 input_offset -= kPointerSize;
1056 if (i == 0) {
1057 // Bottommost handler's next link is deoptimization invariant.
1058 value = input_->GetFrameSlot(input_offset);
1059 } else {
1060 value = next_handler;
1061 }
1062 output_frame->SetFrameSlot(output_offset, value);
1063 next_handler = top_address + output_offset;
1064 if (FLAG_trace_deopt) {
1065 PrintF(" 0x%08x: [top + %d] <- 0x%08x ; handler[%d] next\n",
1066 top_address + output_offset, output_offset, value, i);
1067 }
1068 }
1069 *reinterpret_cast<intptr_t*>(isolate_->handler_address()) = next_handler;
1070 }
1071
1072 // Translate the rest of the frame.
1073 while (output_offset > 0) {
1074 output_offset -= kPointerSize;
1075 DoTranslateCommand(iterator, frame_index, output_offset);
1076 }
975 1077
976 // Compute this frame's PC, state, and continuation. 1078 // Compute this frame's PC, state, and continuation.
977 Code* non_optimized_code = function->shared()->code(); 1079 int pc_offset;
978 FixedArray* raw_data = non_optimized_code->deoptimization_data(); 1080 FullCodeGenerator::State state;
979 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data); 1081 Builtins::Name continuation;
980 Address start = non_optimized_code->instruction_start(); 1082 if (isolate_->optimized_handler_patch_buffer() != NULL) {
981 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared()); 1083 ASSERT(frame_index == 0 && output_count_ == 1);
982 unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state); 1084 // Catching in optimized code. Deopt to the corresponding unoptimized
983 uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset); 1085 // catch handler (not to the instruction following the one that threw).
984 output_frame->SetPc(pc_value); 1086 FixedArray* handler_table = non_optimized_code->handler_table();
985 1087 int handler_index = isolate_->optimized_handler_handler_index();
986 FullCodeGenerator::State state = 1088 pc_offset = Smi::cast(handler_table->get(handler_index))->value();
987 FullCodeGenerator::StateField::decode(pc_and_state); 1089 state = FullCodeGenerator::NO_REGISTERS;
1090 continuation = Builtins::kNotifyLazyDeoptimized;
1091 // The exception value is needed in eax.
1092 output_frame->SetRegister(eax.code(),
1093 reinterpret_cast<intptr_t>(isolate_->optimized_pending_exception()));
1094 isolate_->clear_optimized_pending_exception();
1095 } else {
1096 FixedArray* raw_data = non_optimized_code->deoptimization_data();
1097 DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
1098 unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
1099 pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
1100 state = FullCodeGenerator::StateField::decode(pc_and_state);
1101 continuation = (bailout_type_ == EAGER)
1102 ? Builtins::kNotifyDeoptimized
1103 : Builtins::kNotifyLazyDeoptimized;
1104 // For lazy deopt we preserve eax in the stack. Ensure that it is not
1105 // the zap value (a probably-invalid HeapObject*).
1106 // TODO(mmassi): According to Kevin the test should be "!= EAGER"...
1107 if (bailout_type_ == EAGER && is_topmost) {
1108 output_frame->SetRegister(eax.code(),
1109 reinterpret_cast<intptr_t>(Smi::FromInt(0)));
1110 }
1111 }
1112 byte* code_start = non_optimized_code->instruction_start();
1113 output_frame->SetPc(reinterpret_cast<uint32_t>(code_start + pc_offset));
988 output_frame->SetState(Smi::FromInt(state)); 1114 output_frame->SetState(Smi::FromInt(state));
989
990 // Set the continuation for the topmost frame. 1115 // Set the continuation for the topmost frame.
991 if (is_topmost && bailout_type_ != DEBUGGER) { 1116 if (is_topmost && bailout_type_ != DEBUGGER) {
992 Builtins* builtins = isolate_->builtins(); 1117 Builtins* builtins = isolate_->builtins();
993 Code* continuation = (bailout_type_ == EAGER) 1118 byte* entry = builtins->builtin(continuation)->entry();
994 ? builtins->builtin(Builtins::kNotifyDeoptimized) 1119 output_frame->SetContinuation(reinterpret_cast<uint32_t>(entry));
995 : builtins->builtin(Builtins::kNotifyLazyDeoptimized);
996 output_frame->SetContinuation(
997 reinterpret_cast<uint32_t>(continuation->entry()));
998 } 1120 }
999 } 1121 }
1000 1122
1001 1123
1002 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) { 1124 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
1003 // Set the register values. The values are not important as there are no 1125 // Set the register values. The values are not important as there are no
1004 // callee saved registers in JavaScript frames, so all registers are 1126 // callee saved registers in JavaScript frames, so all registers are
1005 // spilled. Registers ebp and esp are set to the correct values though. 1127 // spilled. Registers ebp and esp are set to the correct values though.
1006 1128
1007 for (int i = 0; i < Register::kNumRegisters; i++) { 1129 for (int i = 0; i < Register::kNumRegisters; i++) {
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
1213 } 1335 }
1214 __ bind(&done); 1336 __ bind(&done);
1215 } 1337 }
1216 1338
1217 #undef __ 1339 #undef __
1218 1340
1219 1341
1220 } } // namespace v8::internal 1342 } } // namespace v8::internal
1221 1343
1222 #endif // V8_TARGET_ARCH_IA32 1344 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/ia32/builtins-ia32.cc ('k') | src/ia32/lithium-codegen-ia32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698