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 // 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.
     33 constexpr 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.
     37 template<class MirrorType>
     38 class 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 
    174 static_assert(std::is_trivially_copyable<ObjPtr<void>>::value,
    175               "ObjPtr should be trivially copyable");
    176 
    177 // Hash function for stl data structures.
    178 class 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 
    186 template<class MirrorType, typename PointerType>
    187 ALWAYS_INLINE bool operator==(const PointerType* a, const ObjPtr<MirrorType>& b)
    188     REQUIRES_SHARED(Locks::mutator_lock_) {
    189   return b == a;
    190 }
    191 
    192 template<class MirrorType>
    193 ALWAYS_INLINE bool operator==(std::nullptr_t, const ObjPtr<MirrorType>& b) {
    194   return b == nullptr;
    195 }
    196 
    197 template<typename MirrorType, typename PointerType>
    198 ALWAYS_INLINE bool operator!=(const PointerType* a, const ObjPtr<MirrorType>& b)
    199     REQUIRES_SHARED(Locks::mutator_lock_) {
    200   return b != a;
    201 }
    202 
    203 template<class MirrorType>
    204 ALWAYS_INLINE bool operator!=(std::nullptr_t, const ObjPtr<MirrorType>& b) {
    205   return b != nullptr;
    206 }
    207 
    208 template<class MirrorType>
    209 static inline ObjPtr<MirrorType> MakeObjPtr(MirrorType* ptr) {
    210   return ObjPtr<MirrorType>(ptr);
    211 }
    212 
    213 template<class MirrorType>
    214 static inline ObjPtr<MirrorType> MakeObjPtr(ObjPtr<MirrorType> ptr) {
    215   return ObjPtr<MirrorType>(ptr);
    216 }
    217 
    218 template<class MirrorType>
    219 ALWAYS_INLINE std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType> ptr);
    220 
    221 }  // namespace art
    222 
    223 #endif  // ART_RUNTIME_OBJ_PTR_H_
    224