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 27 namespace art { 28 29 constexpr bool kObjPtrPoisoning = kIsDebugBuild; 30 31 // Value type representing a pointer to a mirror::Object of type MirrorType 32 // Pass kPoison as a template boolean for testing in non-debug builds. 33 // Since the cookie is thread based, it is not safe to share an ObjPtr between threads. 34 template<class MirrorType> 35 class ObjPtr { 36 static constexpr size_t kCookieShift = 37 sizeof(kHeapReferenceSize) * kBitsPerByte - kObjectAlignmentShift; 38 static constexpr size_t kCookieBits = sizeof(uintptr_t) * kBitsPerByte - kCookieShift; 39 static constexpr uintptr_t kCookieMask = (static_cast<uintptr_t>(1u) << kCookieBits) - 1; 40 41 static_assert(kCookieBits >= kObjectAlignmentShift, 42 "must have a least kObjectAlignmentShift bits"); 43 44 public: 45 ALWAYS_INLINE ObjPtr() REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {} 46 47 // Note: The following constructors allow implicit conversion. This simplifies code that uses 48 // them, e.g., for parameter passing. However, in general, implicit-conversion constructors 49 // are discouraged and detected by cpplint and clang-tidy. So mark these constructors 50 // as NOLINT (without category, as the categories are different). 51 52 ALWAYS_INLINE ObjPtr(std::nullptr_t) // NOLINT 53 REQUIRES_SHARED(Locks::mutator_lock_) 54 : reference_(0u) {} 55 56 template <typename Type, 57 typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type> 58 ALWAYS_INLINE ObjPtr(Type* ptr) // NOLINT 59 REQUIRES_SHARED(Locks::mutator_lock_) 60 : reference_(Encode(static_cast<MirrorType*>(ptr))) { 61 } 62 63 template <typename Type, 64 typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type> 65 ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) // NOLINT 66 REQUIRES_SHARED(Locks::mutator_lock_) 67 : reference_(Encode(static_cast<MirrorType*>(other.Ptr()))) { 68 } 69 70 template <typename Type, 71 typename = typename std::enable_if<std::is_base_of<MirrorType, Type>::value>::type> 72 ALWAYS_INLINE ObjPtr& operator=(const ObjPtr<Type>& other) 73 REQUIRES_SHARED(Locks::mutator_lock_) { 74 reference_ = Encode(static_cast<MirrorType*>(other.Ptr())); 75 return *this; 76 } 77 78 ALWAYS_INLINE ObjPtr& operator=(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) { 79 Assign(ptr); 80 return *this; 81 } 82 83 ALWAYS_INLINE void Assign(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) { 84 reference_ = Encode(ptr); 85 } 86 87 ALWAYS_INLINE MirrorType* operator->() const REQUIRES_SHARED(Locks::mutator_lock_) { 88 return Ptr(); 89 } 90 91 ALWAYS_INLINE bool IsNull() const { 92 return reference_ == 0; 93 } 94 95 // Ptr makes sure that the object pointer is valid. 96 ALWAYS_INLINE MirrorType* Ptr() const REQUIRES_SHARED(Locks::mutator_lock_) { 97 AssertValid(); 98 return PtrUnchecked(); 99 } 100 101 ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_); 102 103 ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_); 104 105 ALWAYS_INLINE bool operator==(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) { 106 return Ptr() == ptr.Ptr(); 107 } 108 109 template <typename PointerType> 110 ALWAYS_INLINE bool operator==(const PointerType* ptr) const 111 REQUIRES_SHARED(Locks::mutator_lock_) { 112 return Ptr() == ptr; 113 } 114 115 ALWAYS_INLINE bool operator==(std::nullptr_t) const { 116 return IsNull(); 117 } 118 119 ALWAYS_INLINE bool operator!=(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) { 120 return Ptr() != ptr.Ptr(); 121 } 122 123 template <typename PointerType> 124 ALWAYS_INLINE bool operator!=(const PointerType* ptr) const 125 REQUIRES_SHARED(Locks::mutator_lock_) { 126 return Ptr() != ptr; 127 } 128 129 ALWAYS_INLINE bool operator!=(std::nullptr_t) const { 130 return !IsNull(); 131 } 132 133 // Ptr unchecked does not check that object pointer is valid. Do not use if you can avoid it. 134 ALWAYS_INLINE MirrorType* PtrUnchecked() const { 135 if (kObjPtrPoisoning) { 136 return reinterpret_cast<MirrorType*>( 137 static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift))); 138 } else { 139 return reinterpret_cast<MirrorType*>(reference_); 140 } 141 } 142 143 // Static function to be friendly with null pointers. 144 template <typename SourceType> 145 static ObjPtr<MirrorType> DownCast(ObjPtr<SourceType> ptr) REQUIRES_SHARED(Locks::mutator_lock_) { 146 static_assert(std::is_base_of<SourceType, MirrorType>::value, 147 "Target type must be a subtype of source type"); 148 return static_cast<MirrorType*>(ptr.Ptr()); 149 } 150 151 private: 152 // Trim off high bits of thread local cookie. 153 ALWAYS_INLINE static uintptr_t TrimCookie(uintptr_t cookie) { 154 return cookie & kCookieMask; 155 } 156 157 ALWAYS_INLINE uintptr_t GetCookie() const { 158 return reference_ >> kCookieShift; 159 } 160 161 ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_); 162 // The encoded reference and cookie. 163 uintptr_t reference_; 164 }; 165 166 static_assert(std::is_trivially_copyable<ObjPtr<void>>::value, 167 "ObjPtr should be trivially copyable"); 168 169 // Hash function for stl data structures. 170 class HashObjPtr { 171 public: 172 template<class MirrorType> 173 size_t operator()(const ObjPtr<MirrorType>& ptr) const NO_THREAD_SAFETY_ANALYSIS { 174 return std::hash<MirrorType*>()(ptr.Ptr()); 175 } 176 }; 177 178 template<class MirrorType, typename PointerType> 179 ALWAYS_INLINE bool operator==(const PointerType* a, const ObjPtr<MirrorType>& b) 180 REQUIRES_SHARED(Locks::mutator_lock_) { 181 return b == a; 182 } 183 184 template<class MirrorType> 185 ALWAYS_INLINE bool operator==(std::nullptr_t, const ObjPtr<MirrorType>& b) { 186 return b == nullptr; 187 } 188 189 template<typename MirrorType, typename PointerType> 190 ALWAYS_INLINE bool operator!=(const PointerType* a, const ObjPtr<MirrorType>& b) 191 REQUIRES_SHARED(Locks::mutator_lock_) { 192 return b != a; 193 } 194 195 template<class MirrorType> 196 ALWAYS_INLINE bool operator!=(std::nullptr_t, const ObjPtr<MirrorType>& b) { 197 return b != nullptr; 198 } 199 200 template<class MirrorType> 201 static inline ObjPtr<MirrorType> MakeObjPtr(MirrorType* ptr) { 202 return ObjPtr<MirrorType>(ptr); 203 } 204 205 template<class MirrorType> 206 static inline ObjPtr<MirrorType> MakeObjPtr(ObjPtr<MirrorType> ptr) { 207 return ObjPtr<MirrorType>(ptr); 208 } 209 210 template<class MirrorType> 211 ALWAYS_INLINE std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType> ptr); 212 213 } // namespace art 214 215 #endif // ART_RUNTIME_OBJ_PTR_H_ 216