| Index: runtime/vm/thread.cc
|
| diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
|
| index c5c6e70a7bb8524c897de04779dcfa75b19f837f..31bcaad6f22fbb863c6ab398bfad8b22c90b22ed 100644
|
| --- a/runtime/vm/thread.cc
|
| +++ b/runtime/vm/thread.cc
|
| @@ -9,6 +9,7 @@
|
| #include "vm/isolate.h"
|
| #include "vm/lockers.h"
|
| #include "vm/log.h"
|
| +#include "vm/message_handler.h"
|
| #include "vm/native_entry.h"
|
| #include "vm/object.h"
|
| #include "vm/os_thread.h"
|
| @@ -21,6 +22,12 @@
|
|
|
| namespace dart {
|
|
|
| +
|
| +DECLARE_FLAG(bool, trace_isolates);
|
| +DECLARE_FLAG(bool, trace_service);
|
| +DECLARE_FLAG(bool, trace_service_verbose);
|
| +
|
| +
|
| Thread::~Thread() {
|
| // We should cleanly exit any isolate before destruction.
|
| ASSERT(isolate_ == NULL);
|
| @@ -49,17 +56,20 @@ Thread::~Thread() {
|
|
|
| Thread::Thread(Isolate* isolate)
|
| : BaseThread(false),
|
| - os_thread_(NULL),
|
| - thread_lock_(new Monitor()),
|
| + stack_limit_(0),
|
| + stack_overflow_flags_(0),
|
| isolate_(NULL),
|
| heap_(NULL),
|
| + top_exit_frame_info_(0),
|
| + store_buffer_block_(NULL),
|
| + vm_tag_(0),
|
| + os_thread_(NULL),
|
| + thread_lock_(new Monitor()),
|
| zone_(NULL),
|
| api_reusable_scope_(NULL),
|
| api_top_scope_(NULL),
|
| - top_exit_frame_info_(0),
|
| top_resource_(NULL),
|
| long_jump_base_(NULL),
|
| - store_buffer_block_(NULL),
|
| no_callback_scope_depth_(0),
|
| #if defined(DEBUG)
|
| top_handle_scope_(NULL),
|
| @@ -67,9 +77,12 @@ Thread::Thread(Isolate* isolate)
|
| no_safepoint_scope_depth_(0),
|
| #endif
|
| reusable_handles_(),
|
| + saved_stack_limit_(0),
|
| + deferred_interrupts_mask_(0),
|
| + deferred_interrupts_(0),
|
| + stack_overflow_count_(0),
|
| cha_(NULL),
|
| deopt_id_(0),
|
| - vm_tag_(0),
|
| pending_functions_(GrowableObjectArray::null()),
|
| sticky_error_(Error::null()),
|
| REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
|
| @@ -282,6 +295,176 @@ void Thread::PrepareForGC() {
|
| }
|
|
|
|
|
| +void Thread::SetStackLimitFromStackBase(uword stack_base) {
|
| + // Set stack limit.
|
| +#if defined(USING_SIMULATOR)
|
| + // Ignore passed-in native stack top and use Simulator stack top.
|
| + Simulator* sim = Simulator::Current(); // May allocate a simulator.
|
| + ASSERT(isolate()->simulator() == sim); // Isolate's simulator is current one.
|
| + stack_base = sim->StackTop();
|
| + // The overflow area is accounted for by the simulator.
|
| +#endif
|
| + SetStackLimit(stack_base - OSThread::GetSpecifiedStackSize());
|
| +}
|
| +
|
| +
|
| +void Thread::SetStackLimit(uword limit) {
|
| + // The thread setting the stack limit is not necessarily the thread which
|
| + // the stack limit is being set on.
|
| + MonitorLocker ml(thread_lock_);
|
| + if (stack_limit_ == saved_stack_limit_) {
|
| + // No interrupt pending, set stack_limit_ too.
|
| + stack_limit_ = limit;
|
| + }
|
| + saved_stack_limit_ = limit;
|
| +}
|
| +
|
| +
|
| +void Thread::ClearStackLimit() {
|
| + SetStackLimit(~static_cast<uword>(0));
|
| +}
|
| +
|
| +
|
| +/* static */
|
| +uword Thread::GetCurrentStackPointer() {
|
| + // Since AddressSanitizer's detect_stack_use_after_return instruments the
|
| + // C++ code to give out fake stack addresses, we call a stub in that case.
|
| + uword (*func)() = reinterpret_cast<uword (*)()>(
|
| + StubCode::GetStackPointer_entry()->EntryPoint());
|
| + // But for performance (and to support simulators), we normally use a local.
|
| +#if defined(__has_feature)
|
| +#if __has_feature(address_sanitizer)
|
| + uword current_sp = func();
|
| + return current_sp;
|
| +#else
|
| + uword stack_allocated_local_address = reinterpret_cast<uword>(&func);
|
| + return stack_allocated_local_address;
|
| +#endif
|
| +#else
|
| + uword stack_allocated_local_address = reinterpret_cast<uword>(&func);
|
| + return stack_allocated_local_address;
|
| +#endif
|
| +}
|
| +
|
| +
|
| +void Thread::ScheduleInterrupts(uword interrupt_bits) {
|
| + MonitorLocker ml(thread_lock_);
|
| + ScheduleInterruptsLocked(interrupt_bits);
|
| +}
|
| +
|
| +
|
| +void Thread::ScheduleInterruptsLocked(uword interrupt_bits) {
|
| + ASSERT(thread_lock_->IsOwnedByCurrentThread());
|
| + ASSERT((interrupt_bits & ~kInterruptsMask) == 0); // Must fit in mask.
|
| +
|
| + // Check to see if any of the requested interrupts should be deferred.
|
| + uword defer_bits = interrupt_bits & deferred_interrupts_mask_;
|
| + if (defer_bits != 0) {
|
| + deferred_interrupts_ |= defer_bits;
|
| + interrupt_bits &= ~deferred_interrupts_mask_;
|
| + if (interrupt_bits == 0) {
|
| + return;
|
| + }
|
| + }
|
| +
|
| + if (stack_limit_ == saved_stack_limit_) {
|
| + stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
|
| + }
|
| + stack_limit_ |= interrupt_bits;
|
| +}
|
| +
|
| +
|
| +uword Thread::GetAndClearInterrupts() {
|
| + MonitorLocker ml(thread_lock_);
|
| + if (stack_limit_ == saved_stack_limit_) {
|
| + return 0; // No interrupt was requested.
|
| + }
|
| + uword interrupt_bits = stack_limit_ & kInterruptsMask;
|
| + stack_limit_ = saved_stack_limit_;
|
| + return interrupt_bits;
|
| +}
|
| +
|
| +
|
| +void Thread::DeferOOBMessageInterrupts() {
|
| + MonitorLocker ml(thread_lock_);
|
| + ASSERT(deferred_interrupts_mask_ == 0);
|
| + deferred_interrupts_mask_ = kMessageInterrupt;
|
| +
|
| + if (stack_limit_ != saved_stack_limit_) {
|
| + // Defer any interrupts which are currently pending.
|
| + deferred_interrupts_ = stack_limit_ & deferred_interrupts_mask_;
|
| +
|
| + // Clear deferrable interrupts, if present.
|
| + stack_limit_ &= ~deferred_interrupts_mask_;
|
| +
|
| + if ((stack_limit_ & kInterruptsMask) == 0) {
|
| + // No other pending interrupts. Restore normal stack limit.
|
| + stack_limit_ = saved_stack_limit_;
|
| + }
|
| + }
|
| + if (FLAG_trace_service && FLAG_trace_service_verbose) {
|
| + OS::Print("[+%" Pd64 "ms] Isolate %s deferring OOB interrupts\n",
|
| + Dart::timestamp(), isolate()->name());
|
| + }
|
| +}
|
| +
|
| +
|
| +void Thread::RestoreOOBMessageInterrupts() {
|
| + MonitorLocker ml(thread_lock_);
|
| + ASSERT(deferred_interrupts_mask_ == kMessageInterrupt);
|
| + deferred_interrupts_mask_ = 0;
|
| + if (deferred_interrupts_ != 0) {
|
| + if (stack_limit_ == saved_stack_limit_) {
|
| + stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
|
| + }
|
| + stack_limit_ |= deferred_interrupts_;
|
| + deferred_interrupts_ = 0;
|
| + }
|
| + if (FLAG_trace_service && FLAG_trace_service_verbose) {
|
| + OS::Print("[+%" Pd64 "ms] Isolate %s restoring OOB interrupts\n",
|
| + Dart::timestamp(), isolate()->name());
|
| + }
|
| +}
|
| +
|
| +
|
| +RawError* Thread::HandleInterrupts() {
|
| + uword interrupt_bits = GetAndClearInterrupts();
|
| + if ((interrupt_bits & kVMInterrupt) != 0) {
|
| + if (isolate()->store_buffer()->Overflowed()) {
|
| + if (FLAG_verbose_gc) {
|
| + OS::PrintErr("Scavenge scheduled by store buffer overflow.\n");
|
| + }
|
| + heap()->CollectGarbage(Heap::kNew);
|
| + }
|
| + }
|
| + if ((interrupt_bits & kMessageInterrupt) != 0) {
|
| + MessageHandler::MessageStatus status =
|
| + isolate()->message_handler()->HandleOOBMessages();
|
| + if (status != MessageHandler::kOK) {
|
| + // False result from HandleOOBMessages signals that the isolate should
|
| + // be terminating.
|
| + if (FLAG_trace_isolates) {
|
| + OS::Print("[!] Terminating isolate due to OOB message:\n"
|
| + "\tisolate: %s\n", isolate()->name());
|
| + }
|
| + Thread* thread = Thread::Current();
|
| + const Error& error = Error::Handle(thread->sticky_error());
|
| + ASSERT(!error.IsNull() && error.IsUnwindError());
|
| + thread->clear_sticky_error();
|
| + return error.raw();
|
| + }
|
| + }
|
| + return Error::null();
|
| +}
|
| +
|
| +
|
| +uword Thread::GetAndClearStackOverflowFlags() {
|
| + uword stack_overflow_flags = stack_overflow_flags_;
|
| + stack_overflow_flags_ = 0;
|
| + return stack_overflow_flags;
|
| +}
|
| +
|
| +
|
| void Thread::StoreBufferBlockProcess(StoreBuffer::ThresholdPolicy policy) {
|
| StoreBufferRelease(policy);
|
| StoreBufferAcquire();
|
|
|