| OLD | NEW | 
|---|
| 1 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2015, 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/thread.h" | 5 #include "vm/thread.h" | 
| 6 | 6 | 
| 7 #include "vm/dart_api_state.h" | 7 #include "vm/dart_api_state.h" | 
| 8 #include "vm/growable_array.h" | 8 #include "vm/growable_array.h" | 
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" | 
| 10 #include "vm/lockers.h" | 10 #include "vm/lockers.h" | 
| 11 #include "vm/log.h" | 11 #include "vm/log.h" | 
|  | 12 #include "vm/message_handler.h" | 
| 12 #include "vm/native_entry.h" | 13 #include "vm/native_entry.h" | 
| 13 #include "vm/object.h" | 14 #include "vm/object.h" | 
| 14 #include "vm/os_thread.h" | 15 #include "vm/os_thread.h" | 
| 15 #include "vm/profiler.h" | 16 #include "vm/profiler.h" | 
| 16 #include "vm/runtime_entry.h" | 17 #include "vm/runtime_entry.h" | 
| 17 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" | 
| 18 #include "vm/symbols.h" | 19 #include "vm/symbols.h" | 
| 19 #include "vm/thread_interrupter.h" | 20 #include "vm/thread_interrupter.h" | 
| 20 #include "vm/thread_registry.h" | 21 #include "vm/thread_registry.h" | 
| 21 | 22 | 
| 22 namespace dart { | 23 namespace dart { | 
| 23 | 24 | 
|  | 25 | 
|  | 26 DECLARE_FLAG(bool, trace_isolates); | 
|  | 27 DECLARE_FLAG(bool, trace_service); | 
|  | 28 DECLARE_FLAG(bool, trace_service_verbose); | 
|  | 29 | 
|  | 30 | 
| 24 Thread::~Thread() { | 31 Thread::~Thread() { | 
| 25   // We should cleanly exit any isolate before destruction. | 32   // We should cleanly exit any isolate before destruction. | 
| 26   ASSERT(isolate_ == NULL); | 33   ASSERT(isolate_ == NULL); | 
| 27   // There should be no top api scopes at this point. | 34   // There should be no top api scopes at this point. | 
| 28   ASSERT(api_top_scope() == NULL); | 35   ASSERT(api_top_scope() == NULL); | 
| 29   // Delete the resusable api scope if there is one. | 36   // Delete the resusable api scope if there is one. | 
| 30   if (api_reusable_scope_) { | 37   if (api_reusable_scope_) { | 
| 31     delete api_reusable_scope_; | 38     delete api_reusable_scope_; | 
| 32     api_reusable_scope_ = NULL; | 39     api_reusable_scope_ = NULL; | 
| 33   } | 40   } | 
| 34   delete thread_lock_; | 41   delete thread_lock_; | 
| 35   thread_lock_ = NULL; | 42   thread_lock_ = NULL; | 
| 36 } | 43 } | 
| 37 | 44 | 
| 38 | 45 | 
| 39 #if defined(DEBUG) | 46 #if defined(DEBUG) | 
| 40 #define REUSABLE_HANDLE_SCOPE_INIT(object)                                     \ | 47 #define REUSABLE_HANDLE_SCOPE_INIT(object)                                     \ | 
| 41   reusable_##object##_handle_scope_active_(false), | 48   reusable_##object##_handle_scope_active_(false), | 
| 42 #else | 49 #else | 
| 43 #define REUSABLE_HANDLE_SCOPE_INIT(object) | 50 #define REUSABLE_HANDLE_SCOPE_INIT(object) | 
| 44 #endif  // defined(DEBUG) | 51 #endif  // defined(DEBUG) | 
| 45 | 52 | 
| 46 #define REUSABLE_HANDLE_INITIALIZERS(object)                                   \ | 53 #define REUSABLE_HANDLE_INITIALIZERS(object)                                   \ | 
| 47   object##_handle_(NULL), | 54   object##_handle_(NULL), | 
| 48 | 55 | 
| 49 | 56 | 
| 50 Thread::Thread(Isolate* isolate) | 57 Thread::Thread(Isolate* isolate) | 
| 51     : BaseThread(false), | 58     : BaseThread(false), | 
|  | 59       stack_limit_(0), | 
|  | 60       stack_overflow_flags_(0), | 
|  | 61       isolate_(NULL), | 
|  | 62       heap_(NULL), | 
|  | 63       top_exit_frame_info_(0), | 
|  | 64       store_buffer_block_(NULL), | 
|  | 65       vm_tag_(0), | 
| 52       os_thread_(NULL), | 66       os_thread_(NULL), | 
| 53       thread_lock_(new Monitor()), | 67       thread_lock_(new Monitor()), | 
| 54       isolate_(NULL), |  | 
| 55       heap_(NULL), |  | 
| 56       zone_(NULL), | 68       zone_(NULL), | 
| 57       api_reusable_scope_(NULL), | 69       api_reusable_scope_(NULL), | 
| 58       api_top_scope_(NULL), | 70       api_top_scope_(NULL), | 
| 59       top_exit_frame_info_(0), |  | 
| 60       top_resource_(NULL), | 71       top_resource_(NULL), | 
| 61       long_jump_base_(NULL), | 72       long_jump_base_(NULL), | 
| 62       store_buffer_block_(NULL), |  | 
| 63       no_callback_scope_depth_(0), | 73       no_callback_scope_depth_(0), | 
| 64 #if defined(DEBUG) | 74 #if defined(DEBUG) | 
| 65       top_handle_scope_(NULL), | 75       top_handle_scope_(NULL), | 
| 66       no_handle_scope_depth_(0), | 76       no_handle_scope_depth_(0), | 
| 67       no_safepoint_scope_depth_(0), | 77       no_safepoint_scope_depth_(0), | 
| 68 #endif | 78 #endif | 
| 69       reusable_handles_(), | 79       reusable_handles_(), | 
|  | 80       saved_stack_limit_(0), | 
|  | 81       deferred_interrupts_mask_(0), | 
|  | 82       deferred_interrupts_(0), | 
|  | 83       stack_overflow_count_(0), | 
| 70       cha_(NULL), | 84       cha_(NULL), | 
| 71       deopt_id_(0), | 85       deopt_id_(0), | 
| 72       vm_tag_(0), |  | 
| 73       pending_functions_(GrowableObjectArray::null()), | 86       pending_functions_(GrowableObjectArray::null()), | 
| 74       sticky_error_(Error::null()), | 87       sticky_error_(Error::null()), | 
| 75       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) | 88       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) | 
| 76       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) | 89       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) | 
| 77       safepoint_state_(0), | 90       safepoint_state_(0), | 
| 78       execution_state_(kThreadInVM), | 91       execution_state_(kThreadInVM), | 
| 79       next_(NULL) { | 92       next_(NULL) { | 
| 80 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \ | 93 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \ | 
| 81   member_name = default_init_value; | 94   member_name = default_init_value; | 
| 82 CACHED_CONSTANTS_LIST(DEFAULT_INIT) | 95 CACHED_CONSTANTS_LIST(DEFAULT_INIT) | 
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 275   // Prevent scheduling another GC by ignoring the threshold. | 288   // Prevent scheduling another GC by ignoring the threshold. | 
| 276   ASSERT(store_buffer_block_ != NULL); | 289   ASSERT(store_buffer_block_ != NULL); | 
| 277   StoreBufferRelease(StoreBuffer::kIgnoreThreshold); | 290   StoreBufferRelease(StoreBuffer::kIgnoreThreshold); | 
| 278   // Make sure to get an *empty* block; the isolate needs all entries | 291   // Make sure to get an *empty* block; the isolate needs all entries | 
| 279   // at GC time. | 292   // at GC time. | 
| 280   // TODO(koda): Replace with an epilogue (PrepareAfterGC) that acquires. | 293   // TODO(koda): Replace with an epilogue (PrepareAfterGC) that acquires. | 
| 281   store_buffer_block_ = isolate()->store_buffer()->PopEmptyBlock(); | 294   store_buffer_block_ = isolate()->store_buffer()->PopEmptyBlock(); | 
| 282 } | 295 } | 
| 283 | 296 | 
| 284 | 297 | 
|  | 298 void Thread::SetStackLimitFromStackBase(uword stack_base) { | 
|  | 299   // Set stack limit. | 
|  | 300 #if defined(USING_SIMULATOR) | 
|  | 301   // Ignore passed-in native stack top and use Simulator stack top. | 
|  | 302   Simulator* sim = Simulator::Current();  // May allocate a simulator. | 
|  | 303   ASSERT(isolate()->simulator() == sim);  // Isolate's simulator is current one. | 
|  | 304   stack_base = sim->StackTop(); | 
|  | 305   // The overflow area is accounted for by the simulator. | 
|  | 306 #endif | 
|  | 307   SetStackLimit(stack_base - OSThread::GetSpecifiedStackSize()); | 
|  | 308 } | 
|  | 309 | 
|  | 310 | 
|  | 311 void Thread::SetStackLimit(uword limit) { | 
|  | 312   // The thread setting the stack limit is not necessarily the thread which | 
|  | 313   // the stack limit is being set on. | 
|  | 314   MonitorLocker ml(thread_lock_); | 
|  | 315   if (stack_limit_ == saved_stack_limit_) { | 
|  | 316     // No interrupt pending, set stack_limit_ too. | 
|  | 317     stack_limit_ = limit; | 
|  | 318   } | 
|  | 319   saved_stack_limit_ = limit; | 
|  | 320 } | 
|  | 321 | 
|  | 322 | 
|  | 323 void Thread::ClearStackLimit() { | 
|  | 324   SetStackLimit(~static_cast<uword>(0)); | 
|  | 325 } | 
|  | 326 | 
|  | 327 | 
|  | 328 /* static */ | 
|  | 329 uword Thread::GetCurrentStackPointer() { | 
|  | 330   // Since AddressSanitizer's detect_stack_use_after_return instruments the | 
|  | 331   // C++ code to give out fake stack addresses, we call a stub in that case. | 
|  | 332   uword (*func)() = reinterpret_cast<uword (*)()>( | 
|  | 333       StubCode::GetStackPointer_entry()->EntryPoint()); | 
|  | 334   // But for performance (and to support simulators), we normally use a local. | 
|  | 335 #if defined(__has_feature) | 
|  | 336 #if __has_feature(address_sanitizer) | 
|  | 337   uword current_sp = func(); | 
|  | 338   return current_sp; | 
|  | 339 #else | 
|  | 340   uword stack_allocated_local_address = reinterpret_cast<uword>(&func); | 
|  | 341   return stack_allocated_local_address; | 
|  | 342 #endif | 
|  | 343 #else | 
|  | 344   uword stack_allocated_local_address = reinterpret_cast<uword>(&func); | 
|  | 345   return stack_allocated_local_address; | 
|  | 346 #endif | 
|  | 347 } | 
|  | 348 | 
|  | 349 | 
|  | 350 void Thread::ScheduleInterrupts(uword interrupt_bits) { | 
|  | 351   MonitorLocker ml(thread_lock_); | 
|  | 352   ScheduleInterruptsLocked(interrupt_bits); | 
|  | 353 } | 
|  | 354 | 
|  | 355 | 
|  | 356 void Thread::ScheduleInterruptsLocked(uword interrupt_bits) { | 
|  | 357   ASSERT(thread_lock_->IsOwnedByCurrentThread()); | 
|  | 358   ASSERT((interrupt_bits & ~kInterruptsMask) == 0);  // Must fit in mask. | 
|  | 359 | 
|  | 360   // Check to see if any of the requested interrupts should be deferred. | 
|  | 361   uword defer_bits = interrupt_bits & deferred_interrupts_mask_; | 
|  | 362   if (defer_bits != 0) { | 
|  | 363     deferred_interrupts_ |= defer_bits; | 
|  | 364     interrupt_bits &= ~deferred_interrupts_mask_; | 
|  | 365     if (interrupt_bits == 0) { | 
|  | 366       return; | 
|  | 367     } | 
|  | 368   } | 
|  | 369 | 
|  | 370   if (stack_limit_ == saved_stack_limit_) { | 
|  | 371     stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask; | 
|  | 372   } | 
|  | 373   stack_limit_ |= interrupt_bits; | 
|  | 374 } | 
|  | 375 | 
|  | 376 | 
|  | 377 uword Thread::GetAndClearInterrupts() { | 
|  | 378   MonitorLocker ml(thread_lock_); | 
|  | 379   if (stack_limit_ == saved_stack_limit_) { | 
|  | 380     return 0;  // No interrupt was requested. | 
|  | 381   } | 
|  | 382   uword interrupt_bits = stack_limit_ & kInterruptsMask; | 
|  | 383   stack_limit_ = saved_stack_limit_; | 
|  | 384   return interrupt_bits; | 
|  | 385 } | 
|  | 386 | 
|  | 387 | 
|  | 388 void Thread::DeferOOBMessageInterrupts() { | 
|  | 389   MonitorLocker ml(thread_lock_); | 
|  | 390   ASSERT(deferred_interrupts_mask_ == 0); | 
|  | 391   deferred_interrupts_mask_ = kMessageInterrupt; | 
|  | 392 | 
|  | 393   if (stack_limit_ != saved_stack_limit_) { | 
|  | 394     // Defer any interrupts which are currently pending. | 
|  | 395     deferred_interrupts_ = stack_limit_ & deferred_interrupts_mask_; | 
|  | 396 | 
|  | 397     // Clear deferrable interrupts, if present. | 
|  | 398     stack_limit_ &= ~deferred_interrupts_mask_; | 
|  | 399 | 
|  | 400     if ((stack_limit_ & kInterruptsMask) == 0) { | 
|  | 401       // No other pending interrupts.  Restore normal stack limit. | 
|  | 402       stack_limit_ = saved_stack_limit_; | 
|  | 403     } | 
|  | 404   } | 
|  | 405   if (FLAG_trace_service && FLAG_trace_service_verbose) { | 
|  | 406     OS::Print("[+%" Pd64 "ms] Isolate %s deferring OOB interrupts\n", | 
|  | 407               Dart::timestamp(), isolate()->name()); | 
|  | 408   } | 
|  | 409 } | 
|  | 410 | 
|  | 411 | 
|  | 412 void Thread::RestoreOOBMessageInterrupts() { | 
|  | 413   MonitorLocker ml(thread_lock_); | 
|  | 414   ASSERT(deferred_interrupts_mask_ == kMessageInterrupt); | 
|  | 415   deferred_interrupts_mask_ = 0; | 
|  | 416   if (deferred_interrupts_ != 0) { | 
|  | 417     if (stack_limit_ == saved_stack_limit_) { | 
|  | 418       stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask; | 
|  | 419     } | 
|  | 420     stack_limit_ |= deferred_interrupts_; | 
|  | 421     deferred_interrupts_ = 0; | 
|  | 422   } | 
|  | 423   if (FLAG_trace_service && FLAG_trace_service_verbose) { | 
|  | 424     OS::Print("[+%" Pd64 "ms] Isolate %s restoring OOB interrupts\n", | 
|  | 425               Dart::timestamp(), isolate()->name()); | 
|  | 426   } | 
|  | 427 } | 
|  | 428 | 
|  | 429 | 
|  | 430 RawError* Thread::HandleInterrupts() { | 
|  | 431   uword interrupt_bits = GetAndClearInterrupts(); | 
|  | 432   if ((interrupt_bits & kVMInterrupt) != 0) { | 
|  | 433     if (isolate()->store_buffer()->Overflowed()) { | 
|  | 434       if (FLAG_verbose_gc) { | 
|  | 435         OS::PrintErr("Scavenge scheduled by store buffer overflow.\n"); | 
|  | 436       } | 
|  | 437       heap()->CollectGarbage(Heap::kNew); | 
|  | 438     } | 
|  | 439   } | 
|  | 440   if ((interrupt_bits & kMessageInterrupt) != 0) { | 
|  | 441     MessageHandler::MessageStatus status = | 
|  | 442         isolate()->message_handler()->HandleOOBMessages(); | 
|  | 443     if (status != MessageHandler::kOK) { | 
|  | 444       // False result from HandleOOBMessages signals that the isolate should | 
|  | 445       // be terminating. | 
|  | 446       if (FLAG_trace_isolates) { | 
|  | 447         OS::Print("[!] Terminating isolate due to OOB message:\n" | 
|  | 448                   "\tisolate:    %s\n", isolate()->name()); | 
|  | 449       } | 
|  | 450       Thread* thread = Thread::Current(); | 
|  | 451       const Error& error = Error::Handle(thread->sticky_error()); | 
|  | 452       ASSERT(!error.IsNull() && error.IsUnwindError()); | 
|  | 453       thread->clear_sticky_error(); | 
|  | 454       return error.raw(); | 
|  | 455     } | 
|  | 456   } | 
|  | 457   return Error::null(); | 
|  | 458 } | 
|  | 459 | 
|  | 460 | 
|  | 461 uword Thread::GetAndClearStackOverflowFlags() { | 
|  | 462   uword stack_overflow_flags = stack_overflow_flags_; | 
|  | 463   stack_overflow_flags_ = 0; | 
|  | 464   return stack_overflow_flags; | 
|  | 465 } | 
|  | 466 | 
|  | 467 | 
| 285 void Thread::StoreBufferBlockProcess(StoreBuffer::ThresholdPolicy policy) { | 468 void Thread::StoreBufferBlockProcess(StoreBuffer::ThresholdPolicy policy) { | 
| 286   StoreBufferRelease(policy); | 469   StoreBufferRelease(policy); | 
| 287   StoreBufferAcquire(); | 470   StoreBufferAcquire(); | 
| 288 } | 471 } | 
| 289 | 472 | 
| 290 | 473 | 
| 291 void Thread::StoreBufferAddObject(RawObject* obj) { | 474 void Thread::StoreBufferAddObject(RawObject* obj) { | 
| 292   store_buffer_block_->Push(obj); | 475   store_buffer_block_->Push(obj); | 
| 293   if (store_buffer_block_->IsFull()) { | 476   if (store_buffer_block_->IsFull()) { | 
| 294     StoreBufferBlockProcess(StoreBuffer::kCheckThreshold); | 477     StoreBufferBlockProcess(StoreBuffer::kCheckThreshold); | 
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 504 | 687 | 
| 505 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { | 688 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { | 
| 506   if (thread() != NULL) { | 689   if (thread() != NULL) { | 
| 507     OSThread* os_thread = thread()->os_thread(); | 690     OSThread* os_thread = thread()->os_thread(); | 
| 508     ASSERT(os_thread != NULL); | 691     ASSERT(os_thread != NULL); | 
| 509     os_thread->EnableThreadInterrupts(); | 692     os_thread->EnableThreadInterrupts(); | 
| 510   } | 693   } | 
| 511 } | 694 } | 
| 512 | 695 | 
| 513 }  // namespace dart | 696 }  // namespace dart | 
| OLD | NEW | 
|---|