| 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/bit_vector.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 | 40 |
| 41 #define I (isolate()) | 41 #define I (isolate()) |
| 42 #define Z (thread->zone()) | 42 #define Z (thread->zone()) |
| 43 | 43 |
| 44 #define TIMELINE_SCOPE(name) \ | 44 #define TIMELINE_SCOPE(name) \ |
| 45 TimelineDurationScope tds##name(Thread::Current(), \ | 45 TimelineDurationScope tds##name(Thread::Current(), \ |
| 46 Timeline::GetIsolateStream(), \ | 46 Timeline::GetIsolateStream(), \ |
| 47 #name) | 47 #name) |
| 48 | 48 |
| 49 | 49 |
| 50 InstanceMorpher::InstanceMorpher(const Class& from, const Class& to) | 50 InstanceMorpher::InstanceMorpher(Zone* zone, const Class& from, const Class& to) |
| 51 : from_(from), to_(to), mapping_() { | 51 : from_(from), to_(to), mapping_() { |
| 52 ComputeMapping(); | 52 ComputeMapping(); |
| 53 before_ = new ZoneGrowableArray<const Instance*>(); | 53 before_ = new ZoneGrowableArray<const Instance*>(zone, 0); |
| 54 after_ = new ZoneGrowableArray<const Instance*>(); | 54 after_ = new ZoneGrowableArray<const Instance*>(zone, 0); |
| 55 ASSERT(from_.id() == to_.id()); | 55 ASSERT(from_.id() == to_.id()); |
| 56 cid_ = from_.id(); | 56 cid_ = from_.id(); |
| 57 } | 57 } |
| 58 | 58 |
| 59 | 59 |
| 60 void InstanceMorpher::AddObject(RawObject* object) const { | 60 void InstanceMorpher::AddObject(RawObject* object) const { |
| 61 ASSERT(object->GetClassId() == cid()); | 61 ASSERT(object->GetClassId() == cid()); |
| 62 const Instance& instance = Instance::Cast(Object::Handle(object)); | 62 const Instance& instance = Instance::Cast(Object::Handle(object)); |
| 63 before_->Add(&instance); | 63 before_->Add(&instance); |
| 64 } | 64 } |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 void ClassReasonForCancelling::AppendTo(JSONArray* array) { | 209 void ClassReasonForCancelling::AppendTo(JSONArray* array) { |
| 210 JSONObject jsobj(array); | 210 JSONObject jsobj(array); |
| 211 jsobj.AddProperty("type", "ReasonForCancelling"); | 211 jsobj.AddProperty("type", "ReasonForCancelling"); |
| 212 jsobj.AddProperty("class", from_); | 212 jsobj.AddProperty("class", from_); |
| 213 const String& message = String::Handle(ToString()); | 213 const String& message = String::Handle(ToString()); |
| 214 jsobj.AddProperty("message", message); | 214 jsobj.AddProperty("message", message); |
| 215 } | 215 } |
| 216 | 216 |
| 217 | 217 |
| 218 RawError* IsolateReloadContext::error() const { | 218 RawError* IsolateReloadContext::error() const { |
| 219 ASSERT(has_error()); | 219 ASSERT(reload_aborted()); |
| 220 // Report the first error to the surroundings. | 220 // Report the first error to the surroundings. |
| 221 const Error& error = | 221 const Error& error = |
| 222 Error::Handle(reasons_to_cancel_reload_.At(0)->ToError()); | 222 Error::Handle(reasons_to_cancel_reload_.At(0)->ToError()); |
| 223 return error.raw(); | 223 return error.raw(); |
| 224 } | 224 } |
| 225 | 225 |
| 226 | 226 |
| 227 class ScriptUrlSetTraits { | 227 class ScriptUrlSetTraits { |
| 228 public: | 228 public: |
| 229 static bool ReportStats() { return false; } | 229 static bool ReportStats() { return false; } |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 const String& a_lib_url = | 352 const String& a_lib_url = |
| 353 String::Handle(a_lib.IsNull() ? String::null() : a_lib.url()); | 353 String::Handle(a_lib.IsNull() ? String::null() : a_lib.url()); |
| 354 const String& b_lib_url = | 354 const String& b_lib_url = |
| 355 String::Handle(b_lib.IsNull() ? String::null() : b_lib.url()); | 355 String::Handle(b_lib.IsNull() ? String::null() : b_lib.url()); |
| 356 return a_lib_url.Equals(b_lib_url); | 356 return a_lib_url.Equals(b_lib_url); |
| 357 } | 357 } |
| 358 | 358 |
| 359 | 359 |
| 360 IsolateReloadContext::IsolateReloadContext(Isolate* isolate, | 360 IsolateReloadContext::IsolateReloadContext(Isolate* isolate, |
| 361 JSONStream* js) | 361 JSONStream* js) |
| 362 : start_time_micros_(OS::GetCurrentMonotonicMicros()), | 362 : zone_(Thread::Current()->zone()), |
| 363 start_time_micros_(OS::GetCurrentMonotonicMicros()), |
| 363 reload_timestamp_(OS::GetCurrentTimeMillis()), | 364 reload_timestamp_(OS::GetCurrentTimeMillis()), |
| 364 isolate_(isolate), | 365 isolate_(isolate), |
| 365 reload_skipped_(false), | 366 reload_skipped_(false), |
| 367 reload_aborted_(false), |
| 366 js_(js), | 368 js_(js), |
| 367 saved_num_cids_(-1), | 369 saved_num_cids_(-1), |
| 368 saved_class_table_(NULL), | 370 saved_class_table_(NULL), |
| 369 num_saved_libs_(-1), | 371 num_saved_libs_(-1), |
| 370 instance_morphers_(), | 372 instance_morphers_(), |
| 371 reasons_to_cancel_reload_(), | 373 reasons_to_cancel_reload_(), |
| 372 cid_mapper_(), | 374 cid_mapper_(), |
| 373 modified_libs_(NULL), | 375 modified_libs_(NULL), |
| 374 script_uri_(String::null()), | 376 script_uri_(String::null()), |
| 375 error_(Error::null()), | 377 error_(Error::null()), |
| 376 old_classes_set_storage_(Array::null()), | 378 old_classes_set_storage_(Array::null()), |
| 377 class_map_storage_(Array::null()), | 379 class_map_storage_(Array::null()), |
| 378 old_libraries_set_storage_(Array::null()), | 380 old_libraries_set_storage_(Array::null()), |
| 379 library_map_storage_(Array::null()), | 381 library_map_storage_(Array::null()), |
| 380 become_map_storage_(Array::null()), | 382 become_map_storage_(Array::null()), |
| 381 become_enum_mappings_(GrowableObjectArray::null()), | 383 become_enum_mappings_(GrowableObjectArray::null()), |
| 382 saved_root_library_(Library::null()), | 384 saved_root_library_(Library::null()), |
| 383 saved_libraries_(GrowableObjectArray::null()) { | 385 saved_libraries_(GrowableObjectArray::null()) { |
| 384 // NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not | 386 // NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not |
| 385 // associated with the isolate yet and if a GC is triggered here the raw | 387 // associated with the isolate yet and if a GC is triggered here the raw |
| 386 // objects will not be properly accounted for. | 388 // objects will not be properly accounted for. |
| 389 ASSERT(zone_ != NULL); |
| 387 } | 390 } |
| 388 | 391 |
| 389 | 392 |
| 390 IsolateReloadContext::~IsolateReloadContext() { | 393 IsolateReloadContext::~IsolateReloadContext() { |
| 391 } | 394 } |
| 392 | 395 |
| 393 | 396 |
| 394 void IsolateReloadContext::ReportError(const Error& error) { | 397 void IsolateReloadContext::ReportError(const Error& error) { |
| 395 if (FLAG_trace_reload) { | 398 if (FLAG_trace_reload) { |
| 396 THR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString()); | 399 THR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString()); |
| 397 } | 400 } |
| 398 ServiceEvent service_event(I, ServiceEvent::kIsolateReload); | 401 ServiceEvent service_event(I, ServiceEvent::kIsolateReload); |
| 399 service_event.set_reload_error(&error); | 402 service_event.set_reload_error(&error); |
| 400 Service::HandleEvent(&service_event); | 403 Service::HandleEvent(&service_event); |
| 401 } | 404 } |
| 402 | 405 |
| 403 | 406 |
| 404 void IsolateReloadContext::ReportSuccess() { | 407 void IsolateReloadContext::ReportSuccess() { |
| 405 ServiceEvent service_event(I, ServiceEvent::kIsolateReload); | 408 ServiceEvent service_event(I, ServiceEvent::kIsolateReload); |
| 406 Service::HandleEvent(&service_event); | 409 Service::HandleEvent(&service_event); |
| 407 } | 410 } |
| 408 | 411 |
| 409 | 412 |
| 410 class Aborted : public ReasonForCancelling { | 413 class Aborted : public ReasonForCancelling { |
| 411 public: | 414 public: |
| 412 explicit Aborted(const Error& error) | 415 explicit Aborted(Zone* zone, const Error& error) |
| 413 : ReasonForCancelling(), error_(error) { } | 416 : ReasonForCancelling(zone), error_(error) { } |
| 414 | 417 |
| 415 private: | 418 private: |
| 416 const Error& error_; | 419 const Error& error_; |
| 417 | 420 |
| 418 RawError* ToError() { return error_.raw(); } | 421 RawError* ToError() { return error_.raw(); } |
| 419 RawString* ToString() { | 422 RawString* ToString() { |
| 420 return String::NewFormatted("%s", error_.ToErrorCString()); | 423 return String::NewFormatted("%s", error_.ToErrorCString()); |
| 421 } | 424 } |
| 422 }; | 425 }; |
| 423 | 426 |
| 424 | 427 |
| 425 void IsolateReloadContext::StartReload(bool force_reload) { | 428 // NOTE: This function returns *after* FinalizeLoading is called. |
| 429 void IsolateReloadContext::Reload(bool force_reload) { |
| 426 TIMELINE_SCOPE(Reload); | 430 TIMELINE_SCOPE(Reload); |
| 427 Thread* thread = Thread::Current(); | 431 Thread* thread = Thread::Current(); |
| 428 ASSERT(isolate() == thread->isolate()); | 432 ASSERT(isolate() == thread->isolate()); |
| 429 | 433 |
| 430 // Grab root library before calling CheckpointBeforeReload. | 434 // Grab root library before calling CheckpointBeforeReload. |
| 431 const Library& root_lib = Library::Handle(object_store()->root_library()); | 435 const Library& root_lib = Library::Handle(object_store()->root_library()); |
| 432 ASSERT(!root_lib.IsNull()); | 436 ASSERT(!root_lib.IsNull()); |
| 433 const String& root_lib_url = String::Handle(root_lib.url()); | 437 const String& root_lib_url = String::Handle(root_lib.url()); |
| 434 | 438 |
| 435 // Check to see which libraries have been modified. | 439 // Check to see which libraries have been modified. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 Api::Scope api_scope(thread); | 483 Api::Scope api_scope(thread); |
| 480 | 484 |
| 481 Dart_Handle retval = | 485 Dart_Handle retval = |
| 482 (I->library_tag_handler())(Dart_kScriptTag, | 486 (I->library_tag_handler())(Dart_kScriptTag, |
| 483 Api::NewHandle(thread, Library::null()), | 487 Api::NewHandle(thread, Library::null()), |
| 484 Api::NewHandle(thread, root_lib_url.raw())); | 488 Api::NewHandle(thread, root_lib_url.raw())); |
| 485 result = Api::UnwrapHandle(retval); | 489 result = Api::UnwrapHandle(retval); |
| 486 } | 490 } |
| 487 if (result.IsError()) { | 491 if (result.IsError()) { |
| 488 const Error& error = Error::Cast(result); | 492 const Error& error = Error::Cast(result); |
| 489 AddReasonForCancelling(new Aborted(error)); | 493 AddReasonForCancelling(new Aborted(zone_, error)); |
| 490 } | 494 } |
| 491 } | 495 } |
| 492 | 496 |
| 493 | 497 |
| 494 void IsolateReloadContext::RegisterClass(const Class& new_cls) { | 498 void IsolateReloadContext::RegisterClass(const Class& new_cls) { |
| 495 const Class& old_cls = Class::Handle(OldClassOrNull(new_cls)); | 499 const Class& old_cls = Class::Handle(OldClassOrNull(new_cls)); |
| 496 if (old_cls.IsNull()) { | 500 if (old_cls.IsNull()) { |
| 497 I->class_table()->Register(new_cls); | 501 I->class_table()->Register(new_cls); |
| 498 | 502 |
| 499 if (FLAG_identity_reload) { | 503 if (FLAG_identity_reload) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 510 isolate()->class_table()->SetAt(old_cls.id(), new_cls.raw()); | 514 isolate()->class_table()->SetAt(old_cls.id(), new_cls.raw()); |
| 511 if (!old_cls.is_enum_class()) { | 515 if (!old_cls.is_enum_class()) { |
| 512 new_cls.CopyCanonicalConstants(old_cls); | 516 new_cls.CopyCanonicalConstants(old_cls); |
| 513 } | 517 } |
| 514 new_cls.CopyCanonicalType(old_cls); | 518 new_cls.CopyCanonicalType(old_cls); |
| 515 AddBecomeMapping(old_cls, new_cls); | 519 AddBecomeMapping(old_cls, new_cls); |
| 516 AddClassMapping(new_cls, old_cls); | 520 AddClassMapping(new_cls, old_cls); |
| 517 } | 521 } |
| 518 | 522 |
| 519 | 523 |
| 520 void IsolateReloadContext::FinishReload() { | 524 // FinalizeLoading will be called *before* Reload() returns. |
| 525 void IsolateReloadContext::FinalizeLoading() { |
| 521 if (reload_skipped_) { | 526 if (reload_skipped_) { |
| 522 return; | 527 return; |
| 523 } | 528 } |
| 524 BuildLibraryMapping(); | 529 BuildLibraryMapping(); |
| 525 TIR_Print("---- DONE FINALIZING\n"); | 530 TIR_Print("---- DONE FINALIZING\n"); |
| 526 if (ValidateReload()) { | 531 if (ValidateReload()) { |
| 527 Commit(); | 532 Commit(); |
| 528 PostCommit(); | 533 PostCommit(); |
| 529 isolate()->set_last_reload_timestamp(reload_timestamp_); | 534 isolate()->set_last_reload_timestamp(reload_timestamp_); |
| 530 } else { | 535 } else { |
| 531 ReportReasonsForCancelling(); | 536 ReportReasonsForCancelling(); |
| 532 Rollback(); | 537 Rollback(); |
| 533 } | 538 } |
| 534 // ValidateReload mutates the direct subclass information and does | 539 // ValidateReload mutates the direct subclass information and does |
| 535 // not remove dead subclasses. Rebuild the direct subclass | 540 // not remove dead subclasses. Rebuild the direct subclass |
| 536 // information from scratch. | 541 // information from scratch. |
| 537 RebuildDirectSubclasses(); | 542 RebuildDirectSubclasses(); |
| 538 | 543 |
| 539 if (FLAG_write_protect_code) { | 544 if (FLAG_write_protect_code) { |
| 540 // Re-enable code page write protection. | 545 // Re-enable code page write protection. |
| 541 I->heap()->WriteProtectCode(true); | 546 I->heap()->WriteProtectCode(true); |
| 542 } | 547 } |
| 543 | 548 |
| 544 BackgroundCompiler::Enable(); | 549 BackgroundCompiler::Enable(); |
| 545 | 550 |
| 551 reload_aborted_ = HasReasonsForCancelling(); |
| 546 ReportOnJSON(js_); | 552 ReportOnJSON(js_); |
| 547 } | 553 } |
| 548 | 554 |
| 549 | 555 |
| 550 void IsolateReloadContext::ReportOnJSON(JSONStream* stream) { | 556 void IsolateReloadContext::ReportOnJSON(JSONStream* stream) { |
| 551 JSONObject jsobj(stream); | 557 JSONObject jsobj(stream); |
| 552 jsobj.AddProperty("type", "ReloadReport"); | 558 jsobj.AddProperty("type", "ReloadReport"); |
| 553 jsobj.AddProperty("success", !HasReasonsForCancelling()); | 559 jsobj.AddProperty("success", !HasReasonsForCancelling()); |
| 554 { | 560 { |
| 555 JSONObject details(&jsobj, "details"); | 561 JSONObject details(&jsobj, "details"); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 573 JSONArray array(&jsobj, "shapeChangeMappings"); | 579 JSONArray array(&jsobj, "shapeChangeMappings"); |
| 574 for (intptr_t i = 0; i < instance_morphers_.length(); i++) { | 580 for (intptr_t i = 0; i < instance_morphers_.length(); i++) { |
| 575 instance_morphers_.At(i)->AppendTo(&array); | 581 instance_morphers_.At(i)->AppendTo(&array); |
| 576 } | 582 } |
| 577 } | 583 } |
| 578 } | 584 } |
| 579 } | 585 } |
| 580 | 586 |
| 581 | 587 |
| 582 void IsolateReloadContext::AbortReload(const Error& error) { | 588 void IsolateReloadContext::AbortReload(const Error& error) { |
| 583 AddReasonForCancelling(new Aborted(error)); | 589 AddReasonForCancelling(new Aborted(zone_, error)); |
| 584 ReportReasonsForCancelling(); | 590 ReportReasonsForCancelling(); |
| 585 Rollback(); | 591 Rollback(); |
| 586 } | 592 } |
| 587 | 593 |
| 588 | 594 |
| 589 void IsolateReloadContext::EnsuredUnoptimizedCodeForStack() { | 595 void IsolateReloadContext::EnsuredUnoptimizedCodeForStack() { |
| 590 TIMELINE_SCOPE(EnsuredUnoptimizedCodeForStack); | 596 TIMELINE_SCOPE(EnsuredUnoptimizedCodeForStack); |
| 591 StackFrameIterator it(StackFrameIterator::kDontValidateFrames); | 597 StackFrameIterator it(StackFrameIterator::kDontValidateFrames); |
| 592 | 598 |
| 593 Function& func = Function::Handle(); | 599 Function& func = Function::Handle(); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 | 721 |
| 716 const GrowableObjectArray& libs = | 722 const GrowableObjectArray& libs = |
| 717 GrowableObjectArray::Handle(object_store()->libraries()); | 723 GrowableObjectArray::Handle(object_store()->libraries()); |
| 718 Library& lib = Library::Handle(); | 724 Library& lib = Library::Handle(); |
| 719 Array& scripts = Array::Handle(); | 725 Array& scripts = Array::Handle(); |
| 720 Script& script = Script::Handle(); | 726 Script& script = Script::Handle(); |
| 721 intptr_t num_libs = libs.Length(); | 727 intptr_t num_libs = libs.Length(); |
| 722 | 728 |
| 723 // Construct the imported-by graph. | 729 // Construct the imported-by graph. |
| 724 ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >* imported_by = | 730 ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >* imported_by = |
| 725 new ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >(num_libs); | 731 new ZoneGrowableArray<ZoneGrowableArray<intptr_t>* >(zone_, num_libs); |
| 726 imported_by->SetLength(num_libs); | 732 imported_by->SetLength(num_libs); |
| 727 for (intptr_t i = 0; i < num_libs; i++) { | 733 for (intptr_t i = 0; i < num_libs; i++) { |
| 728 (*imported_by)[i] = new ZoneGrowableArray<intptr_t>(); | 734 (*imported_by)[i] = new ZoneGrowableArray<intptr_t>(zone_, 0); |
| 729 } | 735 } |
| 730 Array& ports = Array::Handle(); | 736 Array& ports = Array::Handle(); |
| 731 Namespace& ns = Namespace::Handle(); | 737 Namespace& ns = Namespace::Handle(); |
| 732 Library& target = Library::Handle(); | 738 Library& target = Library::Handle(); |
| 733 | 739 |
| 734 for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) { | 740 for (intptr_t lib_idx = 0; lib_idx < num_libs; lib_idx++) { |
| 735 lib ^= libs.At(lib_idx); | 741 lib ^= libs.At(lib_idx); |
| 736 ASSERT(lib_idx == lib.index()); | 742 ASSERT(lib_idx == lib.index()); |
| 737 if (lib.is_dart_scheme()) { | 743 if (lib.is_dart_scheme()) { |
| 738 // We don't care about imports among dart scheme libraries. | 744 // We don't care about imports among dart scheme libraries. |
| (...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1210 // must be zapped to prevent the forwarding in GetClassForHeapWalkAt. | 1216 // must be zapped to prevent the forwarding in GetClassForHeapWalkAt. |
| 1211 // Instance will from now be described by the isolate's class table. | 1217 // Instance will from now be described by the isolate's class table. |
| 1212 free(saved_class_table_); | 1218 free(saved_class_table_); |
| 1213 saved_class_table_ = NULL; | 1219 saved_class_table_ = NULL; |
| 1214 Become::ElementsForwardIdentity(before, after); | 1220 Become::ElementsForwardIdentity(before, after); |
| 1215 } | 1221 } |
| 1216 | 1222 |
| 1217 | 1223 |
| 1218 bool IsolateReloadContext::ValidateReload() { | 1224 bool IsolateReloadContext::ValidateReload() { |
| 1219 TIMELINE_SCOPE(ValidateReload); | 1225 TIMELINE_SCOPE(ValidateReload); |
| 1220 if (has_error()) return false; | 1226 if (reload_aborted()) return false; |
| 1221 | 1227 |
| 1222 // Validate libraries. | 1228 // Validate libraries. |
| 1223 { | 1229 { |
| 1224 ASSERT(library_map_storage_ != Array::null()); | 1230 ASSERT(library_map_storage_ != Array::null()); |
| 1225 UnorderedHashMap<LibraryMapTraits> map(library_map_storage_); | 1231 UnorderedHashMap<LibraryMapTraits> map(library_map_storage_); |
| 1226 UnorderedHashMap<LibraryMapTraits>::Iterator it(&map); | 1232 UnorderedHashMap<LibraryMapTraits>::Iterator it(&map); |
| 1227 Library& lib = Library::Handle(); | 1233 Library& lib = Library::Handle(); |
| 1228 Library& new_lib = Library::Handle(); | 1234 Library& new_lib = Library::Handle(); |
| 1229 while (it.MoveNext()) { | 1235 while (it.MoveNext()) { |
| 1230 const intptr_t entry = it.Current(); | 1236 const intptr_t entry = it.Current(); |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1596 ASSERT(!super_cls.IsNull()); | 1602 ASSERT(!super_cls.IsNull()); |
| 1597 super_cls.AddDirectSubclass(cls); | 1603 super_cls.AddDirectSubclass(cls); |
| 1598 } | 1604 } |
| 1599 } | 1605 } |
| 1600 } | 1606 } |
| 1601 } | 1607 } |
| 1602 | 1608 |
| 1603 #endif // !PRODUCT | 1609 #endif // !PRODUCT |
| 1604 | 1610 |
| 1605 } // namespace dart | 1611 } // namespace dart |
| OLD | NEW |