• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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