proxygen
folly::StampedPtr< T > Struct Template Reference

#include <StampedPtr.h>

Public Member Functions

Tptr () const
 
uint16_t stamp () const
 
void set (T *ptr, uint16_t stamp)
 
void setPtr (T *ptr)
 
void setStamp (uint16_t stamp)
 

Static Public Member Functions

static TunpackPtr (uint64_t raw)
 
static uint16_t unpackStamp (uint64_t raw)
 
static uint64_t pack (T *ptr, uint16_t stamp)
 

Public Attributes

uint64_t raw
 

Static Private Attributes

static constexpr unsigned kInternalStampBits = sizeof(void*) == 4 ? 32 : 16
 

Detailed Description

template<typename T>
struct folly::StampedPtr< T >

StampedPtr packs both a pointer to T and a uint16_t into a 64-bit value, exploiting the fact that current addresses are limited to 48 bits on all current x86-64 and ARM64 processors.

For both x86-64 and ARM64, 64-bit pointers have a canonical form in which the upper 16 bits are equal to bit 47. Intel has announced a 57-bit addressing mode (see https://software.intel.com/ sites/default/files/managed/2b/80/5-level_paging_white_paper.pdf), but it is not yet available. The first problematic platform will probably be ARMv8.2, which supports 52-bit virtual addresses.

This code works on all of the platforms I have available for test, and probably on all currently-shipping platforms that have a hope of compiling folly. Rather than enumerating the supported platforms via ifdef, this code dynamically validates its packing assumption in debug builds on each call to a mutating function. Presumably by the time we are running this process in an operating system image that can address more than 256TB of memory, RAM cost and the latency of 128-bit CAS will have improved enough that this optimization is no longer impactful.

A common approach to this kind of packing seems to be to just assume the top 16 bits are zero, but https://github.com/LuaJIT/LuaJIT/issues/49 indicates that ARM64 platforms in the wild are actually setting bit 47 in their stack addresses. That means that we need to extend bit 47 to do the right thing (it's not expensive, it compiles to one instruction on x86-64 and arm64).

Compare to PackedSyncPtr and DiscriminatedPtr, which perform similar packing but add additional functionality. The name is taken from Java's AtomicStampedReference. Unlike PackedSyncPtr, which tries to act pointer-like, this class acts more like a pair whose elements are named ptr and stamp. It also allows direct access to the internal raw field: since we're already at the metal you might want to play additional games. It is guaranteed that a zero raw value gets decoded as a (ptr,stamp) of (nullptr,0).

Definition at line 63 of file StampedPtr.h.

Member Function Documentation

template<typename T>
static uint64_t folly::StampedPtr< T >::pack ( T ptr,
uint16_t  stamp 
)
inlinestatic

Definition at line 106 of file StampedPtr.h.

References FOLLY_SAFE_DCHECK, folly::StampedPtr< T >::kInternalStampBits, folly::StampedPtr< T >::ptr(), folly::StampedPtr< T >::raw, folly::StampedPtr< T >::stamp(), uint64_t, folly::StampedPtr< T >::unpackPtr(), and folly::StampedPtr< T >::unpackStamp().

Referenced by folly::makeStampedPtr(), folly::StampedPtr< T >::set(), folly::StampedPtr< T >::setPtr(), and folly::StampedPtr< T >::setStamp().

106  {
107  auto shifted = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr))
109  uint64_t raw = shifted | stamp;
110  FOLLY_SAFE_DCHECK(unpackPtr(raw) == ptr, "ptr mismatch.");
111  FOLLY_SAFE_DCHECK(unpackStamp(raw) == stamp, "stamp mismatch.");
112  return raw;
113  }
static uint16_t unpackStamp(uint64_t raw)
Definition: StampedPtr.h:102
static constexpr unsigned kInternalStampBits
Definition: StampedPtr.h:120
uint16_t stamp() const
Definition: StampedPtr.h:76
T * ptr() const
Definition: StampedPtr.h:72
static T * unpackPtr(uint64_t raw)
Definition: StampedPtr.h:92
#define FOLLY_SAFE_DCHECK(expr, msg)
Definition: SafeAssert.h:42
template<typename T>
T* folly::StampedPtr< T >::ptr ( ) const
inline

Definition at line 72 of file StampedPtr.h.

References folly::StampedPtr< T >::unpackPtr().

Referenced by folly::StampedPtr< T >::pack(), and TEST().

72  {
73  return unpackPtr(raw);
74  }
static T * unpackPtr(uint64_t raw)
Definition: StampedPtr.h:92
template<typename T>
void folly::StampedPtr< T >::set ( T ptr,
uint16_t  stamp 
)
inline

Definition at line 80 of file StampedPtr.h.

References folly::StampedPtr< T >::pack(), and folly::StampedPtr< T >::stamp().

Referenced by TEST().

80  {
81  raw = pack(ptr, stamp);
82  }
uint16_t stamp() const
Definition: StampedPtr.h:76
T * ptr() const
Definition: StampedPtr.h:72
static uint64_t pack(T *ptr, uint16_t stamp)
Definition: StampedPtr.h:106
template<typename T>
void folly::StampedPtr< T >::setPtr ( T ptr)
inline

Definition at line 84 of file StampedPtr.h.

References folly::StampedPtr< T >::pack(), and folly::StampedPtr< T >::unpackStamp().

Referenced by TEST().

84  {
85  raw = pack(ptr, unpackStamp(raw));
86  }
static uint16_t unpackStamp(uint64_t raw)
Definition: StampedPtr.h:102
T * ptr() const
Definition: StampedPtr.h:72
static uint64_t pack(T *ptr, uint16_t stamp)
Definition: StampedPtr.h:106
template<typename T>
void folly::StampedPtr< T >::setStamp ( uint16_t  stamp)
inline

Definition at line 88 of file StampedPtr.h.

References folly::StampedPtr< T >::pack(), and folly::StampedPtr< T >::unpackPtr().

Referenced by TEST().

88  {
89  raw = pack(unpackPtr(raw), stamp);
90  }
uint16_t stamp() const
Definition: StampedPtr.h:76
static T * unpackPtr(uint64_t raw)
Definition: StampedPtr.h:92
static uint64_t pack(T *ptr, uint16_t stamp)
Definition: StampedPtr.h:106
template<typename T>
uint16_t folly::StampedPtr< T >::stamp ( ) const
inline

Definition at line 76 of file StampedPtr.h.

References folly::StampedPtr< T >::unpackStamp().

Referenced by folly::StampedPtr< T >::pack(), folly::StampedPtr< T >::set(), and TEST().

76  {
77  return unpackStamp(raw);
78  }
static uint16_t unpackStamp(uint64_t raw)
Definition: StampedPtr.h:102
template<typename T>
static T* folly::StampedPtr< T >::unpackPtr ( uint64_t  raw)
inlinestatic

Definition at line 92 of file StampedPtr.h.

References int64_t, folly::StampedPtr< T >::kInternalStampBits, folly::StampedPtr< T >::raw, and folly::T.

Referenced by folly::StampedPtr< T >::pack(), folly::StampedPtr< T >::ptr(), and folly::StampedPtr< T >::setStamp().

92  {
93  // Canonical form means we need to extend bit 47 of the pointer to
94  // bits 48..63 (unless the operating system never hands those pointers
95  // to us, which is difficult to prove). Signed right-shift of a
96  // negative number is implementation-defined in C++ (not undefined!),
97  // but actually does the right thing on all the platforms I can find.
98  auto extended = static_cast<int64_t>(raw) >> kInternalStampBits;
99  return reinterpret_cast<T*>(static_cast<intptr_t>(extended));
100  }
static constexpr unsigned kInternalStampBits
Definition: StampedPtr.h:120
folly::std T
template<typename T>
static uint16_t folly::StampedPtr< T >::unpackStamp ( uint64_t  raw)
inlinestatic

Definition at line 102 of file StampedPtr.h.

References folly::StampedPtr< T >::raw, and uint16_t.

Referenced by folly::StampedPtr< T >::pack(), folly::StampedPtr< T >::setPtr(), and folly::StampedPtr< T >::stamp().

102  {
103  return static_cast<uint16_t>(raw);
104  }

Member Data Documentation

template<typename T>
constexpr unsigned folly::StampedPtr< T >::kInternalStampBits = sizeof(void*) == 4 ? 32 : 16
staticprivate
template<typename T>
uint64_t folly::StampedPtr< T >::raw

The packing is not guaranteed, except that it is guaranteed that raw == 0 iff ptr() == nullptr && stamp() == 0.

Definition at line 68 of file StampedPtr.h.

Referenced by folly::StampedPtr< T >::pack(), TEST(), folly::StampedPtr< T >::unpackPtr(), and folly::StampedPtr< T >::unpackStamp().


The documentation for this struct was generated from the following file: