Line data Source code
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_POINTER_WITH_PAYLOAD_H_
6 : #define V8_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 : // PointerWithPayload combines a PointerType* an a small PayloadType into
24 : // one. The bits of the storage type get packed into the lower bits of the
25 : // pointer that are free due to alignment. The user needs to specify how many
26 : // bits are needed to store the PayloadType, allowing Types that by default are
27 : // larger to be stored.
28 : //
29 : // Example:
30 : // PointerWithPayload<int *, bool, 1> data_and_flag;
31 : //
32 : // Here we store a bool that needs 1 bit of storage state into the lower bits
33 : // of int *, which points to some int data;
34 :
35 : template <typename PointerType, typename PayloadType, int NumPayloadBits>
36 : class PointerWithPayload {
37 : // We have log2(ptr alignment) kAvailBits free to use
38 : static constexpr int kAvailBits = PointerWithPayloadTraits<
39 : typename std::remove_const<PointerType>::type>::value;
40 : static_assert(
41 : kAvailBits >= NumPayloadBits,
42 : "Ptr does not have sufficient alignment for the selected amount of "
43 : "storage bits.");
44 :
45 : static constexpr uintptr_t kPayloadMask = (uintptr_t{1} << kAvailBits) - 1;
46 : static constexpr uintptr_t kPointerMask = ~kPayloadMask;
47 :
48 : public:
49 0 : PointerWithPayload() {}
50 :
51 : explicit PointerWithPayload(PointerType* pointer)
52 : : pointer_(reinterpret_cast<uintptr_t>(pointer)) {
53 : DCHECK_EQ(GetPointer(), pointer);
54 : DCHECK_EQ(GetPayload(), static_cast<PayloadType>(0));
55 : }
56 :
57 : explicit PointerWithPayload(PayloadType payload)
58 : : pointer_(static_cast<uintptr_t>(payload)) {
59 : DCHECK_EQ(GetPointer(), nullptr);
60 : DCHECK_EQ(GetPayload(), payload);
61 : }
62 :
63 52266987 : PointerWithPayload(PointerType* pointer, PayloadType payload) {
64 : update(pointer, payload);
65 : }
66 :
67 : V8_INLINE PointerType* GetPointer() const {
68 20376883 : return reinterpret_cast<PointerType*>(pointer_ & kPointerMask);
69 : }
70 :
71 : V8_INLINE PointerType* operator->() const { return GetPointer(); }
72 :
73 : V8_INLINE void update(PointerType* new_pointer, PayloadType new_payload) {
74 52526487 : pointer_ = reinterpret_cast<uintptr_t>(new_pointer) |
75 : static_cast<uintptr_t>(new_payload);
76 : DCHECK_EQ(GetPayload(), new_payload);
77 : DCHECK_EQ(GetPointer(), new_pointer);
78 : }
79 :
80 : V8_INLINE void SetPointer(PointerType* newptr) {
81 : DCHECK_EQ(reinterpret_cast<uintptr_t>(newptr) & kPayloadMask, 0);
82 133537 : pointer_ = reinterpret_cast<uintptr_t>(newptr) | (pointer_ & kPayloadMask);
83 : DCHECK_EQ(GetPointer(), newptr);
84 : }
85 :
86 : V8_INLINE PayloadType GetPayload() const {
87 17982932 : return static_cast<PayloadType>(pointer_ & kPayloadMask);
88 : }
89 :
90 : V8_INLINE void SetPayload(PayloadType new_payload) {
91 0 : uintptr_t new_payload_ptr = static_cast<uintptr_t>(new_payload);
92 : DCHECK_EQ(new_payload_ptr & kPayloadMask, new_payload_ptr);
93 0 : pointer_ = (pointer_ & kPointerMask) | new_payload_ptr;
94 : DCHECK_EQ(GetPayload(), new_payload);
95 : }
96 :
97 : private:
98 : uintptr_t pointer_ = 0;
99 : };
100 :
101 : } // namespace internal
102 : } // namespace v8
103 :
104 : #endif // V8_POINTER_WITH_PAYLOAD_H_
|