OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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.h" | 5 #include "vm/isolate.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 #include "include/dart_native_api.h" | 8 #include "include/dart_native_api.h" |
9 #include "platform/assert.h" | 9 #include "platform/assert.h" |
10 #include "platform/text_buffer.h" | 10 #include "platform/text_buffer.h" |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 priority == Isolate::kBeforeNextEventAction /* at_head */); | 337 priority == Isolate::kBeforeNextEventAction /* at_head */); |
338 } | 338 } |
339 break; | 339 break; |
340 } | 340 } |
341 case Isolate::kInterruptMsg: { | 341 case Isolate::kInterruptMsg: { |
342 // [ OOB, kInterruptMsg, pause capability ] | 342 // [ OOB, kInterruptMsg, pause capability ] |
343 if (message.Length() != 3) return Error::null(); | 343 if (message.Length() != 3) return Error::null(); |
344 Object& obj = Object::Handle(zone, message.At(2)); | 344 Object& obj = Object::Handle(zone, message.At(2)); |
345 if (!I->VerifyPauseCapability(obj)) return Error::null(); | 345 if (!I->VerifyPauseCapability(obj)) return Error::null(); |
346 | 346 |
| 347 #if !defined(PRODUCT) |
347 // If we are already paused, don't pause again. | 348 // If we are already paused, don't pause again. |
348 if (FLAG_support_debugger && (I->debugger()->PauseEvent() == NULL)) { | 349 if (I->debugger()->PauseEvent() == NULL) { |
349 return I->debugger()->PauseInterrupted(); | 350 return I->debugger()->PauseInterrupted(); |
350 } | 351 } |
| 352 #endif |
351 break; | 353 break; |
352 } | 354 } |
353 | 355 |
354 case Isolate::kAddExitMsg: | 356 case Isolate::kAddExitMsg: |
355 case Isolate::kDelExitMsg: | 357 case Isolate::kDelExitMsg: |
356 case Isolate::kAddErrorMsg: | 358 case Isolate::kAddErrorMsg: |
357 case Isolate::kDelErrorMsg: { | 359 case Isolate::kDelErrorMsg: { |
358 // [ OOB, msg, listener port ] | 360 // [ OOB, msg, listener port ] |
359 if (message.Length() < 3) return Error::null(); | 361 if (message.Length() < 3) return Error::null(); |
360 const Object& obj = Object::Handle(zone, message.At(2)); | 362 const Object& obj = Object::Handle(zone, message.At(2)); |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 // whether errors are fatal for the current isolate. | 657 // whether errors are fatal for the current isolate. |
656 return StoreError(T, result); | 658 return StoreError(T, result); |
657 } else { | 659 } else { |
658 bool has_listener = I->NotifyErrorListeners(exc_str, stacktrace_str); | 660 bool has_listener = I->NotifyErrorListeners(exc_str, stacktrace_str); |
659 if (I->ErrorsFatal()) { | 661 if (I->ErrorsFatal()) { |
660 if (has_listener) { | 662 if (has_listener) { |
661 T->clear_sticky_error(); | 663 T->clear_sticky_error(); |
662 } else { | 664 } else { |
663 T->set_sticky_error(result); | 665 T->set_sticky_error(result); |
664 } | 666 } |
| 667 #if !defined(PRODUCT) |
665 // Notify the debugger about specific unhandled exceptions which are | 668 // Notify the debugger about specific unhandled exceptions which are |
666 // withheld when being thrown. Do this after setting the sticky error | 669 // withheld when being thrown. Do this after setting the sticky error |
667 // so the isolate has an error set when paused with the unhandled | 670 // so the isolate has an error set when paused with the unhandled |
668 // exception. | 671 // exception. |
669 if (result.IsUnhandledException()) { | 672 if (result.IsUnhandledException()) { |
670 const UnhandledException& error = UnhandledException::Cast(result); | 673 const UnhandledException& error = UnhandledException::Cast(result); |
671 RawInstance* exception = error.exception(); | 674 RawInstance* exception = error.exception(); |
672 if ((exception == I->object_store()->out_of_memory()) || | 675 if ((exception == I->object_store()->out_of_memory()) || |
673 (exception == I->object_store()->stack_overflow())) { | 676 (exception == I->object_store()->stack_overflow())) { |
674 // We didn't notify the debugger when the stack was full. Do it now. | 677 // We didn't notify the debugger when the stack was full. Do it now. |
675 if (FLAG_support_debugger) { | 678 I->debugger()->PauseException(Instance::Handle(exception)); |
676 I->debugger()->PauseException(Instance::Handle(exception)); | |
677 } | |
678 } | 679 } |
679 } | 680 } |
| 681 #endif // !defined(PRODUCT) |
680 return kError; | 682 return kError; |
681 } | 683 } |
682 } | 684 } |
683 return kOK; | 685 return kOK; |
684 } | 686 } |
685 | 687 |
686 void Isolate::FlagsInitialize(Dart_IsolateFlags* api_flags) { | 688 void Isolate::FlagsInitialize(Dart_IsolateFlags* api_flags) { |
687 api_flags->version = DART_FLAGS_CURRENT_VERSION; | 689 api_flags->version = DART_FLAGS_CURRENT_VERSION; |
688 #define INIT_FROM_FLAG(name, isolate_flag, flag) api_flags->isolate_flag = flag; | 690 #define INIT_FROM_FLAG(name, isolate_flag, flag) api_flags->isolate_flag = flag; |
689 ISOLATE_FLAG_LIST(INIT_FROM_FLAG) | 691 ISOLATE_FLAG_LIST(INIT_FROM_FLAG) |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
748 start_time_micros_(OS::GetCurrentMonotonicMicros()), | 750 start_time_micros_(OS::GetCurrentMonotonicMicros()), |
749 main_port_(0), | 751 main_port_(0), |
750 origin_id_(0), | 752 origin_id_(0), |
751 pause_capability_(0), | 753 pause_capability_(0), |
752 terminate_capability_(0), | 754 terminate_capability_(0), |
753 errors_fatal_(true), | 755 errors_fatal_(true), |
754 init_callback_data_(NULL), | 756 init_callback_data_(NULL), |
755 environment_callback_(NULL), | 757 environment_callback_(NULL), |
756 library_tag_handler_(NULL), | 758 library_tag_handler_(NULL), |
757 api_state_(NULL), | 759 api_state_(NULL), |
| 760 #if !defined(PRODUCT) |
758 debugger_(NULL), | 761 debugger_(NULL), |
| 762 #endif |
759 resume_request_(false), | 763 resume_request_(false), |
760 last_resume_timestamp_(OS::GetCurrentTimeMillis()), | 764 last_resume_timestamp_(OS::GetCurrentTimeMillis()), |
761 random_(), | 765 random_(), |
762 simulator_(NULL), | 766 simulator_(NULL), |
763 mutex_(new Mutex()), | 767 mutex_(new Mutex()), |
764 symbols_mutex_(new Mutex()), | 768 symbols_mutex_(new Mutex()), |
765 type_canonicalization_mutex_(new Mutex()), | 769 type_canonicalization_mutex_(new Mutex()), |
766 constant_canonicalization_mutex_(new Mutex()), | 770 constant_canonicalization_mutex_(new Mutex()), |
767 megamorphic_lookup_mutex_(new Mutex()), | 771 megamorphic_lookup_mutex_(new Mutex()), |
768 message_handler_(NULL), | 772 message_handler_(NULL), |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
818 #undef REUSABLE_HANDLE_INITIALIZERS | 822 #undef REUSABLE_HANDLE_INITIALIZERS |
819 | 823 |
820 Isolate::~Isolate() { | 824 Isolate::~Isolate() { |
821 free(name_); | 825 free(name_); |
822 free(debugger_name_); | 826 free(debugger_name_); |
823 delete store_buffer_; | 827 delete store_buffer_; |
824 delete heap_; | 828 delete heap_; |
825 delete object_store_; | 829 delete object_store_; |
826 delete api_state_; | 830 delete api_state_; |
827 #ifndef PRODUCT | 831 #ifndef PRODUCT |
828 if (FLAG_support_debugger) { | 832 delete debugger_; |
829 delete debugger_; | |
830 } | |
831 #endif // !PRODUCT | 833 #endif // !PRODUCT |
832 #if defined(USING_SIMULATOR) | 834 #if defined(USING_SIMULATOR) |
833 delete simulator_; | 835 delete simulator_; |
834 #endif | 836 #endif |
835 delete mutex_; | 837 delete mutex_; |
836 mutex_ = NULL; // Fail fast if interrupts are scheduled on a dead isolate. | 838 mutex_ = NULL; // Fail fast if interrupts are scheduled on a dead isolate. |
837 delete symbols_mutex_; | 839 delete symbols_mutex_; |
838 symbols_mutex_ = NULL; | 840 symbols_mutex_ = NULL; |
839 delete type_canonicalization_mutex_; | 841 delete type_canonicalization_mutex_; |
840 type_canonicalization_mutex_ = NULL; | 842 type_canonicalization_mutex_ = NULL; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 #if defined(DEBUG) | 915 #if defined(DEBUG) |
914 // Verify that we are never reusing a live origin id. | 916 // Verify that we are never reusing a live origin id. |
915 VerifyOriginId id_verifier(result->main_port()); | 917 VerifyOriginId id_verifier(result->main_port()); |
916 Isolate::VisitIsolates(&id_verifier); | 918 Isolate::VisitIsolates(&id_verifier); |
917 #endif | 919 #endif |
918 result->set_origin_id(result->main_port()); | 920 result->set_origin_id(result->main_port()); |
919 result->set_pause_capability(result->random()->NextUInt64()); | 921 result->set_pause_capability(result->random()->NextUInt64()); |
920 result->set_terminate_capability(result->random()->NextUInt64()); | 922 result->set_terminate_capability(result->random()->NextUInt64()); |
921 | 923 |
922 result->BuildName(name_prefix); | 924 result->BuildName(name_prefix); |
923 if (FLAG_support_debugger) { | 925 #if !defined(PRODUCT) |
924 result->debugger_ = new Debugger(); | 926 result->debugger_ = new Debugger(); |
925 result->debugger_->Initialize(result); | 927 result->debugger_->Initialize(result); |
926 } | 928 #endif |
927 if (FLAG_trace_isolates) { | 929 if (FLAG_trace_isolates) { |
928 if (name_prefix == NULL || strcmp(name_prefix, "vm-isolate") != 0) { | 930 if (name_prefix == NULL || strcmp(name_prefix, "vm-isolate") != 0) { |
929 OS::Print( | 931 OS::Print( |
930 "[+] Starting isolate:\n" | 932 "[+] Starting isolate:\n" |
931 "\tisolate: %s\n", | 933 "\tisolate: %s\n", |
932 result->name()); | 934 result->name()); |
933 } | 935 } |
934 } | 936 } |
935 | 937 |
936 #ifndef PRODUCT | 938 #ifndef PRODUCT |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
974 void Isolate::set_debugger_name(const char* name) { | 976 void Isolate::set_debugger_name(const char* name) { |
975 free(debugger_name_); | 977 free(debugger_name_); |
976 debugger_name_ = strdup(name); | 978 debugger_name_ = strdup(name); |
977 } | 979 } |
978 | 980 |
979 int64_t Isolate::UptimeMicros() const { | 981 int64_t Isolate::UptimeMicros() const { |
980 return OS::GetCurrentMonotonicMicros() - start_time_micros_; | 982 return OS::GetCurrentMonotonicMicros() - start_time_micros_; |
981 } | 983 } |
982 | 984 |
983 bool Isolate::IsPaused() const { | 985 bool Isolate::IsPaused() const { |
| 986 #if defined(PRODUCT) |
| 987 return false; |
| 988 #else |
984 return (debugger_ != NULL) && (debugger_->PauseEvent() != NULL); | 989 return (debugger_ != NULL) && (debugger_->PauseEvent() != NULL); |
| 990 #endif |
985 } | 991 } |
986 | 992 |
987 RawError* Isolate::PausePostRequest() { | 993 RawError* Isolate::PausePostRequest() { |
988 if (!FLAG_support_debugger) { | 994 #if !defined(PRODUCT) |
989 return Error::null(); | |
990 } | |
991 if (debugger_ == NULL) { | 995 if (debugger_ == NULL) { |
992 return Error::null(); | 996 return Error::null(); |
993 } | 997 } |
994 ASSERT(!IsPaused()); | 998 ASSERT(!IsPaused()); |
995 const Error& error = Error::Handle(debugger_->PausePostRequest()); | 999 const Error& error = Error::Handle(debugger_->PausePostRequest()); |
996 if (!error.IsNull()) { | 1000 if (!error.IsNull()) { |
997 if (Thread::Current()->top_exit_frame_info() == 0) { | 1001 if (Thread::Current()->top_exit_frame_info() == 0) { |
998 return error.raw(); | 1002 return error.raw(); |
999 } else { | 1003 } else { |
1000 Exceptions::PropagateError(error); | 1004 Exceptions::PropagateError(error); |
1001 UNREACHABLE(); | 1005 UNREACHABLE(); |
1002 } | 1006 } |
1003 } | 1007 } |
| 1008 #endif |
1004 return Error::null(); | 1009 return Error::null(); |
1005 } | 1010 } |
1006 | 1011 |
1007 void Isolate::BuildName(const char* name_prefix) { | 1012 void Isolate::BuildName(const char* name_prefix) { |
1008 ASSERT(name_ == NULL); | 1013 ASSERT(name_ == NULL); |
1009 if (name_prefix == NULL) { | 1014 if (name_prefix == NULL) { |
1010 name_prefix = "isolate"; | 1015 name_prefix = "isolate"; |
1011 } | 1016 } |
1012 set_debugger_name(name_prefix); | 1017 set_debugger_name(name_prefix); |
1013 if (ServiceIsolate::NameEquals(name_prefix)) { | 1018 if (ServiceIsolate::NameEquals(name_prefix)) { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1085 MutexLocker ml(mutex_); | 1090 MutexLocker ml(mutex_); |
1086 // Check if we are in a valid state to make the isolate runnable. | 1091 // Check if we are in a valid state to make the isolate runnable. |
1087 if (is_runnable() == true) { | 1092 if (is_runnable() == true) { |
1088 return false; // Already runnable. | 1093 return false; // Already runnable. |
1089 } | 1094 } |
1090 // Set the isolate as runnable and if we are being spawned schedule | 1095 // Set the isolate as runnable and if we are being spawned schedule |
1091 // isolate on thread pool for execution. | 1096 // isolate on thread pool for execution. |
1092 ASSERT(object_store()->root_library() != Library::null()); | 1097 ASSERT(object_store()->root_library() != Library::null()); |
1093 set_is_runnable(true); | 1098 set_is_runnable(true); |
1094 #ifndef PRODUCT | 1099 #ifndef PRODUCT |
1095 if (FLAG_support_debugger) { | 1100 if (!ServiceIsolate::IsServiceIsolate(this)) { |
1096 if (!ServiceIsolate::IsServiceIsolate(this)) { | 1101 debugger()->OnIsolateRunnable(); |
1097 debugger()->OnIsolateRunnable(); | 1102 if (FLAG_pause_isolates_on_unhandled_exceptions) { |
1098 if (FLAG_pause_isolates_on_unhandled_exceptions) { | 1103 debugger()->SetExceptionPauseInfo(kPauseOnUnhandledExceptions); |
1099 debugger()->SetExceptionPauseInfo(kPauseOnUnhandledExceptions); | |
1100 } | |
1101 } | 1104 } |
1102 } | 1105 } |
1103 #endif // !PRODUCT | 1106 #endif // !PRODUCT |
1104 IsolateSpawnState* state = spawn_state(); | 1107 IsolateSpawnState* state = spawn_state(); |
1105 if (state != NULL) { | 1108 if (state != NULL) { |
1106 ASSERT(this == state->isolate()); | 1109 ASSERT(this == state->isolate()); |
1107 Run(); | 1110 Run(); |
1108 } | 1111 } |
1109 #ifndef PRODUCT | 1112 #ifndef PRODUCT |
1110 if (FLAG_support_timeline) { | 1113 if (FLAG_support_timeline) { |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1377 ASSERT(result.IsFunction()); | 1380 ASSERT(result.IsFunction()); |
1378 Function& func = Function::Handle(thread->zone()); | 1381 Function& func = Function::Handle(thread->zone()); |
1379 func ^= result.raw(); | 1382 func ^= result.raw(); |
1380 | 1383 |
1381 // TODO(turnidge): Currently we need a way to force a one-time | 1384 // TODO(turnidge): Currently we need a way to force a one-time |
1382 // breakpoint for all spawned isolates to support isolate | 1385 // breakpoint for all spawned isolates to support isolate |
1383 // debugging. Remove this once the vmservice becomes the standard | 1386 // debugging. Remove this once the vmservice becomes the standard |
1384 // way to debug. Set the breakpoint on the static function instead | 1387 // way to debug. Set the breakpoint on the static function instead |
1385 // of its implicit closure function because that latter is merely | 1388 // of its implicit closure function because that latter is merely |
1386 // a dispatcher that is marked as undebuggable. | 1389 // a dispatcher that is marked as undebuggable. |
1387 if (FLAG_support_debugger && FLAG_break_at_isolate_spawn) { | 1390 #if !defined(PRODUCT) |
| 1391 if (FLAG_break_at_isolate_spawn) { |
1388 isolate->debugger()->OneTimeBreakAtEntry(func); | 1392 isolate->debugger()->OneTimeBreakAtEntry(func); |
1389 } | 1393 } |
| 1394 #endif |
1390 | 1395 |
1391 func = func.ImplicitClosureFunction(); | 1396 func = func.ImplicitClosureFunction(); |
1392 | 1397 |
1393 const Array& capabilities = Array::Handle(Array::New(2)); | 1398 const Array& capabilities = Array::Handle(Array::New(2)); |
1394 Capability& capability = Capability::Handle(); | 1399 Capability& capability = Capability::Handle(); |
1395 capability = Capability::New(isolate->pause_capability()); | 1400 capability = Capability::New(isolate->pause_capability()); |
1396 capabilities.SetAt(0, capability); | 1401 capabilities.SetAt(0, capability); |
1397 // Check whether this isolate should be started in paused state. | 1402 // Check whether this isolate should be started in paused state. |
1398 if (state->paused()) { | 1403 if (state->paused()) { |
1399 bool added = isolate->AddResumeCapability(capability); | 1404 bool added = isolate->AddResumeCapability(capability); |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1556 | 1561 |
1557 // Notify exit listeners that this isolate is shutting down. | 1562 // Notify exit listeners that this isolate is shutting down. |
1558 if (object_store() != NULL) { | 1563 if (object_store() != NULL) { |
1559 const Error& error = Error::Handle(thread->sticky_error()); | 1564 const Error& error = Error::Handle(thread->sticky_error()); |
1560 if (error.IsNull() || !error.IsUnwindError() || | 1565 if (error.IsNull() || !error.IsUnwindError() || |
1561 UnwindError::Cast(error).is_user_initiated()) { | 1566 UnwindError::Cast(error).is_user_initiated()) { |
1562 NotifyExitListeners(); | 1567 NotifyExitListeners(); |
1563 } | 1568 } |
1564 } | 1569 } |
1565 | 1570 |
| 1571 #if !defined(PRODUCT) |
1566 // Clean up debugger resources. | 1572 // Clean up debugger resources. |
1567 if (FLAG_support_debugger) { | 1573 debugger()->Shutdown(); |
1568 debugger()->Shutdown(); | 1574 #endif |
1569 } | |
1570 | 1575 |
1571 // Close all the ports owned by this isolate. | 1576 // Close all the ports owned by this isolate. |
1572 PortMap::ClosePorts(message_handler()); | 1577 PortMap::ClosePorts(message_handler()); |
1573 | 1578 |
1574 // Fail fast if anybody tries to post any more messages to this isolate. | 1579 // Fail fast if anybody tries to post any more messages to this isolate. |
1575 delete message_handler(); | 1580 delete message_handler(); |
1576 set_message_handler(NULL); | 1581 set_message_handler(NULL); |
1577 if (FLAG_support_timeline) { | 1582 if (FLAG_support_timeline) { |
1578 // Before analyzing the isolate's timeline blocks- reclaim all cached | 1583 // Before analyzing the isolate's timeline blocks- reclaim all cached |
1579 // blocks. | 1584 // blocks. |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1776 // Visit the registered service extension handlers. | 1781 // Visit the registered service extension handlers. |
1777 visitor->VisitPointer( | 1782 visitor->VisitPointer( |
1778 reinterpret_cast<RawObject**>(®istered_service_extension_handlers_)); | 1783 reinterpret_cast<RawObject**>(®istered_service_extension_handlers_)); |
1779 | 1784 |
1780 // Visit the boxed_field_list_. | 1785 // Visit the boxed_field_list_. |
1781 // 'boxed_field_list_' access via mutator and background compilation threads | 1786 // 'boxed_field_list_' access via mutator and background compilation threads |
1782 // is guarded with a monitor. This means that we can visit it only | 1787 // is guarded with a monitor. This means that we can visit it only |
1783 // when at safepoint or the field_list_mutex_ lock has been taken. | 1788 // when at safepoint or the field_list_mutex_ lock has been taken. |
1784 visitor->VisitPointer(reinterpret_cast<RawObject**>(&boxed_field_list_)); | 1789 visitor->VisitPointer(reinterpret_cast<RawObject**>(&boxed_field_list_)); |
1785 | 1790 |
| 1791 #if !defined(PRODUCT) |
1786 // Visit objects in the debugger. | 1792 // Visit objects in the debugger. |
1787 if (FLAG_support_debugger) { | 1793 debugger()->VisitObjectPointers(visitor); |
1788 debugger()->VisitObjectPointers(visitor); | |
1789 } | |
1790 | 1794 |
1791 #if !defined(PRODUCT) | |
1792 // Visit objects that are being used for isolate reload. | 1795 // Visit objects that are being used for isolate reload. |
1793 if (reload_context() != NULL) { | 1796 if (reload_context() != NULL) { |
1794 reload_context()->VisitObjectPointers(visitor); | 1797 reload_context()->VisitObjectPointers(visitor); |
1795 } | 1798 } |
1796 if (ServiceIsolate::IsServiceIsolate(this)) { | 1799 if (ServiceIsolate::IsServiceIsolate(this)) { |
1797 ServiceIsolate::VisitObjectPointers(visitor); | 1800 ServiceIsolate::VisitObjectPointers(visitor); |
1798 } | 1801 } |
1799 #endif // !defined(PRODUCT) | 1802 #endif // !defined(PRODUCT) |
1800 | 1803 |
1801 #if !defined(DART_PRECOMPILED_RUNTIME) | 1804 #if !defined(DART_PRECOMPILED_RUNTIME) |
(...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2833 void IsolateSpawnState::DecrementSpawnCount() { | 2836 void IsolateSpawnState::DecrementSpawnCount() { |
2834 ASSERT(spawn_count_monitor_ != NULL); | 2837 ASSERT(spawn_count_monitor_ != NULL); |
2835 ASSERT(spawn_count_ != NULL); | 2838 ASSERT(spawn_count_ != NULL); |
2836 MonitorLocker ml(spawn_count_monitor_); | 2839 MonitorLocker ml(spawn_count_monitor_); |
2837 ASSERT(*spawn_count_ > 0); | 2840 ASSERT(*spawn_count_ > 0); |
2838 *spawn_count_ = *spawn_count_ - 1; | 2841 *spawn_count_ = *spawn_count_ - 1; |
2839 ml.Notify(); | 2842 ml.Notify(); |
2840 } | 2843 } |
2841 | 2844 |
2842 } // namespace dart | 2845 } // namespace dart |
OLD | NEW |