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

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

Issue 2179983002: Implemented schema change for the isolate reload operation. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: CL response 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
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/object.h" 5 #include "vm/object.h"
6 6
7 #include "vm/hash_table.h" 7 #include "vm/hash_table.h"
8 #include "vm/isolate_reload.h" 8 #include "vm/isolate_reload.h"
9 #include "vm/log.h" 9 #include "vm/log.h"
10 #include "vm/resolver.h" 10 #include "vm/resolver.h"
11 #include "vm/symbols.h" 11 #include "vm/symbols.h"
12 12
13 namespace dart { 13 namespace dart {
14 14
15 #ifndef PRODUCT 15 #ifndef PRODUCT
16 16
17 DECLARE_FLAG(bool, trace_reload); 17 DECLARE_FLAG(bool, trace_reload);
18 DECLARE_FLAG(bool, trace_reload_verbose); 18 DECLARE_FLAG(bool, trace_reload_verbose);
19 DECLARE_FLAG(bool, two_args_smi_icd); 19 DECLARE_FLAG(bool, two_args_smi_icd);
20 20
21 #define IRC (Isolate::Current()->reload_context())
22 21
23 class ObjectReloadUtils : public AllStatic { 22 class ObjectReloadUtils : public AllStatic {
24 static void DumpLibraryDictionary(const Library& lib) { 23 static void DumpLibraryDictionary(const Library& lib) {
25 DictionaryIterator it(lib); 24 DictionaryIterator it(lib);
26 Object& entry = Object::Handle(); 25 Object& entry = Object::Handle();
27 String& name = String::Handle(); 26 String& name = String::Handle();
28 TIR_Print("Dumping dictionary for %s\n", lib.ToCString()); 27 TIR_Print("Dumping dictionary for %s\n", lib.ToCString());
29 while (it.HasNext()) { 28 while (it.HasNext()) {
30 entry = it.GetNext(); 29 entry = it.GetNext();
31 name = entry.DictionaryName(); 30 name = entry.DictionaryName();
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 ASSERT(!owner.IsNull()); 356 ASSERT(!owner.IsNull());
358 if (!owner.IsPatchClass()) { 357 if (!owner.IsPatchClass()) {
359 ASSERT(owner.raw() == this->raw()); 358 ASSERT(owner.raw() == this->raw());
360 field.set_owner(patch); 359 field.set_owner(patch);
361 } 360 }
362 field.ForceDynamicGuardedCidAndLength(); 361 field.ForceDynamicGuardedCidAndLength();
363 } 362 }
364 } 363 }
365 364
366 365
367 bool Class::CanReload(const Class& replacement) const { 366 class EnumClassConflict : public ClassReasonForCancelling {
367 public:
368 EnumClassConflict(const Class& from, const Class& to)
369 : ClassReasonForCancelling(from, to) { }
370
371 RawString* ToString() {
372 return String::NewFormatted(
373 from_.is_enum_class()
374 ? "Enum class cannot be redefined to be a non-enum class: %s"
375 : "Class cannot be redefined to be a enum class: %s",
376 from_.ToCString());
377 }
378 };
379
380
381 class EnsureFinalizedError : public ClassReasonForCancelling {
382 public:
383 EnsureFinalizedError(const Class& from, const Class& to, const Error& error)
384 : ClassReasonForCancelling(from, to), error_(error) { }
385
386 private:
387 const Error& error_;
388
389 RawError* ToError() { return error_.raw(); }
390 };
391
392
393 class NativeFieldsConflict : public ClassReasonForCancelling {
394 public:
395 NativeFieldsConflict(const Class& from, const Class& to)
396 : ClassReasonForCancelling(from, to) { }
397
398 private:
399 RawString* ToString() {
400 return String::NewFormatted(
401 "Number of native fields changed in %s", from_.ToCString());
402 }
403 };
404
405
406 class TypeParametersChanged : public ClassReasonForCancelling {
407 public:
408 TypeParametersChanged(const Class& from, const Class& to)
409 : ClassReasonForCancelling(from, to) {}
410
411 RawString* ToString() {
412 return String::NewFormatted(
413 "Limitation: type parameters have changed for %s", from_.ToCString());
414 }
415 };
416
417
418 class PreFinalizedConflict : public ClassReasonForCancelling {
419 public:
420 PreFinalizedConflict(const Class& from, const Class& to)
421 : ClassReasonForCancelling(from, to) {}
422
423 private:
424 RawString* ToString() {
425 return String::NewFormatted(
426 "Original class ('%s') is prefinalized and replacement class "
427 "('%s') is not ",
428 from_.ToCString(), to_.ToCString());
429 }
430 };
431
432
433 class InstanceSizeConflict : public ClassReasonForCancelling {
434 public:
435 InstanceSizeConflict(const Class& from, const Class& to)
436 : ClassReasonForCancelling(from, to) {}
437
438 private:
439 RawString* ToString() {
440 return String::NewFormatted(
441 "Instance size mismatch between '%s' (%" Pd ") and replacement "
442 "'%s' ( %" Pd ")",
443 from_.ToCString(),
444 from_.instance_size(),
445 to_.ToCString(),
446 to_.instance_size());
447 }
448 };
449
450
451 class UnimplementedDeferredLibrary : public ReasonForCancelling {
452 public:
453 UnimplementedDeferredLibrary(const Library& from,
454 const Library& to,
455 const String& name)
456 : ReasonForCancelling(), from_(from), to_(to), name_(name) {}
457
458 private:
459 const Library& from_;
460 const Library& to_;
461 const String& name_;
462
463 RawString* ToString() {
464 const String& lib_url = String::Handle(to_.url());
465 return String::NewFormatted(
466 "Reloading support for deferred loading has not yet been implemented:"
467 " library '%s' has deferred import '%s'",
468 lib_url.ToCString(), name_.ToCString());
469 }
470 };
471
472
473 // This is executed before interating over the instances.
474 void Class::CheckReload(const Class& replacement,
475 IsolateReloadContext* context) const {
368 ASSERT(IsolateReloadContext::IsSameClass(*this, replacement)); 476 ASSERT(IsolateReloadContext::IsSameClass(*this, replacement));
369 477
370 if (is_enum_class() && !replacement.is_enum_class()) { 478 // Class cannot change enum property.
371 IRC->ReportError(String::Handle(String::NewFormatted( 479 if (is_enum_class() != replacement.is_enum_class()) {
372 "Enum class cannot be redefined to be a non-enum class: %s", 480 context->AddReasonForCancelling(
373 ToCString()))); 481 new EnumClassConflict(*this, replacement));
374 return false; 482 return;
375 }
376
377 if (!is_enum_class() && replacement.is_enum_class()) {
378 IRC->ReportError(String::Handle(String::NewFormatted(
379 "Class cannot be redefined to be a enum class: %s",
380 ToCString())));
381 return false;
382 } 483 }
383 484
384 if (is_finalized()) { 485 if (is_finalized()) {
486 // Ensure the replacement class is also finalized.
385 const Error& error = 487 const Error& error =
386 Error::Handle(replacement.EnsureIsFinalized(Thread::Current())); 488 Error::Handle(replacement.EnsureIsFinalized(Thread::Current()));
387 if (!error.IsNull()) { 489 if (!error.IsNull()) {
388 IRC->ReportError(error); 490 context->AddReasonForCancelling(
389 return false; 491 new EnsureFinalizedError(*this, replacement, error));
492 return; // No reason to check other properties.
390 } 493 }
391 TIR_Print("Finalized replacement class for %s\n", ToCString()); 494 TIR_Print("Finalized replacement class for %s\n", ToCString());
392 } 495 }
393 496
394 // At this point the original and replacement must be in the same state. 497 // Native field count cannot change.
498 if (num_native_fields() != replacement.num_native_fields()) {
499 context->AddReasonForCancelling(
500 new NativeFieldsConflict(*this, replacement));
501 return;
502 }
503
504 // Just checking.
505 ASSERT(is_enum_class() == replacement.is_enum_class());
506 ASSERT(num_native_fields() == replacement.num_native_fields());
507
508 if (is_finalized()) {
509 if (!CanReloadFinalized(replacement, context)) return;
510 }
511 if (is_prefinalized()) {
512 if (!CanReloadPreFinalized(replacement, context)) return;
513 }
395 ASSERT(is_finalized() == replacement.is_finalized()); 514 ASSERT(is_finalized() == replacement.is_finalized());
396 515 TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n",
397 if (is_finalized()) { 516 ToCString(), id(), replacement.id());
398 // Get the field maps for both classes. These field maps walk the class 517 }
399 // hierarchy. 518
400 const Array& fields = 519
401 Array::Handle(OffsetToFieldMap()); 520
402 const Array& replacement_fields = 521 bool Class::RequiresInstanceMorphing(const Class& replacement) const {
403 Array::Handle(replacement.OffsetToFieldMap()); 522 // Get the field maps for both classes. These field maps walk the class
404 523 // hierarchy.
405 // Check that the size of the instance is the same. 524 const Array& fields = Array::Handle(OffsetToFieldMap());
406 if (fields.Length() != replacement_fields.Length()) { 525 const Array& replacement_fields
407 IRC->ReportError(String::Handle(String::NewFormatted( 526 = Array::Handle(replacement.OffsetToFieldMap());
408 "Number of instance fields changed in %s", ToCString()))); 527
528 // Check that the size of the instance is the same.
529 if (fields.Length() != replacement_fields.Length()) return true;
530
531 // Check that we have the same next field offset. This check is not
532 // redundant with the one above because the instance OffsetToFieldMap
533 // array length is based on the instance size (which may be aligned up).
534 if (next_field_offset() != replacement.next_field_offset()) return true;
535
536 // Verify that field names / offsets match across the entire hierarchy.
537 Field& field = Field::Handle();
538 String& field_name = String::Handle();
539 Field& replacement_field = Field::Handle();
540 String& replacement_field_name = String::Handle();
541
542 for (intptr_t i = 0; i < fields.Length(); i++) {
543 if (fields.At(i) == Field::null()) {
544 ASSERT(replacement_fields.At(i) == Field::null());
545 continue;
546 }
547 field = Field::RawCast(fields.At(i));
548 replacement_field = Field::RawCast(replacement_fields.At(i));
549 field_name = field.name();
550 replacement_field_name = replacement_field.name();
551 if (!field_name.Equals(replacement_field_name)) return true;
552 }
553 return false;
554 }
555
556
557 bool Class::CanReloadFinalized(const Class& replacement,
558 IsolateReloadContext* context) const {
559 // Make sure the declaration types matches for the two classes.
560 // ex. class A<int,B> {} cannot be replace with class A<B> {}.
561
562 const AbstractType& dt = AbstractType::Handle(DeclarationType());
563 const AbstractType& replacement_dt =
564 AbstractType::Handle(replacement.DeclarationType());
565 if (!dt.Equals(replacement_dt)) {
566 context->AddReasonForCancelling(
567 new TypeParametersChanged(*this, replacement));
568 return false;
569 }
570 if (RequiresInstanceMorphing(replacement)) {
571 context->AddInstanceMorpher(new InstanceMorpher(*this, replacement));
572 }
573 return true;
574 }
575
576
577 bool Class::CanReloadPreFinalized(const Class& replacement,
578 IsolateReloadContext* context) const {
579 // The replacement class must also prefinalized.
580 if (!replacement.is_prefinalized()) {
581 context->AddReasonForCancelling(
582 new PreFinalizedConflict(*this, replacement));
409 return false; 583 return false;
410 } 584 }
411 585 // Check the instance sizes are equal.
412 // Check that we have the same next field offset. This check is not 586 if (instance_size() != replacement.instance_size()) {
413 // redundant with the one above because the instance OffsetToFieldMap 587 context->AddReasonForCancelling(
414 // array length is based on the instance size (which may be aligned up). 588 new InstanceSizeConflict(*this, replacement));
415 if (next_field_offset() != replacement.next_field_offset()) {
416 IRC->ReportError(String::Handle(String::NewFormatted(
417 "Number of instance fields changed in %s", ToCString())));
418 return false; 589 return false;
419 } 590 }
420
421 if (NumTypeArguments() != replacement.NumTypeArguments()) {
422 IRC->ReportError(String::Handle(String::NewFormatted(
423 "Number of type arguments changed in %s", ToCString())));
424 return false;
425 }
426
427 // Verify that field names / offsets match across the entire hierarchy.
428 Field& field = Field::Handle();
429 String& field_name = String::Handle();
430 Field& replacement_field = Field::Handle();
431 String& replacement_field_name = String::Handle();
432 for (intptr_t i = 0; i < fields.Length(); i++) {
433 if (fields.At(i) == Field::null()) {
434 ASSERT(replacement_fields.At(i) == Field::null());
435 continue;
436 }
437 field = Field::RawCast(fields.At(i));
438 replacement_field = Field::RawCast(replacement_fields.At(i));
439 field_name = field.name();
440 replacement_field_name = replacement_field.name();
441 if (!field_name.Equals(replacement_field_name)) {
442 IRC->ReportError(String::Handle(String::NewFormatted(
443 "Name of instance field changed ('%s' vs '%s') in '%s'",
444 field_name.ToCString(),
445 replacement_field_name.ToCString(),
446 ToCString())));
447 return false;
448 }
449 }
450 } else if (is_prefinalized()) {
451 if (!replacement.is_prefinalized()) {
452 IRC->ReportError(String::Handle(String::NewFormatted(
453 "Original class ('%s') is prefinalized and replacement class "
454 "('%s') is not ",
455 ToCString(), replacement.ToCString())));
456 return false;
457 }
458 if (instance_size() != replacement.instance_size()) {
459 IRC->ReportError(String::Handle(String::NewFormatted(
460 "Instance size mismatch between '%s' (%" Pd ") and replacement "
461 "'%s' ( %" Pd ")",
462 ToCString(),
463 instance_size(),
464 replacement.ToCString(),
465 replacement.instance_size())));
466 return false;
467 }
468 }
469
470 // native field count check.
471 if (num_native_fields() != replacement.num_native_fields()) {
472 IRC->ReportError(String::Handle(String::NewFormatted(
473 "Number of native fields changed in %s", ToCString())));
474 return false;
475 }
476
477 // TODO(johnmccutchan) type parameter count check.
478
479 TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n",
480 ToCString(),
481 id(),
482 replacement.id());
483 return true; 591 return true;
484 } 592 }
485 593
486 594
487 bool Library::CanReload(const Library& replacement) const { 595 void Library::CheckReload(const Library& replacement,
596 IsolateReloadContext* context) const {
488 // TODO(26878): If the replacement library uses deferred loading, 597 // TODO(26878): If the replacement library uses deferred loading,
489 // reject it. We do not yet support reloading deferred libraries. 598 // reject it. We do not yet support reloading deferred libraries.
490 LibraryPrefix& prefix = LibraryPrefix::Handle(); 599 LibraryPrefix& prefix = LibraryPrefix::Handle();
491 LibraryPrefixIterator it(replacement); 600 LibraryPrefixIterator it(replacement);
492 while (it.HasNext()) { 601 while (it.HasNext()) {
493 prefix = it.GetNext(); 602 prefix = it.GetNext();
494 if (prefix.is_deferred_load()) { 603 if (prefix.is_deferred_load()) {
495 const String& lib_url = String::Handle(replacement.url());
496 const String& prefix_name = String::Handle(prefix.name()); 604 const String& prefix_name = String::Handle(prefix.name());
497 IRC->ReportError(String::Handle(String::NewFormatted( 605 context->AddReasonForCancelling(
498 "Reloading support for deferred loading has not yet been implemented:" 606 new UnimplementedDeferredLibrary(*this, replacement, prefix_name));
499 " library '%s' has deferred import '%s'", 607 return;
500 lib_url.ToCString(), prefix_name.ToCString())));
501 return false;
502 } 608 }
503 } 609 }
504 return true;
505 } 610 }
506 611
507 612
508 static const Function* static_call_target = NULL; 613 static const Function* static_call_target = NULL;
509 614
615
510 void ICData::Reset() const { 616 void ICData::Reset() const {
511 if (is_static_call()) { 617 if (is_static_call()) {
512 const Function& old_target = Function::Handle(GetTargetAt(0)); 618 const Function& old_target = Function::Handle(GetTargetAt(0));
513 if (old_target.IsNull()) { 619 if (old_target.IsNull()) {
514 FATAL("old_target is NULL.\n"); 620 FATAL("old_target is NULL.\n");
515 } 621 }
516 static_call_target = &old_target; 622 static_call_target = &old_target;
517 623
518 const String& selector = String::Handle(old_target.name()); 624 const String& selector = String::Handle(old_target.name());
519 Function& new_target = Function::Handle(); 625 Function& new_target = Function::Handle();
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 } 680 }
575 ClearAndSetStaticTarget(new_target); 681 ClearAndSetStaticTarget(new_target);
576 } else { 682 } else {
577 ClearWithSentinel(); 683 ClearWithSentinel();
578 } 684 }
579 } 685 }
580 686
581 #endif // !PRODUCT 687 #endif // !PRODUCT
582 688
583 } // namespace dart. 689 } // namespace dart.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698