1 // Copyright 2018 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_UTILS_POINTER_WITH_PAYLOAD_H_ 6 #define V8_UTILS_POINTER_WITH_PAYLOAD_H_ 7 8 #include <cstdint> 9 #include <type_traits> 10 11 #include "include/v8config.h" 12 #include "src/base/logging.h" 13 14 namespace v8 { 15 namespace internal { 16 17 template <typename PointerType> 18 struct PointerWithPayloadTraits { 19 static constexpr int value = 20 alignof(PointerType) >= 8 ? 3 : alignof(PointerType) >= 4 ? 2 : 1; 21 }; 22 23 // Assume void* has the same payloads as void**, under the assumption that it's 24 // used for classes that contain at least one pointer. 25 template <> 26 struct PointerWithPayloadTraits<void> : public PointerWithPayloadTraits<void*> { 27 }; 28 29 // PointerWithPayload combines a PointerType* an a small PayloadType into 30 // one. The bits of the storage type get packed into the lower bits of the 31 // pointer that are free due to alignment. The user needs to specify how many 32 // bits are needed to store the PayloadType, allowing Types that by default are 33 // larger to be stored. 34 // 35 // Example: 36 // PointerWithPayload<int *, bool, 1> data_and_flag; 37 // 38 // Here we store a bool that needs 1 bit of storage state into the lower bits 39 // of int *, which points to some int data; 40 41 template <typename PointerType, typename PayloadType, int NumPayloadBits> 42 class PointerWithPayload { 43 // We have log2(ptr alignment) kAvailBits free to use 44 static constexpr int kAvailBits = PointerWithPayloadTraits< 45 typename std::remove_const<PointerType>::type>::value; 46 static_assert( 47 kAvailBits >= NumPayloadBits, 48 "Ptr does not have sufficient alignment for the selected amount of " 49 "storage bits."); 50 51 static constexpr uintptr_t kPayloadMask = 52 (uintptr_t{1} << NumPayloadBits) - 1; 53 static constexpr uintptr_t kPointerMask = ~kPayloadMask; 54 55 public: 56 PointerWithPayload() = default; 57 58 explicit PointerWithPayload(PointerType* pointer) 59 : pointer_(reinterpret_cast<uintptr_t>(pointer)) { 60 DCHECK_EQ(GetPointer(), pointer); 61 DCHECK_EQ(GetPayload(), static_cast<PayloadType>(0)); 62 } 63 64 explicit PointerWithPayload(PayloadType payload) 65 : pointer_(static_cast<uintptr_t>(payload)) { 66 DCHECK_EQ(GetPointer(), nullptr); 67 DCHECK_EQ(GetPayload(), payload); 68 } 69 70 PointerWithPayload(PointerType* pointer, PayloadType payload) { 71 update(pointer, payload); 72 } 73 74 V8_INLINE PointerType* GetPointer() const { 75 return reinterpret_cast<PointerType*>(pointer_ & kPointerMask); 76 } 77 78 // An optimized version of GetPointer for when we know the payload value. 79 V8_INLINE PointerType* GetPointerWithKnownPayload(PayloadType payload) const { 80 DCHECK_EQ(GetPayload(), payload); 81 return reinterpret_cast<PointerType*>(pointer_ - 82 static_cast<uintptr_t>(payload)); 83 } 84 85 V8_INLINE PointerType* operator->() const { return GetPointer(); } 86 87 V8_INLINE void update(PointerType* new_pointer, PayloadType new_payload) { 88 pointer_ = reinterpret_cast<uintptr_t>(new_pointer) | 89 static_cast<uintptr_t>(new_payload); 90 DCHECK_EQ(GetPayload(), new_payload); 91 DCHECK_EQ(GetPointer(), new_pointer); 92 } 93 94 V8_INLINE void SetPointer(PointerType* newptr) { 95 DCHECK_EQ(reinterpret_cast<uintptr_t>(newptr) & kPayloadMask, 0); 96 pointer_ = reinterpret_cast<uintptr_t>(newptr) | (pointer_ & kPayloadMask); 97 DCHECK_EQ(GetPointer(), newptr); 98 } 99 100 V8_INLINE PayloadType GetPayload() const { 101 return static_cast<PayloadType>(pointer_ & kPayloadMask); 102 } 103 104 V8_INLINE void SetPayload(PayloadType new_payload) { 105 uintptr_t new_payload_ptr = static_cast<uintptr_t>(new_payload); 106 DCHECK_EQ(new_payload_ptr & kPayloadMask, new_payload_ptr); 107 pointer_ = (pointer_ & kPointerMask) | new_payload_ptr; 108 DCHECK_EQ(GetPayload(), new_payload); 109 } 110 111 private: 112 uintptr_t pointer_ = 0; 113 }; 114 115 } // namespace internal 116 } // namespace v8 117 118 #endif // V8_UTILS_POINTER_WITH_PAYLOAD_H_ 119