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(); |