OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/isolate_reload.h" | 5 #include "vm/isolate_reload.h" |
6 | 6 |
7 #include "vm/become.h" | 7 #include "vm/become.h" |
8 #include "vm/code_generator.h" | 8 #include "vm/code_generator.h" |
9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
10 #include "vm/dart_api_impl.h" | 10 #include "vm/dart_api_impl.h" |
11 #include "vm/hash_table.h" | 11 #include "vm/hash_table.h" |
12 #include "vm/isolate.h" | 12 #include "vm/isolate.h" |
13 #include "vm/log.h" | 13 #include "vm/log.h" |
14 #include "vm/object.h" | 14 #include "vm/object.h" |
15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
16 #include "vm/parser.h" | 16 #include "vm/parser.h" |
17 #include "vm/safepoint.h" | 17 #include "vm/safepoint.h" |
18 #include "vm/service_event.h" | 18 #include "vm/service_event.h" |
19 #include "vm/stack_frame.h" | 19 #include "vm/stack_frame.h" |
20 #include "vm/thread.h" | 20 #include "vm/thread.h" |
21 #include "vm/timeline.h" | 21 #include "vm/timeline.h" |
22 #include "vm/visitor.h" | 22 #include "vm/visitor.h" |
23 | 23 |
24 namespace dart { | 24 namespace dart { |
25 | 25 |
26 DEFINE_FLAG(bool, trace_reload, false, "Trace isolate reloading"); | 26 DEFINE_FLAG(bool, trace_reload, false, "Trace isolate reloading"); |
| 27 DEFINE_FLAG(bool, trace_reload_verbose, false, |
| 28 "trace isolate reloading verbose"); |
27 DEFINE_FLAG(bool, identity_reload, false, "Enable checks for identity reload."); | 29 DEFINE_FLAG(bool, identity_reload, false, "Enable checks for identity reload."); |
28 DEFINE_FLAG(int, reload_every, 0, "Reload every N stack overflow checks."); | 30 DEFINE_FLAG(int, reload_every, 0, "Reload every N stack overflow checks."); |
29 DEFINE_FLAG(bool, reload_every_optimized, true, "Only from optimized code."); | 31 DEFINE_FLAG(bool, reload_every_optimized, true, "Only from optimized code."); |
30 DEFINE_FLAG(bool, reload_every_back_off, false, | 32 DEFINE_FLAG(bool, reload_every_back_off, false, |
31 "Double the --reload-every value after each reload."); | 33 "Double the --reload-every value after each reload."); |
32 DEFINE_FLAG(bool, check_reloaded, false, | 34 DEFINE_FLAG(bool, check_reloaded, false, |
33 "Assert that an isolate has reloaded at least once.") | 35 "Assert that an isolate has reloaded at least once.") |
34 #ifndef PRODUCT | 36 #ifndef PRODUCT |
35 | 37 |
36 #define I (isolate()) | 38 #define I (isolate()) |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 static uword Hash(const Object& obj) { | 112 static uword Hash(const Object& obj) { |
111 if (obj.IsLibrary()) { | 113 if (obj.IsLibrary()) { |
112 return Library::Cast(obj).UrlHash(); | 114 return Library::Cast(obj).UrlHash(); |
113 } else if (obj.IsClass()) { | 115 } else if (obj.IsClass()) { |
114 if (Class::Cast(obj).id() == kFreeListElement) { | 116 if (Class::Cast(obj).id() == kFreeListElement) { |
115 return 0; | 117 return 0; |
116 } | 118 } |
117 return String::HashRawSymbol(Class::Cast(obj).Name()); | 119 return String::HashRawSymbol(Class::Cast(obj).Name()); |
118 } else if (obj.IsField()) { | 120 } else if (obj.IsField()) { |
119 return String::HashRawSymbol(Field::Cast(obj).name()); | 121 return String::HashRawSymbol(Field::Cast(obj).name()); |
| 122 } else if (obj.IsInstance()) { |
| 123 return Smi::Handle(Smi::RawCast(Instance::Cast(obj).HashCode())).Value(); |
120 } | 124 } |
121 return 0; | 125 return 0; |
122 } | 126 } |
123 }; | 127 }; |
124 | 128 |
125 | 129 |
126 bool IsolateReloadContext::IsSameField(const Field& a, const Field& b) { | 130 bool IsolateReloadContext::IsSameField(const Field& a, const Field& b) { |
127 if (a.is_static() != b.is_static()) { | 131 if (a.is_static() != b.is_static()) { |
128 return false; | 132 return false; |
129 } | 133 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 saved_num_cids_(-1), | 185 saved_num_cids_(-1), |
182 saved_class_table_(NULL), | 186 saved_class_table_(NULL), |
183 num_saved_libs_(-1), | 187 num_saved_libs_(-1), |
184 script_uri_(String::null()), | 188 script_uri_(String::null()), |
185 error_(Error::null()), | 189 error_(Error::null()), |
186 old_classes_set_storage_(Array::null()), | 190 old_classes_set_storage_(Array::null()), |
187 class_map_storage_(Array::null()), | 191 class_map_storage_(Array::null()), |
188 old_libraries_set_storage_(Array::null()), | 192 old_libraries_set_storage_(Array::null()), |
189 library_map_storage_(Array::null()), | 193 library_map_storage_(Array::null()), |
190 become_map_storage_(Array::null()), | 194 become_map_storage_(Array::null()), |
| 195 become_enum_mappings_(GrowableObjectArray::null()), |
191 saved_root_library_(Library::null()), | 196 saved_root_library_(Library::null()), |
192 saved_libraries_(GrowableObjectArray::null()) { | 197 saved_libraries_(GrowableObjectArray::null()) { |
193 // NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not | 198 // NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not |
194 // associated with the isolate yet and if a GC is triggered here the raw | 199 // associated with the isolate yet and if a GC is triggered here the raw |
195 // objects will not be properly accounted for. | 200 // objects will not be properly accounted for. |
196 } | 201 } |
197 | 202 |
198 | 203 |
199 IsolateReloadContext::~IsolateReloadContext() { | 204 IsolateReloadContext::~IsolateReloadContext() { |
200 } | 205 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 old_classes_set_storage_ = | 242 old_classes_set_storage_ = |
238 HashTables::New<UnorderedHashSet<ClassMapTraits> >(4); | 243 HashTables::New<UnorderedHashSet<ClassMapTraits> >(4); |
239 class_map_storage_ = | 244 class_map_storage_ = |
240 HashTables::New<UnorderedHashMap<ClassMapTraits> >(4); | 245 HashTables::New<UnorderedHashMap<ClassMapTraits> >(4); |
241 old_libraries_set_storage_ = | 246 old_libraries_set_storage_ = |
242 HashTables::New<UnorderedHashSet<LibraryMapTraits> >(4); | 247 HashTables::New<UnorderedHashSet<LibraryMapTraits> >(4); |
243 library_map_storage_ = | 248 library_map_storage_ = |
244 HashTables::New<UnorderedHashMap<LibraryMapTraits> >(4); | 249 HashTables::New<UnorderedHashMap<LibraryMapTraits> >(4); |
245 become_map_storage_ = | 250 become_map_storage_ = |
246 HashTables::New<UnorderedHashMap<BecomeMapTraits> >(4); | 251 HashTables::New<UnorderedHashMap<BecomeMapTraits> >(4); |
| 252 // Keep a separate array for enum mappings to avoid having to invoke |
| 253 // hashCode on the instances. |
| 254 become_enum_mappings_ = GrowableObjectArray::New(Heap::kOld); |
247 | 255 |
248 // Disable the background compiler while we are performing the reload. | 256 // Disable the background compiler while we are performing the reload. |
249 BackgroundCompiler::Disable(); | 257 BackgroundCompiler::Disable(); |
250 | 258 |
251 if (FLAG_write_protect_code) { | 259 if (FLAG_write_protect_code) { |
252 // Disable code page write protection while we are reloading. | 260 // Disable code page write protection while we are reloading. |
253 I->heap()->WriteProtectCode(false); | 261 I->heap()->WriteProtectCode(false); |
254 } | 262 } |
255 | 263 |
256 // Ensure all functions on the stack have unoptimized code. | 264 // Ensure all functions on the stack have unoptimized code. |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 { | 603 { |
596 UnorderedHashMap<ClassMapTraits>::Iterator it(&class_map); | 604 UnorderedHashMap<ClassMapTraits>::Iterator it(&class_map); |
597 while (it.MoveNext()) { | 605 while (it.MoveNext()) { |
598 const intptr_t entry = it.Current(); | 606 const intptr_t entry = it.Current(); |
599 new_cls = Class::RawCast(class_map.GetKey(entry)); | 607 new_cls = Class::RawCast(class_map.GetKey(entry)); |
600 cls = Class::RawCast(class_map.GetPayload(entry, 0)); | 608 cls = Class::RawCast(class_map.GetPayload(entry, 0)); |
601 if (new_cls.raw() != cls.raw()) { | 609 if (new_cls.raw() != cls.raw()) { |
602 ASSERT(new_cls.is_enum_class() == cls.is_enum_class()); | 610 ASSERT(new_cls.is_enum_class() == cls.is_enum_class()); |
603 if (new_cls.is_enum_class() && new_cls.is_finalized()) { | 611 if (new_cls.is_enum_class() && new_cls.is_finalized()) { |
604 new_cls.ReplaceEnum(cls); | 612 new_cls.ReplaceEnum(cls); |
| 613 } else { |
| 614 new_cls.CopyStaticFieldValues(cls); |
605 } | 615 } |
606 new_cls.CopyStaticFieldValues(cls); | |
607 cls.PatchFieldsAndFunctions(); | 616 cls.PatchFieldsAndFunctions(); |
608 } | 617 } |
609 } | 618 } |
610 } | 619 } |
611 | 620 |
612 class_map.Release(); | 621 class_map.Release(); |
613 } | 622 } |
614 | 623 |
615 // Copy over certain properties of libraries, e.g. is the library | 624 // Copy over certain properties of libraries, e.g. is the library |
616 // debuggable? | 625 // debuggable? |
(...skipping 22 matching lines...) Expand all Loading... |
639 } | 648 } |
640 | 649 |
641 { | 650 { |
642 TIMELINE_SCOPE(UpdateLibrariesArray); | 651 TIMELINE_SCOPE(UpdateLibrariesArray); |
643 // Update the libraries array. | 652 // Update the libraries array. |
644 Library& lib = Library::Handle(); | 653 Library& lib = Library::Handle(); |
645 const GrowableObjectArray& libs = GrowableObjectArray::Handle( | 654 const GrowableObjectArray& libs = GrowableObjectArray::Handle( |
646 I->object_store()->libraries()); | 655 I->object_store()->libraries()); |
647 for (intptr_t i = 0; i < libs.Length(); i++) { | 656 for (intptr_t i = 0; i < libs.Length(); i++) { |
648 lib = Library::RawCast(libs.At(i)); | 657 lib = Library::RawCast(libs.At(i)); |
649 TIR_Print("Lib '%s' at index %" Pd "\n", lib.ToCString(), i); | 658 VTIR_Print("Lib '%s' at index %" Pd "\n", lib.ToCString(), i); |
650 lib.set_index(i); | 659 lib.set_index(i); |
651 } | 660 } |
652 | 661 |
653 // Initialize library side table. | 662 // Initialize library side table. |
654 library_infos_.SetLength(libs.Length()); | 663 library_infos_.SetLength(libs.Length()); |
655 for (intptr_t i = 0; i < libs.Length(); i++) { | 664 for (intptr_t i = 0; i < libs.Length(); i++) { |
656 lib = Library::RawCast(libs.At(i)); | 665 lib = Library::RawCast(libs.At(i)); |
657 // Mark the library dirty if it comes after the libraries we saved. | 666 // Mark the library dirty if it comes after the libraries we saved. |
658 library_infos_[i].dirty = i >= num_saved_libs_; | 667 library_infos_[i].dirty = i >= num_saved_libs_; |
659 } | 668 } |
660 } | 669 } |
661 | 670 |
662 { | 671 { |
| 672 const GrowableObjectArray& become_enum_mappings = |
| 673 GrowableObjectArray::Handle(become_enum_mappings_); |
663 UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_); | 674 UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_); |
664 intptr_t replacement_count = become_map.NumOccupied(); | 675 intptr_t replacement_count = become_map.NumOccupied() + |
| 676 become_enum_mappings.Length() / 2; |
665 const Array& before = | 677 const Array& before = |
666 Array::Handle(Array::New(replacement_count, Heap::kOld)); | 678 Array::Handle(Array::New(replacement_count, Heap::kOld)); |
667 const Array& after = | 679 const Array& after = |
668 Array::Handle(Array::New(replacement_count, Heap::kOld)); | 680 Array::Handle(Array::New(replacement_count, Heap::kOld)); |
669 Object& obj = Object::Handle(); | 681 Object& obj = Object::Handle(); |
670 intptr_t replacement_index = 0; | 682 intptr_t replacement_index = 0; |
671 UnorderedHashMap<BecomeMapTraits>::Iterator it(&become_map); | 683 UnorderedHashMap<BecomeMapTraits>::Iterator it(&become_map); |
672 while (it.MoveNext()) { | 684 while (it.MoveNext()) { |
673 const intptr_t entry = it.Current(); | 685 const intptr_t entry = it.Current(); |
674 obj = become_map.GetKey(entry); | 686 obj = become_map.GetKey(entry); |
675 before.SetAt(replacement_index, obj); | 687 before.SetAt(replacement_index, obj); |
676 obj = become_map.GetPayload(entry, 0); | 688 obj = become_map.GetPayload(entry, 0); |
677 after.SetAt(replacement_index, obj); | 689 after.SetAt(replacement_index, obj); |
678 replacement_index++; | 690 replacement_index++; |
679 } | 691 } |
| 692 for (intptr_t i = 0; i < become_enum_mappings.Length(); i += 2) { |
| 693 obj = become_enum_mappings.At(i); |
| 694 before.SetAt(replacement_index, obj); |
| 695 obj = become_enum_mappings.At(i + 1); |
| 696 after.SetAt(replacement_index, obj); |
| 697 replacement_index++; |
| 698 } |
680 ASSERT(replacement_index == replacement_count); | 699 ASSERT(replacement_index == replacement_count); |
681 become_map.Release(); | 700 become_map.Release(); |
682 | 701 |
683 Become::ElementsForwardIdentity(before, after); | 702 Become::ElementsForwardIdentity(before, after); |
684 } | 703 } |
685 | 704 |
686 if (FLAG_identity_reload) { | 705 if (FLAG_identity_reload) { |
687 if (saved_num_cids_ != I->class_table()->NumCids()) { | 706 if (saved_num_cids_ != I->class_table()->NumCids()) { |
688 TIR_Print("Identity reload failed! B#C=%" Pd " A#C=%" Pd "\n", | 707 TIR_Print("Identity reload failed! B#C=%" Pd " A#C=%" Pd "\n", |
689 saved_num_cids_, | 708 saved_num_cids_, |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1062 void IsolateReloadContext::AddBecomeMapping(const Object& old, | 1081 void IsolateReloadContext::AddBecomeMapping(const Object& old, |
1063 const Object& neu) { | 1082 const Object& neu) { |
1064 ASSERT(become_map_storage_ != Array::null()); | 1083 ASSERT(become_map_storage_ != Array::null()); |
1065 UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_); | 1084 UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_); |
1066 bool update = become_map.UpdateOrInsert(old, neu); | 1085 bool update = become_map.UpdateOrInsert(old, neu); |
1067 ASSERT(!update); | 1086 ASSERT(!update); |
1068 become_map_storage_ = become_map.Release().raw(); | 1087 become_map_storage_ = become_map.Release().raw(); |
1069 } | 1088 } |
1070 | 1089 |
1071 | 1090 |
| 1091 void IsolateReloadContext::AddEnumBecomeMapping(const Object& old, |
| 1092 const Object& neu) { |
| 1093 const GrowableObjectArray& become_enum_mappings = |
| 1094 GrowableObjectArray::Handle(become_enum_mappings_); |
| 1095 become_enum_mappings.Add(old); |
| 1096 become_enum_mappings.Add(neu); |
| 1097 ASSERT((become_enum_mappings.Length() % 2) == 0); |
| 1098 } |
| 1099 |
| 1100 |
1072 void IsolateReloadContext::RebuildDirectSubclasses() { | 1101 void IsolateReloadContext::RebuildDirectSubclasses() { |
1073 ClassTable* class_table = I->class_table(); | 1102 ClassTable* class_table = I->class_table(); |
1074 intptr_t num_cids = class_table->NumCids(); | 1103 intptr_t num_cids = class_table->NumCids(); |
1075 | 1104 |
1076 // Clear the direct subclasses for all classes. | 1105 // Clear the direct subclasses for all classes. |
1077 Class& cls = Class::Handle(); | 1106 Class& cls = Class::Handle(); |
1078 GrowableObjectArray& subclasses = GrowableObjectArray::Handle(); | 1107 GrowableObjectArray& subclasses = GrowableObjectArray::Handle(); |
1079 for (intptr_t i = 1; i < num_cids; i++) { | 1108 for (intptr_t i = 1; i < num_cids; i++) { |
1080 if (class_table->HasValidClassAt(i)) { | 1109 if (class_table->HasValidClassAt(i)) { |
1081 cls = class_table->At(i); | 1110 cls = class_table->At(i); |
(...skipping 16 matching lines...) Expand all Loading... |
1098 ASSERT(!super_cls.IsNull()); | 1127 ASSERT(!super_cls.IsNull()); |
1099 super_cls.AddDirectSubclass(cls); | 1128 super_cls.AddDirectSubclass(cls); |
1100 } | 1129 } |
1101 } | 1130 } |
1102 } | 1131 } |
1103 } | 1132 } |
1104 | 1133 |
1105 #endif // !PRODUCT | 1134 #endif // !PRODUCT |
1106 | 1135 |
1107 } // namespace dart | 1136 } // namespace dart |
OLD | NEW |