1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef ART_RUNTIME_OBJ_PTR_H_ 18#define ART_RUNTIME_OBJ_PTR_H_ 19 20#include <ostream> 21#include <type_traits> 22 23#include "base/macros.h" 24#include "base/mutex.h" // For Locks::mutator_lock_. 25#include "globals.h" 26 27namespace art { 28 29constexpr bool kObjPtrPoisoning = kIsDebugBuild; 30 31// It turns out that most of the performance overhead comes from copying. Don't validate for now. 32// This defers finding stale ObjPtr objects until they are used. 33constexpr bool kObjPtrPoisoningValidateOnCopy = false; 34 35// Value type representing a pointer to a mirror::Object of type MirrorType 36// Since the cookie is thread based, it is not safe to share an ObjPtr between threads. 37template<class MirrorType> 38class ObjPtr { 39 static constexpr size_t kCookieShift = 40 kHeapReferenceSize * kBitsPerByte - kObjectAlignmentShift; 41 static constexpr size_t kCookieBits = sizeof(uintptr_t) * kBitsPerByte - kCookieShift; 42 static constexpr uintptr_t kCookieMask = (static_cast<uintptr_t>(1u) << kCookieBits) - 1; 43 44 static_assert(kCookieBits >= kObjectAlignmentShift, 45 "must have a least kObjectAlignmentShift bits"); 46 47 public: 48 ALWAYS_INLINE ObjPtr() REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {} 49 50 // Note: The following constructors allow implicit conversion. This simplifies code that uses 51 // them, e.g., for parameter passing. However, in general, implicit-conversion constructors 52 // are discouraged and detected by clang-tidy. 53 54 ALWAYS_INLINE ObjPtr(std::nullptr_t) 55 REQUIRES_SHARED(Locks::mutator_lock_) 56 : reference_(0u) {} 57 58 template <typename Type, 59 typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type> 60 ALWAYS_INLINE ObjPtr(Type* ptr) 61 REQUIRES_SHARED(Locks::mutator_lock_) 62 : reference_(Encode(static_cast<MirrorType*>(ptr))) { 63 } 64 65 template <typename Type, 66 typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type> 67 ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) 68 REQUIRES_SHARED(Locks::mutator_lock_) 69 : reference_(kObjPtrPoisoningValidateOnCopy 70 ? Encode(static_cast<MirrorType*>(other.Ptr())) 71 : other.reference_) { 72 } 73 74 template <typename Type, 75 typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type> 76 ALWAYS_INLINE ObjPtr& operator=(const ObjPtr<Type>& other) 77 REQUIRES_SHARED(Locks::mutator_lock_) { 78 reference_ = kObjPtrPoisoningValidateOnCopy 79 ? Encode(static_cast<MirrorType*>(other.Ptr())) 80 : other.reference_; 81 return *this; 82 } 83 84 ALWAYS_INLINE ObjPtr& operator=(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) { 85 Assign(ptr); 86 return *this; 87 } 88 89 ALWAYS_INLINE void Assign(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) { 90 reference_ = Encode(ptr); 91 } 92 93 ALWAYS_INLINE MirrorType* operator->() const REQUIRES_SHARED(Locks::mutator_lock_) { 94 return Ptr(); 95 } 96 97 ALWAYS_INLINE bool IsNull() const { 98 return reference_ == 0; 99 } 100 101 // Ptr makes sure that the object pointer is valid. 102 ALWAYS_INLINE MirrorType* Ptr() const REQUIRES_SHARED(Locks::mutator_lock_) { 103 AssertValid(); 104 return PtrUnchecked(); 105 } 106 107 ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_); 108 109 ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_); 110 111 ALWAYS_INLINE bool operator==(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) { 112 return Ptr() == ptr.Ptr(); 113 } 114 115 template <typename PointerType> 116 ALWAYS_INLINE bool operator==(const PointerType* ptr) const 117 REQUIRES_SHARED(Locks::mutator_lock_) { 118 return Ptr() == ptr; 119 } 120 121 ALWAYS_INLINE bool operator==(std::nullptr_t) const { 122 return IsNull(); 123 } 124 125 ALWAYS_INLINE bool operator!=(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) { 126 return Ptr() != ptr.Ptr(); 127 } 128 129 template <typename PointerType> 130 ALWAYS_INLINE bool operator!=(const PointerType* ptr) const 131 REQUIRES_SHARED(Locks::mutator_lock_) { 132 return Ptr() != ptr; 133 } 134 135 ALWAYS_INLINE bool operator!=(std::nullptr_t) const { 136 return !IsNull(); 137 } 138 139 // Ptr unchecked does not check that object pointer is valid. Do not use if you can avoid it. 140 ALWAYS_INLINE MirrorType* PtrUnchecked() const { 141 if (kObjPtrPoisoning) { 142 return reinterpret_cast<MirrorType*>( 143 static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift))); 144 } else { 145 return reinterpret_cast<MirrorType*>(reference_); 146 } 147 } 148 149 // Static function to be friendly with null pointers. 150 template <typename SourceType> 151 static ObjPtr<MirrorType> DownCast(ObjPtr<SourceType> ptr) REQUIRES_SHARED(Locks::mutator_lock_) { 152 static_assert(std::is_base_of<SourceType, MirrorType>::value, 153 "Target type must be a subtype of source type"); 154 return static_cast<MirrorType*>(ptr.Ptr()); 155 } 156 157 private: 158 // Trim off high bits of thread local cookie. 159 ALWAYS_INLINE static uintptr_t TrimCookie(uintptr_t cookie) { 160 return cookie & kCookieMask; 161 } 162 163 ALWAYS_INLINE uintptr_t GetCookie() const { 164 return reference_ >> kCookieShift; 165 } 166 167 ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_); 168 // The encoded reference and cookie. 169 uintptr_t reference_; 170 171 template <class T> friend class ObjPtr; // Required for reference_ access in copy cons/operator. 172}; 173 174static_assert(std::is_trivially_copyable<ObjPtr<void>>::value, 175 "ObjPtr should be trivially copyable"); 176 177// Hash function for stl data structures. 178class HashObjPtr { 179 public: 180 template<class MirrorType> 181 size_t operator()(const ObjPtr<MirrorType>& ptr) const NO_THREAD_SAFETY_ANALYSIS { 182 return std::hash<MirrorType*>()(ptr.Ptr()); 183 } 184}; 185 186template<class MirrorType, typename PointerType> 187ALWAYS_INLINE bool operator==(const PointerType* a, const ObjPtr<MirrorType>& b) 188 REQUIRES_SHARED(Locks::mutator_lock_) { 189 return b == a; 190} 191 192template<class MirrorType> 193ALWAYS_INLINE bool operator==(std::nullptr_t, const ObjPtr<MirrorType>& b) { 194 return b == nullptr; 195} 196 197template<typename MirrorType, typename PointerType> 198ALWAYS_INLINE bool operator!=(const PointerType* a, const ObjPtr<MirrorType>& b) 199 REQUIRES_SHARED(Locks::mutator_lock_) { 200 return b != a; 201} 202 203template<class MirrorType> 204ALWAYS_INLINE bool operator!=(std::nullptr_t, const ObjPtr<MirrorType>& b) { 205 return b != nullptr; 206} 207 208template<class MirrorType> 209static inline ObjPtr<MirrorType> MakeObjPtr(MirrorType* ptr) { 210 return ObjPtr<MirrorType>(ptr); 211} 212 213template<class MirrorType> 214static inline ObjPtr<MirrorType> MakeObjPtr(ObjPtr<MirrorType> ptr) { 215 return ObjPtr<MirrorType>(ptr); 216} 217 218template<class MirrorType> 219ALWAYS_INLINE std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType> ptr); 220 221} // namespace art 222 223#endif // ART_RUNTIME_OBJ_PTR_H_ 224