function.c (assign_parm_adjust_stack_rtl): Revise STRICT_ALIGNMENT check to use targe...
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_ring_buffer.h
blob39ee6315a708abd471cf2de8c5dd8678ec458225
1 //===-- sanitizer_ring_buffer.h ---------------------------------*- C++ -*-===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // Simple ring buffer.
9 //
10 //===----------------------------------------------------------------------===//
11 #ifndef SANITIZER_RING_BUFFER_H
12 #define SANITIZER_RING_BUFFER_H
14 #include "sanitizer_common.h"
16 namespace __sanitizer {
17 // RingBuffer<T>: fixed-size ring buffer optimized for speed of push().
18 // T should be a POD type and sizeof(T) should be divisible by sizeof(void*).
19 // At creation, all elements are zero.
20 template<class T>
21 class RingBuffer {
22 public:
23 COMPILER_CHECK(sizeof(T) % sizeof(void *) == 0);
24 static RingBuffer *New(uptr Size) {
25 void *Ptr = MmapOrDie(SizeInBytes(Size), "RingBuffer");
26 RingBuffer *RB = reinterpret_cast<RingBuffer*>(Ptr);
27 uptr End = reinterpret_cast<uptr>(Ptr) + SizeInBytes(Size);
28 RB->last_ = RB->next_ = reinterpret_cast<T*>(End - sizeof(T));
29 return RB;
31 void Delete() {
32 UnmapOrDie(this, SizeInBytes(size()));
34 uptr size() const {
35 return last_ + 1 -
36 reinterpret_cast<T *>(reinterpret_cast<uptr>(this) +
37 2 * sizeof(T *));
40 static uptr SizeInBytes(uptr Size) {
41 return Size * sizeof(T) + 2 * sizeof(T*);
44 uptr SizeInBytes() { return SizeInBytes(size()); }
46 void push(T t) {
47 *next_ = t;
48 next_--;
49 // The condition below works only if sizeof(T) is divisible by sizeof(T*).
50 if (next_ <= reinterpret_cast<T*>(&next_))
51 next_ = last_;
54 T operator[](uptr Idx) const {
55 CHECK_LT(Idx, size());
56 sptr IdxNext = Idx + 1;
57 if (IdxNext > last_ - next_)
58 IdxNext -= size();
59 return next_[IdxNext];
62 private:
63 RingBuffer() {}
64 ~RingBuffer() {}
65 RingBuffer(const RingBuffer&) = delete;
67 // Data layout:
68 // LNDDDDDDDD
69 // D: data elements.
70 // L: last_, always points to the last data element.
71 // N: next_, initially equals to last_, is decremented on every push,
72 // wraps around if it's less or equal than its own address.
73 T *last_;
74 T *next_;
75 T data_[1]; // flexible array.
78 // A ring buffer with externally provided storage that encodes its state in 8
79 // bytes. Has significant constraints on size and alignment of storage.
80 // See a comment in hwasan/hwasan_thread_list.h for the motivation behind this.
81 #if SANITIZER_WORDSIZE == 64
82 template <class T>
83 class CompactRingBuffer {
84 // Top byte of long_ stores the buffer size in pages.
85 // Lower bytes store the address of the next buffer element.
86 static constexpr int kPageSizeBits = 12;
87 static constexpr int kSizeShift = 56;
88 static constexpr uptr kNextMask = (1ULL << kSizeShift) - 1;
90 uptr GetStorageSize() const { return (long_ >> kSizeShift) << kPageSizeBits; }
92 void Init(void *storage, uptr size) {
93 CHECK_EQ(sizeof(CompactRingBuffer<T>), sizeof(void *));
94 CHECK(IsPowerOfTwo(size));
95 CHECK_GE(size, 1 << kPageSizeBits);
96 CHECK_LE(size, 128 << kPageSizeBits);
97 CHECK_EQ(size % 4096, 0);
98 CHECK_EQ(size % sizeof(T), 0);
99 CHECK_EQ((uptr)storage % (size * 2), 0);
100 long_ = (uptr)storage | ((size >> kPageSizeBits) << kSizeShift);
103 void SetNext(const T *next) {
104 long_ = (long_ & ~kNextMask) | (uptr)next;
107 public:
108 CompactRingBuffer(void *storage, uptr size) {
109 Init(storage, size);
112 // A copy constructor of sorts.
113 CompactRingBuffer(const CompactRingBuffer &other, void *storage) {
114 uptr size = other.GetStorageSize();
115 internal_memcpy(storage, other.StartOfStorage(), size);
116 Init(storage, size);
117 uptr Idx = other.Next() - (const T *)other.StartOfStorage();
118 SetNext((const T *)storage + Idx);
121 T *Next() const { return (T *)(long_ & kNextMask); }
123 void *StartOfStorage() const {
124 return (void *)((uptr)Next() & ~(GetStorageSize() - 1));
127 void *EndOfStorage() const {
128 return (void *)((uptr)StartOfStorage() + GetStorageSize());
131 uptr size() const { return GetStorageSize() / sizeof(T); }
133 void push(T t) {
134 T *next = Next();
135 *next = t;
136 next++;
137 next = (T *)((uptr)next & ~GetStorageSize());
138 SetNext(next);
141 T operator[](uptr Idx) const {
142 CHECK_LT(Idx, size());
143 const T *Begin = (const T *)StartOfStorage();
144 sptr StorageIdx = Next() - Begin;
145 StorageIdx -= (sptr)(Idx + 1);
146 if (StorageIdx < 0)
147 StorageIdx += size();
148 return Begin[StorageIdx];
151 public:
152 ~CompactRingBuffer() {}
153 CompactRingBuffer(const CompactRingBuffer &) = delete;
155 uptr long_;
157 #endif
158 } // namespace __sanitizer
160 #endif // SANITIZER_RING_BUFFER_H