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 |