Home | History | Annotate | Download | only in runtime
      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