// upon destruction.
class SCOPED_CAPABILITY MutexLock {
public:
- explicit MutexLock(Thread* self, Mutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) : self_(self), mu_(mu) {
+ explicit MutexLock(Thread* self, Mutex& mu) ACQUIRE(mu) : self_(self), mu_(mu) {
mu_.ExclusiveLock(self_);
}
- ~MutexLock() UNLOCK_FUNCTION() {
+ ~MutexLock() RELEASE() {
mu_.ExclusiveUnlock(self_);
}
// construction and releases it upon destruction.
class SCOPED_CAPABILITY ReaderMutexLock {
public:
- explicit ReaderMutexLock(Thread* self, ReaderWriterMutex& mu) EXCLUSIVE_LOCK_FUNCTION(mu) :
+ explicit ReaderMutexLock(Thread* self, ReaderWriterMutex& mu) ACQUIRE(mu) :
self_(self), mu_(mu) {
mu_.SharedLock(self_);
}
- ~ReaderMutexLock() UNLOCK_FUNCTION() {
+ ~ReaderMutexLock() RELEASE() {
mu_.SharedUnlock(self_);
}
// "WriterMutexLock mu(lock)".
#define WriterMutexLock(x) static_assert(0, "WriterMutexLock declaration missing variable name")
+// For StartNoThreadSuspension and EndNoThreadSuspension.
+class CAPABILITY("role") Role {
+ public:
+ void Acquire() ACQUIRE() {}
+ void Release() RELEASE() {}
+ const Role& operator!() const { return *this; }
+};
+
+class Uninterruptible : public Role {
+};
+
// Global mutexes corresponding to the levels above.
class Locks {
public:
static Mutex* lambda_table_lock_ ACQUIRED_AFTER(mutator_lock_);
};
+class Roles {
+ public:
+ static Uninterruptible uninterruptible_;
+};
+
} // namespace art
#endif // ART_RUNTIME_BASE_MUTEX_H_
return DotToDescriptor(name->ToModifiedUtf8().c_str());
}
-ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class,
- ArtMethod* proxy_method) {
+ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, ArtMethod* proxy_method) {
DCHECK(proxy_class->IsProxyClass());
DCHECK(proxy_method->IsProxyMethod());
{
self, old_virtuals, old_method_count * method_size, new_method_count * method_size));
if (UNLIKELY(virtuals == nullptr)) {
self->AssertPendingOOMException();
+ self->EndAssertNoThreadSuspension(old_cause);
return false;
}
ScopedArenaUnorderedMap<ArtMethod*, ArtMethod*> move_table(allocator.Adapter());
// result in the DexCache. The referrer is used to identity the
// target DexCache and ClassLoader to use for resolution.
mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx, mirror::Class* referrer)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Resolve a Type with the given index from the DexFile, storing the
// result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
mirror::Class* ResolveType(uint16_t type_idx, ArtMethod* referrer)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
mirror::Class* ResolveType(uint16_t type_idx, ArtField* referrer)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Resolve a type with the given ID from the DexFile, storing the
// result in DexCache. The ClassLoader is used to search for the
mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Resolve a method with a given ID from the DexFile, storing the
// result in DexCache. The ClassLinker and ClassLoader are used as
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader, ArtMethod* referrer,
InvokeType type)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
ArtMethod* GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer)
SHARED_REQUIRES(Locks::mutator_lock_);
ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
ArtField* GetResolvedField(uint32_t field_idx, mirror::Class* field_declaring_class)
SHARED_REQUIRES(Locks::mutator_lock_);
ArtField* GetResolvedField(uint32_t field_idx, mirror::DexCache* dex_cache)
SHARED_REQUIRES(Locks::mutator_lock_);
ArtField* ResolveField(uint32_t field_idx, ArtMethod* referrer, bool is_static)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Resolve a field with a given ID from the DexFile, storing the
// result in DexCache. The ClassLinker and ClassLoader are used as
ArtField* ResolveField(const DexFile& dex_file, uint32_t field_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader, bool is_static)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Resolve a field with a given ID from the DexFile, storing the
// result in DexCache. The ClassLinker and ClassLoader are used as
ArtField* ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Get shorty from method index without resolution. Used to do handlerization.
const char* MethodShorty(uint32_t method_idx, ArtMethod* referrer, uint32_t* length)
// given the restriction that no <clinit> execution is possible.
bool EnsureInitialized(Thread* self, Handle<mirror::Class> c, bool can_init_fields,
bool can_init_parents)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Initializes classes that have instances in the image but that have
// <clinit> methods so they could not be initialized by the compiler.
- void RunRootClinits() SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ void RunRootClinits() SHARED_REQUIRES(Locks::mutator_lock_)
+ REQUIRES(!dex_lock_, !Roles::uninterruptible_);
void RegisterDexFile(const DexFile& dex_file)
REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
REQUIRES(!dex_lock_, !Locks::mutator_lock_);
// Allocate an instance of a java.lang.Object.
- mirror::Object* AllocObject(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_);
+ mirror::Object* AllocObject(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
// TODO: replace this with multiple methods that allocate the correct managed type.
template <class T>
mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
mirror::ObjectArray<mirror::Class>* AllocClassArray(Thread* self, size_t length)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
mirror::ObjectArray<mirror::String>* AllocStringArray(Thread* self, size_t length)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+ ArtField* AllocArtFieldArray(Thread* self, size_t length);
ArtMethod* AllocArtMethodArray(Thread* self, size_t length);
mirror::PointerArray* AllocPointerArray(Thread* self, size_t length)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
mirror::IfTable* AllocIfTable(Thread* self, size_t ifcount)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
- ArtField* AllocArtFieldArray(Thread* self, size_t length)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
- mirror::ObjectArray<mirror::StackTraceElement>* AllocStackTraceElementArray(Thread* self,
- size_t length)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ mirror::ObjectArray<mirror::StackTraceElement>* AllocStackTraceElementArray(
+ Thread* self, size_t length) SHARED_REQUIRES(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
void VerifyClass(Thread* self, Handle<mirror::Class> klass)
SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
REQUIRES(!dex_lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
- void FinishInit(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ void FinishInit(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_)
+ REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// For early bootstrapping by Init
mirror::Class* AllocClass(Thread* self, mirror::Class* java_lang_Class, uint32_t class_size)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
// Alloc* convenience functions to avoid needing to pass in mirror::Class*
// values that are known to the ClassLinker such as
// kObjectArrayClass and kJavaLangString etc.
mirror::Class* AllocClass(Thread* self, uint32_t class_size)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
mirror::DexCache* AllocDexCache(Thread* self, const DexFile& dex_file)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
mirror::Class* CreatePrimitiveClass(Thread* self, Primitive::Type type)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
mirror::Class* InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
mirror::Class* CreateArrayClass(Thread* self, const char* descriptor, size_t hash,
Handle<mirror::ClassLoader> class_loader)
- SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_);
void AppendToBootClassPath(Thread* self, const DexFile& dex_file)
SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_);
mirror::Object* AllocObject(Thread* self, mirror::Class* klass, size_t num_bytes,
const PreFenceVisitor& pre_fence_visitor)
SHARED_REQUIRES(Locks::mutator_lock_)
- REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_) {
+ REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_,
+ !Roles::uninterruptible_) {
return AllocObjectWithAllocator<kInstrumented, true>(
self, klass, num_bytes, GetCurrentAllocator(), pre_fence_visitor);
}
mirror::Object* AllocNonMovableObject(Thread* self, mirror::Class* klass, size_t num_bytes,
const PreFenceVisitor& pre_fence_visitor)
SHARED_REQUIRES(Locks::mutator_lock_)
- REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_) {
+ REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_,
+ !Roles::uninterruptible_) {
return AllocObjectWithAllocator<kInstrumented, true>(
self, klass, num_bytes, GetCurrentNonMovingAllocator(), pre_fence_visitor);
}
Thread* self, mirror::Class* klass, size_t byte_count, AllocatorType allocator,
const PreFenceVisitor& pre_fence_visitor)
SHARED_REQUIRES(Locks::mutator_lock_)
- REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_);
+ REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_,
+ !Roles::uninterruptible_);
AllocatorType GetCurrentAllocator() const {
return current_allocator_;
template <bool kIsInstrumented, bool kFillUsable = false>
ALWAYS_INLINE static Array* Alloc(Thread* self, Class* array_class, int32_t component_count,
size_t component_size_shift, gc::AllocatorType allocator_type)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
static Array* CreateMultiArray(Thread* self, Handle<Class> element_class,
Handle<IntArray> dimensions)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
ALWAYS_INLINE bool CheckIsValidIndex(int32_t index) SHARED_REQUIRES(Locks::mutator_lock_);
- Array* CopyOf(Thread* self, int32_t new_length) SHARED_REQUIRES(Locks::mutator_lock_);
+ Array* CopyOf(Thread* self, int32_t new_length) SHARED_REQUIRES(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
protected:
void ThrowArrayStoreException(Object* object) SHARED_REQUIRES(Locks::mutator_lock_);
typedef T ElementType;
static PrimitiveArray<T>* Alloc(Thread* self, size_t length)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
const T* GetData() const ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
return reinterpret_cast<const T*>(GetRawData(sizeof(T), 0));
// Creates a raw object instance but does not invoke the default constructor.
template<bool kIsInstrumented, bool kCheckAddFinalizer = true>
ALWAYS_INLINE Object* Alloc(Thread* self, gc::AllocatorType allocator_type)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
Object* AllocObject(Thread* self)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
Object* AllocNonMovableObject(Thread* self)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
size_t SizeOf() SHARED_REQUIRES(Locks::mutator_lock_);
- Object* Clone(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_);
+ Object* Clone(Thread* self) SHARED_REQUIRES(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
int32_t IdentityHashCode() const
SHARED_REQUIRES(Locks::mutator_lock_)
static ObjectArray<T>* Alloc(Thread* self, Class* object_array_class, int32_t length,
gc::AllocatorType allocator_type)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
static ObjectArray<T>* Alloc(Thread* self, Class* object_array_class, int32_t length)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
T* Get(int32_t i) ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_);
SHARED_REQUIRES(Locks::mutator_lock_);
ObjectArray<T>* CopyOf(Thread* self, int32_t new_length)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
// TODO fix thread safety analysis broken by the use of template. This should be
// SHARED_REQUIRES(Locks::mutator_lock_).
trace_(nullptr),
pointer_size_(Runtime::Current()->GetClassLinker()->GetImagePointerSize()) {}
- bool Init(int depth)
- SHARED_REQUIRES(Locks::mutator_lock_) {
+ bool Init(int depth) SHARED_REQUIRES(Locks::mutator_lock_) ACQUIRE(Roles::uninterruptible_) {
// Allocate method trace with format [method pointers][pcs].
auto* cl = Runtime::Current()->GetClassLinker();
trace_ = cl->AllocPointerArray(self_, depth * 2);
+ const char* last_no_suspend_cause =
+ self_->StartAssertNoThreadSuspension("Building internal stack trace");
if (trace_ == nullptr) {
self_->AssertPendingOOMException();
return false;
}
// If We are called from native, use non-transactional mode.
- const char* last_no_suspend_cause =
- self_->StartAssertNoThreadSuspension("Building internal stack trace");
CHECK(last_no_suspend_cause == nullptr) << last_no_suspend_cause;
return true;
}
- virtual ~BuildInternalStackTraceVisitor() {
- if (trace_ != nullptr) {
- self_->EndAssertNoThreadSuspension(nullptr);
- }
+ virtual ~BuildInternalStackTraceVisitor() RELEASE(Roles::uninterruptible_) {
+ self_->EndAssertNoThreadSuspension(nullptr);
}
bool VisitFrame() SHARED_REQUIRES(Locks::mutator_lock_) {
// Transition from runnable into a state where mutator privileges are denied. Releases share of
// mutator lock.
void TransitionFromRunnableToSuspended(ThreadState new_state)
- REQUIRES(!Locks::thread_suspend_count_lock_)
+ REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_)
UNLOCK_FUNCTION(Locks::mutator_lock_)
ALWAYS_INLINE;
// Once called thread suspension will cause an assertion failure.
- const char* StartAssertNoThreadSuspension(const char* cause) {
+ const char* StartAssertNoThreadSuspension(const char* cause) ACQUIRE(Roles::uninterruptible_) {
+ Roles::uninterruptible_.Acquire(); // No-op.
if (kIsDebugBuild) {
CHECK(cause != nullptr);
const char* previous_cause = tlsPtr_.last_no_thread_suspension_cause;
}
// End region where no thread suspension is expected.
- void EndAssertNoThreadSuspension(const char* old_cause) {
+ void EndAssertNoThreadSuspension(const char* old_cause) RELEASE(Roles::uninterruptible_) {
if (kIsDebugBuild) {
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;
}
+ Roles::uninterruptible_.Release(); // No-op.
}
void AssertThreadSuspensionIsAllowable(bool check_locks = true) const;
DISALLOW_COPY_AND_ASSIGN(Thread);
};
-class ScopedAssertNoThreadSuspension {
+class SCOPED_CAPABILITY ScopedAssertNoThreadSuspension {
public:
- ScopedAssertNoThreadSuspension(Thread* self, const char* cause)
+ ScopedAssertNoThreadSuspension(Thread* self, const char* cause) ACQUIRE(Roles::uninterruptible_)
: self_(self), old_cause_(self->StartAssertNoThreadSuspension(cause)) {
}
- ~ScopedAssertNoThreadSuspension() {
+ ~ScopedAssertNoThreadSuspension() RELEASE(Roles::uninterruptible_) {
self_->EndAssertNoThreadSuspension(old_cause_);
}
Thread* Self() {