| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 562 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 private: | 573 private: |
| 574 static const int kFunctionNameOffset_ = 0; | 574 static const int kFunctionNameOffset_ = 0; |
| 575 static const int kStartPositionOffset_ = 1; | 575 static const int kStartPositionOffset_ = 1; |
| 576 static const int kEndPositionOffset_ = 2; | 576 static const int kEndPositionOffset_ = 2; |
| 577 static const int kSharedInfoOffset_ = 3; | 577 static const int kSharedInfoOffset_ = 3; |
| 578 static const int kSize_ = 4; | 578 static const int kSize_ = 4; |
| 579 | 579 |
| 580 friend class JSArrayBasedStruct<SharedInfoWrapper>; | 580 friend class JSArrayBasedStruct<SharedInfoWrapper>; |
| 581 }; | 581 }; |
| 582 | 582 |
| 583 // Data describing possible stack manipulations or a failure descriptions. |
| 584 // The function index is used both in success/failure cases. |
| 585 class StackManipulationInfo : public JSArrayBasedStruct<StackManipulationInfo> { |
| 586 public: |
| 587 static Handle<JSArray> CreateError(const char* error_message, |
| 588 int function_index) { |
| 589 StackManipulationInfo info = StackManipulationInfo::Create(); |
| 590 info.SetProperties(error_message, function_index, |
| 591 Handle<Object>(Heap::undefined_value())); |
| 592 return info.GetJSArray(); |
| 593 } |
| 594 |
| 595 static Handle<JSArray> CreateSuccess(int bottom_function_index, |
| 596 Handle<Object> drop_data) { |
| 597 StackManipulationInfo info = StackManipulationInfo::Create(); |
| 598 info.SetProperties(NULL, bottom_function_index, drop_data); |
| 599 return info.GetJSArray(); |
| 600 } |
| 601 |
| 602 static Handle<JSArray> CreateEmpty() { |
| 603 StackManipulationInfo info = StackManipulationInfo::Create(); |
| 604 return info.GetJSArray(); |
| 605 } |
| 606 |
| 607 explicit StackManipulationInfo(Handle<JSArray> array) |
| 608 : JSArrayBasedStruct<StackManipulationInfo>(array) { |
| 609 } |
| 610 |
| 611 private: |
| 612 void SetProperties(const char* error_message, int function_index, |
| 613 Handle<Object> drop_data) { |
| 614 HandleScope scope; |
| 615 if (error_message == NULL) { |
| 616 this->SetField(kErrorMessageOffset_, |
| 617 Handle<Object>(Heap::undefined_value())); |
| 618 } else { |
| 619 Handle<String> message_string = |
| 620 Factory::NewStringFromAscii(CStrVector(error_message)); |
| 621 this->SetField(kErrorMessageOffset_, message_string); |
| 622 } |
| 623 this->SetField(kBottomFunctionIndexOffset_, |
| 624 Handle<Object>(Smi::FromInt(function_index))); |
| 625 Handle<JSValue> drop_data_wrapper = WrapInJSValue(*drop_data); |
| 626 this->SetField(kDropDataOffset_, drop_data_wrapper); |
| 627 } |
| 628 |
| 629 static const int kErrorMessageOffset_ = 0; |
| 630 static const int kBottomFunctionIndexOffset_ = 1; |
| 631 static const int kDropDataOffset_ = 2; |
| 632 static const int kSize_ = 3; |
| 633 |
| 634 friend class JSArrayBasedStruct<StackManipulationInfo>; |
| 635 }; |
| 636 |
| 583 class FunctionInfoListener { | 637 class FunctionInfoListener { |
| 584 public: | 638 public: |
| 585 FunctionInfoListener() { | 639 FunctionInfoListener() { |
| 586 current_parent_index_ = -1; | 640 current_parent_index_ = -1; |
| 587 len_ = 0; | 641 len_ = 0; |
| 588 result_ = Factory::NewJSArray(10); | 642 result_ = Factory::NewJSArray(10); |
| 589 } | 643 } |
| 590 | 644 |
| 591 void FunctionStarted(FunctionLiteral* fun) { | 645 void FunctionStarted(FunctionLiteral* fun) { |
| 592 HandleScope scope; | 646 HandleScope scope; |
| 593 FunctionInfoWrapper info = FunctionInfoWrapper::Create(); | 647 FunctionInfoWrapper info = FunctionInfoWrapper::Create(); |
| 594 info.SetInitialProperties(fun->name(), fun->start_position(), | 648 info.SetInitialProperties(fun->name(), fun->start_position(), |
| 595 fun->end_position(), fun->num_parameters(), | 649 fun->end_position(), fun->num_parameters(), |
| 596 current_parent_index_); | 650 current_parent_index_); |
| 597 current_parent_index_ = len_; | 651 current_parent_index_ = len_; |
| 598 SetElement(result_, len_, info.GetJSArray()); | 652 SetElement(result_, len_, info.GetJSArray()); |
| 599 len_++; | 653 len_++; |
| 600 } | 654 } |
| 601 | 655 |
| 602 void FunctionDone() { | 656 void FunctionDone() { |
| 603 HandleScope scope; | 657 HandleScope scope; |
| 604 FunctionInfoWrapper info = | 658 FunctionInfoWrapper info = |
| 605 FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_)); | 659 FunctionInfoWrapper::cast(result_->GetElement(current_parent_index_)); |
| 606 current_parent_index_ = info.GetParentIndex(); | 660 current_parent_index_ = info.GetParentIndex(); |
| 607 } | 661 } |
| 608 | 662 |
| 609 // TODO(LiveEdit): Move private method below. | 663 // TODO(LiveEdit): Move private method below. |
| 610 // This private section was created here to avoid moving the function | 664 // This private section was created here to avoid moving the function |
| 611 // to keep already complex diff simpler. | 665 // to keep already complex diff simpler. |
| 612 private: | 666 private: |
| 613 Object* SerializeFunctionScope(Scope* scope) { | 667 Object* SerializeFunctionScope(Scope* scope) { |
| 614 HandleScope handle_scope; | 668 HandleScope handle_scope; |
| 615 | 669 |
| 616 Handle<JSArray> scope_info_list = Factory::NewJSArray(10); | 670 Handle<JSArray> scope_info_list = Factory::NewJSArray(10); |
| 617 int scope_info_length = 0; | 671 int scope_info_length = 0; |
| 618 | 672 |
| 619 // Saves some description of scope. It stores name and indexes of | 673 // Saves some description of scope. It stores name and indexes of |
| 620 // variables in the whole scope chain. Null-named slots delimit | 674 // variables in the whole scope chain. Null-named slots delimit |
| 621 // scopes of this chain. | 675 // scopes of this chain. |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 790 void VisitThread(ThreadLocalTop* top) { | 844 void VisitThread(ThreadLocalTop* top) { |
| 791 StackFrame::UncookFramesForThread(top); | 845 StackFrame::UncookFramesForThread(top); |
| 792 } | 846 } |
| 793 }; | 847 }; |
| 794 | 848 |
| 795 static void IterateAllThreads(ThreadVisitor* visitor) { | 849 static void IterateAllThreads(ThreadVisitor* visitor) { |
| 796 Top::IterateThread(visitor); | 850 Top::IterateThread(visitor); |
| 797 ThreadManager::IterateArchivedThreads(visitor); | 851 ThreadManager::IterateArchivedThreads(visitor); |
| 798 } | 852 } |
| 799 | 853 |
| 854 // Forward declarations. Introduced to keep functions in the same order |
| 855 // to simplify diff during a complex source modification. |
| 856 // TODO(LiveEdit): reorder functions and get rid of forward declarations |
| 857 static void PerformActiveStackModification( |
| 858 ByteArray* stack_manipulation_data, |
| 859 SharedFunctionInfo* expected_function); |
| 860 static void AddRestarterRInfo(Handle<Code> code, int patch_pc, |
| 861 int source_position); |
| 862 |
| 863 static Handle<Code> PatchCodeWithRestarter(Handle<Code> code, |
| 864 int function_source_pos); |
| 865 |
| 866 |
| 867 |
| 800 // Finds all references to original and replaces them with substitution. | 868 // Finds all references to original and replaces them with substitution. |
| 801 static void ReplaceCodeObject(Code* original, Code* substitution) { | 869 // Performs stack manipulation (if data is provided) in the same transaction. |
| 870 static void ReplaceCodeObject(Code* original, Code* substitution, |
| 871 ByteArray* stack_manipulation_data, |
| 872 SharedFunctionInfo* function) { |
| 802 ASSERT(!Heap::InNewSpace(substitution)); | 873 ASSERT(!Heap::InNewSpace(substitution)); |
| 803 | 874 |
| 804 AssertNoAllocation no_allocations_please; | 875 AssertNoAllocation no_allocations_please; |
| 805 | 876 |
| 806 // A zone scope for ReferenceCollectorVisitor. | 877 // A zone scope for ReferenceCollectorVisitor. |
| 807 ZoneScope scope(DELETE_ON_EXIT); | 878 ZoneScope scope(DELETE_ON_EXIT); |
| 808 | 879 |
| 809 ReferenceCollectorVisitor visitor(original); | 880 ReferenceCollectorVisitor visitor(original); |
| 810 | 881 |
| 811 // Iterate over all roots. Stack frames may have pointer into original code, | 882 // Iterate over all roots. Stack frames may have pointer into original code, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 822 } | 893 } |
| 823 | 894 |
| 824 // Now iterate over all pointers of all objects, including code_target | 895 // Now iterate over all pointers of all objects, including code_target |
| 825 // implicit pointers. | 896 // implicit pointers. |
| 826 HeapIterator iterator; | 897 HeapIterator iterator; |
| 827 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | 898 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
| 828 obj->Iterate(&visitor); | 899 obj->Iterate(&visitor); |
| 829 } | 900 } |
| 830 | 901 |
| 831 visitor.Replace(substitution); | 902 visitor.Replace(substitution); |
| 903 |
| 904 if (stack_manipulation_data != NULL) { |
| 905 // Performs stack manipulations for the cases when the actually function was |
| 906 // on stack. The manipulations are expected to restart this function. |
| 907 PerformActiveStackModification(stack_manipulation_data, function); |
| 908 } |
| 832 } | 909 } |
| 833 | 910 |
| 834 | 911 |
| 835 // Check whether the code is natural function code (not a lazy-compile stub | 912 // Check whether the code is natural function code (not a lazy-compile stub |
| 836 // code). | 913 // code). |
| 837 static bool IsJSFunctionCode(Code* code) { | 914 static bool IsJSFunctionCode(Code* code) { |
| 838 return code->kind() == Code::FUNCTION; | 915 return code->kind() == Code::FUNCTION; |
| 839 } | 916 } |
| 840 | 917 |
| 841 | 918 |
| 842 Object* LiveEdit::ReplaceFunctionCode(Handle<JSArray> new_compile_info_array, | 919 Object* LiveEdit::ReplaceFunctionCode( |
| 843 Handle<JSArray> shared_info_array) { | 920 Handle<JSArray> new_compile_info_array, |
| 921 Handle<JSArray> shared_info_array, |
| 922 Handle<ByteArray> stack_manipulation_data) { |
| 923 |
| 844 HandleScope scope; | 924 HandleScope scope; |
| 845 | |
| 846 if (!SharedInfoWrapper::IsInstance(shared_info_array)) { | 925 if (!SharedInfoWrapper::IsInstance(shared_info_array)) { |
| 847 return Top::ThrowIllegalOperation(); | 926 return Top::ThrowIllegalOperation(); |
| 848 } | 927 } |
| 849 | 928 |
| 850 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array); | 929 FunctionInfoWrapper compile_info_wrapper(new_compile_info_array); |
| 851 SharedInfoWrapper shared_info_wrapper(shared_info_array); | 930 SharedInfoWrapper shared_info_wrapper(shared_info_array); |
| 852 | 931 |
| 853 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); | 932 Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo(); |
| 854 | 933 |
| 934 Handle<Code> new_code = compile_info_wrapper.GetFunctionCode(); |
| 935 |
| 936 shared_info->set_start_position(compile_info_wrapper.GetStartPosition()); |
| 937 shared_info->set_end_position(compile_info_wrapper.GetEndPosition()); |
| 938 |
| 855 if (IsJSFunctionCode(shared_info->code())) { | 939 if (IsJSFunctionCode(shared_info->code())) { |
| 856 ReplaceCodeObject(shared_info->code(), | 940 if (stack_manipulation_data.is_null()) { |
| 857 *(compile_info_wrapper.GetFunctionCode())); | 941 ReplaceCodeObject(shared_info->code(), *new_code, NULL, NULL); |
| 942 } else { |
| 943 new_code = PatchCodeWithRestarter(new_code, |
| 944 shared_info->start_position()); |
| 945 ReplaceCodeObject(shared_info->code(), *new_code, |
| 946 *stack_manipulation_data, *shared_info); |
| 947 } |
| 858 } | 948 } |
| 859 | 949 |
| 860 if (shared_info->debug_info()->IsDebugInfo()) { | 950 if (shared_info->debug_info()->IsDebugInfo()) { |
| 861 Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info())); | 951 Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info())); |
| 862 Handle<Code> new_original_code = | 952 Handle<Code> new_original_code = Factory::CopyCode(new_code); |
| 863 Factory::CopyCode(compile_info_wrapper.GetFunctionCode()); | |
| 864 debug_info->set_original_code(*new_original_code); | 953 debug_info->set_original_code(*new_original_code); |
| 865 } | 954 } |
| 866 | 955 |
| 867 shared_info->set_start_position(compile_info_wrapper.GetStartPosition()); | |
| 868 shared_info->set_end_position(compile_info_wrapper.GetEndPosition()); | |
| 869 | |
| 870 shared_info->set_construct_stub( | 956 shared_info->set_construct_stub( |
| 871 Builtins::builtin(Builtins::JSConstructStubGeneric)); | 957 Builtins::builtin(Builtins::JSConstructStubGeneric)); |
| 872 | 958 |
| 873 return Heap::undefined_value(); | 959 return Heap::undefined_value(); |
| 874 } | 960 } |
| 875 | 961 |
| 876 | 962 |
| 963 // Returns the offset of restarted patch within the code or -1. Technically |
| 964 // patch offset is not its starting point. |
| 965 static int GetRestarterPatchOffset(Code* code) { |
| 966 Handle<Code> restarter_patch( |
| 967 Builtins::builtin(Builtins::RestarterPatch_LiveEdit)); |
| 968 int patch_len = restarter_patch->instruction_size(); |
| 969 if (code->instruction_size() < patch_len) { |
| 970 return -1; |
| 971 } |
| 972 Address pos1 = code->instruction_start() + code->instruction_size(); |
| 973 Address pos2 = restarter_patch->instruction_start() + patch_len; |
| 974 |
| 975 for (int i = 0; i < patch_len; i++) { |
| 976 pos1--; |
| 977 pos2--; |
| 978 if (*pos1 != *pos2) { |
| 979 return -1; |
| 980 } |
| 981 } |
| 982 return code->instruction_size() - patch_len; |
| 983 } |
| 984 |
| 985 |
| 986 bool LiveEdit::IsAtFrameResetPatch(const JavaScriptFrame* frame) { |
| 987 return frame->fp() == Debug::GetRestartedFrameFp(); |
| 988 } |
| 989 |
| 990 |
| 991 Address LiveEdit::GetRestarterPatchEntryPoint(Code* code) { |
| 992 int entry_offset = GetRestarterPatchOffset(code); |
| 993 ASSERT(entry_offset != -1); |
| 994 return code->instruction_start() + entry_offset + |
| 995 Debug::kFrameRestarterEntryOffset; |
| 996 } |
| 997 |
| 998 |
| 999 // Returns patched code instruction offset from entry point. |
| 1000 static Handle<Code> PatchCodeWithRestarter(Handle<Code> code, |
| 1001 int function_source_pos) { |
| 1002 if (GetRestarterPatchOffset(*code) == -1) { |
| 1003 Handle<Code> restarter_patch( |
| 1004 Builtins::builtin(Builtins::RestarterPatch_LiveEdit)); |
| 1005 Handle<Code> patched_code = Factory::AddPatchToCode(code, restarter_patch); |
| 1006 AddRestarterRInfo(patched_code, code->instruction_size(), |
| 1007 function_source_pos); |
| 1008 code = patched_code; |
| 1009 } |
| 1010 return code; |
| 1011 } |
| 1012 |
| 1013 |
| 877 // TODO(635): Eval caches its scripts (same text -- same compiled info). | 1014 // TODO(635): Eval caches its scripts (same text -- same compiled info). |
| 878 // Make sure we clear such caches. | 1015 // Make sure we clear such caches. |
| 879 void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper, | 1016 void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper, |
| 880 Handle<Object> script_handle) { | 1017 Handle<Object> script_handle) { |
| 881 Handle<SharedFunctionInfo> shared_info = | 1018 Handle<SharedFunctionInfo> shared_info = |
| 882 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper)); | 1019 Handle<SharedFunctionInfo>::cast(UnwrapJSValue(function_wrapper)); |
| 883 shared_info->set_script(*script_handle); | 1020 shared_info->set_script(*script_handle); |
| 884 } | 1021 } |
| 885 | 1022 |
| 886 | 1023 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 985 } | 1122 } |
| 986 | 1123 |
| 987 RelocInfoWriter reloc_info_writer_; | 1124 RelocInfoWriter reloc_info_writer_; |
| 988 byte* buffer_; | 1125 byte* buffer_; |
| 989 int buffer_size_; | 1126 int buffer_size_; |
| 990 | 1127 |
| 991 static const int kBufferGap = RelocInfoWriter::kMaxSize; | 1128 static const int kBufferGap = RelocInfoWriter::kMaxSize; |
| 992 static const int kMaximalBufferSize = 512*MB; | 1129 static const int kMaximalBufferSize = 512*MB; |
| 993 }; | 1130 }; |
| 994 | 1131 |
| 995 // Patch positions in code (changes relocation info section) and possibly | 1132 |
| 996 // returns new instance of code. | 1133 static void AddRestarterRInfo(Handle<Code> code, int patch_pc, |
| 997 static Handle<Code> PatchPositionsInCode(Handle<Code> code, | 1134 int source_position) { |
| 1135 RelocInfoBuffer buffer_writer(code->relocation_size(), |
| 1136 code->instruction_start()); |
| 1137 |
| 1138 { |
| 1139 AssertNoAllocation no_allocations_please; |
| 1140 for (RelocIterator it(*code); !it.done(); it.next()) { |
| 1141 buffer_writer.Write(it.rinfo()); |
| 1142 } |
| 1143 byte* pc = code->instruction_start() + patch_pc; |
| 1144 intptr_t position_value = source_position; |
| 1145 RelocInfo additional_info(pc, RelocInfo::POSITION, position_value); |
| 1146 buffer_writer.Write(&additional_info); |
| 1147 } |
| 1148 |
| 1149 Vector<byte> buffer = buffer_writer.GetResult(); |
| 1150 Handle<ByteArray> array = Factory::NewByteArray(buffer.length(), TENURED); |
| 1151 code->set_relocation_info(*array); |
| 1152 |
| 1153 memcpy(code->relocation_start(), buffer.start(), buffer.length()); |
| 1154 } |
| 1155 |
| 1156 |
| 1157 |
| 1158 // Patch positions in code (changes relocation info section). |
| 1159 static void PatchPositionsInCode(Handle<Code> code, |
| 998 Handle<JSArray> position_change_array) { | 1160 Handle<JSArray> position_change_array) { |
| 999 | 1161 |
| 1000 RelocInfoBuffer buffer_writer(code->relocation_size(), | 1162 RelocInfoBuffer buffer_writer(code->relocation_size(), |
| 1001 code->instruction_start()); | 1163 code->instruction_start()); |
| 1002 | 1164 |
| 1003 { | 1165 { |
| 1004 AssertNoAllocation no_allocations_please; | 1166 AssertNoAllocation no_allocations_please; |
| 1005 for (RelocIterator it(*code); !it.done(); it.next()) { | 1167 for (RelocIterator it(*code); !it.done(); it.next()) { |
| 1006 RelocInfo* rinfo = it.rinfo(); | 1168 RelocInfo* rinfo = it.rinfo(); |
| 1007 if (RelocInfo::IsPosition(rinfo->rmode())) { | 1169 if (RelocInfo::IsPosition(rinfo->rmode())) { |
| 1008 int position = static_cast<int>(rinfo->data()); | 1170 int position = static_cast<int>(rinfo->data()); |
| 1009 int new_position = TranslatePosition(position, | 1171 int new_position = TranslatePosition(position, |
| 1010 position_change_array); | 1172 position_change_array); |
| 1011 if (position != new_position) { | 1173 if (position != new_position) { |
| 1012 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position); | 1174 RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position); |
| 1013 buffer_writer.Write(&info_copy); | 1175 buffer_writer.Write(&info_copy); |
| 1014 continue; | 1176 continue; |
| 1015 } | 1177 } |
| 1016 } | 1178 } |
| 1017 buffer_writer.Write(it.rinfo()); | 1179 buffer_writer.Write(it.rinfo()); |
| 1018 } | 1180 } |
| 1019 } | 1181 } |
| 1020 | 1182 |
| 1021 Vector<byte> buffer = buffer_writer.GetResult(); | 1183 Vector<byte> buffer = buffer_writer.GetResult(); |
| 1022 | 1184 |
| 1023 if (buffer.length() == code->relocation_size()) { | 1185 if (buffer.length() != code->relocation_size()) { |
| 1024 // Simply patch relocation area of code. | 1186 // Relocation info section now has different size. |
| 1025 memcpy(code->relocation_start(), buffer.start(), buffer.length()); | 1187 Handle<ByteArray> array = Factory::NewByteArray(buffer.length(), TENURED); |
| 1026 return code; | 1188 code->set_relocation_info(*array); |
| 1027 } else { | |
| 1028 // Relocation info section now has different size. We cannot simply | |
| 1029 // rewrite it inside code object. Instead we have to create a new | |
| 1030 // code object. | |
| 1031 Handle<Code> result(Factory::CopyCode(code, buffer)); | |
| 1032 return result; | |
| 1033 } | 1189 } |
| 1190 memcpy(code->relocation_start(), buffer.start(), buffer.length()); |
| 1034 } | 1191 } |
| 1035 | 1192 |
| 1036 | 1193 |
| 1037 Object* LiveEdit::PatchFunctionPositions( | 1194 Object* LiveEdit::PatchFunctionPositions( |
| 1038 Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) { | 1195 Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) { |
| 1039 | 1196 |
| 1040 if (!SharedInfoWrapper::IsInstance(shared_info_array)) { | 1197 if (!SharedInfoWrapper::IsInstance(shared_info_array)) { |
| 1041 return Top::ThrowIllegalOperation(); | 1198 return Top::ThrowIllegalOperation(); |
| 1042 } | 1199 } |
| 1043 | 1200 |
| 1044 SharedInfoWrapper shared_info_wrapper(shared_info_array); | 1201 SharedInfoWrapper shared_info_wrapper(shared_info_array); |
| 1045 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo(); | 1202 Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo(); |
| 1046 | 1203 |
| 1047 int old_function_start = info->start_position(); | 1204 int old_function_start = info->start_position(); |
| 1048 int new_function_start = TranslatePosition(old_function_start, | 1205 int new_function_start = TranslatePosition(old_function_start, |
| 1049 position_change_array); | 1206 position_change_array); |
| 1050 info->set_start_position(new_function_start); | 1207 info->set_start_position(new_function_start); |
| 1051 info->set_end_position(TranslatePosition(info->end_position(), | 1208 info->set_end_position(TranslatePosition(info->end_position(), |
| 1052 position_change_array)); | 1209 position_change_array)); |
| 1053 | 1210 |
| 1054 info->set_function_token_position( | 1211 info->set_function_token_position( |
| 1055 TranslatePosition(info->function_token_position(), | 1212 TranslatePosition(info->function_token_position(), |
| 1056 position_change_array)); | 1213 position_change_array)); |
| 1057 | 1214 |
| 1058 if (IsJSFunctionCode(info->code())) { | 1215 if (IsJSFunctionCode(info->code())) { |
| 1059 // Patch relocation info section of the code. | 1216 // Patch relocation info section of the code. |
| 1060 Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()), | 1217 PatchPositionsInCode(Handle<Code>(info->code()), position_change_array); |
| 1061 position_change_array); | |
| 1062 if (*patched_code != info->code()) { | |
| 1063 // Replace all references to the code across the heap. In particular, | |
| 1064 // some stubs may refer to this code and this code may be being executed | |
| 1065 // on stack (it is safe to substitute the code object on stack, because | |
| 1066 // we only change the structure of rinfo and leave instructions | |
| 1067 // untouched). | |
| 1068 ReplaceCodeObject(info->code(), *patched_code); | |
| 1069 } | |
| 1070 } | 1218 } |
| 1071 | 1219 |
| 1072 return Heap::undefined_value(); | 1220 return Heap::undefined_value(); |
| 1073 } | 1221 } |
| 1074 | 1222 |
| 1075 | 1223 |
| 1076 static Handle<Script> CreateScriptCopy(Handle<Script> original) { | 1224 static Handle<Script> CreateScriptCopy(Handle<Script> original) { |
| 1077 Handle<String> original_source(String::cast(original->source())); | 1225 Handle<String> original_source(String::cast(original->source())); |
| 1078 | 1226 |
| 1079 Handle<Script> copy = Factory::NewScript(original_source); | 1227 Handle<Script> copy = Factory::NewScript(original_source); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) { | 1279 for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) { |
| 1132 if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) { | 1280 if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) { |
| 1133 if (it.rinfo()->target_object() == *orig_shared) { | 1281 if (it.rinfo()->target_object() == *orig_shared) { |
| 1134 it.rinfo()->set_target_object(*subst_shared); | 1282 it.rinfo()->set_target_object(*subst_shared); |
| 1135 } | 1283 } |
| 1136 } | 1284 } |
| 1137 } | 1285 } |
| 1138 } | 1286 } |
| 1139 | 1287 |
| 1140 | 1288 |
| 1141 // Check an activation against list of functions. If there is a function | 1289 // Check an activation against the list of functions. If there is a function |
| 1142 // that matches, its status in result array is changed to status argument value. | 1290 // that matches its index is returned. Otherwise returns -1. |
| 1143 static bool CheckActivation(Handle<JSArray> shared_info_array, | 1291 static int CheckActivation(Handle<JSArray> shared_info_array, |
| 1144 Handle<JSArray> result, StackFrame* frame, | 1292 StackFrame* frame) { |
| 1145 LiveEdit::FunctionPatchabilityStatus status) { | |
| 1146 if (!frame->is_java_script()) { | 1293 if (!frame->is_java_script()) { |
| 1147 return false; | 1294 return -1; |
| 1148 } | 1295 } |
| 1149 int len = Smi::cast(shared_info_array->length())->value(); | 1296 int len = Smi::cast(shared_info_array->length())->value(); |
| 1150 for (int i = 0; i < len; i++) { | 1297 for (int i = 0; i < len; i++) { |
| 1151 JSValue* wrapper = JSValue::cast(shared_info_array->GetElement(i)); | 1298 JSValue* wrapper = JSValue::cast(shared_info_array->GetElement(i)); |
| 1299 if (!wrapper->value()->IsSharedFunctionInfo()) { |
| 1300 continue; |
| 1301 } |
| 1152 Handle<SharedFunctionInfo> shared( | 1302 Handle<SharedFunctionInfo> shared( |
| 1153 SharedFunctionInfo::cast(wrapper->value())); | 1303 SharedFunctionInfo::cast(wrapper->value())); |
| 1154 | 1304 |
| 1155 if (frame->code() == shared->code()) { | 1305 if (frame->code() == shared->code()) { |
| 1156 SetElement(result, i, Handle<Smi>(Smi::FromInt(status))); | 1306 return i; |
| 1157 return true; | |
| 1158 } | 1307 } |
| 1159 } | 1308 } |
| 1160 return false; | 1309 return -1; |
| 1161 } | 1310 } |
| 1162 | 1311 |
| 1163 | 1312 |
| 1164 // Iterates over handler chain and removes all elements that are inside | 1313 // Iterates over handler chain and removes all elements that are inside |
| 1165 // frames being dropped. | 1314 // frames being dropped. |
| 1166 static bool FixTryCatchHandler(StackFrame* top_frame, | 1315 static bool FixTryCatchHandler(StackFrame* top_frame, |
| 1167 StackFrame* bottom_frame) { | 1316 StackFrame* bottom_frame) { |
| 1168 Address* pointer_address = | 1317 Address* pointer_address = |
| 1169 &Memory::Address_at(Top::get_address_from_id(Top::k_handler_address)); | 1318 &Memory::Address_at(Top::get_address_from_id(Top::k_handler_address)); |
| 1170 | 1319 |
| 1171 while (*pointer_address < top_frame->sp()) { | 1320 while (*pointer_address < top_frame->sp()) { |
| 1172 pointer_address = &Memory::Address_at(*pointer_address); | 1321 pointer_address = &Memory::Address_at(*pointer_address); |
| 1173 } | 1322 } |
| 1174 Address* above_frame_address = pointer_address; | 1323 Address* above_frame_address = pointer_address; |
| 1175 while (*pointer_address < bottom_frame->fp()) { | 1324 while (*pointer_address < bottom_frame->fp()) { |
| 1176 pointer_address = &Memory::Address_at(*pointer_address); | 1325 pointer_address = &Memory::Address_at(*pointer_address); |
| 1177 } | 1326 } |
| 1178 bool change = *above_frame_address != *pointer_address; | 1327 bool change = *above_frame_address != *pointer_address; |
| 1179 *above_frame_address = *pointer_address; | 1328 *above_frame_address = *pointer_address; |
| 1180 return change; | 1329 return change; |
| 1181 } | 1330 } |
| 1182 | 1331 |
| 1183 | 1332 |
| 1184 // Removes specified range of frames from stack. There may be 1 or more | 1333 // If function was in some nested scope (e.g. 'with'), reset it back to |
| 1185 // frames in range. Anyway the bottom frame is restarted rather than dropped, | 1334 // function scope. |
| 1186 // and therefore has to be a JavaScript frame. | 1335 static void ResetFrameScope(JavaScriptFrame* js_frame) { |
| 1187 // Returns error message or NULL. | 1336 Context* original_context = Context::cast(js_frame->context()); |
| 1188 static const char* DropFrames(Vector<StackFrame*> frames, | 1337 Context* context = original_context; |
| 1189 int top_frame_index, | 1338 while (!context->is_function_context()) { |
| 1190 int bottom_js_frame_index, | 1339 context = context->previous(); |
| 1191 Debug::FrameDropMode* mode) { | 1340 ASSERT(context->IsContext()); |
| 1192 if (Debug::kFrameDropperFrameSize < 0) { | |
| 1193 return "Stack manipulations are not supported in this architecture."; | |
| 1194 } | 1341 } |
| 1342 if (original_context != context) { |
| 1343 js_frame->SetContext(context); |
| 1344 } |
| 1345 } |
| 1346 |
| 1347 |
| 1348 // The header of stack modification data that is stored in byte array. |
| 1349 // This header is followed by 3 StackFrame objects. |
| 1350 struct StackModificationPlanHeader { |
| 1351 Address unused_stack_top; |
| 1352 Address unused_stack_bottom; |
| 1353 Debug::FrameDropMode frame_drop_mode; |
| 1354 }; |
| 1355 |
| 1356 |
| 1357 // Plans the stack manipulations. The input defines a range of frames |
| 1358 // with the bottom frames being a JavaScriptFrame. Returns a successfully |
| 1359 // created plan or an error description. |
| 1360 static Handle<JSArray> PrepareDropFrames(Vector<StackFrame*> frames, |
| 1361 int top_frame_index, |
| 1362 int bottom_js_frame_index, |
| 1363 int target_function_index) { |
| 1364 if (Debug::kRestartedFrameHeight < 0) { |
| 1365 return StackManipulationInfo::CreateError( |
| 1366 "Stack manipulations are not supported in this architecture", |
| 1367 target_function_index); |
| 1368 } |
| 1369 |
| 1370 Debug::FrameDropMode mode; |
| 1195 | 1371 |
| 1196 StackFrame* pre_top_frame = frames[top_frame_index - 1]; | 1372 StackFrame* pre_top_frame = frames[top_frame_index - 1]; |
| 1197 StackFrame* top_frame = frames[top_frame_index]; | 1373 StackFrame* top_frame = frames[top_frame_index]; |
| 1198 StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; | 1374 StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; |
| 1199 | 1375 |
| 1200 ASSERT(bottom_js_frame->is_java_script()); | 1376 ASSERT(bottom_js_frame->is_java_script()); |
| 1201 | 1377 |
| 1202 // Check the nature of the top frame. | 1378 // Check the nature of the top frame. |
| 1203 if (pre_top_frame->code()->is_inline_cache_stub() && | 1379 if (pre_top_frame->code()->is_inline_cache_stub() && |
| 1204 pre_top_frame->code()->ic_state() == DEBUG_BREAK) { | 1380 pre_top_frame->code()->ic_state() == DEBUG_BREAK) { |
| 1205 // OK, we can drop inline cache calls. | 1381 // OK, we can drop inline cache calls. |
| 1206 *mode = Debug::FRAME_DROPPED_IN_IC_CALL; | 1382 mode = Debug::FRAME_DROPPED_IN_IC_CALL; |
| 1207 } else if (pre_top_frame->code() == Debug::debug_break_slot()) { | 1383 } else if (pre_top_frame->code() == Debug::debug_break_slot()) { |
| 1208 // OK, we can drop debug break slot. | 1384 // OK, we can drop debug break slot. |
| 1209 *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL; | 1385 mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL; |
| 1210 } else if (pre_top_frame->code() == | 1386 } else if (Debug::GetRestartedFrameFp() != 0) { |
| 1211 Builtins::builtin(Builtins::FrameDropper_LiveEdit)) { | 1387 // The top frame must be restarted. |
| 1212 // OK, we can drop our own code. | 1388 // OK, we can drop our own code. |
| 1213 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL; | 1389 mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL; |
| 1214 } else if (pre_top_frame->code()->kind() == Code::STUB && | 1390 } else if (pre_top_frame->code()->kind() == Code::STUB && |
| 1215 pre_top_frame->code()->major_key()) { | 1391 pre_top_frame->code()->major_key()) { |
| 1216 // Entry from our unit tests, it's fine, we support this case. | 1392 // Entry from our unit tests, it's fine, we support this case. |
| 1217 *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL; | 1393 mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL; |
| 1218 } else { | 1394 } else { |
| 1219 return "Unknown structure of stack above changing function"; | 1395 return StackManipulationInfo::CreateError( |
| 1396 "Unknown structure of stack above JavaScript frames", |
| 1397 target_function_index); |
| 1220 } | 1398 } |
| 1221 | 1399 |
| 1222 Address unused_stack_top = top_frame->sp(); | 1400 Address unused_stack_top = top_frame->sp(); |
| 1223 Address unused_stack_bottom = bottom_js_frame->fp() | 1401 Address unused_stack_bottom = bottom_js_frame->fp() |
| 1224 - Debug::kFrameDropperFrameSize * kPointerSize // Size of the new frame. | 1402 - Debug::kRestartedFrameHeight * kPointerSize // Size of the new frame. |
| 1225 + kPointerSize; // Bigger address end is exclusive. | 1403 + kPointerSize; // Bigger address end is exclusive. |
| 1226 | 1404 |
| 1227 if (unused_stack_top > unused_stack_bottom) { | 1405 if (unused_stack_top > unused_stack_bottom) { |
| 1228 return "Not enough space for frame dropper frame"; | 1406 return StackManipulationInfo::CreateError( |
| 1407 "Not enough space in stack to do stack manipulations", |
| 1408 target_function_index); |
| 1409 } |
| 1410 StackModificationPlanHeader plan; |
| 1411 plan.unused_stack_top = unused_stack_top; |
| 1412 plan.unused_stack_bottom = unused_stack_bottom; |
| 1413 plan.frame_drop_mode = mode; |
| 1414 |
| 1415 StackFrame* three_frames[] = { pre_top_frame, top_frame, bottom_js_frame }; |
| 1416 |
| 1417 int data_size = sizeof(plan); |
| 1418 for (int i = 0; i < 3; i++) { |
| 1419 data_size += GetStackFrameObjectSize(three_frames[i]); |
| 1229 } | 1420 } |
| 1230 | 1421 |
| 1231 // Committing now. After this point we should return only NULL value. | 1422 Handle<ByteArray> array = Factory::NewByteArray(data_size); |
| 1423 { |
| 1424 AssertNoAllocation no_allocations_please; |
| 1425 byte* dst = array->GetDataStartAddress(); |
| 1426 memcpy(dst, &plan, sizeof(plan)); |
| 1427 dst += sizeof(plan); |
| 1428 for (int i = 0; i < 3; i++) { |
| 1429 int size = GetStackFrameObjectSize(three_frames[i]); |
| 1430 memcpy(dst, three_frames[i], size); |
| 1431 dst += size; |
| 1432 } |
| 1433 } |
| 1434 return StackManipulationInfo::CreateSuccess(target_function_index, array); |
| 1435 } |
| 1232 | 1436 |
| 1437 // Actually modifies the active stack. Within the range of frames, |
| 1438 // restarts the function in a bottom one and zeroes out all other. |
| 1439 static void DoDropFrames(StackFrame* pre_top_frame, StackFrame* top_frame, |
| 1440 JavaScriptFrame* bottom_js_frame, |
| 1441 Address unused_stack_top, Address unused_stack_bottom, |
| 1442 SharedFunctionInfo* expected_function) { |
| 1233 FixTryCatchHandler(pre_top_frame, bottom_js_frame); | 1443 FixTryCatchHandler(pre_top_frame, bottom_js_frame); |
| 1234 // Make sure FixTryCatchHandler is idempotent. | 1444 // Make sure FixTryCatchHandler is idempotent. |
| 1235 ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); | 1445 ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); |
| 1236 | 1446 |
| 1237 Handle<Code> code(Builtins::builtin(Builtins::FrameDropper_LiveEdit)); | 1447 ResetFrameScope(bottom_js_frame); |
| 1238 top_frame->set_pc(code->entry()); | 1448 |
| 1449 SharedFunctionInfo* bottom_function = |
| 1450 JSFunction::cast(bottom_js_frame->function())->shared(); |
| 1451 |
| 1452 ASSERT_EQ(bottom_function, expected_function); |
| 1453 |
| 1454 Code* bottom_frame_code = bottom_function->code(); |
| 1455 |
| 1456 top_frame->set_pc(LiveEdit::GetRestarterPatchEntryPoint(bottom_frame_code)); |
| 1239 pre_top_frame->SetCallerFp(bottom_js_frame->fp()); | 1457 pre_top_frame->SetCallerFp(bottom_js_frame->fp()); |
| 1240 | 1458 |
| 1241 Debug::SetUpFrameDropperFrame(bottom_js_frame, code); | |
| 1242 | |
| 1243 for (Address a = unused_stack_top; | 1459 for (Address a = unused_stack_top; |
| 1244 a < unused_stack_bottom; | 1460 a < unused_stack_bottom; |
| 1245 a += kPointerSize) { | 1461 a += kPointerSize) { |
| 1246 Memory::Object_at(a) = Smi::FromInt(0); | 1462 Memory::Object_at(a) = Smi::FromInt(0); |
| 1247 } | 1463 } |
| 1464 } |
| 1248 | 1465 |
| 1249 return NULL; | |
| 1250 } | |
| 1251 | 1466 |
| 1252 | 1467 |
| 1253 static bool IsDropableFrame(StackFrame* frame) { | 1468 static bool IsDropableFrame(StackFrame* frame) { |
| 1254 return !frame->is_exit(); | 1469 return !frame->is_exit(); |
| 1255 } | 1470 } |
| 1256 | 1471 |
| 1257 // Fills result array with statuses of functions. Modifies the stack | 1472 // Iterates over the stack and decides whether it contains any of listed |
| 1258 // removing all listed function if possible and if do_drop is true. | 1473 // functions' activations or not. If it does contain, return the plan on |
| 1259 static const char* DropActivationsInActiveThread( | 1474 // how the stack could be modified or failure description. |
| 1260 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) { | 1475 static Handle<JSArray> PrepareActiveStackModification( |
| 1476 Handle<JSArray> shared_info_array) { |
| 1261 | 1477 |
| 1262 ZoneScope scope(DELETE_ON_EXIT); | 1478 ZoneScope scope(DELETE_ON_EXIT); |
| 1263 Vector<StackFrame*> frames = CreateStackMap(); | 1479 Vector<StackFrame*> frames = CreateStackMap(); |
| 1264 | 1480 |
| 1265 int array_len = Smi::cast(shared_info_array->length())->value(); | |
| 1266 | |
| 1267 int top_frame_index = -1; | 1481 int top_frame_index = -1; |
| 1268 int frame_index = 0; | 1482 int frame_index = 0; |
| 1269 for (; frame_index < frames.length(); frame_index++) { | 1483 for (; frame_index < frames.length(); frame_index++) { |
| 1270 StackFrame* frame = frames[frame_index]; | 1484 StackFrame* frame = frames[frame_index]; |
| 1271 if (frame->id() == Debug::break_frame_id()) { | 1485 if (frame->id() == Debug::break_frame_id()) { |
| 1272 top_frame_index = frame_index; | 1486 top_frame_index = frame_index; |
| 1273 break; | 1487 break; |
| 1274 } | 1488 } |
| 1275 if (CheckActivation(shared_info_array, result, frame, | 1489 int problem_function_index = CheckActivation(shared_info_array, frame); |
| 1276 LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) { | 1490 if (problem_function_index != -1) { |
| 1277 // We are still above break_frame. It is not a target frame, | 1491 return StackManipulationInfo::CreateError( |
| 1278 // it is a problem. | 1492 "Debugger mark-up on stack is not found", |
| 1279 return "Debugger mark-up on stack is not found"; | 1493 problem_function_index); |
| 1280 } | 1494 } |
| 1281 } | 1495 } |
| 1282 | 1496 |
| 1283 if (top_frame_index == -1) { | 1497 if (top_frame_index == -1) { |
| 1284 // We haven't found break frame, but no function is blocking us anyway. | 1498 // We haven't found break frame, but no function is blocking us anyway. |
| 1285 return NULL; | 1499 return StackManipulationInfo::CreateEmpty(); |
| 1286 } | 1500 } |
| 1287 | 1501 |
| 1288 bool target_frame_found = false; | 1502 int target_function_index = -1; |
| 1289 int bottom_js_frame_index = top_frame_index; | 1503 int bottom_js_frame_index = top_frame_index; |
| 1290 bool c_code_found = false; | 1504 bool c_code_found = false; |
| 1291 | 1505 |
| 1292 for (; frame_index < frames.length(); frame_index++) { | 1506 for (; frame_index < frames.length(); frame_index++) { |
| 1293 StackFrame* frame = frames[frame_index]; | 1507 StackFrame* frame = frames[frame_index]; |
| 1294 if (!IsDropableFrame(frame)) { | 1508 if (!IsDropableFrame(frame)) { |
| 1295 c_code_found = true; | 1509 c_code_found = true; |
| 1296 break; | 1510 break; |
| 1297 } | 1511 } |
| 1298 if (CheckActivation(shared_info_array, result, frame, | 1512 int problem_function_index = CheckActivation(shared_info_array, frame); |
| 1299 LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { | 1513 if (problem_function_index != -1) { |
| 1300 target_frame_found = true; | 1514 target_function_index = problem_function_index; |
| 1301 bottom_js_frame_index = frame_index; | 1515 bottom_js_frame_index = frame_index; |
| 1302 } | 1516 } |
| 1303 } | 1517 } |
| 1304 | 1518 |
| 1305 if (c_code_found) { | 1519 if (c_code_found) { |
| 1306 // There is a C frames on stack. Check that there are no target frames | 1520 // There is a C frames on stack. Check that there are no target frames |
| 1307 // below them. | 1521 // below them. |
| 1308 for (; frame_index < frames.length(); frame_index++) { | 1522 for (; frame_index < frames.length(); frame_index++) { |
| 1309 StackFrame* frame = frames[frame_index]; | 1523 StackFrame* frame = frames[frame_index]; |
| 1310 if (frame->is_java_script()) { | 1524 if (frame->is_java_script()) { |
| 1311 if (CheckActivation(shared_info_array, result, frame, | 1525 int problem_function_index = CheckActivation(shared_info_array, frame); |
| 1312 LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) { | 1526 if (problem_function_index != -1) { |
| 1313 // Cannot drop frame under C frames. | 1527 return StackManipulationInfo::CreateError( |
| 1314 return NULL; | 1528 "Cannot drop frame under C frames", |
| 1529 problem_function_index); |
| 1315 } | 1530 } |
| 1316 } | 1531 } |
| 1317 } | 1532 } |
| 1318 } | 1533 } |
| 1319 | 1534 |
| 1320 if (!do_drop) { | 1535 if (target_function_index == -1) { |
| 1321 // We are in check-only mode. | 1536 return StackManipulationInfo::CreateEmpty(); |
| 1322 return NULL; | |
| 1323 } | 1537 } |
| 1324 | 1538 |
| 1325 if (!target_frame_found) { | 1539 return PrepareDropFrames(frames, top_frame_index, bottom_js_frame_index, |
| 1326 // Nothing to drop. | 1540 target_function_index); |
| 1327 return NULL; | 1541 } |
| 1542 |
| 1543 |
| 1544 // Unpacks stack manipulation data and operates stack manipulation procedure. |
| 1545 static void PerformActiveStackModification( |
| 1546 ByteArray* stack_manipulation_data, |
| 1547 SharedFunctionInfo* expected_function) { |
| 1548 StackModificationPlanHeader* plan = |
| 1549 reinterpret_cast<StackModificationPlanHeader*>( |
| 1550 stack_manipulation_data->GetDataStartAddress()); |
| 1551 |
| 1552 StackFrame* pre_top_frame; |
| 1553 StackFrame* top_frame; |
| 1554 StackFrame* bottom_frame; |
| 1555 { |
| 1556 byte* pos = reinterpret_cast<byte*>(plan); |
| 1557 pos += sizeof(StackModificationPlanHeader); |
| 1558 pre_top_frame = reinterpret_cast<StackFrame*>(pos); |
| 1559 pos += GetStackFrameObjectSize(pre_top_frame); |
| 1560 top_frame = reinterpret_cast<StackFrame*>(pos); |
| 1561 pos += GetStackFrameObjectSize(top_frame); |
| 1562 bottom_frame = reinterpret_cast<StackFrame*>(pos); |
| 1328 } | 1563 } |
| 1564 JavaScriptFrame* bottom_js_frame = JavaScriptFrame::cast(bottom_frame); |
| 1329 | 1565 |
| 1330 Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED; | |
| 1331 const char* error_message = DropFrames(frames, top_frame_index, | |
| 1332 bottom_js_frame_index, &drop_mode); | |
| 1333 | 1566 |
| 1334 if (error_message != NULL) { | 1567 DoDropFrames(pre_top_frame, top_frame, bottom_js_frame, |
| 1335 return error_message; | 1568 plan->unused_stack_top, plan->unused_stack_bottom, |
| 1336 } | 1569 expected_function); |
| 1337 | 1570 |
| 1338 // Adjust break_frame after some frames has been dropped. | 1571 Debug::FramesHaveBeenDropped(bottom_js_frame, plan->frame_drop_mode); |
| 1339 StackFrame::Id new_id = StackFrame::NO_ID; | 1572 ASSERT(LiveEdit::IsAtFrameResetPatch(bottom_js_frame)); |
| 1340 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) { | |
| 1341 if (frames[i]->type() == StackFrame::JAVA_SCRIPT) { | |
| 1342 new_id = frames[i]->id(); | |
| 1343 break; | |
| 1344 } | |
| 1345 } | |
| 1346 Debug::FramesHaveBeenDropped(new_id, drop_mode); | |
| 1347 | |
| 1348 // Replace "blocked on active" with "replaced on active" status. | |
| 1349 for (int i = 0; i < array_len; i++) { | |
| 1350 if (result->GetElement(i) == | |
| 1351 Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { | |
| 1352 result->SetElement(i, Smi::FromInt( | |
| 1353 LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK)); | |
| 1354 } | |
| 1355 } | |
| 1356 return NULL; | |
| 1357 } | 1573 } |
| 1358 | 1574 |
| 1359 | 1575 |
| 1360 class InactiveThreadActivationsChecker : public ThreadVisitor { | 1576 class InactiveThreadActivationsChecker : public ThreadVisitor { |
| 1361 public: | 1577 public: |
| 1362 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array, | 1578 explicit InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array) |
| 1363 Handle<JSArray> result) | 1579 : shared_info_array_(shared_info_array), blocked_function_index_(-1) { |
| 1364 : shared_info_array_(shared_info_array), result_(result), | |
| 1365 has_blocked_functions_(false) { | |
| 1366 } | 1580 } |
| 1367 void VisitThread(ThreadLocalTop* top) { | 1581 void VisitThread(ThreadLocalTop* top) { |
| 1368 for (StackFrameIterator it(top); !it.done(); it.Advance()) { | 1582 for (StackFrameIterator it(top); !it.done(); it.Advance()) { |
| 1369 has_blocked_functions_ |= CheckActivation( | 1583 if (blocked_function_index_ == -1) { |
| 1370 shared_info_array_, result_, it.frame(), | 1584 blocked_function_index_ = CheckActivation(shared_info_array_, |
| 1371 LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK); | 1585 it.frame()); |
| 1586 } |
| 1372 } | 1587 } |
| 1373 } | 1588 } |
| 1374 bool HasBlockedFunctions() { | 1589 int GetBlockedFunctionIndex() { |
| 1375 return has_blocked_functions_; | 1590 return blocked_function_index_; |
| 1376 } | 1591 } |
| 1377 | 1592 |
| 1378 private: | 1593 private: |
| 1379 Handle<JSArray> shared_info_array_; | 1594 Handle<JSArray> shared_info_array_; |
| 1380 Handle<JSArray> result_; | 1595 int blocked_function_index_; |
| 1381 bool has_blocked_functions_; | |
| 1382 }; | 1596 }; |
| 1383 | 1597 |
| 1384 | 1598 |
| 1385 Handle<JSArray> LiveEdit::CheckAndDropActivations( | 1599 Handle<JSArray> LiveEdit::CheckActivations(Handle<JSArray> shared_info_array) { |
| 1386 Handle<JSArray> shared_info_array, bool do_drop) { | 1600 // First check inactive threads. Fail if some functions are blocked there. |
| 1387 int len = Smi::cast(shared_info_array->length())->value(); | 1601 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array); |
| 1602 ThreadManager::IterateArchivedThreads(&inactive_threads_checker); |
| 1388 | 1603 |
| 1389 Handle<JSArray> result = Factory::NewJSArray(len); | 1604 if (inactive_threads_checker.GetBlockedFunctionIndex() != -1) { |
| 1390 | 1605 return StackManipulationInfo::CreateError( |
| 1391 // Fill the default values. | 1606 "Cannot patch function that is activated in inactive thread", |
| 1392 for (int i = 0; i < len; i++) { | 1607 inactive_threads_checker.GetBlockedFunctionIndex()); |
| 1393 SetElement(result, i, | |
| 1394 Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH))); | |
| 1395 } | 1608 } |
| 1396 | 1609 |
| 1397 | 1610 return PrepareActiveStackModification(shared_info_array); |
| 1398 // First check inactive threads. Fail if some functions are blocked there. | |
| 1399 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array, | |
| 1400 result); | |
| 1401 ThreadManager::IterateArchivedThreads(&inactive_threads_checker); | |
| 1402 if (inactive_threads_checker.HasBlockedFunctions()) { | |
| 1403 return result; | |
| 1404 } | |
| 1405 | |
| 1406 // Try to drop activations from the current stack. | |
| 1407 const char* error_message = | |
| 1408 DropActivationsInActiveThread(shared_info_array, result, do_drop); | |
| 1409 if (error_message != NULL) { | |
| 1410 // Add error message as an array extra element. | |
| 1411 Vector<const char> vector_message(error_message, StrLength(error_message)); | |
| 1412 Handle<String> str = Factory::NewStringFromAscii(vector_message); | |
| 1413 SetElement(result, len, str); | |
| 1414 } | |
| 1415 return result; | |
| 1416 } | 1611 } |
| 1417 | 1612 |
| 1418 | 1613 |
| 1419 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { | 1614 LiveEditFunctionTracker::LiveEditFunctionTracker(FunctionLiteral* fun) { |
| 1420 if (active_function_info_listener != NULL) { | 1615 if (active_function_info_listener != NULL) { |
| 1421 active_function_info_listener->FunctionStarted(fun); | 1616 active_function_info_listener->FunctionStarted(fun); |
| 1422 } | 1617 } |
| 1423 } | 1618 } |
| 1424 | 1619 |
| 1425 | 1620 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1471 | 1666 |
| 1472 bool LiveEditFunctionTracker::IsActive() { | 1667 bool LiveEditFunctionTracker::IsActive() { |
| 1473 return false; | 1668 return false; |
| 1474 } | 1669 } |
| 1475 | 1670 |
| 1476 #endif // ENABLE_DEBUGGER_SUPPORT | 1671 #endif // ENABLE_DEBUGGER_SUPPORT |
| 1477 | 1672 |
| 1478 | 1673 |
| 1479 | 1674 |
| 1480 } } // namespace v8::internal | 1675 } } // namespace v8::internal |
| OLD | NEW |