diff options
Diffstat (limited to 'deps/v8/src/utils/pointer-with-payload.h')
-rw-r--r-- | deps/v8/src/utils/pointer-with-payload.h | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/deps/v8/src/utils/pointer-with-payload.h b/deps/v8/src/utils/pointer-with-payload.h new file mode 100644 index 0000000000..1c140ff684 --- /dev/null +++ b/deps/v8/src/utils/pointer-with-payload.h @@ -0,0 +1,104 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_UTILS_POINTER_WITH_PAYLOAD_H_ +#define V8_UTILS_POINTER_WITH_PAYLOAD_H_ + +#include <cstdint> +#include <type_traits> + +#include "include/v8config.h" +#include "src/base/logging.h" + +namespace v8 { +namespace internal { + +template <typename PointerType> +struct PointerWithPayloadTraits { + static constexpr int value = + alignof(PointerType) >= 8 ? 3 : alignof(PointerType) >= 4 ? 2 : 1; +}; + +// PointerWithPayload combines a PointerType* an a small PayloadType into +// one. The bits of the storage type get packed into the lower bits of the +// pointer that are free due to alignment. The user needs to specify how many +// bits are needed to store the PayloadType, allowing Types that by default are +// larger to be stored. +// +// Example: +// PointerWithPayload<int *, bool, 1> data_and_flag; +// +// Here we store a bool that needs 1 bit of storage state into the lower bits +// of int *, which points to some int data; + +template <typename PointerType, typename PayloadType, int NumPayloadBits> +class PointerWithPayload { + // We have log2(ptr alignment) kAvailBits free to use + static constexpr int kAvailBits = PointerWithPayloadTraits< + typename std::remove_const<PointerType>::type>::value; + static_assert( + kAvailBits >= NumPayloadBits, + "Ptr does not have sufficient alignment for the selected amount of " + "storage bits."); + + static constexpr uintptr_t kPayloadMask = (uintptr_t{1} << kAvailBits) - 1; + static constexpr uintptr_t kPointerMask = ~kPayloadMask; + + public: + PointerWithPayload() {} + + explicit PointerWithPayload(PointerType* pointer) + : pointer_(reinterpret_cast<uintptr_t>(pointer)) { + DCHECK_EQ(GetPointer(), pointer); + DCHECK_EQ(GetPayload(), static_cast<PayloadType>(0)); + } + + explicit PointerWithPayload(PayloadType payload) + : pointer_(static_cast<uintptr_t>(payload)) { + DCHECK_EQ(GetPointer(), nullptr); + DCHECK_EQ(GetPayload(), payload); + } + + PointerWithPayload(PointerType* pointer, PayloadType payload) { + update(pointer, payload); + } + + V8_INLINE PointerType* GetPointer() const { + return reinterpret_cast<PointerType*>(pointer_ & kPointerMask); + } + + V8_INLINE PointerType* operator->() const { return GetPointer(); } + + V8_INLINE void update(PointerType* new_pointer, PayloadType new_payload) { + pointer_ = reinterpret_cast<uintptr_t>(new_pointer) | + static_cast<uintptr_t>(new_payload); + DCHECK_EQ(GetPayload(), new_payload); + DCHECK_EQ(GetPointer(), new_pointer); + } + + V8_INLINE void SetPointer(PointerType* newptr) { + DCHECK_EQ(reinterpret_cast<uintptr_t>(newptr) & kPayloadMask, 0); + pointer_ = reinterpret_cast<uintptr_t>(newptr) | (pointer_ & kPayloadMask); + DCHECK_EQ(GetPointer(), newptr); + } + + V8_INLINE PayloadType GetPayload() const { + return static_cast<PayloadType>(pointer_ & kPayloadMask); + } + + V8_INLINE void SetPayload(PayloadType new_payload) { + uintptr_t new_payload_ptr = static_cast<uintptr_t>(new_payload); + DCHECK_EQ(new_payload_ptr & kPayloadMask, new_payload_ptr); + pointer_ = (pointer_ & kPointerMask) | new_payload_ptr; + DCHECK_EQ(GetPayload(), new_payload); + } + + private: + uintptr_t pointer_ = 0; +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_UTILS_POINTER_WITH_PAYLOAD_H_ |