| 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" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 #define REUSABLE_HANDLE_SCOPE_INIT(object) | 34 #define REUSABLE_HANDLE_SCOPE_INIT(object) |
| 35 #endif // defined(DEBUG) | 35 #endif // defined(DEBUG) |
| 36 | 36 |
| 37 #define REUSABLE_HANDLE_INITIALIZERS(object) \ | 37 #define REUSABLE_HANDLE_INITIALIZERS(object) \ |
| 38 object##_handle_(NULL), | 38 object##_handle_(NULL), |
| 39 | 39 |
| 40 | 40 |
| 41 Thread::Thread(Isolate* isolate) | 41 Thread::Thread(Isolate* isolate) |
| 42 : BaseThread(false), | 42 : BaseThread(false), |
| 43 os_thread_(NULL), | 43 os_thread_(NULL), |
| 44 thread_lock_(new Monitor()), |
| 44 isolate_(NULL), | 45 isolate_(NULL), |
| 45 heap_(NULL), | 46 heap_(NULL), |
| 46 zone_(NULL), | 47 zone_(NULL), |
| 47 api_reusable_scope_(NULL), | 48 api_reusable_scope_(NULL), |
| 48 api_top_scope_(NULL), | 49 api_top_scope_(NULL), |
| 49 top_exit_frame_info_(0), | 50 top_exit_frame_info_(0), |
| 50 top_resource_(NULL), | 51 top_resource_(NULL), |
| 51 long_jump_base_(NULL), | 52 long_jump_base_(NULL), |
| 52 store_buffer_block_(NULL), | 53 store_buffer_block_(NULL), |
| 53 no_callback_scope_depth_(0), | 54 no_callback_scope_depth_(0), |
| 54 #if defined(DEBUG) | 55 #if defined(DEBUG) |
| 55 top_handle_scope_(NULL), | 56 top_handle_scope_(NULL), |
| 56 no_handle_scope_depth_(0), | 57 no_handle_scope_depth_(0), |
| 57 no_safepoint_scope_depth_(0), | 58 no_safepoint_scope_depth_(0), |
| 58 #endif | 59 #endif |
| 59 reusable_handles_(), | 60 reusable_handles_(), |
| 60 cha_(NULL), | 61 cha_(NULL), |
| 61 deopt_id_(0), | 62 deopt_id_(0), |
| 62 vm_tag_(0), | 63 vm_tag_(0), |
| 63 pending_functions_(GrowableObjectArray::null()), | 64 pending_functions_(GrowableObjectArray::null()), |
| 64 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) | 65 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) |
| 65 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) | 66 REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) |
| 67 safepoint_state_(0), |
| 68 execution_state_(kThreadInVM), |
| 66 next_(NULL) { | 69 next_(NULL) { |
| 67 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \ | 70 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \ |
| 68 member_name = default_init_value; | 71 member_name = default_init_value; |
| 69 CACHED_CONSTANTS_LIST(DEFAULT_INIT) | 72 CACHED_CONSTANTS_LIST(DEFAULT_INIT) |
| 70 #undef DEFAULT_INIT | 73 #undef DEFAULT_INIT |
| 71 | 74 |
| 72 #define DEFAULT_INIT(name) \ | 75 #define DEFAULT_INIT(name) \ |
| 73 name##_entry_point_ = 0; | 76 name##_entry_point_ = 0; |
| 74 RUNTIME_ENTRY_LIST(DEFAULT_INIT) | 77 RUNTIME_ENTRY_LIST(DEFAULT_INIT) |
| 75 #undef DEFAULT_INIT | 78 #undef DEFAULT_INIT |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 RawGrowableObjectArray* Thread::pending_functions() { | 170 RawGrowableObjectArray* Thread::pending_functions() { |
| 168 if (pending_functions_ == GrowableObjectArray::null()) { | 171 if (pending_functions_ == GrowableObjectArray::null()) { |
| 169 pending_functions_ = GrowableObjectArray::New(Heap::kOld); | 172 pending_functions_ = GrowableObjectArray::New(Heap::kOld); |
| 170 } | 173 } |
| 171 return pending_functions_; | 174 return pending_functions_; |
| 172 } | 175 } |
| 173 | 176 |
| 174 | 177 |
| 175 bool Thread::EnterIsolate(Isolate* isolate) { | 178 bool Thread::EnterIsolate(Isolate* isolate) { |
| 176 const bool kIsMutatorThread = true; | 179 const bool kIsMutatorThread = true; |
| 177 const bool kDontBypassSafepoints = false; | 180 Thread* thread = isolate->ScheduleThread(kIsMutatorThread); |
| 178 ThreadRegistry* tr = isolate->thread_registry(); | |
| 179 Thread* thread = tr->Schedule( | |
| 180 isolate, kIsMutatorThread, kDontBypassSafepoints); | |
| 181 if (thread != NULL) { | 181 if (thread != NULL) { |
| 182 isolate->MakeCurrentThreadMutator(thread); | |
| 183 thread->set_vm_tag(VMTag::kVMTagId); | |
| 184 ASSERT(thread->store_buffer_block_ == NULL); | 182 ASSERT(thread->store_buffer_block_ == NULL); |
| 185 thread->StoreBufferAcquire(); | 183 thread->StoreBufferAcquire(); |
| 186 return true; | 184 return true; |
| 187 } | 185 } |
| 188 return false; | 186 return false; |
| 189 } | 187 } |
| 190 | 188 |
| 191 | 189 |
| 192 void Thread::ExitIsolate() { | 190 void Thread::ExitIsolate() { |
| 193 Thread* thread = Thread::Current(); | 191 Thread* thread = Thread::Current(); |
| 194 ASSERT(thread != NULL); | 192 ASSERT(thread != NULL && thread->IsMutatorThread()); |
| 195 ASSERT(thread->IsMutatorThread()); | 193 DEBUG_ASSERT(!thread->IsAnyReusableHandleScopeActive()); |
| 196 #if defined(DEBUG) | 194 |
| 197 ASSERT(!thread->IsAnyReusableHandleScopeActive()); | 195 Isolate* isolate = thread->isolate(); |
| 198 #endif // DEBUG | 196 ASSERT(isolate != NULL); |
| 197 ASSERT(thread->execution_state() == Thread::kThreadInVM); |
| 199 // Clear since GC will not visit the thread once it is unscheduled. | 198 // Clear since GC will not visit the thread once it is unscheduled. |
| 200 thread->ClearReusableHandles(); | 199 thread->ClearReusableHandles(); |
| 201 thread->StoreBufferRelease(); | 200 thread->StoreBufferRelease(); |
| 202 Isolate* isolate = thread->isolate(); | |
| 203 ASSERT(isolate != NULL); | |
| 204 if (isolate->is_runnable()) { | 201 if (isolate->is_runnable()) { |
| 205 thread->set_vm_tag(VMTag::kIdleTagId); | 202 thread->set_vm_tag(VMTag::kIdleTagId); |
| 206 } else { | 203 } else { |
| 207 thread->set_vm_tag(VMTag::kLoadWaitTagId); | 204 thread->set_vm_tag(VMTag::kLoadWaitTagId); |
| 208 } | 205 } |
| 209 const bool kIsMutatorThread = true; | 206 const bool kIsMutatorThread = true; |
| 210 const bool kDontBypassSafepoints = false; | 207 isolate->UnscheduleThread(thread, kIsMutatorThread); |
| 211 ThreadRegistry* tr = isolate->thread_registry(); | |
| 212 tr->Unschedule(thread, kIsMutatorThread, kDontBypassSafepoints); | |
| 213 isolate->ClearMutatorThread(); | |
| 214 } | 208 } |
| 215 | 209 |
| 216 | 210 |
| 217 bool Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { | 211 bool Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { |
| 218 const bool kIsNotMutatorThread = false; | 212 const bool kIsNotMutatorThread = false; |
| 219 ThreadRegistry* tr = isolate->thread_registry(); | 213 Thread* thread = isolate->ScheduleThread(kIsNotMutatorThread, |
| 220 Thread* thread = tr->Schedule(isolate, kIsNotMutatorThread, bypass_safepoint); | 214 bypass_safepoint); |
| 221 if (thread != NULL) { | 215 if (thread != NULL) { |
| 222 ASSERT(thread->store_buffer_block_ == NULL); | 216 ASSERT(thread->store_buffer_block_ == NULL); |
| 223 // TODO(koda): Use StoreBufferAcquire once we properly flush | 217 // TODO(koda): Use StoreBufferAcquire once we properly flush |
| 224 // before Scavenge. | 218 // before Scavenge. |
| 225 thread->store_buffer_block_ = | 219 thread->store_buffer_block_ = |
| 226 thread->isolate()->store_buffer()->PopEmptyBlock(); | 220 thread->isolate()->store_buffer()->PopEmptyBlock(); |
| 227 // This thread should not be the main mutator. | 221 // This thread should not be the main mutator. |
| 228 ASSERT(!thread->IsMutatorThread()); | 222 ASSERT(!thread->IsMutatorThread()); |
| 229 return true; | 223 return true; |
| 230 } | 224 } |
| 231 return false; | 225 return false; |
| 232 } | 226 } |
| 233 | 227 |
| 234 | 228 |
| 235 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { | 229 void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { |
| 236 Thread* thread = Thread::Current(); | 230 Thread* thread = Thread::Current(); |
| 237 ASSERT(thread != NULL); | 231 ASSERT(thread != NULL); |
| 238 ASSERT(!thread->IsMutatorThread()); | 232 ASSERT(!thread->IsMutatorThread()); |
| 233 ASSERT(thread->execution_state() == Thread::kThreadInVM); |
| 239 thread->StoreBufferRelease(); | 234 thread->StoreBufferRelease(); |
| 240 Isolate* isolate = thread->isolate(); | 235 Isolate* isolate = thread->isolate(); |
| 241 ASSERT(isolate != NULL); | 236 ASSERT(isolate != NULL); |
| 242 const bool kIsNotMutatorThread = false; | 237 const bool kIsNotMutatorThread = false; |
| 243 ThreadRegistry* tr = isolate->thread_registry(); | 238 isolate->UnscheduleThread(thread, kIsNotMutatorThread, bypass_safepoint); |
| 244 tr->Unschedule(thread, kIsNotMutatorThread, bypass_safepoint); | |
| 245 } | 239 } |
| 246 | 240 |
| 247 | 241 |
| 248 void Thread::PrepareForGC() { | 242 void Thread::PrepareForGC() { |
| 249 ASSERT(isolate()->thread_registry()->AtSafepoint()); | 243 ASSERT(IsAtSafepoint()); |
| 250 // Prevent scheduling another GC by ignoring the threshold. | 244 // Prevent scheduling another GC by ignoring the threshold. |
| 245 ASSERT(store_buffer_block_ != NULL); |
| 251 StoreBufferRelease(StoreBuffer::kIgnoreThreshold); | 246 StoreBufferRelease(StoreBuffer::kIgnoreThreshold); |
| 252 // Make sure to get an *empty* block; the isolate needs all entries | 247 // Make sure to get an *empty* block; the isolate needs all entries |
| 253 // at GC time. | 248 // at GC time. |
| 254 // TODO(koda): Replace with an epilogue (PrepareAfterGC) that acquires. | 249 // TODO(koda): Replace with an epilogue (PrepareAfterGC) that acquires. |
| 255 store_buffer_block_ = isolate()->store_buffer()->PopEmptyBlock(); | 250 store_buffer_block_ = isolate()->store_buffer()->PopEmptyBlock(); |
| 256 } | 251 } |
| 257 | 252 |
| 258 | 253 |
| 259 void Thread::StoreBufferBlockProcess(StoreBuffer::ThresholdPolicy policy) { | 254 void Thread::StoreBufferBlockProcess(StoreBuffer::ThresholdPolicy policy) { |
| 260 StoreBufferRelease(policy); | 255 StoreBufferRelease(policy); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 | 287 |
| 293 bool Thread::IsMutatorThread() const { | 288 bool Thread::IsMutatorThread() const { |
| 294 return ((isolate_ != NULL) && (isolate_->mutator_thread() == this)); | 289 return ((isolate_ != NULL) && (isolate_->mutator_thread() == this)); |
| 295 } | 290 } |
| 296 | 291 |
| 297 | 292 |
| 298 bool Thread::CanCollectGarbage() const { | 293 bool Thread::CanCollectGarbage() const { |
| 299 // We have non mutator threads grow the heap instead of triggering | 294 // We have non mutator threads grow the heap instead of triggering |
| 300 // a garbage collection when they are at a safepoint (e.g: background | 295 // a garbage collection when they are at a safepoint (e.g: background |
| 301 // compiler thread finalizing and installing code at a safepoint). | 296 // compiler thread finalizing and installing code at a safepoint). |
| 302 // Note: This code will change once the new Safepoint logic is in place. | 297 return (IsMutatorThread() || IsAtSafepoint()); |
| 303 return (IsMutatorThread() || | |
| 304 (isolate_ != NULL && !isolate_->thread_registry()->AtSafepoint())); | |
| 305 } | 298 } |
| 306 | 299 |
| 307 | 300 |
| 308 bool Thread::IsExecutingDartCode() const { | 301 bool Thread::IsExecutingDartCode() const { |
| 309 return (top_exit_frame_info() == 0) && | 302 return (top_exit_frame_info() == 0) && |
| 310 (vm_tag() == VMTag::kDartTagId); | 303 (vm_tag() == VMTag::kDartTagId); |
| 311 } | 304 } |
| 312 | 305 |
| 313 | 306 |
| 314 bool Thread::HasExitedDartCode() const { | 307 bool Thread::HasExitedDartCode() const { |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 while (scope != NULL && | 440 while (scope != NULL && |
| 448 scope->stack_marker() != 0 && | 441 scope->stack_marker() != 0 && |
| 449 scope->stack_marker() == stack_marker) { | 442 scope->stack_marker() == stack_marker) { |
| 450 api_top_scope_ = scope->previous(); | 443 api_top_scope_ = scope->previous(); |
| 451 delete scope; | 444 delete scope; |
| 452 scope = api_top_scope_; | 445 scope = api_top_scope_; |
| 453 } | 446 } |
| 454 } | 447 } |
| 455 | 448 |
| 456 | 449 |
| 450 void Thread::EnterSafepointUsingLock() { |
| 451 isolate()->safepoint_handler()->EnterSafepointUsingLock(this); |
| 452 } |
| 453 |
| 454 |
| 455 void Thread::ExitSafepointUsingLock() { |
| 456 isolate()->safepoint_handler()->ExitSafepointUsingLock(this); |
| 457 } |
| 458 |
| 459 |
| 460 void Thread::BlockForSafepoint() { |
| 461 isolate()->safepoint_handler()->BlockForSafepoint(this); |
| 462 } |
| 463 |
| 464 |
| 457 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread) | 465 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread) |
| 458 : StackResource(thread) { | 466 : StackResource(thread) { |
| 459 if (thread != NULL) { | 467 if (thread != NULL) { |
| 460 OSThread* os_thread = thread->os_thread(); | 468 OSThread* os_thread = thread->os_thread(); |
| 461 ASSERT(os_thread != NULL); | 469 ASSERT(os_thread != NULL); |
| 462 os_thread->DisableThreadInterrupts(); | 470 os_thread->DisableThreadInterrupts(); |
| 463 } | 471 } |
| 464 } | 472 } |
| 465 | 473 |
| 466 | 474 |
| 467 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { | 475 DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { |
| 468 if (thread() != NULL) { | 476 if (thread() != NULL) { |
| 469 OSThread* os_thread = thread()->os_thread(); | 477 OSThread* os_thread = thread()->os_thread(); |
| 470 ASSERT(os_thread != NULL); | 478 ASSERT(os_thread != NULL); |
| 471 os_thread->EnableThreadInterrupts(); | 479 os_thread->EnableThreadInterrupts(); |
| 472 } | 480 } |
| 473 } | 481 } |
| 474 | 482 |
| 475 } // namespace dart | 483 } // namespace dart |
| OLD | NEW |