diff options
Diffstat (limited to 'runtime/thread.h')
-rw-r--r-- | runtime/thread.h | 716 |
1 files changed, 436 insertions, 280 deletions
diff --git a/runtime/thread.h b/runtime/thread.h index 63d22c5d7..59fe724f0 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -92,7 +92,7 @@ enum ThreadFlag { kCheckpointRequest = 2 // Request that the thread do some checkpoint work and then continue. }; -class PACKED(4) Thread { +class Thread { public: // Space to throw a StackOverflowError in. // TODO: shrink reserved space, in particular for 64bit. @@ -145,7 +145,8 @@ class PACKED(4) Thread { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Translates 172 to pAllocArrayFromCode and so on. - static void DumpThreadOffset(std::ostream& os, uint32_t offset, size_t size_of_pointers); + template<size_t size_of_pointers> + static void DumpThreadOffset(std::ostream& os, uint32_t offset); // Dumps a one-line summary of thread state (used for operator<<). void ShortDump(std::ostream& os) const; @@ -162,32 +163,24 @@ class PACKED(4) Thread { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ThreadState GetState() const { - DCHECK(state_and_flags_.as_struct.state >= kTerminated && state_and_flags_.as_struct.state <= kSuspended); - return static_cast<ThreadState>(state_and_flags_.as_struct.state); - } - - // This function can be used to make sure a thread's state is valid. - void CheckState(int id) const { - if (state_and_flags_.as_struct.state >= kTerminated && state_and_flags_.as_struct.state <= kSuspended) { - return; - } - LOG(INFO) << "Thread " << this << " state is invalid: " << state_and_flags_.as_struct.state << " id=" << id; - CHECK(false); + DCHECK_GE(tls32_.state_and_flags.as_struct.state, kTerminated); + DCHECK_LE(tls32_.state_and_flags.as_struct.state, kSuspended); + return static_cast<ThreadState>(tls32_.state_and_flags.as_struct.state); } ThreadState SetState(ThreadState new_state); int GetSuspendCount() const EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_suspend_count_lock_) { - return suspend_count_; + return tls32_.suspend_count; } int GetDebugSuspendCount() const EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_suspend_count_lock_) { - return debug_suspend_count_; + return tls32_.debug_suspend_count; } bool IsSuspended() const { union StateAndFlags state_and_flags; - state_and_flags.as_int = state_and_flags_.as_int; + state_and_flags.as_int = tls32_.state_and_flags.as_int; return state_and_flags.as_struct.state != kRunnable && (state_and_flags.as_struct.flags & kSuspendRequest) != 0; } @@ -221,9 +214,9 @@ class PACKED(4) Thread { const char* StartAssertNoThreadSuspension(const char* cause) { if (kIsDebugBuild) { CHECK(cause != NULL); - const char* previous_cause = last_no_thread_suspension_cause_; - no_thread_suspension_++; - last_no_thread_suspension_cause_ = cause; + const char* previous_cause = tlsPtr_.last_no_thread_suspension_cause; + tls32_.no_thread_suspension++; + tlsPtr_.last_no_thread_suspension_cause = cause; return previous_cause; } else { return nullptr; @@ -233,20 +226,20 @@ class PACKED(4) Thread { // End region where no thread suspension is expected. void EndAssertNoThreadSuspension(const char* old_cause) { if (kIsDebugBuild) { - CHECK(old_cause != NULL || no_thread_suspension_ == 1); - CHECK_GT(no_thread_suspension_, 0U); - no_thread_suspension_--; - last_no_thread_suspension_cause_ = old_cause; + CHECK(old_cause != nullptr || tls32_.no_thread_suspension == 1); + CHECK_GT(tls32_.no_thread_suspension, 0U); + tls32_.no_thread_suspension--; + tlsPtr_.last_no_thread_suspension_cause = old_cause; } } void AssertThreadSuspensionIsAllowable(bool check_locks = true) const; bool IsDaemon() const { - return daemon_; + return tls32_.daemon; } - bool HoldsLock(mirror::Object*) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool HoldsLock(mirror::Object*) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); /* * Changes the priority of this thread to match that of the java.lang.Thread object. @@ -265,11 +258,11 @@ class PACKED(4) Thread { static int GetNativePriority(); uint32_t GetThreadId() const { - return thin_lock_thread_id_; + return tls32_.thin_lock_thread_id; } pid_t GetTid() const { - return tid_; + return tls32_.tid; } // Returns the java.lang.Thread's name, or NULL if this Thread* doesn't have a peer. @@ -287,30 +280,30 @@ class PACKED(4) Thread { uint64_t GetCpuMicroTime() const; mirror::Object* GetPeer() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(jpeer_ == NULL); - return opeer_; + CHECK(tlsPtr_.jpeer == nullptr); + return tlsPtr_.opeer; } bool HasPeer() const { - return jpeer_ != NULL || opeer_ != NULL; + return tlsPtr_.jpeer != nullptr || tlsPtr_.opeer != nullptr; } RuntimeStats* GetStats() { - return &stats_; + return &tls64_.stats; } bool IsStillStarting() const; bool IsExceptionPending() const { - return exception_ != NULL; + return tlsPtr_.exception != nullptr; } mirror::Throwable* GetException(ThrowLocation* throw_location) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (throw_location != NULL) { - *throw_location = throw_location_; + if (throw_location != nullptr) { + *throw_location = tlsPtr_.throw_location; } - return exception_; + return tlsPtr_.exception; } void AssertNoPendingException() const; @@ -320,13 +313,13 @@ class PACKED(4) Thread { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { CHECK(new_exception != NULL); // TODO: DCHECK(!IsExceptionPending()); - exception_ = new_exception; - throw_location_ = throw_location; + tlsPtr_.exception = new_exception; + tlsPtr_.throw_location = throw_location; } void ClearException() { - exception_ = NULL; - throw_location_.Clear(); + tlsPtr_.exception = nullptr; + tlsPtr_.throw_location.Clear(); } // Find catch block and perform long jump to appropriate exception handle @@ -334,8 +327,8 @@ class PACKED(4) Thread { Context* GetLongJumpContext(); void ReleaseLongJumpContext(Context* context) { - DCHECK(long_jump_context_ == NULL); - long_jump_context_ = context; + DCHECK(tlsPtr_.long_jump_context == nullptr); + tlsPtr_.long_jump_context = context; } mirror::ArtMethod* GetCurrentMethod(uint32_t* dex_pc) const @@ -344,16 +337,17 @@ class PACKED(4) Thread { ThrowLocation GetCurrentLocationForThrow() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetTopOfStack(mirror::ArtMethod** top_method, uintptr_t pc) { - managed_stack_.SetTopQuickFrame(top_method); - managed_stack_.SetTopQuickFramePc(pc); + tlsPtr_.managed_stack.SetTopQuickFrame(top_method); + tlsPtr_.managed_stack.SetTopQuickFramePc(pc); } void SetTopOfShadowStack(ShadowFrame* top) { - managed_stack_.SetTopShadowFrame(top); + tlsPtr_.managed_stack.SetTopShadowFrame(top); } bool HasManagedStack() const { - return managed_stack_.GetTopQuickFrame() != NULL || managed_stack_.GetTopShadowFrame() != NULL; + return (tlsPtr_.managed_stack.GetTopQuickFrame() != nullptr) || + (tlsPtr_.managed_stack.GetTopShadowFrame() != nullptr); } // If 'msg' is NULL, no detail message is set. @@ -387,21 +381,65 @@ class PACKED(4) Thread { // JNI methods JNIEnvExt* GetJniEnv() const { - return jni_env_; + return tlsPtr_.jni_env; } // Convert a jobject into a Object* mirror::Object* DecodeJObject(jobject obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + mirror::Object* GetMonitorEnterObject() const { + return tlsPtr_.monitor_enter_object; + } + + void SetMonitorEnterObject(mirror::Object* obj) { + tlsPtr_.monitor_enter_object = obj; + } + // Implements java.lang.Thread.interrupted. - bool Interrupted(); + bool Interrupted() LOCKS_EXCLUDED(wait_mutex_); // Implements java.lang.Thread.isInterrupted. - bool IsInterrupted(); - void Interrupt(); - void Notify(); + bool IsInterrupted() LOCKS_EXCLUDED(wait_mutex_); + bool IsInterruptedLocked() EXCLUSIVE_LOCKS_REQUIRED(wait_mutex_) { + return interrupted_; + } + void Interrupt(Thread* self) LOCKS_EXCLUDED(wait_mutex_); + void SetInterruptedLocked(bool i) EXCLUSIVE_LOCKS_REQUIRED(wait_mutex_) { + interrupted_ = i; + } + void Notify() LOCKS_EXCLUDED(wait_mutex_); + + private: + void NotifyLocked(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(wait_mutex_); + + public: + Mutex* GetWaitMutex() const LOCK_RETURNED(wait_mutex_) { + return wait_mutex_; + } + + ConditionVariable* GetWaitConditionVariable() const EXCLUSIVE_LOCKS_REQUIRED(wait_mutex_) { + return wait_cond_; + } + + Monitor* GetWaitMonitor() const EXCLUSIVE_LOCKS_REQUIRED(wait_mutex_) { + return wait_monitor_; + } + + void SetWaitMonitor(Monitor* mon) EXCLUSIVE_LOCKS_REQUIRED(wait_mutex_) { + wait_monitor_ = mon; + } + + + // Waiter link-list support. + Thread* GetWaitNext() const { + return tlsPtr_.wait_next; + } + + void SetWaitNext(Thread* next) { + tlsPtr_.wait_next = next; + } mirror::ClassLoader* GetClassLoaderOverride() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return class_loader_override_; + return tlsPtr_.class_loader_override; } void SetClassLoaderOverride(mirror::ClassLoader* class_loader_override) @@ -428,41 +466,99 @@ class PACKED(4) Thread { // Offsets of various members of native Thread class, used by compiled code. // - static ThreadOffset SelfOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, self_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> ThinLockIdOffset() { + return ThreadOffset<pointer_size>( + OFFSETOF_MEMBER(Thread, tls32_) + + OFFSETOF_MEMBER(tls_32bit_sized_values, thin_lock_thread_id)); + } + + template<size_t pointer_size> + static ThreadOffset<pointer_size> ThreadFlagsOffset() { + return ThreadOffset<pointer_size>( + OFFSETOF_MEMBER(Thread, tls32_) + + OFFSETOF_MEMBER(tls_32bit_sized_values, state_and_flags)); + } + + private: + template<size_t pointer_size> + static ThreadOffset<pointer_size> ThreadOffsetFromTlsPtr(size_t tls_ptr_offset) { + size_t base = OFFSETOF_MEMBER(Thread, tlsPtr_); + size_t scale; + size_t shrink; + if (pointer_size == sizeof(void*)) { + scale = 1; + shrink = 1; + } else if (pointer_size > sizeof(void*)) { + scale = pointer_size / sizeof(void*); + shrink = 1; + } else { + DCHECK_GT(sizeof(void*), pointer_size); + scale = 1; + shrink = sizeof(void*) / pointer_size; + } + return ThreadOffset<pointer_size>(base + ((tls_ptr_offset * scale) / shrink)); + } + + public: + template<size_t pointer_size> + static ThreadOffset<pointer_size> QuickEntryPointOffset(size_t quick_entrypoint_offset) { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, quick_entrypoints) + quick_entrypoint_offset); + } + + template<size_t pointer_size> + static ThreadOffset<pointer_size> InterpreterEntryPointOffset(size_t interp_entrypoint_offset) { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, interpreter_entrypoints) + interp_entrypoint_offset); } - static ThreadOffset ExceptionOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, exception_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> JniEntryPointOffset(size_t jni_entrypoint_offset) { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, jni_entrypoints) + jni_entrypoint_offset); } - static ThreadOffset PeerOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, opeer_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> PortableEntryPointOffset(size_t port_entrypoint_offset) { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, portable_entrypoints) + port_entrypoint_offset); } - static ThreadOffset ThinLockIdOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, thin_lock_thread_id_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> SelfOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values, self)); } - static ThreadOffset CardTableOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, card_table_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> ExceptionOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values, exception)); } - static ThreadOffset ThreadFlagsOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, state_and_flags_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> PeerOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values, opeer)); } - static ThreadOffset ThreadSuspendTriggerOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, suspend_trigger_)); + + template<size_t pointer_size> + static ThreadOffset<pointer_size> CardTableOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values, card_table)); + } + + template<size_t pointer_size> + static ThreadOffset<pointer_size> ThreadSuspendTriggerOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, suspend_trigger)); } // Size of stack less any space reserved for stack overflow size_t GetStackSize() const { - return stack_size_ - (stack_end_ - stack_begin_); + return tlsPtr_.stack_size - (tlsPtr_.stack_end - tlsPtr_.stack_begin); } byte* GetStackEnd() const { - return stack_end_; + return tlsPtr_.stack_end; } // Set the stack end to that to be used during a stack overflow @@ -475,9 +571,9 @@ class PACKED(4) Thread { if (implicit_overflow_check) { // For implicit checks we also need to add in the protected region above the // overflow region. - stack_end_ = stack_begin_ + kStackOverflowImplicitCheckSize; + tlsPtr_.stack_end = tlsPtr_.stack_begin + kStackOverflowImplicitCheckSize; } else { - stack_end_ = stack_begin_ + kStackOverflowReservedBytes; + tlsPtr_.stack_end = tlsPtr_.stack_begin + kStackOverflowReservedBytes; } } @@ -485,55 +581,65 @@ class PACKED(4) Thread { void InstallImplicitProtection(bool is_main_stack); bool IsHandlingStackOverflow() const { - return stack_end_ == stack_begin_; + return tlsPtr_.stack_end == tlsPtr_.stack_begin; } - static ThreadOffset StackEndOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, stack_end_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> StackEndOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, stack_end)); } - static ThreadOffset JniEnvOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, jni_env_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> JniEnvOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, jni_env)); } - static ThreadOffset TopOfManagedStackOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, managed_stack_) + - ManagedStack::TopQuickFrameOffset()); + template<size_t pointer_size> + static ThreadOffset<pointer_size> TopOfManagedStackOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, managed_stack) + + ManagedStack::TopQuickFrameOffset()); } - static ThreadOffset TopOfManagedStackPcOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, managed_stack_) + - ManagedStack::TopQuickFramePcOffset()); + template<size_t pointer_size> + static ThreadOffset<pointer_size> TopOfManagedStackPcOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, managed_stack) + + ManagedStack::TopQuickFramePcOffset()); } const ManagedStack* GetManagedStack() const { - return &managed_stack_; + return &tlsPtr_.managed_stack; } // Linked list recording fragments of managed stack. void PushManagedStackFragment(ManagedStack* fragment) { - managed_stack_.PushManagedStackFragment(fragment); + tlsPtr_.managed_stack.PushManagedStackFragment(fragment); } void PopManagedStackFragment(const ManagedStack& fragment) { - managed_stack_.PopManagedStackFragment(fragment); + tlsPtr_.managed_stack.PopManagedStackFragment(fragment); } ShadowFrame* PushShadowFrame(ShadowFrame* new_top_frame) { - return managed_stack_.PushShadowFrame(new_top_frame); + return tlsPtr_.managed_stack.PushShadowFrame(new_top_frame); } ShadowFrame* PopShadowFrame() { - return managed_stack_.PopShadowFrame(); + return tlsPtr_.managed_stack.PopShadowFrame(); } - static ThreadOffset TopShadowFrameOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, managed_stack_) + - ManagedStack::TopShadowFrameOffset()); + template<size_t pointer_size> + static ThreadOffset<pointer_size> TopShadowFrameOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>( + OFFSETOF_MEMBER(tls_ptr_sized_values, managed_stack) + + ManagedStack::TopShadowFrameOffset()); } // Number of references allocated in JNI ShadowFrames on this thread. size_t NumJniShadowFrameReferences() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return managed_stack_.NumJniShadowFrameReferences(); + return tlsPtr_.managed_stack.NumJniShadowFrameReferences(); } // Number of references in SIRTs on this thread. @@ -551,27 +657,28 @@ class PACKED(4) Thread { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void PushSirt(StackIndirectReferenceTable* sirt) { - sirt->SetLink(top_sirt_); - top_sirt_ = sirt; + sirt->SetLink(tlsPtr_.top_sirt); + tlsPtr_.top_sirt = sirt; } StackIndirectReferenceTable* PopSirt() { - StackIndirectReferenceTable* sirt = top_sirt_; + StackIndirectReferenceTable* sirt = tlsPtr_.top_sirt; DCHECK(sirt != NULL); - top_sirt_ = top_sirt_->GetLink(); + tlsPtr_.top_sirt = tlsPtr_.top_sirt->GetLink(); return sirt; } - static ThreadOffset TopSirtOffset() { - return ThreadOffset(OFFSETOF_MEMBER(Thread, top_sirt_)); + template<size_t pointer_size> + static ThreadOffset<pointer_size> TopSirtOffset() { + return ThreadOffsetFromTlsPtr<pointer_size>(OFFSETOF_MEMBER(tls_ptr_sized_values, top_sirt)); } - DebugInvokeReq* GetInvokeReq() { - return debug_invoke_req_; + DebugInvokeReq* GetInvokeReq() const { + return tlsPtr_.debug_invoke_req; } SingleStepControl* GetSingleStepControl() const { - return single_step_control_; + return tlsPtr_.single_step_control; } void SetDeoptimizationShadowFrame(ShadowFrame* sf); @@ -580,41 +687,41 @@ class PACKED(4) Thread { ShadowFrame* GetAndClearDeoptimizationShadowFrame(JValue* ret_val); std::deque<instrumentation::InstrumentationStackFrame>* GetInstrumentationStack() { - return instrumentation_stack_; + return tlsPtr_.instrumentation_stack; } std::vector<mirror::ArtMethod*>* GetStackTraceSample() const { - return stack_trace_sample_; + return tlsPtr_.stack_trace_sample; } void SetStackTraceSample(std::vector<mirror::ArtMethod*>* sample) { - stack_trace_sample_ = sample; + tlsPtr_.stack_trace_sample = sample; } uint64_t GetTraceClockBase() const { - return trace_clock_base_; + return tls64_.trace_clock_base; } void SetTraceClockBase(uint64_t clock_base) { - trace_clock_base_ = clock_base; + tls64_.trace_clock_base = clock_base; } BaseMutex* GetHeldMutex(LockLevel level) const { - return held_mutexes_[level]; + return tlsPtr_.held_mutexes[level]; } void SetHeldMutex(LockLevel level, BaseMutex* mutex) { - held_mutexes_[level] = mutex; + tlsPtr_.held_mutexes[level] = mutex; } void RunCheckpointFunction(); bool ReadFlag(ThreadFlag flag) const { - return (state_and_flags_.as_struct.flags & flag) != 0; + return (tls32_.state_and_flags.as_struct.flags & flag) != 0; } bool TestAllFlags() const { - return (state_and_flags_.as_struct.flags != 0); + return (tls32_.state_and_flags.as_struct.flags != 0); } void AtomicSetFlag(ThreadFlag flag); @@ -623,11 +730,57 @@ class PACKED(4) Thread { void ResetQuickAllocEntryPointsForThread(); - private: - // We have no control over the size of 'bool', but want our boolean fields - // to be 4-byte quantities. - typedef uint32_t bool32_t; + // Returns the remaining space in the TLAB. + size_t TlabSize() const; + // Doesn't check that there is room. + mirror::Object* AllocTlab(size_t bytes); + void SetTlab(byte* start, byte* end); + bool HasTlab() const; + + // Remove the suspend trigger for this thread by making the suspend_trigger_ TLS value + // equal to a valid pointer. + // TODO: does this need to atomic? I don't think so. + void RemoveSuspendTrigger() { + tlsPtr_.suspend_trigger = reinterpret_cast<uintptr_t*>(&tlsPtr_.suspend_trigger); + } + + // Trigger a suspend check by making the suspend_trigger_ TLS value an invalid pointer. + // The next time a suspend check is done, it will load from the value at this address + // and trigger a SIGSEGV. + void TriggerSuspend() { + tlsPtr_.suspend_trigger = nullptr; + } + + + // Push an object onto the allocation stack. + bool PushOnThreadLocalAllocationStack(mirror::Object* obj); + + // Set the thread local allocation pointers to the given pointers. + void SetThreadLocalAllocationStack(mirror::Object** start, mirror::Object** end); + + // Resets the thread local allocation pointers. + void RevokeThreadLocalAllocationStack(); + + size_t GetThreadLocalBytesAllocated() const { + return tlsPtr_.thread_local_pos - tlsPtr_.thread_local_start; + } + + size_t GetThreadLocalObjectsAllocated() const { + return tlsPtr_.thread_local_objects; + } + + // ROS alloc TLS. + static constexpr size_t kRosAllocNumOfSizeBrackets = 34; + + void* GetRosAllocRun(size_t index) const { + return tlsPtr_.rosalloc_runs[index]; + } + + void SetRosAllocRun(size_t index, void* run) { + tlsPtr_.rosalloc_runs[index] = run; + } + private: explicit Thread(bool daemon); ~Thread() LOCKS_EXCLUDED(Locks::mutator_lock_, Locks::thread_suspend_count_lock_); @@ -644,7 +797,7 @@ class PACKED(4) Thread { // Dbg::Disconnected. ThreadState SetStateUnsafe(ThreadState new_state) { ThreadState old_state = GetState(); - state_and_flags_.as_struct.state = new_state; + tls32_.state_and_flags.as_struct.state = new_state; return old_state; } @@ -678,22 +831,6 @@ class PACKED(4) Thread { void SetUpAlternateSignalStack(); void TearDownAlternateSignalStack(); - void NotifyLocked(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(wait_mutex_); - - static void ThreadExitCallback(void* arg); - - // Has Thread::Startup been called? - static bool is_started_; - - // TLS key used to retrieve the Thread*. - static pthread_key_t pthread_key_self_; - - // Used to notify threads that they should attempt to resume, they will suspend again if - // their suspend count is > 0. - static ConditionVariable* resume_cond_ GUARDED_BY(Locks::thread_suspend_count_lock_); - - // --- Frequently accessed fields first for short offsets --- - // 32 bits of atomically changed state and flags. Keeping as 32 bits allows and atomic CAS to // change from being Suspended to Runnable without a suspend request occurring. union PACKED(4) StateAndFlags { @@ -715,206 +852,225 @@ class PACKED(4) Thread { // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47409 DISALLOW_COPY_AND_ASSIGN(StateAndFlags); }; - union StateAndFlags state_and_flags_; - COMPILE_ASSERT(sizeof(union StateAndFlags) == sizeof(int32_t), - sizeof_state_and_flags_and_int32_are_different); - // A non-zero value is used to tell the current thread to enter a safe point - // at the next poll. - int suspend_count_ GUARDED_BY(Locks::thread_suspend_count_lock_); + static void ThreadExitCallback(void* arg); - // The biased card table, see CardTable for details - byte* card_table_; + // Maximum number of checkpoint functions. + static constexpr uint32_t kMaxCheckpoints = 3; - // The pending exception or NULL. - mirror::Throwable* exception_; + // Has Thread::Startup been called? + static bool is_started_; - // The end of this thread's stack. This is the lowest safely-addressable address on the stack. - // We leave extra space so there's room for the code that throws StackOverflowError. - byte* stack_end_; + // TLS key used to retrieve the Thread*. + static pthread_key_t pthread_key_self_; - // The top of the managed stack often manipulated directly by compiler generated code. - ManagedStack managed_stack_; + // Used to notify threads that they should attempt to resume, they will suspend again if + // their suspend count is > 0. + static ConditionVariable* resume_cond_ GUARDED_BY(Locks::thread_suspend_count_lock_); - // Every thread may have an associated JNI environment - JNIEnvExt* jni_env_; + /***********************************************************************************************/ + // Thread local storage. Fields are grouped by size to enable 32 <-> 64 searching to account for + // pointer size differences. To encourage shorter encoding, more frequently used values appear + // first if possible. + /***********************************************************************************************/ + + struct PACKED(4) tls_32bit_sized_values { + // We have no control over the size of 'bool', but want our boolean fields + // to be 4-byte quantities. + typedef uint32_t bool32_t; + + explicit tls_32bit_sized_values(bool is_daemon) : + suspend_count(0), debug_suspend_count(0), thin_lock_thread_id(0), tid(0), + daemon(is_daemon), throwing_OutOfMemoryError(false), no_thread_suspension(0), + thread_exit_check_count(0) { + } - // Initialized to "this". On certain architectures (such as x86) reading - // off of Thread::Current is easy but getting the address of Thread::Current - // is hard. This field can be read off of Thread::Current to give the address. - Thread* self_; + union StateAndFlags state_and_flags; + COMPILE_ASSERT(sizeof(union StateAndFlags) == sizeof(int32_t), + sizeof_state_and_flags_and_int32_are_different); - // Our managed peer (an instance of java.lang.Thread). The jobject version is used during thread - // start up, until the thread is registered and the local opeer_ is used. - mirror::Object* opeer_; - jobject jpeer_; + // A non-zero value is used to tell the current thread to enter a safe point + // at the next poll. + int suspend_count GUARDED_BY(Locks::thread_suspend_count_lock_); - // The "lowest addressable byte" of the stack - byte* stack_begin_; + // How much of 'suspend_count_' is by request of the debugger, used to set things right + // when the debugger detaches. Must be <= suspend_count_. + int debug_suspend_count GUARDED_BY(Locks::thread_suspend_count_lock_); - // Size of the stack - size_t stack_size_; + // Thin lock thread id. This is a small integer used by the thin lock implementation. + // This is not to be confused with the native thread's tid, nor is it the value returned + // by java.lang.Thread.getId --- this is a distinct value, used only for locking. One + // important difference between this id and the ids visible to managed code is that these + // ones get reused (to ensure that they fit in the number of bits available). + uint32_t thin_lock_thread_id; - // Thin lock thread id. This is a small integer used by the thin lock implementation. - // This is not to be confused with the native thread's tid, nor is it the value returned - // by java.lang.Thread.getId --- this is a distinct value, used only for locking. One - // important difference between this id and the ids visible to managed code is that these - // ones get reused (to ensure that they fit in the number of bits available). - uint32_t thin_lock_thread_id_; + // System thread id. + uint32_t tid; - // Pointer to previous stack trace captured by sampling profiler. - std::vector<mirror::ArtMethod*>* stack_trace_sample_; + // Is the thread a daemon? + const bool32_t daemon; - // The clock base used for tracing. - uint64_t trace_clock_base_; + // A boolean telling us whether we're recursively throwing OOME. + bool32_t throwing_OutOfMemoryError; - // System thread id. - pid_t tid_; + // A positive value implies we're in a region where thread suspension isn't expected. + uint32_t no_thread_suspension; - ThrowLocation throw_location_; + // How many times has our pthread key's destructor been called? + uint32_t thread_exit_check_count; + } tls32_; - // Guards the 'interrupted_' and 'wait_monitor_' members. - mutable Mutex* wait_mutex_ DEFAULT_MUTEX_ACQUIRED_AFTER; - // Condition variable waited upon during a wait. - ConditionVariable* wait_cond_ GUARDED_BY(wait_mutex_); - // Pointer to the monitor lock we're currently waiting on or NULL if not waiting. - Monitor* wait_monitor_ GUARDED_BY(wait_mutex_); - // Thread "interrupted" status; stays raised until queried or thrown. - bool32_t interrupted_ GUARDED_BY(wait_mutex_); - // The next thread in the wait set this thread is part of or NULL if not waiting. - Thread* wait_next_; + struct PACKED(8) tls_64bit_sized_values { + tls_64bit_sized_values() : trace_clock_base(0), deoptimization_return_value() { + } + // The clock base used for tracing. + uint64_t trace_clock_base; + + // Return value used by deoptimization. + JValue deoptimization_return_value; + + RuntimeStats stats; + } tls64_; + + struct PACKED(4) tls_ptr_sized_values { + tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr), + managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), self(nullptr), opeer(nullptr), + jpeer(nullptr), stack_begin(nullptr), stack_size(0), throw_location(), + stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr), + top_sirt(nullptr), class_loader_override(nullptr), long_jump_context(nullptr), + instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr), + deoptimization_shadow_frame(nullptr), name(nullptr), pthread_self(0), + last_no_thread_suspension_cause(nullptr), thread_local_start(nullptr), + thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_objects(0), + thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr) { + } - // If we're blocked in MonitorEnter, this is the object we're trying to lock. - mirror::Object* monitor_enter_object_; + // The biased card table, see CardTable for details. + byte* card_table; - // Top of linked list of stack indirect reference tables or NULL for none - StackIndirectReferenceTable* top_sirt_; + // The pending exception or NULL. + mirror::Throwable* exception; - Runtime* runtime_; + // The end of this thread's stack. This is the lowest safely-addressable address on the stack. + // We leave extra space so there's room for the code that throws StackOverflowError. + byte* stack_end; - RuntimeStats stats_; + // The top of the managed stack often manipulated directly by compiler generated code. + ManagedStack managed_stack; - // Needed to get the right ClassLoader in JNI_OnLoad, but also - // useful for testing. - mirror::ClassLoader* class_loader_override_; + // In certain modes, setting this to 0 will trigger a SEGV and thus a suspend check. It is + // normally set to the address of itself. + uintptr_t* suspend_trigger; - // Thread local, lazily allocated, long jump context. Used to deliver exceptions. - Context* long_jump_context_; + // Every thread may have an associated JNI environment + JNIEnvExt* jni_env; - // A boolean telling us whether we're recursively throwing OOME. - bool32_t throwing_OutOfMemoryError_; + // Initialized to "this". On certain architectures (such as x86) reading off of Thread::Current + // is easy but getting the address of Thread::Current is hard. This field can be read off of + // Thread::Current to give the address. + Thread* self; - // How much of 'suspend_count_' is by request of the debugger, used to set things right - // when the debugger detaches. Must be <= suspend_count_. - int debug_suspend_count_ GUARDED_BY(Locks::thread_suspend_count_lock_); + // Our managed peer (an instance of java.lang.Thread). The jobject version is used during thread + // start up, until the thread is registered and the local opeer_ is used. + mirror::Object* opeer; + jobject jpeer; - // JDWP invoke-during-breakpoint support. - DebugInvokeReq* debug_invoke_req_; + // The "lowest addressable byte" of the stack. + byte* stack_begin; - // JDWP single-stepping support. - SingleStepControl* single_step_control_; + // Size of the stack. + size_t stack_size; - // Shadow frame that is used temporarily during the deoptimization of a method. - ShadowFrame* deoptimization_shadow_frame_; - JValue deoptimization_return_value_; + // The location the current exception was thrown from. + ThrowLocation throw_location; - // Additional stack used by method instrumentation to store method and return pc values. - // Stored as a pointer since std::deque is not PACKED. - std::deque<instrumentation::InstrumentationStackFrame>* instrumentation_stack_; + // Pointer to previous stack trace captured by sampling profiler. + std::vector<mirror::ArtMethod*>* stack_trace_sample; - // A cached copy of the java.lang.Thread's name. - std::string* name_; + // The next thread in the wait set this thread is part of or NULL if not waiting. + Thread* wait_next; - // Is the thread a daemon? - const bool32_t daemon_; + // If we're blocked in MonitorEnter, this is the object we're trying to lock. + mirror::Object* monitor_enter_object; - // A cached pthread_t for the pthread underlying this Thread*. - pthread_t pthread_self_; + // Top of linked list of stack indirect reference tables or NULL for none. + StackIndirectReferenceTable* top_sirt; - // Support for Mutex lock hierarchy bug detection. - BaseMutex* held_mutexes_[kLockLevelCount]; + // Needed to get the right ClassLoader in JNI_OnLoad, but also + // useful for testing. + mirror::ClassLoader* class_loader_override; - // A positive value implies we're in a region where thread suspension isn't expected. - uint32_t no_thread_suspension_; + // Thread local, lazily allocated, long jump context. Used to deliver exceptions. + Context* long_jump_context; - // If no_thread_suspension_ is > 0, what is causing that assertion. - const char* last_no_thread_suspension_cause_; + // Additional stack used by method instrumentation to store method and return pc values. + // Stored as a pointer since std::deque is not PACKED. + std::deque<instrumentation::InstrumentationStackFrame>* instrumentation_stack; - // Maximum number of checkpoint functions. - static constexpr uint32_t kMaxCheckpoints = 3; + // JDWP invoke-during-breakpoint support. + DebugInvokeReq* debug_invoke_req; - // Pending checkpoint function or NULL if non-pending. Installation guarding by - // Locks::thread_suspend_count_lock_. - Closure* checkpoint_functions_[kMaxCheckpoints]; + // JDWP single-stepping support. + SingleStepControl* single_step_control; - public: - // Entrypoint function pointers - // TODO: move this near the top, since changing its offset requires all oats to be recompiled! - InterpreterEntryPoints interpreter_entrypoints_; - JniEntryPoints jni_entrypoints_; - PortableEntryPoints portable_entrypoints_; - QuickEntryPoints quick_entrypoints_; - - // Setting this to 0 will trigger a SEGV and thus a suspend check. It is normally - // set to the address of itself. - uintptr_t* suspend_trigger_; - - // How many times has our pthread key's destructor been called? - uint32_t thread_exit_check_count_; - - // Thread-local allocation pointer. - byte* thread_local_start_; - byte* thread_local_pos_; - byte* thread_local_end_; - size_t thread_local_objects_; - // Returns the remaining space in the TLAB. - size_t TlabSize() const; - // Doesn't check that there is room. - mirror::Object* AllocTlab(size_t bytes); - void SetTlab(byte* start, byte* end); - bool HasTlab() const; + // Shadow frame stack that is used temporarily during the deoptimization of a method. + ShadowFrame* deoptimization_shadow_frame; - // Remove the suspend trigger for this thread by making the suspend_trigger_ TLS value - // equal to a valid pointer. - // TODO: does this need to atomic? I don't think so. - void RemoveSuspendTrigger() { - suspend_trigger_ = reinterpret_cast<uintptr_t*>(&suspend_trigger_); - } + // A cached copy of the java.lang.Thread's name. + std::string* name; - // Trigger a suspend check by making the suspend_trigger_ TLS value an invalid pointer. - // The next time a suspend check is done, it will load from the value at this address - // and trigger a SIGSEGV. - void TriggerSuspend() { - suspend_trigger_ = nullptr; - } + // A cached pthread_t for the pthread underlying this Thread*. + pthread_t pthread_self; - // Thread-local rosalloc runs. There are 34 size brackets in rosalloc - // runs (RosAlloc::kNumOfSizeBrackets). We can't refer to the - // RosAlloc class due to a header file circular dependency issue. - // To compensate, we check that the two values match at RosAlloc - // initialization time. - static const size_t kRosAllocNumOfSizeBrackets = 34; - void* rosalloc_runs_[kRosAllocNumOfSizeBrackets]; + // Support for Mutex lock hierarchy bug detection. + BaseMutex* held_mutexes[kLockLevelCount]; - // Thread-local allocation stack data/routines. - mirror::Object** thread_local_alloc_stack_top_; - mirror::Object** thread_local_alloc_stack_end_; + // If no_thread_suspension_ is > 0, what is causing that assertion. + const char* last_no_thread_suspension_cause; - // Push an object onto the allocation stack. - bool PushOnThreadLocalAllocationStack(mirror::Object* obj); + // Pending checkpoint function or NULL if non-pending. Installation guarding by + // Locks::thread_suspend_count_lock_. + Closure* checkpoint_functions[kMaxCheckpoints]; - // Set the thread local allocation pointers to the given pointers. - void SetThreadLocalAllocationStack(mirror::Object** start, mirror::Object** end); + // Entrypoint function pointers. + // TODO: move this to more of a global offset table model to avoid per-thread duplication. + InterpreterEntryPoints interpreter_entrypoints; + JniEntryPoints jni_entrypoints; + PortableEntryPoints portable_entrypoints; + QuickEntryPoints quick_entrypoints; - // Resets the thread local allocation pointers. - void RevokeThreadLocalAllocationStack(); + // Thread-local allocation pointer. + byte* thread_local_start; + byte* thread_local_pos; + byte* thread_local_end; + size_t thread_local_objects; + + // Thread-local rosalloc runs. There are 34 size brackets in rosalloc + // runs (RosAlloc::kNumOfSizeBrackets). We can't refer to the + // RosAlloc class due to a header file circular dependency issue. + // To compensate, we check that the two values match at RosAlloc + // initialization time. + void* rosalloc_runs[kRosAllocNumOfSizeBrackets]; + + // Thread-local allocation stack data/routines. + mirror::Object** thread_local_alloc_stack_top; + mirror::Object** thread_local_alloc_stack_end; + } tlsPtr_; + + // Guards the 'interrupted_' and 'wait_monitor_' members. + Mutex* wait_mutex_ DEFAULT_MUTEX_ACQUIRED_AFTER; + + // Condition variable waited upon during a wait. + ConditionVariable* wait_cond_ GUARDED_BY(wait_mutex_); + // Pointer to the monitor lock we're currently waiting on or NULL if not waiting. + Monitor* wait_monitor_ GUARDED_BY(wait_mutex_); + + // Thread "interrupted" status; stays raised until queried or thrown. + bool interrupted_ GUARDED_BY(wait_mutex_); - private: friend class Dbg; // For SetStateUnsafe. friend class gc::collector::SemiSpace; // For getting stack traces. - friend class Monitor; - friend class MonitorInfo; friend class Runtime; // For CreatePeer. friend class ScopedThreadStateChange; friend class SignalCatcher; // For SetStateUnsafe. |