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()), | |
Cutch
2016/07/29 14:37:04
Why does the reload context and the isolate have a
turnidge
2016/07/29 17:37:37
The isolate's reload timestamp is the timestamp of
| |
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(); |
321 } else { | 337 } else { |
322 Rollback(); | 338 Rollback(); |
323 } | 339 } |
324 // ValidateReload mutates the direct subclass information and does | 340 // ValidateReload mutates the direct subclass information and does |
325 // not remove dead subclasses. Rebuild the direct subclass | 341 // not remove dead subclasses. Rebuild the direct subclass |
326 // information from scratch. | 342 // information from scratch. |
327 RebuildDirectSubclasses(); | 343 RebuildDirectSubclasses(); |
328 | 344 |
329 if (FLAG_write_protect_code) { | 345 if (FLAG_write_protect_code) { |
330 // Disable code page write protection while we are reloading. | 346 // Re-enable code page write protection. |
331 I->heap()->WriteProtectCode(true); | 347 I->heap()->WriteProtectCode(true); |
332 } | 348 } |
333 | 349 |
334 BackgroundCompiler::Enable(); | 350 BackgroundCompiler::Enable(); |
335 } | 351 } |
336 | 352 |
337 | 353 |
338 void IsolateReloadContext::AbortReload(const Error& error) { | 354 void IsolateReloadContext::AbortReload(const Error& error) { |
339 ReportError(error); | 355 ReportError(error); |
340 Rollback(); | 356 Rollback(); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
427 local_saved_class_table[i] = NULL; | 443 local_saved_class_table[i] = NULL; |
428 } | 444 } |
429 } | 445 } |
430 old_classes_set_storage_ = old_classes_set.Release().raw(); | 446 old_classes_set_storage_ = old_classes_set.Release().raw(); |
431 // Assigning the field must be done after saving the class table. | 447 // Assigning the field must be done after saving the class table. |
432 saved_class_table_ = local_saved_class_table; | 448 saved_class_table_ = local_saved_class_table; |
433 TIR_Print("---- System had %" Pd " classes\n", saved_num_cids_); | 449 TIR_Print("---- System had %" Pd " classes\n", saved_num_cids_); |
434 } | 450 } |
435 | 451 |
436 | 452 |
437 bool IsolateReloadContext::IsCleanLibrary(const Library& lib) { | 453 Dart_FileModifiedCallback IsolateReloadContext::file_modified_callback_ = NULL; |
438 return lib.is_dart_scheme(); | 454 |
455 | |
456 bool IsolateReloadContext::ScriptModifiedSince(const Script& script, | |
457 int64_t since) { | |
458 if (file_modified_callback_ == NULL) { | |
459 return true; | |
460 } | |
461 // We use the resolved url to determine if the script has been modified. | |
462 const String& url = String::Handle(script.resolved_url()); | |
463 const char* url_chars = url.ToCString(); | |
464 return (*file_modified_callback_)(url_chars, since); | |
439 } | 465 } |
440 | 466 |
441 | 467 |
468 static void PropagateLibraryModified( | |
469 const ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >* imported_by, | |
470 intptr_t lib_index, | |
471 BitVector* modified_libs) { | |
472 ZoneGrowableArray<intptr_t>* dep_libs = (*imported_by)[lib_index]; | |
473 for (intptr_t i = 0; i < dep_libs->length(); i++) { | |
474 intptr_t dep_lib_index = (*dep_libs)[i]; | |
475 if (!modified_libs->Contains(dep_lib_index)) { | |
476 modified_libs->Add(dep_lib_index); | |
477 PropagateLibraryModified(imported_by, dep_lib_index, modified_libs); | |
478 } | |
479 } | |
480 } | |
481 | |
482 | |
483 BitVector* IsolateReloadContext::FindModifiedLibraries(bool force_reload) { | |
484 Thread* thread = Thread::Current(); | |
485 int64_t last_reload = I->reload_timestamp(); | |
486 | |
487 const GrowableObjectArray& libs = | |
488 GrowableObjectArray::Handle(object_store()->libraries()); | |
489 Library& lib = Library::Handle(); | |
490 Array& scripts = Array::Handle(); | |
491 Script& script = Script::Handle(); | |
492 intptr_t num_libs = libs.Length(); | |
493 | |
494 // Construct the imported-by graph. | |
495 ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >* imported_by = | |
496 new ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >(num_libs); | |
497 imported_by->SetLength(num_libs); | |
498 for (intptr_t i = 0; i < num_libs; i++) { | |
499 (*imported_by)[i] = new ZoneGrowableArray<intptr_t>(); | |
500 } | |
501 Array& imports = Array::Handle(); | |
502 Namespace& ns = Namespace::Handle(); | |
503 Library& target = Library::Handle(); | |
504 | |
505 for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) { | |
506 lib ^= libs.At(lib_idx); | |
507 ASSERT(lib_idx == lib.index()); | |
508 if (lib.is_dart_scheme()) { | |
509 // We don't care about imports among dart scheme libraries. | |
510 continue; | |
511 } | |
512 | |
513 // Add imports to the import-by graph. | |
514 imports = lib.imports(); | |
515 for (intptr_t import_idx = 0; import_idx < imports.Length(); import_idx++) { | |
516 ns ^= imports.At(import_idx); | |
517 if (!ns.IsNull()) { | |
518 target = ns.library(); | |
519 (*imported_by)[target.index()]->Add(lib.index()); | |
520 } | |
521 } | |
522 | |
523 // Add prefixed imports to the import-by graph. | |
524 DictionaryIterator entries(lib); | |
525 Object& entry = Object::Handle(); | |
526 LibraryPrefix& prefix = LibraryPrefix::Handle(); | |
527 while (entries.HasNext()) { | |
528 entry = entries.GetNext(); | |
529 if (entry.IsLibraryPrefix()) { | |
530 prefix ^= entry.raw(); | |
531 imports = prefix.imports(); | |
532 for (intptr_t import_idx = 0; import_idx < imports.Length(); | |
533 import_idx++) { | |
534 ns ^= imports.At(import_idx); | |
535 if (!ns.IsNull()) { | |
536 target = ns.library(); | |
537 (*imported_by)[target.index()]->Add(lib.index()); | |
538 } | |
539 } | |
540 } | |
541 } | |
542 } | |
543 | |
544 BitVector* modified_libs = new(Z) BitVector(Z, num_libs); | |
545 | |
546 for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) { | |
547 lib ^= libs.At(lib_idx); | |
548 if (lib.is_dart_scheme() || modified_libs->Contains(lib_idx)) { | |
549 // We don't consider dart scheme libraries during reload. If | |
550 // the modified libs set already contains this library, then we | |
551 // have already visited it. | |
552 continue; | |
553 } | |
554 scripts = lib.LoadedScripts(); | |
555 for (intptr_t script_idx = 0; script_idx < scripts.Length(); script_idx++) { | |
556 script ^= scripts.At(script_idx); | |
557 if (force_reload) { | |
558 modified_libs->Add(lib_idx); | |
559 break; | |
560 } | |
561 if (ScriptModifiedSince(script, last_reload)) { | |
Cutch
2016/07/29 14:37:04
maybe merge these two ifs:
if (force_reload || Sc
turnidge
2016/07/29 17:37:37
Done.
| |
562 modified_libs->Add(lib_idx); | |
563 break; | |
564 } | |
565 } | |
566 if (modified_libs->Contains(lib_idx)) { | |
567 PropagateLibraryModified(imported_by, lib_idx, modified_libs); | |
Cutch
2016/07/29 14:37:04
Could this be rolled into the if statement above?
turnidge
2016/07/29 17:37:37
Done.
| |
568 } | |
569 } | |
570 | |
571 return modified_libs; | |
572 } | |
573 | |
574 | |
442 void IsolateReloadContext::CheckpointLibraries() { | 575 void IsolateReloadContext::CheckpointLibraries() { |
443 TIMELINE_SCOPE(CheckpointLibraries); | 576 TIMELINE_SCOPE(CheckpointLibraries); |
444 | 577 |
445 // Save the root library in case we abort the reload. | 578 // Save the root library in case we abort the reload. |
446 const Library& root_lib = | 579 const Library& root_lib = |
447 Library::Handle(object_store()->root_library()); | 580 Library::Handle(object_store()->root_library()); |
448 set_saved_root_library(root_lib); | 581 set_saved_root_library(root_lib); |
449 | 582 |
450 // Save the old libraries array in case we abort the reload. | 583 // Save the old libraries array in case we abort the reload. |
451 const GrowableObjectArray& libs = | 584 const GrowableObjectArray& libs = |
452 GrowableObjectArray::Handle(object_store()->libraries()); | 585 GrowableObjectArray::Handle(object_store()->libraries()); |
453 set_saved_libraries(libs); | 586 set_saved_libraries(libs); |
454 | 587 |
455 // Make a filtered copy of the old libraries array. Keep "clean" libraries | 588 // Make a filtered copy of the old libraries array. Keep "clean" libraries |
456 // that we will use instead of reloading. | 589 // that we will use instead of reloading. |
457 const GrowableObjectArray& new_libs = GrowableObjectArray::Handle( | 590 const GrowableObjectArray& new_libs = GrowableObjectArray::Handle( |
458 GrowableObjectArray::New(Heap::kOld)); | 591 GrowableObjectArray::New(Heap::kOld)); |
459 Library& lib = Library::Handle(); | 592 Library& lib = Library::Handle(); |
460 UnorderedHashSet<LibraryMapTraits> | 593 UnorderedHashSet<LibraryMapTraits> |
461 old_libraries_set(old_libraries_set_storage_); | 594 old_libraries_set(old_libraries_set_storage_); |
462 num_saved_libs_ = 0; | 595 num_saved_libs_ = 0; |
463 for (intptr_t i = 0; i < libs.Length(); i++) { | 596 for (intptr_t i = 0; i < libs.Length(); i++) { |
464 lib ^= libs.At(i); | 597 lib ^= libs.At(i); |
465 if (IsCleanLibrary(lib)) { | 598 if (modified_libs_->Contains(i)) { |
599 // We are going to reload this library. Clear the index. | |
600 lib.set_index(-1); | |
601 } else { | |
466 // We are preserving this library across the reload, assign its new index | 602 // We are preserving this library across the reload, assign its new index |
467 lib.set_index(new_libs.Length()); | 603 lib.set_index(new_libs.Length()); |
468 new_libs.Add(lib, Heap::kOld); | 604 new_libs.Add(lib, Heap::kOld); |
469 num_saved_libs_++; | 605 num_saved_libs_++; |
470 } else { | |
471 // We are going to reload this library. Clear the index. | |
472 lib.set_index(-1); | |
473 } | 606 } |
474 // Add old library to old libraries set. | 607 // Add old library to old libraries set. |
475 bool already_present = old_libraries_set.Insert(lib); | 608 bool already_present = old_libraries_set.Insert(lib); |
476 ASSERT(!already_present); | 609 ASSERT(!already_present); |
477 } | 610 } |
611 modified_libs_ = NULL; // Renumbering the libraries has invalidated this. | |
478 old_libraries_set_storage_ = old_libraries_set.Release().raw(); | 612 old_libraries_set_storage_ = old_libraries_set.Release().raw(); |
479 | 613 |
480 // Reset the registered libraries to the filtered array. | 614 // Reset the registered libraries to the filtered array. |
481 Library::RegisterLibraries(Thread::Current(), new_libs); | 615 Library::RegisterLibraries(Thread::Current(), new_libs); |
482 // Reset the root library to null. | 616 // Reset the root library to null. |
483 object_store()->set_root_library(Library::Handle()); | 617 object_store()->set_root_library(Library::Handle()); |
484 } | 618 } |
485 | 619 |
486 | 620 |
487 // While reloading everything we do must be reversible so that we can abort | 621 // 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(); | 1153 return lib.raw(); |
1020 } | 1154 } |
1021 | 1155 |
1022 | 1156 |
1023 void IsolateReloadContext::BuildLibraryMapping() { | 1157 void IsolateReloadContext::BuildLibraryMapping() { |
1024 const GrowableObjectArray& libs = | 1158 const GrowableObjectArray& libs = |
1025 GrowableObjectArray::Handle(object_store()->libraries()); | 1159 GrowableObjectArray::Handle(object_store()->libraries()); |
1026 | 1160 |
1027 Library& replacement_or_new = Library::Handle(); | 1161 Library& replacement_or_new = Library::Handle(); |
1028 Library& old = Library::Handle(); | 1162 Library& old = Library::Handle(); |
1029 for (intptr_t i = 0; i < libs.Length(); i++) { | 1163 for (intptr_t i = num_saved_libs_; i < libs.Length(); i++) { |
1030 replacement_or_new = Library::RawCast(libs.At(i)); | 1164 replacement_or_new = Library::RawCast(libs.At(i)); |
1031 if (IsCleanLibrary(replacement_or_new)) { | |
1032 continue; | |
1033 } | |
1034 old ^= OldLibraryOrNull(replacement_or_new); | 1165 old ^= OldLibraryOrNull(replacement_or_new); |
1035 if (old.IsNull()) { | 1166 if (old.IsNull()) { |
1036 if (FLAG_identity_reload) { | 1167 if (FLAG_identity_reload) { |
1037 TIR_Print("Could not find original library for %s\n", | 1168 TIR_Print("Could not find original library for %s\n", |
1038 replacement_or_new.ToCString()); | 1169 replacement_or_new.ToCString()); |
1039 UNREACHABLE(); | 1170 UNREACHABLE(); |
1040 } | 1171 } |
1041 // New library. | 1172 // New library. |
1042 AddLibraryMapping(replacement_or_new, replacement_or_new); | 1173 AddLibraryMapping(replacement_or_new, replacement_or_new); |
1043 } else { | 1174 } else { |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1131 ASSERT(!super_cls.IsNull()); | 1262 ASSERT(!super_cls.IsNull()); |
1132 super_cls.AddDirectSubclass(cls); | 1263 super_cls.AddDirectSubclass(cls); |
1133 } | 1264 } |
1134 } | 1265 } |
1135 } | 1266 } |
1136 } | 1267 } |
1137 | 1268 |
1138 #endif // !PRODUCT | 1269 #endif // !PRODUCT |
1139 | 1270 |
1140 } // namespace dart | 1271 } // namespace dart |
OLD | NEW |