| /* |
| * 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 <android-base/logging.h> |
| |
| #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 T> class Handle; |
| |
| // 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 T> |
| class Handle : public ValueObject { |
| public: |
| Handle() : reference_(nullptr) { |
| } |
| |
| ALWAYS_INLINE Handle(const Handle<T>& handle) = default; |
| |
| ALWAYS_INLINE Handle<T>& operator=(const Handle<T>& handle) = default; |
| |
| ALWAYS_INLINE explicit Handle(StackReference<T>* 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<T*>(reference_->AsMirrorPtr()); |
| } |
| |
| 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<jobject>(reference_); |
| } |
| |
| ALWAYS_INLINE StackReference<mirror::Object>* GetReference() { |
| return reference_; |
| } |
| |
| ALWAYS_INLINE const StackReference<mirror::Object>* 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<typename S> |
| explicit Handle(StackReference<S>* reference) |
| : reference_(reference) { |
| } |
| template<typename S> |
| explicit Handle(const Handle<S>& handle) |
| : reference_(handle.reference_) { |
| } |
| |
| StackReference<mirror::Object>* reference_; |
| |
| private: |
| friend class BuildGenericJniFrameVisitor; |
| template<class S> friend class Handle; |
| friend class HandleScope; |
| template<class S> friend class HandleWrapper; |
| template<size_t kNumReferences> friend class StackHandleScope; |
| }; |
| |
| // Handles that support assignment. |
| template<class T> |
| class MutableHandle : public Handle<T> { |
| public: |
| MutableHandle() { |
| } |
| |
| ALWAYS_INLINE MutableHandle(const MutableHandle<T>& handle) |
| REQUIRES_SHARED(Locks::mutator_lock_) = default; |
| |
| ALWAYS_INLINE MutableHandle<T>& operator=(const MutableHandle<T>& handle) |
| REQUIRES_SHARED(Locks::mutator_lock_) = default; |
| |
| ALWAYS_INLINE explicit MutableHandle(StackReference<T>* reference) |
| REQUIRES_SHARED(Locks::mutator_lock_) |
| : Handle<T>(reference) { |
| } |
| |
| ALWAYS_INLINE T* Assign(T* reference) REQUIRES_SHARED(Locks::mutator_lock_) { |
| StackReference<mirror::Object>* ref = Handle<T>::GetReference(); |
| T* old = down_cast<T*>(ref->AsMirrorPtr()); |
| ref->Assign(reference); |
| return old; |
| } |
| |
| ALWAYS_INLINE T* Assign(ObjPtr<T> reference) REQUIRES_SHARED(Locks::mutator_lock_) { |
| StackReference<mirror::Object>* ref = Handle<T>::GetReference(); |
| T* old = down_cast<T*>(ref->AsMirrorPtr()); |
| ref->Assign(reference.Ptr()); |
| return old; |
| } |
| |
| |
| template<typename S> |
| explicit MutableHandle(const MutableHandle<S>& handle) REQUIRES_SHARED(Locks::mutator_lock_) |
| : Handle<T>(handle) { |
| } |
| |
| template<typename S> |
| explicit MutableHandle(StackReference<S>* reference) REQUIRES_SHARED(Locks::mutator_lock_) |
| : Handle<T>(reference) { |
| } |
| |
| private: |
| friend class BuildGenericJniFrameVisitor; |
| friend class HandleScope; |
| template<class S> friend class HandleWrapper; |
| template<size_t kNumReferences> friend class StackHandleScope; |
| }; |
| |
| // A special case of Handle that only holds references to null. Invalid when if it goes out of |
| // scope. Example: Handle<T> h = ScopedNullHandle<T> will leave h being undefined. |
| template<class T> |
| class ScopedNullHandle : public Handle<T> { |
| public: |
| ScopedNullHandle() : Handle<T>(&null_ref_) {} |
| |
| private: |
| StackReference<mirror::Object> null_ref_; |
| }; |
| |
| } // namespace art |
| |
| #endif // ART_RUNTIME_HANDLE_H_ |