| 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/bit_vector.h" |
| 8 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 9 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| 10 #include "vm/dart_api_impl.h" | 11 #include "vm/dart_api_impl.h" |
| 11 #include "vm/hash_table.h" | 12 #include "vm/hash_table.h" |
| 12 #include "vm/isolate.h" | 13 #include "vm/isolate.h" |
| 13 #include "vm/log.h" | 14 #include "vm/log.h" |
| 14 #include "vm/object.h" | 15 #include "vm/object.h" |
| 15 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
| 16 #include "vm/parser.h" | 17 #include "vm/parser.h" |
| 17 #include "vm/safepoint.h" | 18 #include "vm/safepoint.h" |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 const String& a_lib_url = | 173 const String& a_lib_url = |
| 173 String::Handle(a_lib.IsNull() ? String::null() : a_lib.url()); | 174 String::Handle(a_lib.IsNull() ? String::null() : a_lib.url()); |
| 174 const String& b_lib_url = | 175 const String& b_lib_url = |
| 175 String::Handle(b_lib.IsNull() ? String::null() : b_lib.url()); | 176 String::Handle(b_lib.IsNull() ? String::null() : b_lib.url()); |
| 176 return a_lib_url.Equals(b_lib_url); | 177 return a_lib_url.Equals(b_lib_url); |
| 177 } | 178 } |
| 178 | 179 |
| 179 | 180 |
| 180 IsolateReloadContext::IsolateReloadContext(Isolate* isolate) | 181 IsolateReloadContext::IsolateReloadContext(Isolate* isolate) |
| 181 : start_time_micros_(OS::GetCurrentMonotonicMicros()), | 182 : start_time_micros_(OS::GetCurrentMonotonicMicros()), |
| 183 reload_timestamp_(OS::GetCurrentTimeMillis()), |
| 182 isolate_(isolate), | 184 isolate_(isolate), |
| 185 reload_skipped_(false), |
| 183 has_error_(false), | 186 has_error_(false), |
| 184 saved_num_cids_(-1), | 187 saved_num_cids_(-1), |
| 185 saved_class_table_(NULL), | 188 saved_class_table_(NULL), |
| 186 num_saved_libs_(-1), | 189 num_saved_libs_(-1), |
| 190 modified_libs_(NULL), |
| 187 script_uri_(String::null()), | 191 script_uri_(String::null()), |
| 188 error_(Error::null()), | 192 error_(Error::null()), |
| 189 old_classes_set_storage_(Array::null()), | 193 old_classes_set_storage_(Array::null()), |
| 190 class_map_storage_(Array::null()), | 194 class_map_storage_(Array::null()), |
| 191 old_libraries_set_storage_(Array::null()), | 195 old_libraries_set_storage_(Array::null()), |
| 192 library_map_storage_(Array::null()), | 196 library_map_storage_(Array::null()), |
| 193 become_map_storage_(Array::null()), | 197 become_map_storage_(Array::null()), |
| 194 become_enum_mappings_(GrowableObjectArray::null()), | 198 become_enum_mappings_(GrowableObjectArray::null()), |
| 195 saved_root_library_(Library::null()), | 199 saved_root_library_(Library::null()), |
| 196 saved_libraries_(GrowableObjectArray::null()) { | 200 saved_libraries_(GrowableObjectArray::null()) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 220 ReportError(LanguageError::Handle(LanguageError::New(error_msg))); | 224 ReportError(LanguageError::Handle(LanguageError::New(error_msg))); |
| 221 } | 225 } |
| 222 | 226 |
| 223 | 227 |
| 224 void IsolateReloadContext::ReportSuccess() { | 228 void IsolateReloadContext::ReportSuccess() { |
| 225 ServiceEvent service_event(I, ServiceEvent::kIsolateReload); | 229 ServiceEvent service_event(I, ServiceEvent::kIsolateReload); |
| 226 Service::HandleEvent(&service_event); | 230 Service::HandleEvent(&service_event); |
| 227 } | 231 } |
| 228 | 232 |
| 229 | 233 |
| 230 void IsolateReloadContext::StartReload() { | 234 void IsolateReloadContext::StartReload(bool force_reload) { |
| 231 TIMELINE_SCOPE(Reload); | 235 TIMELINE_SCOPE(Reload); |
| 232 Thread* thread = Thread::Current(); | 236 Thread* thread = Thread::Current(); |
| 233 ASSERT(isolate() == thread->isolate()); | 237 ASSERT(isolate() == thread->isolate()); |
| 234 | 238 |
| 235 // Grab root library before calling CheckpointBeforeReload. | 239 // Grab root library before calling CheckpointBeforeReload. |
| 236 const Library& root_lib = Library::Handle(object_store()->root_library()); | 240 const Library& root_lib = Library::Handle(object_store()->root_library()); |
| 237 ASSERT(!root_lib.IsNull()); | 241 ASSERT(!root_lib.IsNull()); |
| 238 const String& root_lib_url = String::Handle(root_lib.url()); | 242 const String& root_lib_url = String::Handle(root_lib.url()); |
| 239 | 243 |
| 244 // Check to see which libraries have been modified. |
| 245 modified_libs_ = FindModifiedLibraries(force_reload); |
| 246 if (!modified_libs_->Contains(root_lib.index())) { |
| 247 ASSERT(modified_libs_->IsEmpty()); |
| 248 reload_skipped_ = true; |
| 249 TIR_Print("Skipping reload. No libraries were modified\n"); |
| 250 return; |
| 251 } |
| 252 |
| 240 // Preallocate storage for maps. | 253 // Preallocate storage for maps. |
| 241 old_classes_set_storage_ = | 254 old_classes_set_storage_ = |
| 242 HashTables::New<UnorderedHashSet<ClassMapTraits> >(4); | 255 HashTables::New<UnorderedHashSet<ClassMapTraits> >(4); |
| 243 class_map_storage_ = | 256 class_map_storage_ = |
| 244 HashTables::New<UnorderedHashMap<ClassMapTraits> >(4); | 257 HashTables::New<UnorderedHashMap<ClassMapTraits> >(4); |
| 245 old_libraries_set_storage_ = | 258 old_libraries_set_storage_ = |
| 246 HashTables::New<UnorderedHashSet<LibraryMapTraits> >(4); | 259 HashTables::New<UnorderedHashSet<LibraryMapTraits> >(4); |
| 247 library_map_storage_ = | 260 library_map_storage_ = |
| 248 HashTables::New<UnorderedHashMap<LibraryMapTraits> >(4); | 261 HashTables::New<UnorderedHashMap<LibraryMapTraits> >(4); |
| 249 become_map_storage_ = | 262 become_map_storage_ = |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 if (!old_cls.is_enum_class()) { | 319 if (!old_cls.is_enum_class()) { |
| 307 new_cls.CopyCanonicalConstants(old_cls); | 320 new_cls.CopyCanonicalConstants(old_cls); |
| 308 } | 321 } |
| 309 new_cls.CopyCanonicalType(old_cls); | 322 new_cls.CopyCanonicalType(old_cls); |
| 310 AddBecomeMapping(old_cls, new_cls); | 323 AddBecomeMapping(old_cls, new_cls); |
| 311 AddClassMapping(new_cls, old_cls); | 324 AddClassMapping(new_cls, old_cls); |
| 312 } | 325 } |
| 313 | 326 |
| 314 | 327 |
| 315 void IsolateReloadContext::FinishReload() { | 328 void IsolateReloadContext::FinishReload() { |
| 329 if (reload_skipped_) { |
| 330 return; |
| 331 } |
| 316 BuildLibraryMapping(); | 332 BuildLibraryMapping(); |
| 317 TIR_Print("---- DONE FINALIZING\n"); | 333 TIR_Print("---- DONE FINALIZING\n"); |
| 318 if (ValidateReload()) { | 334 if (ValidateReload()) { |
| 319 Commit(); | 335 Commit(); |
| 320 PostCommit(); | 336 PostCommit(); |
| 337 isolate()->set_last_reload_timestamp(reload_timestamp_); |
| 321 } else { | 338 } else { |
| 322 Rollback(); | 339 Rollback(); |
| 323 } | 340 } |
| 324 // ValidateReload mutates the direct subclass information and does | 341 // ValidateReload mutates the direct subclass information and does |
| 325 // not remove dead subclasses. Rebuild the direct subclass | 342 // not remove dead subclasses. Rebuild the direct subclass |
| 326 // information from scratch. | 343 // information from scratch. |
| 327 RebuildDirectSubclasses(); | 344 RebuildDirectSubclasses(); |
| 328 | 345 |
| 329 if (FLAG_write_protect_code) { | 346 if (FLAG_write_protect_code) { |
| 330 // Disable code page write protection while we are reloading. | 347 // Re-enable code page write protection. |
| 331 I->heap()->WriteProtectCode(true); | 348 I->heap()->WriteProtectCode(true); |
| 332 } | 349 } |
| 333 | 350 |
| 334 BackgroundCompiler::Enable(); | 351 BackgroundCompiler::Enable(); |
| 335 } | 352 } |
| 336 | 353 |
| 337 | 354 |
| 338 void IsolateReloadContext::AbortReload(const Error& error) { | 355 void IsolateReloadContext::AbortReload(const Error& error) { |
| 339 ReportError(error); | 356 ReportError(error); |
| 340 Rollback(); | 357 Rollback(); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 local_saved_class_table[i] = NULL; | 444 local_saved_class_table[i] = NULL; |
| 428 } | 445 } |
| 429 } | 446 } |
| 430 old_classes_set_storage_ = old_classes_set.Release().raw(); | 447 old_classes_set_storage_ = old_classes_set.Release().raw(); |
| 431 // Assigning the field must be done after saving the class table. | 448 // Assigning the field must be done after saving the class table. |
| 432 saved_class_table_ = local_saved_class_table; | 449 saved_class_table_ = local_saved_class_table; |
| 433 TIR_Print("---- System had %" Pd " classes\n", saved_num_cids_); | 450 TIR_Print("---- System had %" Pd " classes\n", saved_num_cids_); |
| 434 } | 451 } |
| 435 | 452 |
| 436 | 453 |
| 437 bool IsolateReloadContext::IsCleanLibrary(const Library& lib) { | 454 Dart_FileModifiedCallback IsolateReloadContext::file_modified_callback_ = NULL; |
| 438 return lib.is_dart_scheme(); | 455 |
| 456 |
| 457 bool IsolateReloadContext::ScriptModifiedSince(const Script& script, |
| 458 int64_t since) { |
| 459 if (file_modified_callback_ == NULL) { |
| 460 return true; |
| 461 } |
| 462 // We use the resolved url to determine if the script has been modified. |
| 463 const String& url = String::Handle(script.resolved_url()); |
| 464 const char* url_chars = url.ToCString(); |
| 465 return (*file_modified_callback_)(url_chars, since); |
| 439 } | 466 } |
| 440 | 467 |
| 441 | 468 |
| 469 static void PropagateLibraryModified( |
| 470 const ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >* imported_by, |
| 471 intptr_t lib_index, |
| 472 BitVector* modified_libs) { |
| 473 ZoneGrowableArray<intptr_t>* dep_libs = (*imported_by)[lib_index]; |
| 474 for (intptr_t i = 0; i < dep_libs->length(); i++) { |
| 475 intptr_t dep_lib_index = (*dep_libs)[i]; |
| 476 if (!modified_libs->Contains(dep_lib_index)) { |
| 477 modified_libs->Add(dep_lib_index); |
| 478 PropagateLibraryModified(imported_by, dep_lib_index, modified_libs); |
| 479 } |
| 480 } |
| 481 } |
| 482 |
| 483 |
| 484 BitVector* IsolateReloadContext::FindModifiedLibraries(bool force_reload) { |
| 485 Thread* thread = Thread::Current(); |
| 486 int64_t last_reload = I->last_reload_timestamp(); |
| 487 |
| 488 const GrowableObjectArray& libs = |
| 489 GrowableObjectArray::Handle(object_store()->libraries()); |
| 490 Library& lib = Library::Handle(); |
| 491 Array& scripts = Array::Handle(); |
| 492 Script& script = Script::Handle(); |
| 493 intptr_t num_libs = libs.Length(); |
| 494 |
| 495 // Construct the imported-by graph. |
| 496 ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >* imported_by = |
| 497 new ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >(num_libs); |
| 498 imported_by->SetLength(num_libs); |
| 499 for (intptr_t i = 0; i < num_libs; i++) { |
| 500 (*imported_by)[i] = new ZoneGrowableArray<intptr_t>(); |
| 501 } |
| 502 Array& imports = Array::Handle(); |
| 503 Namespace& ns = Namespace::Handle(); |
| 504 Library& target = Library::Handle(); |
| 505 |
| 506 for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) { |
| 507 lib ^= libs.At(lib_idx); |
| 508 ASSERT(lib_idx == lib.index()); |
| 509 if (lib.is_dart_scheme()) { |
| 510 // We don't care about imports among dart scheme libraries. |
| 511 continue; |
| 512 } |
| 513 |
| 514 // Add imports to the import-by graph. |
| 515 imports = lib.imports(); |
| 516 for (intptr_t import_idx = 0; import_idx < imports.Length(); import_idx++) { |
| 517 ns ^= imports.At(import_idx); |
| 518 if (!ns.IsNull()) { |
| 519 target = ns.library(); |
| 520 (*imported_by)[target.index()]->Add(lib.index()); |
| 521 } |
| 522 } |
| 523 |
| 524 // Add prefixed imports to the import-by graph. |
| 525 DictionaryIterator entries(lib); |
| 526 Object& entry = Object::Handle(); |
| 527 LibraryPrefix& prefix = LibraryPrefix::Handle(); |
| 528 while (entries.HasNext()) { |
| 529 entry = entries.GetNext(); |
| 530 if (entry.IsLibraryPrefix()) { |
| 531 prefix ^= entry.raw(); |
| 532 imports = prefix.imports(); |
| 533 for (intptr_t import_idx = 0; import_idx < imports.Length(); |
| 534 import_idx++) { |
| 535 ns ^= imports.At(import_idx); |
| 536 if (!ns.IsNull()) { |
| 537 target = ns.library(); |
| 538 (*imported_by)[target.index()]->Add(lib.index()); |
| 539 } |
| 540 } |
| 541 } |
| 542 } |
| 543 } |
| 544 |
| 545 BitVector* modified_libs = new(Z) BitVector(Z, num_libs); |
| 546 |
| 547 for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) { |
| 548 lib ^= libs.At(lib_idx); |
| 549 if (lib.is_dart_scheme() || modified_libs->Contains(lib_idx)) { |
| 550 // We don't consider dart scheme libraries during reload. If |
| 551 // the modified libs set already contains this library, then we |
| 552 // have already visited it. |
| 553 continue; |
| 554 } |
| 555 scripts = lib.LoadedScripts(); |
| 556 for (intptr_t script_idx = 0; script_idx < scripts.Length(); script_idx++) { |
| 557 script ^= scripts.At(script_idx); |
| 558 if (force_reload || ScriptModifiedSince(script, last_reload)) { |
| 559 modified_libs->Add(lib_idx); |
| 560 PropagateLibraryModified(imported_by, lib_idx, modified_libs); |
| 561 break; |
| 562 } |
| 563 } |
| 564 } |
| 565 |
| 566 return modified_libs; |
| 567 } |
| 568 |
| 569 |
| 442 void IsolateReloadContext::CheckpointLibraries() { | 570 void IsolateReloadContext::CheckpointLibraries() { |
| 443 TIMELINE_SCOPE(CheckpointLibraries); | 571 TIMELINE_SCOPE(CheckpointLibraries); |
| 444 | 572 |
| 445 // Save the root library in case we abort the reload. | 573 // Save the root library in case we abort the reload. |
| 446 const Library& root_lib = | 574 const Library& root_lib = |
| 447 Library::Handle(object_store()->root_library()); | 575 Library::Handle(object_store()->root_library()); |
| 448 set_saved_root_library(root_lib); | 576 set_saved_root_library(root_lib); |
| 449 | 577 |
| 450 // Save the old libraries array in case we abort the reload. | 578 // Save the old libraries array in case we abort the reload. |
| 451 const GrowableObjectArray& libs = | 579 const GrowableObjectArray& libs = |
| 452 GrowableObjectArray::Handle(object_store()->libraries()); | 580 GrowableObjectArray::Handle(object_store()->libraries()); |
| 453 set_saved_libraries(libs); | 581 set_saved_libraries(libs); |
| 454 | 582 |
| 455 // Make a filtered copy of the old libraries array. Keep "clean" libraries | 583 // Make a filtered copy of the old libraries array. Keep "clean" libraries |
| 456 // that we will use instead of reloading. | 584 // that we will use instead of reloading. |
| 457 const GrowableObjectArray& new_libs = GrowableObjectArray::Handle( | 585 const GrowableObjectArray& new_libs = GrowableObjectArray::Handle( |
| 458 GrowableObjectArray::New(Heap::kOld)); | 586 GrowableObjectArray::New(Heap::kOld)); |
| 459 Library& lib = Library::Handle(); | 587 Library& lib = Library::Handle(); |
| 460 UnorderedHashSet<LibraryMapTraits> | 588 UnorderedHashSet<LibraryMapTraits> |
| 461 old_libraries_set(old_libraries_set_storage_); | 589 old_libraries_set(old_libraries_set_storage_); |
| 462 num_saved_libs_ = 0; | 590 num_saved_libs_ = 0; |
| 463 for (intptr_t i = 0; i < libs.Length(); i++) { | 591 for (intptr_t i = 0; i < libs.Length(); i++) { |
| 464 lib ^= libs.At(i); | 592 lib ^= libs.At(i); |
| 465 if (IsCleanLibrary(lib)) { | 593 if (modified_libs_->Contains(i)) { |
| 594 // We are going to reload this library. Clear the index. |
| 595 lib.set_index(-1); |
| 596 } else { |
| 466 // We are preserving this library across the reload, assign its new index | 597 // We are preserving this library across the reload, assign its new index |
| 467 lib.set_index(new_libs.Length()); | 598 lib.set_index(new_libs.Length()); |
| 468 new_libs.Add(lib, Heap::kOld); | 599 new_libs.Add(lib, Heap::kOld); |
| 469 num_saved_libs_++; | 600 num_saved_libs_++; |
| 470 } else { | |
| 471 // We are going to reload this library. Clear the index. | |
| 472 lib.set_index(-1); | |
| 473 } | 601 } |
| 474 // Add old library to old libraries set. | 602 // Add old library to old libraries set. |
| 475 bool already_present = old_libraries_set.Insert(lib); | 603 bool already_present = old_libraries_set.Insert(lib); |
| 476 ASSERT(!already_present); | 604 ASSERT(!already_present); |
| 477 } | 605 } |
| 606 modified_libs_ = NULL; // Renumbering the libraries has invalidated this. |
| 478 old_libraries_set_storage_ = old_libraries_set.Release().raw(); | 607 old_libraries_set_storage_ = old_libraries_set.Release().raw(); |
| 479 | 608 |
| 480 // Reset the registered libraries to the filtered array. | 609 // Reset the registered libraries to the filtered array. |
| 481 Library::RegisterLibraries(Thread::Current(), new_libs); | 610 Library::RegisterLibraries(Thread::Current(), new_libs); |
| 482 // Reset the root library to null. | 611 // Reset the root library to null. |
| 483 object_store()->set_root_library(Library::Handle()); | 612 object_store()->set_root_library(Library::Handle()); |
| 484 } | 613 } |
| 485 | 614 |
| 486 | 615 |
| 487 // While reloading everything we do must be reversible so that we can abort | 616 // While reloading everything we do must be reversible so that we can abort |
| (...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1019 return lib.raw(); | 1148 return lib.raw(); |
| 1020 } | 1149 } |
| 1021 | 1150 |
| 1022 | 1151 |
| 1023 void IsolateReloadContext::BuildLibraryMapping() { | 1152 void IsolateReloadContext::BuildLibraryMapping() { |
| 1024 const GrowableObjectArray& libs = | 1153 const GrowableObjectArray& libs = |
| 1025 GrowableObjectArray::Handle(object_store()->libraries()); | 1154 GrowableObjectArray::Handle(object_store()->libraries()); |
| 1026 | 1155 |
| 1027 Library& replacement_or_new = Library::Handle(); | 1156 Library& replacement_or_new = Library::Handle(); |
| 1028 Library& old = Library::Handle(); | 1157 Library& old = Library::Handle(); |
| 1029 for (intptr_t i = 0; i < libs.Length(); i++) { | 1158 for (intptr_t i = num_saved_libs_; i < libs.Length(); i++) { |
| 1030 replacement_or_new = Library::RawCast(libs.At(i)); | 1159 replacement_or_new = Library::RawCast(libs.At(i)); |
| 1031 if (IsCleanLibrary(replacement_or_new)) { | |
| 1032 continue; | |
| 1033 } | |
| 1034 old ^= OldLibraryOrNull(replacement_or_new); | 1160 old ^= OldLibraryOrNull(replacement_or_new); |
| 1035 if (old.IsNull()) { | 1161 if (old.IsNull()) { |
| 1036 if (FLAG_identity_reload) { | 1162 if (FLAG_identity_reload) { |
| 1037 TIR_Print("Could not find original library for %s\n", | 1163 TIR_Print("Could not find original library for %s\n", |
| 1038 replacement_or_new.ToCString()); | 1164 replacement_or_new.ToCString()); |
| 1039 UNREACHABLE(); | 1165 UNREACHABLE(); |
| 1040 } | 1166 } |
| 1041 // New library. | 1167 // New library. |
| 1042 AddLibraryMapping(replacement_or_new, replacement_or_new); | 1168 AddLibraryMapping(replacement_or_new, replacement_or_new); |
| 1043 } else { | 1169 } else { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 ASSERT(!super_cls.IsNull()); | 1257 ASSERT(!super_cls.IsNull()); |
| 1132 super_cls.AddDirectSubclass(cls); | 1258 super_cls.AddDirectSubclass(cls); |
| 1133 } | 1259 } |
| 1134 } | 1260 } |
| 1135 } | 1261 } |
| 1136 } | 1262 } |
| 1137 | 1263 |
| 1138 #endif // !PRODUCT | 1264 #endif // !PRODUCT |
| 1139 | 1265 |
| 1140 } // namespace dart | 1266 } // namespace dart |
| OLD | NEW |