/* * Copyright (C) 2014 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_RUNTIME_HANDLE_H_ #define ART_RUNTIME_HANDLE_H_ #include #include "base/casts.h" #include "base/locks.h" #include "base/macros.h" #include "base/value_object.h" #include "jni.h" #include "obj_ptr.h" #include "stack_reference.h" namespace art { class Thread; template class Handle; template class IterationRange; namespace mirror { template class ObjectArray; template class ArrayIter; template using HandleArrayIter = ArrayIter>>; template using ConstHandleArrayIter = ArrayIter>>; } // namespace mirror // Handles are memory locations that contain GC roots. As the mirror::Object*s within a handle are // GC visible then the GC may move the references within them, something that couldn't be done with // a wrap pointer. Handles are generally allocated within HandleScopes. Handle is a super-class // of MutableHandle and doesn't support assignment operations. template class Handle : public ValueObject { public: Handle() : reference_(nullptr) { } ALWAYS_INLINE Handle(const Handle& handle) = default; ALWAYS_INLINE Handle& operator=(const Handle& handle) = default; template >> ALWAYS_INLINE Handle(const Handle& other) : reference_(other.reference_) { } ALWAYS_INLINE explicit Handle(StackReference* reference) : reference_(reference) { } ALWAYS_INLINE T& operator*() const REQUIRES_SHARED(Locks::mutator_lock_) { return *Get(); } ALWAYS_INLINE T* operator->() const REQUIRES_SHARED(Locks::mutator_lock_) { return Get(); } ALWAYS_INLINE T* Get() const REQUIRES_SHARED(Locks::mutator_lock_) { return down_cast(reference_->AsMirrorPtr()); } template , T>>> ALWAYS_INLINE IterationRange> ConstIterate() const REQUIRES_SHARED(Locks::mutator_lock_) { return T::ConstIterate(*this); } template , T>>> ALWAYS_INLINE IterationRange> Iterate() REQUIRES_SHARED(Locks::mutator_lock_) { return T::Iterate(*this); } ALWAYS_INLINE bool IsNull() const { // It's safe to null-check it without a read barrier. return reference_->IsNull(); } ALWAYS_INLINE jobject ToJObject() const REQUIRES_SHARED(Locks::mutator_lock_) { if (UNLIKELY(reference_->AsMirrorPtr() == nullptr)) { // Special case so that we work with null handles. return nullptr; } return reinterpret_cast(reference_); } ALWAYS_INLINE StackReference* GetReference() { return reference_; } ALWAYS_INLINE const StackReference* GetReference() const { return reference_; } ALWAYS_INLINE bool operator!=(std::nullptr_t) const REQUIRES_SHARED(Locks::mutator_lock_) { return !IsNull(); } ALWAYS_INLINE bool operator==(std::nullptr_t) const REQUIRES_SHARED(Locks::mutator_lock_) { return IsNull(); } protected: template explicit Handle(StackReference* reference) : reference_(reference) { } template explicit Handle(const Handle& handle) : reference_(handle.reference_) { } StackReference* reference_; private: friend class BuildGenericJniFrameVisitor; template friend class Handle; friend class HandleScope; template friend class HandleWrapper; template friend class StackHandleScope; }; // Handles that support assignment. template class MutableHandle : public Handle { public: MutableHandle() { } ALWAYS_INLINE MutableHandle(const MutableHandle& handle) REQUIRES_SHARED(Locks::mutator_lock_) = default; ALWAYS_INLINE MutableHandle& operator=(const MutableHandle& handle) REQUIRES_SHARED(Locks::mutator_lock_) = default; ALWAYS_INLINE explicit MutableHandle(StackReference* reference) REQUIRES_SHARED(Locks::mutator_lock_) : Handle(reference) { } ALWAYS_INLINE T* Assign(T* reference) REQUIRES_SHARED(Locks::mutator_lock_) { StackReference* ref = Handle::GetReference(); T* old = down_cast(ref->AsMirrorPtr()); ref->Assign(reference); return old; } ALWAYS_INLINE T* Assign(ObjPtr reference) REQUIRES_SHARED(Locks::mutator_lock_) { StackReference* ref = Handle::GetReference(); T* old = down_cast(ref->AsMirrorPtr()); ref->Assign(reference.Ptr()); return old; } template explicit MutableHandle(const MutableHandle& handle) REQUIRES_SHARED(Locks::mutator_lock_) : Handle(handle) { } template explicit MutableHandle(StackReference* reference) REQUIRES_SHARED(Locks::mutator_lock_) : Handle(reference) { } private: friend class BuildGenericJniFrameVisitor; friend class HandleScope; template friend class HandleWrapper; template friend class StackHandleScope; }; // A special case of Handle that only holds references to null. Invalid when if it goes out of // scope. Example: Handle h = ScopedNullHandle will leave h being undefined. template class ScopedNullHandle : public Handle { public: ScopedNullHandle() : Handle(&null_ref_) {} private: StackReference null_ref_; }; } // namespace art #endif // ART_RUNTIME_HANDLE_H_