diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/base/mutex-inl.h | 149 | ||||
| -rw-r--r-- | src/base/mutex.cc | 139 | ||||
| -rw-r--r-- | src/base/mutex.h | 4 | ||||
| -rw-r--r-- | src/gc/garbage_collector.cc | 2 | ||||
| -rw-r--r-- | src/gc/mark_sweep.cc | 1 | ||||
| -rw-r--r-- | src/gc/space_bitmap-inl.h | 2 | ||||
| -rw-r--r-- | src/jdwp/jdwp_event.cc | 2 | ||||
| -rw-r--r-- | src/jdwp/jdwp_handler.cc | 2 | ||||
| -rw-r--r-- | src/mirror/class-inl.h | 83 | ||||
| -rw-r--r-- | src/mirror/class.cc | 83 | ||||
| -rw-r--r-- | src/mirror/class.h | 2 | ||||
| -rw-r--r-- | src/native/java_lang_System.cc | 1 | ||||
| -rw-r--r-- | src/oat/runtime/arm/oat_support_entrypoints_arm.cc | 13 | ||||
| -rw-r--r-- | src/oat/runtime/mips/oat_support_entrypoints_mips.cc | 24 | ||||
| -rw-r--r-- | src/oat/runtime/oat_support_entrypoints.h | 20 | ||||
| -rw-r--r-- | src/oat/runtime/support_cast.cc | 1 | ||||
| -rw-r--r-- | src/oat/runtime/support_jni.cc | 20 | ||||
| -rw-r--r-- | src/oat/runtime/x86/oat_support_entrypoints_x86.cc | 13 | ||||
| -rw-r--r-- | src/runtime_support.h | 1 | ||||
| -rw-r--r-- | src/scoped_thread_state_change.h | 2 | ||||
| -rw-r--r-- | src/thread-inl.h | 119 | ||||
| -rw-r--r-- | src/thread.cc | 88 | ||||
| -rw-r--r-- | src/thread.h | 12 | ||||
| -rw-r--r-- | src/verifier/reg_type.cc | 1 |
24 files changed, 414 insertions, 370 deletions
diff --git a/src/base/mutex-inl.h b/src/base/mutex-inl.h new file mode 100644 index 0000000000..03ec6f84b7 --- /dev/null +++ b/src/base/mutex-inl.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_BASE_MUTEX_INL_H_ +#define ART_SRC_BASE_MUTEX_INL_H_ + +#include "mutex.h" + +#include "cutils/atomic-inline.h" +#include "runtime.h" +#include "thread.h" + +namespace art { + +#define CHECK_MUTEX_CALL(call, args) CHECK_PTHREAD_CALL(call, args, name_) + +#if ART_USE_FUTEXES +#include "linux/futex.h" +#include "sys/syscall.h" +#ifndef SYS_futex +#define SYS_futex __NR_futex +#endif +static inline int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout, volatile int *uaddr2, int val3) { + return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3); +} +#endif // ART_USE_FUTEXES + +class ScopedContentionRecorder { + public: + ScopedContentionRecorder(BaseMutex* mutex, uint64_t blocked_tid, uint64_t owner_tid) : + mutex_(mutex), blocked_tid_(blocked_tid), owner_tid_(owner_tid), + start_milli_time_(MilliTime()) { + } + + ~ScopedContentionRecorder() { + uint64_t end_milli_time = MilliTime(); + mutex_->RecordContention(blocked_tid_, owner_tid_, end_milli_time - start_milli_time_); + } + + private: + BaseMutex* const mutex_; + uint64_t blocked_tid_; + uint64_t owner_tid_; + const uint64_t start_milli_time_; +}; + +static inline uint64_t SafeGetTid(const Thread* self) { + if (self != NULL) { + return static_cast<uint64_t>(self->GetTid()); + } else { + return static_cast<uint64_t>(GetTid()); + } +} + +static inline void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALYSIS { + // The check below enumerates the cases where we expect not to be able to sanity check locks + // on a thread. Lock checking is disabled to avoid deadlock when checking shutdown lock. + // TODO: tighten this check. + if (kDebugLocking) { + Runtime* runtime = Runtime::Current(); + CHECK(runtime == NULL || !runtime->IsStarted() || runtime->IsShuttingDown() || + level == kDefaultMutexLevel || level == kRuntimeShutdownLock || + level == kThreadListLock || level == kLoggingLock || level == kAbortLock); + } +} + +inline void BaseMutex::RegisterAsUnlocked(Thread* self) { + if (UNLIKELY(self == NULL)) { + CheckUnattachedThread(level_); + return; + } + if (level_ != kMonitorLock) { + if (kDebugLocking && !gAborting) { + CHECK(self->GetHeldMutex(level_) == this) << "Unlocking on unacquired mutex: " << name_; + } + self->SetHeldMutex(level_, NULL); + } +} + +inline void ReaderWriterMutex::SharedLock(Thread* self) { + DCHECK(self == NULL || self == Thread::Current()); +#if ART_USE_FUTEXES + bool done = false; + do { + int32_t cur_state = state_; + if (cur_state >= 0) { + // Add as an extra reader. + done = android_atomic_acquire_cas(cur_state, cur_state + 1, &state_) == 0; + } else { + // Owner holds it exclusively, hang up. + ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self)); + android_atomic_inc(&num_pending_readers_); + if (futex(&state_, FUTEX_WAIT, cur_state, NULL, NULL, 0) != 0) { + if (errno != EAGAIN) { + PLOG(FATAL) << "futex wait failed for " << name_; + } + } + android_atomic_dec(&num_pending_readers_); + } + } while(!done); +#else + CHECK_MUTEX_CALL(pthread_rwlock_rdlock, (&rwlock_)); +#endif + RegisterAsLocked(self); + AssertSharedHeld(self); +} + +inline void ReaderWriterMutex::SharedUnlock(Thread* self) { + DCHECK(self == NULL || self == Thread::Current()); + AssertSharedHeld(self); + RegisterAsUnlocked(self); +#if ART_USE_FUTEXES + bool done = false; + do { + int32_t cur_state = state_; + if (LIKELY(cur_state > 0)) { + // Reduce state by 1. + done = android_atomic_release_cas(cur_state, cur_state - 1, &state_) == 0; + if (done && (cur_state - 1) == 0) { // cas may fail due to noise? + if (num_pending_writers_ > 0 || num_pending_readers_ > 0) { + // Wake any exclusive waiters as there are now no readers. + futex(&state_, FUTEX_WAKE, -1, NULL, NULL, 0); + } + } + } else { + LOG(FATAL) << "Unexpected state_:" << cur_state << " for " << name_; + } + } while(!done); +#else + CHECK_MUTEX_CALL(pthread_rwlock_unlock, (&rwlock_)); +#endif +} + +} // namespace art + +#endif // ART_SRC_BASE_MUTEX_INL_H_ diff --git a/src/base/mutex.cc b/src/base/mutex.cc index d09a6a27f6..fa7a617cd6 100644 --- a/src/base/mutex.cc +++ b/src/base/mutex.cc @@ -21,28 +21,13 @@ #include "base/logging.h" #include "cutils/atomic.h" +#include "cutils/atomic-inline.h" +#include "mutex-inl.h" #include "runtime.h" #include "scoped_thread_state_change.h" #include "thread.h" #include "utils.h" -#define CHECK_MUTEX_CALL(call, args) CHECK_PTHREAD_CALL(call, args, name_) - -extern int pthread_mutex_lock(pthread_mutex_t* mutex) EXCLUSIVE_LOCK_FUNCTION(mutex); -extern int pthread_mutex_unlock(pthread_mutex_t* mutex) UNLOCK_FUNCTION(1); -extern int pthread_mutex_trylock(pthread_mutex_t* mutex) EXCLUSIVE_TRYLOCK_FUNCTION(0, mutex); - -#if ART_USE_FUTEXES -#include "linux/futex.h" -#include "sys/syscall.h" -#ifndef SYS_futex -#define SYS_futex __NR_futex -#endif -int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout, volatile int *uaddr2, int val3) { - return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3); -} -#endif // ART_USE_FUTEXES - namespace art { // This works on Mac OS 10.6 but hasn't been tested on older releases. @@ -85,14 +70,6 @@ struct __attribute__((__may_alias__)) glibc_pthread_rwlock_t { // ...other stuff we don't care about. }; -static uint64_t SafeGetTid(const Thread* self) { - if (self != NULL) { - return static_cast<uint64_t>(self->GetTid()); - } else { - return static_cast<uint64_t>(GetTid()); - } -} - #if ART_USE_FUTEXES static bool ComputeRelativeTimeSpec(timespec* result_ts, const timespec& lhs, const timespec& rhs) { const long int one_sec = 1000 * 1000 * 1000; // one second in nanoseconds. @@ -164,18 +141,6 @@ void BaseMutex::DumpAll(std::ostream& os) { #endif } -static void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALYSIS { - // The check below enumerates the cases where we expect not to be able to sanity check locks - // on a thread. Lock checking is disabled to avoid deadlock when checking shutdown lock. - // TODO: tighten this check. - if (kDebugLocking) { - Runtime* runtime = Runtime::Current(); - CHECK(runtime == NULL || !runtime->IsStarted() || runtime->IsShuttingDown() || - level == kDefaultMutexLevel || level == kRuntimeShutdownLock || - level == kThreadListLock || level == kLoggingLock || level == kAbortLock); - } -} - void BaseMutex::RegisterAsLocked(Thread* self) { if (UNLIKELY(self == NULL)) { CheckUnattachedThread(level_); @@ -204,19 +169,6 @@ void BaseMutex::RegisterAsLocked(Thread* self) { } } -void BaseMutex::RegisterAsUnlocked(Thread* self) { - if (UNLIKELY(self == NULL)) { - CheckUnattachedThread(level_); - return; - } - if (level_ != kMonitorLock) { - if (kDebugLocking && !gAborting) { - CHECK(self->GetHeldMutex(level_) == this) << "Unlocking on unacquired mutex: " << name_; - } - self->SetHeldMutex(level_, NULL); - } -} - void BaseMutex::CheckSafeToWait(Thread* self) { if (self == NULL) { CheckUnattachedThread(level_); @@ -262,25 +214,6 @@ void BaseMutex::RecordContention(uint64_t blocked_tid, uint64_t owner_tid, uint6 #endif } -class ScopedContentionRecorder { - public: - ScopedContentionRecorder(BaseMutex* mutex, uint64_t blocked_tid, uint64_t owner_tid) : - mutex_(mutex), blocked_tid_(blocked_tid), owner_tid_(owner_tid), - start_milli_time_(MilliTime()) { - } - - ~ScopedContentionRecorder() { - uint64_t end_milli_time = MilliTime(); - mutex_->RecordContention(blocked_tid_, owner_tid_, end_milli_time - start_milli_time_); - } - - private: - BaseMutex* const mutex_; - uint64_t blocked_tid_; - uint64_t owner_tid_; - const uint64_t start_milli_time_; -}; - void BaseMutex::DumpContention(std::ostream& os) const { #if CONTENTION_LOGGING uint32_t wait_time = wait_time_; @@ -395,7 +328,7 @@ void Mutex::ExclusiveLock(Thread* self) { int32_t cur_state = state_; if (cur_state == 0) { // Change state from 0 to 1. - done = android_atomic_cmpxchg(0, 1, &state_) == 0; + done = android_atomic_acquire_cas(0, 1, &state_) == 0; } else { // Failed to acquire, hang up. ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self)); @@ -435,7 +368,7 @@ bool Mutex::ExclusiveTryLock(Thread* self) { int32_t cur_state = state_; if (cur_state == 0) { // Change state from 0 to 1. - done = android_atomic_cmpxchg(0, 1, &state_) == 0; + done = android_atomic_acquire_cas(0, 1, &state_) == 0; } else { return false; } @@ -481,7 +414,7 @@ void Mutex::ExclusiveUnlock(Thread* self) { // We're no longer the owner. exclusive_owner_ = 0; // Change state to 0. - done = android_atomic_cmpxchg(cur_state, 0, &state_) == 0; + done = android_atomic_release_cas(cur_state, 0, &state_) == 0; if (done) { // Spurious fail? // Wake a contender if (num_contenders_ > 0) { @@ -588,7 +521,7 @@ void ReaderWriterMutex::ExclusiveLock(Thread* self) { int32_t cur_state = state_; if (cur_state == 0) { // Change state from 0 to -1. - done = android_atomic_cmpxchg(0, -1, &state_) == 0; + done = android_atomic_acquire_cas(0, -1, &state_) == 0; } else { // Failed to acquire, hang up. ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self)); @@ -622,7 +555,7 @@ void ReaderWriterMutex::ExclusiveUnlock(Thread* self) { // We're no longer the owner. exclusive_owner_ = 0; // Change state from -1 to 0. - done = android_atomic_cmpxchg(-1, 0, &state_) == 0; + done = android_atomic_release_cas(-1, 0, &state_) == 0; if (done) { // cmpxchg may fail due to noise? // Wake any waiters. if (num_pending_readers_ > 0 || num_pending_writers_ > 0) { @@ -649,7 +582,7 @@ bool ReaderWriterMutex::ExclusiveLockWithTimeout(Thread* self, int64_t ms, int32 int32_t cur_state = state_; if (cur_state == 0) { // Change state from 0 to -1. - done = android_atomic_cmpxchg(0, -1, &state_) == 0; + done = android_atomic_acquire_cas(0, -1, &state_) == 0; } else { // Failed to acquire, hang up. timespec now_abs_ts; @@ -690,34 +623,6 @@ bool ReaderWriterMutex::ExclusiveLockWithTimeout(Thread* self, int64_t ms, int32 } #endif -void ReaderWriterMutex::SharedLock(Thread* self) { - DCHECK(self == NULL || self == Thread::Current()); -#if ART_USE_FUTEXES - bool done = false; - do { - int32_t cur_state = state_; - if (cur_state >= 0) { - // Add as an extra reader. - done = android_atomic_cmpxchg(cur_state, cur_state + 1, &state_) == 0; - } else { - // Owner holds it exclusively, hang up. - ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self)); - android_atomic_inc(&num_pending_readers_); - if (futex(&state_, FUTEX_WAIT, cur_state, NULL, NULL, 0) != 0) { - if (errno != EAGAIN) { - PLOG(FATAL) << "futex wait failed for " << name_; - } - } - android_atomic_dec(&num_pending_readers_); - } - } while(!done); -#else - CHECK_MUTEX_CALL(pthread_rwlock_rdlock, (&rwlock_)); -#endif - RegisterAsLocked(self); - AssertSharedHeld(self); -} - bool ReaderWriterMutex::SharedTryLock(Thread* self) { DCHECK(self == NULL || self == Thread::Current()); #if ART_USE_FUTEXES @@ -726,7 +631,7 @@ bool ReaderWriterMutex::SharedTryLock(Thread* self) { int32_t cur_state = state_; if (cur_state >= 0) { // Add as an extra reader. - done = android_atomic_cmpxchg(cur_state, cur_state + 1, &state_) == 0; + done = android_atomic_acquire_cas(cur_state, cur_state + 1, &state_) == 0; } else { // Owner holds it exclusively. return false; @@ -747,32 +652,6 @@ bool ReaderWriterMutex::SharedTryLock(Thread* self) { return true; } -void ReaderWriterMutex::SharedUnlock(Thread* self) { - DCHECK(self == NULL || self == Thread::Current()); - AssertSharedHeld(self); - RegisterAsUnlocked(self); -#if ART_USE_FUTEXES - bool done = false; - do { - int32_t cur_state = state_; - if (LIKELY(cur_state > 0)) { - // Reduce state by 1. - done = android_atomic_cmpxchg(cur_state, cur_state - 1, &state_) == 0; - if (done && (cur_state - 1) == 0) { // cmpxchg may fail due to noise? - if (num_pending_writers_ > 0 || num_pending_readers_ > 0) { - // Wake any exclusive waiters as there are now no readers. - futex(&state_, FUTEX_WAKE, -1, NULL, NULL, 0); - } - } - } else { - LOG(FATAL) << "Unexpected state_:" << cur_state << " for " << name_; - } - } while(!done); -#else - CHECK_MUTEX_CALL(pthread_rwlock_unlock, (&rwlock_)); -#endif -} - bool ReaderWriterMutex::IsExclusiveHeld(const Thread* self) const { DCHECK(self == NULL || self == Thread::Current()); bool result = (GetExclusiveOwnerTid() == SafeGetTid(self)); diff --git a/src/base/mutex.h b/src/base/mutex.h index 8576c03eee..b530b752dc 100644 --- a/src/base/mutex.h +++ b/src/base/mutex.h @@ -223,14 +223,14 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex { #endif // Block until ReaderWriterMutex is shared or free then acquire a share on the access. - void SharedLock(Thread* self) SHARED_LOCK_FUNCTION(); + void SharedLock(Thread* self) SHARED_LOCK_FUNCTION() __attribute__ ((always_inline)); void ReaderLock(Thread* self) SHARED_LOCK_FUNCTION() { SharedLock(self); } // Try to acquire share of ReaderWriterMutex. bool SharedTryLock(Thread* self) EXCLUSIVE_TRYLOCK_FUNCTION(true); // Release a share of the access. - void SharedUnlock(Thread* self) UNLOCK_FUNCTION(); + void SharedUnlock(Thread* self) UNLOCK_FUNCTION() __attribute__ ((always_inline)); void ReaderUnlock(Thread* self) UNLOCK_FUNCTION() { SharedUnlock(self); } // Is the current thread the exclusive holder of the ReaderWriterMutex. diff --git a/src/gc/garbage_collector.cc b/src/gc/garbage_collector.cc index fbcdbafd0a..94daec7c31 100644 --- a/src/gc/garbage_collector.cc +++ b/src/gc/garbage_collector.cc @@ -15,6 +15,8 @@ */ #include "garbage_collector.h" + +#include "base/mutex-inl.h" #include "thread.h" #include "thread_list.h" diff --git a/src/gc/mark_sweep.cc b/src/gc/mark_sweep.cc index 40102b2036..81d5e170a2 100644 --- a/src/gc/mark_sweep.cc +++ b/src/gc/mark_sweep.cc @@ -24,6 +24,7 @@ #include "barrier.h" #include "base/logging.h" #include "base/macros.h" +#include "base/mutex-inl.h" #include "card_table.h" #include "card_table-inl.h" #include "heap.h" diff --git a/src/gc/space_bitmap-inl.h b/src/gc/space_bitmap-inl.h index e1fdd29d8d..dd91403756 100644 --- a/src/gc/space_bitmap-inl.h +++ b/src/gc/space_bitmap-inl.h @@ -18,7 +18,7 @@ #define ART_SRC_GC_SPACE_BITMAP_INL_H_ #include "base/logging.h" -#include "cutils/atomic.h" +#include "cutils/atomic-inline.h" namespace art { diff --git a/src/jdwp/jdwp_event.cc b/src/jdwp/jdwp_event.cc index 71e91d4958..a2c10b5eac 100644 --- a/src/jdwp/jdwp_event.cc +++ b/src/jdwp/jdwp_event.cc @@ -28,7 +28,7 @@ #include "jdwp/jdwp_expand_buf.h" #include "jdwp/jdwp_handler.h" #include "jdwp/jdwp_priv.h" -#include "thread.h" +#include "thread-inl.h" /* General notes: diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc index aa5a8a05d7..dd80089dc6 100644 --- a/src/jdwp/jdwp_handler.cc +++ b/src/jdwp/jdwp_handler.cc @@ -43,7 +43,7 @@ #include "jdwp/jdwp_expand_buf.h" #include "jdwp/jdwp_priv.h" #include "runtime.h" -#include "thread.h" +#include "thread-inl.h" #include "UniquePtr.h" namespace art { diff --git a/src/mirror/class-inl.h b/src/mirror/class-inl.h index 7eb8601cd6..3ca4c3023c 100644 --- a/src/mirror/class-inl.h +++ b/src/mirror/class-inl.h @@ -130,6 +130,89 @@ inline void Class::SetVTable(ObjectArray<AbstractMethod>* new_vtable) SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false); } +inline bool Class::Implements(const Class* klass) const { + DCHECK(klass != NULL); + DCHECK(klass->IsInterface()) << PrettyClass(this); + // All interfaces implemented directly and by our superclass, and + // recursively all super-interfaces of those interfaces, are listed + // in iftable_, so we can just do a linear scan through that. + int32_t iftable_count = GetIfTableCount(); + IfTable* iftable = GetIfTable(); + for (int32_t i = 0; i < iftable_count; i++) { + if (iftable->GetInterface(i) == klass) { + return true; + } + } + return false; +} + +// Determine whether "this" is assignable from "src", where both of these +// are array classes. +// +// Consider an array class, e.g. Y[][], where Y is a subclass of X. +// Y[][] = Y[][] --> true (identity) +// X[][] = Y[][] --> true (element superclass) +// Y = Y[][] --> false +// Y[] = Y[][] --> false +// Object = Y[][] --> true (everything is an object) +// Object[] = Y[][] --> true +// Object[][] = Y[][] --> true +// Object[][][] = Y[][] --> false (too many []s) +// Serializable = Y[][] --> true (all arrays are Serializable) +// Serializable[] = Y[][] --> true +// Serializable[][] = Y[][] --> false (unless Y is Serializable) +// +// Don't forget about primitive types. +// Object[] = int[] --> false +// +inline bool Class::IsArrayAssignableFromArray(const Class* src) const { + DCHECK(IsArrayClass()) << PrettyClass(this); + DCHECK(src->IsArrayClass()) << PrettyClass(src); + return GetComponentType()->IsAssignableFrom(src->GetComponentType()); +} + +inline bool Class::IsAssignableFromArray(const Class* src) const { + DCHECK(!IsInterface()) << PrettyClass(this); // handled first in IsAssignableFrom + DCHECK(src->IsArrayClass()) << PrettyClass(src); + if (!IsArrayClass()) { + // If "this" is not also an array, it must be Object. + // src's super should be java_lang_Object, since it is an array. + Class* java_lang_Object = src->GetSuperClass(); + DCHECK(java_lang_Object != NULL) << PrettyClass(src); + DCHECK(java_lang_Object->GetSuperClass() == NULL) << PrettyClass(src); + return this == java_lang_Object; + } + return IsArrayAssignableFromArray(src); +} + +inline bool Class::IsSubClass(const Class* klass) const { + DCHECK(!IsInterface()) << PrettyClass(this); + DCHECK(!IsArrayClass()) << PrettyClass(this); + const Class* current = this; + do { + if (current == klass) { + return true; + } + current = current->GetSuperClass(); + } while (current != NULL); + return false; +} + +inline AbstractMethod* Class::FindVirtualMethodForInterface(AbstractMethod* method) const { + Class* declaring_class = method->GetDeclaringClass(); + DCHECK(declaring_class != NULL) << PrettyClass(this); + DCHECK(declaring_class->IsInterface()) << PrettyMethod(method); + // TODO cache to improve lookup speed + int32_t iftable_count = GetIfTableCount(); + IfTable* iftable = GetIfTable(); + for (int32_t i = 0; i < iftable_count; i++) { + if (iftable->GetInterface(i) == declaring_class) { + return iftable->GetMethodArray(i)->Get(method->GetMethodIndex()); + } + } + return NULL; +} + inline AbstractMethod* Class::FindVirtualMethodForVirtual(AbstractMethod* method) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(!method->GetDeclaringClass()->IsInterface()); diff --git a/src/mirror/class.cc b/src/mirror/class.cc index 7f52d17616..e3347a88f4 100644 --- a/src/mirror/class.cc +++ b/src/mirror/class.cc @@ -238,74 +238,6 @@ void Class::SetReferenceStaticOffsets(uint32_t new_reference_offsets) { new_reference_offsets, false); } -bool Class::Implements(const Class* klass) const { - DCHECK(klass != NULL); - DCHECK(klass->IsInterface()) << PrettyClass(this); - // All interfaces implemented directly and by our superclass, and - // recursively all super-interfaces of those interfaces, are listed - // in iftable_, so we can just do a linear scan through that. - int32_t iftable_count = GetIfTableCount(); - IfTable* iftable = GetIfTable(); - for (int32_t i = 0; i < iftable_count; i++) { - if (iftable->GetInterface(i) == klass) { - return true; - } - } - return false; -} - -// Determine whether "this" is assignable from "src", where both of these -// are array classes. -// -// Consider an array class, e.g. Y[][], where Y is a subclass of X. -// Y[][] = Y[][] --> true (identity) -// X[][] = Y[][] --> true (element superclass) -// Y = Y[][] --> false -// Y[] = Y[][] --> false -// Object = Y[][] --> true (everything is an object) -// Object[] = Y[][] --> true -// Object[][] = Y[][] --> true -// Object[][][] = Y[][] --> false (too many []s) -// Serializable = Y[][] --> true (all arrays are Serializable) -// Serializable[] = Y[][] --> true -// Serializable[][] = Y[][] --> false (unless Y is Serializable) -// -// Don't forget about primitive types. -// Object[] = int[] --> false -// -bool Class::IsArrayAssignableFromArray(const Class* src) const { - DCHECK(IsArrayClass()) << PrettyClass(this); - DCHECK(src->IsArrayClass()) << PrettyClass(src); - return GetComponentType()->IsAssignableFrom(src->GetComponentType()); -} - -bool Class::IsAssignableFromArray(const Class* src) const { - DCHECK(!IsInterface()) << PrettyClass(this); // handled first in IsAssignableFrom - DCHECK(src->IsArrayClass()) << PrettyClass(src); - if (!IsArrayClass()) { - // If "this" is not also an array, it must be Object. - // src's super should be java_lang_Object, since it is an array. - Class* java_lang_Object = src->GetSuperClass(); - DCHECK(java_lang_Object != NULL) << PrettyClass(src); - DCHECK(java_lang_Object->GetSuperClass() == NULL) << PrettyClass(src); - return this == java_lang_Object; - } - return IsArrayAssignableFromArray(src); -} - -bool Class::IsSubClass(const Class* klass) const { - DCHECK(!IsInterface()) << PrettyClass(this); - DCHECK(!IsArrayClass()) << PrettyClass(this); - const Class* current = this; - do { - if (current == klass) { - return true; - } - current = current->GetSuperClass(); - } while (current != NULL); - return false; -} - bool Class::IsInSamePackage(const StringPiece& descriptor1, const StringPiece& descriptor2) { size_t i = 0; while (descriptor1[i] != '\0' && descriptor1[i] == descriptor2[i]) { @@ -378,21 +310,6 @@ void Class::SetClassLoader(ClassLoader* new_class_loader) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false); } -AbstractMethod* Class::FindVirtualMethodForInterface(AbstractMethod* method) const { - Class* declaring_class = method->GetDeclaringClass(); - DCHECK(declaring_class != NULL) << PrettyClass(this); - DCHECK(declaring_class->IsInterface()) << PrettyMethod(method); - // TODO cache to improve lookup speed - int32_t iftable_count = GetIfTableCount(); - IfTable* iftable = GetIfTable(); - for (int32_t i = 0; i < iftable_count; i++) { - if (iftable->GetInterface(i) == declaring_class) { - return iftable->GetMethodArray(i)->Get(method->GetMethodIndex()); - } - } - return NULL; -} - AbstractMethod* Class::FindInterfaceMethod(const StringPiece& name, const StringPiece& signature) const { // Check the current class before checking the interfaces. AbstractMethod* method = FindDeclaredVirtualMethod(name, signature); diff --git a/src/mirror/class.h b/src/mirror/class.h index 843e07cb37..9e440b46a7 100644 --- a/src/mirror/class.h +++ b/src/mirror/class.h @@ -542,7 +542,7 @@ class MANAGED Class : public StaticStorageBase { // super class or interface, return the specific implementation // method for this class. AbstractMethod* FindVirtualMethodForInterface(AbstractMethod* method) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) __attribute__ ((always_inline, hot)); AbstractMethod* FindInterfaceMethod(const StringPiece& name, const StringPiece& descriptor) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/src/native/java_lang_System.cc b/src/native/java_lang_System.cc index 54ee2e914e..79614aeab4 100644 --- a/src/native/java_lang_System.cc +++ b/src/native/java_lang_System.cc @@ -20,6 +20,7 @@ #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" +#include "mirror/object_array-inl.h" #include "scoped_thread_state_change.h" /* diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc index c43b7e279e..dea2600aaa 100644 --- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc +++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc @@ -63,19 +63,6 @@ extern "C" void* art_get_obj_static_from_code(uint32_t); // FillArray entrypoint. extern "C" void art_handle_fill_data_from_code(void*, void*); -// JNI entrypoints. -extern void* FindNativeMethod(Thread* thread); -extern uint32_t JniMethodStart(Thread* self); -extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self); -extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self); -extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, - Thread* self); -extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie, - Thread* self); -extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result, - uint32_t saved_local_ref_cookie, - jobject locked, Thread* self); - // Lock entrypoints. extern "C" void art_lock_object_from_code(void*); extern "C" void art_unlock_object_from_code(void*); diff --git a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc index db773bad59..9c84a8f666 100644 --- a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc +++ b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc @@ -28,12 +28,13 @@ extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t); extern "C" void* art_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t); // Cast entrypoints. -extern "C" uint32_t artIsAssignableFromCode(const Class* klass, const Class* ref_class); +extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass, + const mirror::Class* ref_class); extern "C" void art_can_put_array_element_from_code(void*, void*); extern "C" void art_check_cast_from_code(void*, void*); // Debug entrypoints. -extern void DebugMe(AbstractMethod* method, uint32_t info); +extern void DebugMe(mirror::AbstractMethod* method, uint32_t info); extern "C" void art_update_debugger(void*, void*, int32_t, void*); // DexCache entrypoints. @@ -62,19 +63,6 @@ extern "C" void* art_get_obj_static_from_code(uint32_t); // FillArray entrypoint. extern "C" void art_handle_fill_data_from_code(void*, void*); -// JNI entrypoints. -extern void* FindNativeMethod(Thread* thread); -extern uint32_t JniMethodStart(Thread* self); -extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self); -extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self); -extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, - Thread* self); -extern Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie, - Thread* self); -extern Object* JniMethodEndWithReferenceSynchronized(jobject result, - uint32_t saved_local_ref_cookie, - jobject locked, Thread* self); - // Lock entrypoints. extern "C" void art_lock_object_from_code(void*); extern "C" void art_unlock_object_from_code(void*); @@ -115,7 +103,8 @@ extern "C" int32_t art_indexof(void*, uint32_t, uint32_t, uint32_t); extern "C" int32_t art_string_compareto(void*, void*); // Invoke entrypoints. -const void* UnresolvedDirectMethodTrampolineFromCode(AbstractMethod*, AbstractMethod**, Thread*, +const void* UnresolvedDirectMethodTrampolineFromCode(mirror::AbstractMethod*, + mirror::AbstractMethod**, Thread*, Runtime::TrampolineType); extern "C" void art_invoke_direct_trampoline_with_access_check(uint32_t, void*); extern "C" void art_invoke_interface_trampoline(uint32_t, void*); @@ -129,7 +118,8 @@ extern void CheckSuspendFromCode(Thread* thread); extern "C" void art_test_suspend(); // Throw entrypoints. -extern void ThrowAbstractMethodErrorFromCode(AbstractMethod* method, Thread* thread, AbstractMethod** sp); +extern void ThrowAbstractMethodErrorFromCode(mirror::AbstractMethod* method, Thread* thread, + mirror::AbstractMethod** sp); extern "C" void art_deliver_exception_from_code(void*); extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit); extern "C" void art_throw_div_zero_from_code(); diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h index a08a584660..ee59df495c 100644 --- a/src/oat/runtime/oat_support_entrypoints.h +++ b/src/oat/runtime/oat_support_entrypoints.h @@ -141,6 +141,26 @@ struct PACKED(4) EntryPoints { void (*pThrowStackOverflowFromCode)(void*); }; +// JNI entrypoints. +extern void* FindNativeMethod(Thread* thread) LOCKS_EXCLUDED(Locks::mutator_lock_); +extern uint32_t JniMethodStart(Thread* self) + UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot)); +extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self) + UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot)); +extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot)); +extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, + Thread* self) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot)); +extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie, + Thread* self) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot)); + +extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result, + uint32_t saved_local_ref_cookie, + jobject locked, Thread* self) + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot)); + // Initialize an entry point data structure. void InitEntryPoints(EntryPoints* points); diff --git a/src/oat/runtime/support_cast.cc b/src/oat/runtime/support_cast.cc index 71a37efe2c..0b1fb742ef 100644 --- a/src/oat/runtime/support_cast.cc +++ b/src/oat/runtime/support_cast.cc @@ -17,6 +17,7 @@ #include "callee_save_frame.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" +#include "mirror/object_array-inl.h" #include "runtime_support.h" namespace art { diff --git a/src/oat/runtime/support_jni.cc b/src/oat/runtime/support_jni.cc index 0e21700cac..6799159fdc 100644 --- a/src/oat/runtime/support_jni.cc +++ b/src/oat/runtime/support_jni.cc @@ -27,7 +27,7 @@ namespace art { // Used by the JNI dlsym stub to find the native method to invoke if none is registered. -extern void* FindNativeMethod(Thread* self) LOCKS_EXCLUDED(Locks::mutator_lock_) { +extern void* FindNativeMethod(Thread* self) { Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native. DCHECK(Thread::Current() == self); ScopedObjectAccess soa(self); @@ -49,7 +49,7 @@ extern void* FindNativeMethod(Thread* self) LOCKS_EXCLUDED(Locks::mutator_lock_) } // Called on entry to JNI, transition out of Runnable and release share of mutator_lock_. -extern uint32_t JniMethodStart(Thread* self) UNLOCK_FUNCTION(GlobalSynchronizatio::mutator_lock_) { +extern uint32_t JniMethodStart(Thread* self) { JNIEnvExt* env = self->GetJniEnv(); DCHECK(env != NULL); uint32_t saved_local_ref_cookie = env->local_ref_cookie; @@ -58,8 +58,7 @@ extern uint32_t JniMethodStart(Thread* self) UNLOCK_FUNCTION(GlobalSynchronizati return saved_local_ref_cookie; } -extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self) - UNLOCK_FUNCTION(Locks::mutator_lock_) { +extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self) { self->DecodeJObject(to_lock)->MonitorEnter(self); return JniMethodStart(self); } @@ -71,23 +70,21 @@ static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) { self->PopSirt(); } -extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { +extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) { self->TransitionFromSuspendedToRunnable(); PopLocalReferences(saved_local_ref_cookie, self); } -extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, Thread* self) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { +extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, + Thread* self) { self->TransitionFromSuspendedToRunnable(); UnlockJniSynchronizedMethod(locked, self); // Must decode before pop. PopLocalReferences(saved_local_ref_cookie, self); } extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie, - Thread* self) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { + Thread* self) { self->TransitionFromSuspendedToRunnable(); mirror::Object* o = self->DecodeJObject(result); // Must decode before pop. PopLocalReferences(saved_local_ref_cookie, self); @@ -103,8 +100,7 @@ extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_ extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result, uint32_t saved_local_ref_cookie, - jobject locked, Thread* self) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_) { + jobject locked, Thread* self) { self->TransitionFromSuspendedToRunnable(); UnlockJniSynchronizedMethod(locked, self); // Must decode before pop. mirror::Object* o = self->DecodeJObject(result); diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc index 445ae2a5a7..48ec5bfc3d 100644 --- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc +++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc @@ -60,19 +60,6 @@ extern "C" void* art_get_obj_static_from_code(uint32_t); // FillArray entrypoint. extern "C" void art_handle_fill_data_from_code(void*, void*); -// JNI entrypoints. -extern void* FindNativeMethod(Thread* thread); -extern uint32_t JniMethodStart(Thread* self); -extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self); -extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self); -extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, - Thread* self); -extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie, - Thread* self); -extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result, - uint32_t saved_local_ref_cookie, - jobject locked, Thread* self); - // Lock entrypoints. extern "C" void art_lock_object_from_code(void*); extern "C" void art_unlock_object_from_code(void*); diff --git a/src/runtime_support.h b/src/runtime_support.h index a504237044..09ca0aab51 100644 --- a/src/runtime_support.h +++ b/src/runtime_support.h @@ -25,6 +25,7 @@ #include "jni_internal.h" #include "mirror/abstract_method.h" #include "mirror/array.h" +#include "mirror/class-inl.h" #include "mirror/throwable.h" #include "object_utils.h" #include "thread.h" diff --git a/src/scoped_thread_state_change.h b/src/scoped_thread_state_change.h index 80d47c5528..31f178d079 100644 --- a/src/scoped_thread_state_change.h +++ b/src/scoped_thread_state_change.h @@ -19,7 +19,7 @@ #include "base/casts.h" #include "jni_internal.h" -#include "thread.h" +#include "thread-inl.h" namespace art { diff --git a/src/thread-inl.h b/src/thread-inl.h new file mode 100644 index 0000000000..93aa10e240 --- /dev/null +++ b/src/thread-inl.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SRC_THREAD_INL_H_ +#define ART_SRC_THREAD_INL_H_ + +#include "thread.h" + +#include "base/mutex-inl.h" +#include "cutils/atomic-inline.h" + +namespace art { + +inline void Thread::AssertThreadSuspensionIsAllowable(bool check_locks) const { +#ifdef NDEBUG + UNUSED(check_locks); // Keep GCC happy about unused parameters. +#else + CHECK_EQ(0u, no_thread_suspension_) << last_no_thread_suspension_cause_; + if (check_locks) { + bool bad_mutexes_held = false; + for (int i = kMaxMutexLevel; i >= 0; --i) { + // We expect no locks except the mutator_lock_. + if (i != kMutatorLock) { + BaseMutex* held_mutex = GetHeldMutex(static_cast<LockLevel>(i)); + if (held_mutex != NULL) { + LOG(ERROR) << "holding \"" << held_mutex->GetName() + << "\" at point where thread suspension is expected"; + bad_mutexes_held = true; + } + } + } + CHECK(!bad_mutexes_held); + } +#endif +} + +inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) { + AssertThreadSuspensionIsAllowable(); + DCHECK_NE(new_state, kRunnable); + DCHECK_EQ(this, Thread::Current()); + // Change to non-runnable state, thereby appearing suspended to the system. + DCHECK_EQ(GetState(), kRunnable); + union StateAndFlags old_state_and_flags; + union StateAndFlags new_state_and_flags; + do { + old_state_and_flags = state_and_flags_; + // Copy over flags and try to clear the checkpoint bit if it is set. + new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags & ~kCheckpointRequest; + new_state_and_flags.as_struct.state = new_state; + // CAS the value without a memory barrier, that will occur in the unlock below. + } while (UNLIKELY(android_atomic_cas(old_state_and_flags.as_int, new_state_and_flags.as_int, + &state_and_flags_.as_int) != 0)); + // If we toggled the checkpoint flag we must have cleared it. + uint16_t flag_change = new_state_and_flags.as_struct.flags ^ old_state_and_flags.as_struct.flags; + if (UNLIKELY((flag_change & kCheckpointRequest) != 0)) { + RunCheckpointFunction(); + } + // Release share on mutator_lock_. + Locks::mutator_lock_->SharedUnlock(this); +} + +inline ThreadState Thread::TransitionFromSuspendedToRunnable() { + bool done = false; + union StateAndFlags old_state_and_flags = state_and_flags_; + int16_t old_state = old_state_and_flags.as_struct.state; + DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable); + do { + Locks::mutator_lock_->AssertNotHeld(this); // Otherwise we starve GC.. + old_state_and_flags = state_and_flags_; + DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); + if (UNLIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0)) { + // Wait while our suspend count is non-zero. + MutexLock mu(this, *Locks::thread_suspend_count_lock_); + old_state_and_flags = state_and_flags_; + DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); + while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) { + // Re-check when Thread::resume_cond_ is notified. + Thread::resume_cond_->Wait(this); + old_state_and_flags = state_and_flags_; + DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); + } + DCHECK_EQ(GetSuspendCount(), 0); + } + // Re-acquire shared mutator_lock_ access. + Locks::mutator_lock_->SharedLock(this); + // Atomically change from suspended to runnable if no suspend request pending. + old_state_and_flags = state_and_flags_; + DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); + if (LIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0)) { + union StateAndFlags new_state_and_flags = old_state_and_flags; + new_state_and_flags.as_struct.state = kRunnable; + // CAS the value without a memory barrier, that occurred in the lock above. + done = android_atomic_cas(old_state_and_flags.as_int, new_state_and_flags.as_int, + &state_and_flags_.as_int) == 0; + } + if (UNLIKELY(!done)) { + // Failed to transition to Runnable. Release shared mutator_lock_ access and try again. + Locks::mutator_lock_->SharedUnlock(this); + } + } while (UNLIKELY(!done)); + return static_cast<ThreadState>(old_state); +} + +} // namespace art + +#endif // ART_SRC_THREAD_INL_H_ diff --git a/src/thread.cc b/src/thread.cc index 01d6072f12..5b1a3251e6 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -56,6 +56,7 @@ #include "gc/space.h" #include "stack.h" #include "stack_indirect_reference_table.h" +#include "thread-inl.h" #include "thread_list.h" #include "utils.h" #include "verifier/dex_gc_map.h" @@ -608,72 +609,6 @@ void Thread::FullSuspendCheck() { VLOG(threads) << this << " self-reviving"; } -void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) { - AssertThreadSuspensionIsAllowable(); - DCHECK_NE(new_state, kRunnable); - DCHECK_EQ(this, Thread::Current()); - // Change to non-runnable state, thereby appearing suspended to the system. - DCHECK_EQ(GetState(), kRunnable); - union StateAndFlags old_state_and_flags; - union StateAndFlags new_state_and_flags; - do { - old_state_and_flags = state_and_flags_; - // Copy over flags and try to clear the checkpoint bit if it is set. - new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags & ~kCheckpointRequest; - new_state_and_flags.as_struct.state = new_state; - } while (android_atomic_cmpxchg(old_state_and_flags.as_int, new_state_and_flags.as_int, - &state_and_flags_.as_int) != 0); - // If we toggled the checkpoint flag we must have cleared it. - uint16_t flag_change = new_state_and_flags.as_struct.flags ^ old_state_and_flags.as_struct.flags; - if ((flag_change & kCheckpointRequest) != 0) { - RunCheckpointFunction(); - } - // Release share on mutator_lock_. - Locks::mutator_lock_->SharedUnlock(this); -} - -ThreadState Thread::TransitionFromSuspendedToRunnable() { - bool done = false; - union StateAndFlags old_state_and_flags = state_and_flags_; - int16_t old_state = old_state_and_flags.as_struct.state; - DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable); - do { - Locks::mutator_lock_->AssertNotHeld(this); // Otherwise we starve GC.. - old_state_and_flags = state_and_flags_; - DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); - if ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) { - // Wait while our suspend count is non-zero. - MutexLock mu(this, *Locks::thread_suspend_count_lock_); - old_state_and_flags = state_and_flags_; - DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); - while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) { - // Re-check when Thread::resume_cond_ is notified. - Thread::resume_cond_->Wait(this); - old_state_and_flags = state_and_flags_; - DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); - } - DCHECK_EQ(GetSuspendCount(), 0); - } - // Re-acquire shared mutator_lock_ access. - Locks::mutator_lock_->SharedLock(this); - // Atomically change from suspended to runnable if no suspend request pending. - old_state_and_flags = state_and_flags_; - DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); - if ((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0) { - union StateAndFlags new_state_and_flags = old_state_and_flags; - new_state_and_flags.as_struct.state = kRunnable; - done = android_atomic_cmpxchg(old_state_and_flags.as_int, new_state_and_flags.as_int, - &state_and_flags_.as_int) - == 0; - } - if (!done) { - // Failed to transition to Runnable. Release shared mutator_lock_ access and try again. - Locks::mutator_lock_->SharedUnlock(this); - } - } while (!done); - return static_cast<ThreadState>(old_state); -} - Thread* Thread::SuspendForDebugger(jobject peer, bool request_suspension, bool* timed_out) { static const useconds_t kTimeoutUs = 30 * 1000000; // 30s. useconds_t total_delay_us = 0; @@ -2112,25 +2047,4 @@ std::ostream& operator<<(std::ostream& os, const Thread& thread) { return os; } -#ifndef NDEBUG -void Thread::AssertThreadSuspensionIsAllowable(bool check_locks) const { - CHECK_EQ(0u, no_thread_suspension_) << last_no_thread_suspension_cause_; - if (check_locks) { - bool bad_mutexes_held = false; - for (int i = kMaxMutexLevel; i >= 0; --i) { - // We expect no locks except the mutator_lock_. - if (i != kMutatorLock) { - BaseMutex* held_mutex = GetHeldMutex(static_cast<LockLevel>(i)); - if (held_mutex != NULL) { - LOG(ERROR) << "holding \"" << held_mutex->GetName() - << "\" at point where thread suspension is expected"; - bad_mutexes_held = true; - } - } - } - CHECK(!bad_mutexes_held); - } -} -#endif - } // namespace art diff --git a/src/thread.h b/src/thread.h index 5e424c1cd5..58de45de65 100644 --- a/src/thread.h +++ b/src/thread.h @@ -169,13 +169,15 @@ class PACKED(4) Thread { // Transition from non-runnable to runnable state acquiring share on mutator_lock_. ThreadState TransitionFromSuspendedToRunnable() LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) - SHARED_LOCK_FUNCTION(Locks::mutator_lock_); + SHARED_LOCK_FUNCTION(Locks::mutator_lock_) + __attribute__ ((always_inline)); // Transition from runnable into a state where mutator privileges are denied. Releases share of // mutator lock. void TransitionFromRunnableToSuspended(ThreadState new_state) LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) - UNLOCK_FUNCTION(Locks::mutator_lock_); + UNLOCK_FUNCTION(Locks::mutator_lock_) + __attribute__ ((always_inline)); // Wait for a debugger suspension on the thread associated with the given peer. Returns the // thread on success, else NULL. If the thread should be suspended then request_suspension should @@ -215,13 +217,7 @@ class PACKED(4) Thread { #endif -#ifndef NDEBUG void AssertThreadSuspensionIsAllowable(bool check_locks = true) const; -#else - void AssertThreadSuspensionIsAllowable(bool check_locks = true) const { - UNUSED(check_locks); // Keep GCC happy about unused parameters. - } -#endif bool IsDaemon() const { return daemon_; diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc index a18c8b1837..f4125812eb 100644 --- a/src/verifier/reg_type.cc +++ b/src/verifier/reg_type.cc @@ -19,6 +19,7 @@ #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" +#include "mirror/object_array-inl.h" #include "object_utils.h" #include "reg_type_cache.h" |