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

Side by Side Diff: runtime/vm/isolate_reload.cc

Issue 2186423002: Only reload libraries when they may have been modified. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Code review Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/isolate_reload.h ('k') | runtime/vm/isolate_reload_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/isolate_reload.h ('k') | runtime/vm/isolate_reload_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698