1*7c3d14c8STreehugger Robot //===-- sanitizer_stackdepotbase.h ------------------------------*- C++ -*-===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // Implementation of a mapping from arbitrary values to unique 32-bit
11*7c3d14c8STreehugger Robot // identifiers.
12*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
13*7c3d14c8STreehugger Robot
14*7c3d14c8STreehugger Robot #ifndef SANITIZER_STACKDEPOTBASE_H
15*7c3d14c8STreehugger Robot #define SANITIZER_STACKDEPOTBASE_H
16*7c3d14c8STreehugger Robot
17*7c3d14c8STreehugger Robot #include "sanitizer_internal_defs.h"
18*7c3d14c8STreehugger Robot #include "sanitizer_mutex.h"
19*7c3d14c8STreehugger Robot #include "sanitizer_atomic.h"
20*7c3d14c8STreehugger Robot #include "sanitizer_persistent_allocator.h"
21*7c3d14c8STreehugger Robot
22*7c3d14c8STreehugger Robot namespace __sanitizer {
23*7c3d14c8STreehugger Robot
24*7c3d14c8STreehugger Robot template <class Node, int kReservedBits, int kTabSizeLog>
25*7c3d14c8STreehugger Robot class StackDepotBase {
26*7c3d14c8STreehugger Robot public:
27*7c3d14c8STreehugger Robot typedef typename Node::args_type args_type;
28*7c3d14c8STreehugger Robot typedef typename Node::handle_type handle_type;
29*7c3d14c8STreehugger Robot // Maps stack trace to an unique id.
30*7c3d14c8STreehugger Robot handle_type Put(args_type args, bool *inserted = nullptr);
31*7c3d14c8STreehugger Robot // Retrieves a stored stack trace by the id.
32*7c3d14c8STreehugger Robot args_type Get(u32 id);
33*7c3d14c8STreehugger Robot
GetStats()34*7c3d14c8STreehugger Robot StackDepotStats *GetStats() { return &stats; }
35*7c3d14c8STreehugger Robot
36*7c3d14c8STreehugger Robot void LockAll();
37*7c3d14c8STreehugger Robot void UnlockAll();
38*7c3d14c8STreehugger Robot
39*7c3d14c8STreehugger Robot private:
40*7c3d14c8STreehugger Robot static Node *find(Node *s, args_type args, u32 hash);
41*7c3d14c8STreehugger Robot static Node *lock(atomic_uintptr_t *p);
42*7c3d14c8STreehugger Robot static void unlock(atomic_uintptr_t *p, Node *s);
43*7c3d14c8STreehugger Robot
44*7c3d14c8STreehugger Robot static const int kTabSize = 1 << kTabSizeLog; // Hash table size.
45*7c3d14c8STreehugger Robot static const int kPartBits = 8;
46*7c3d14c8STreehugger Robot static const int kPartShift = sizeof(u32) * 8 - kPartBits - kReservedBits;
47*7c3d14c8STreehugger Robot static const int kPartCount =
48*7c3d14c8STreehugger Robot 1 << kPartBits; // Number of subparts in the table.
49*7c3d14c8STreehugger Robot static const int kPartSize = kTabSize / kPartCount;
50*7c3d14c8STreehugger Robot static const int kMaxId = 1 << kPartShift;
51*7c3d14c8STreehugger Robot
52*7c3d14c8STreehugger Robot atomic_uintptr_t tab[kTabSize]; // Hash table of Node's.
53*7c3d14c8STreehugger Robot atomic_uint32_t seq[kPartCount]; // Unique id generators.
54*7c3d14c8STreehugger Robot
55*7c3d14c8STreehugger Robot StackDepotStats stats;
56*7c3d14c8STreehugger Robot
57*7c3d14c8STreehugger Robot friend class StackDepotReverseMap;
58*7c3d14c8STreehugger Robot };
59*7c3d14c8STreehugger Robot
60*7c3d14c8STreehugger Robot template <class Node, int kReservedBits, int kTabSizeLog>
find(Node * s,args_type args,u32 hash)61*7c3d14c8STreehugger Robot Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::find(Node *s,
62*7c3d14c8STreehugger Robot args_type args,
63*7c3d14c8STreehugger Robot u32 hash) {
64*7c3d14c8STreehugger Robot // Searches linked list s for the stack, returns its id.
65*7c3d14c8STreehugger Robot for (; s; s = s->link) {
66*7c3d14c8STreehugger Robot if (s->eq(hash, args)) {
67*7c3d14c8STreehugger Robot return s;
68*7c3d14c8STreehugger Robot }
69*7c3d14c8STreehugger Robot }
70*7c3d14c8STreehugger Robot return nullptr;
71*7c3d14c8STreehugger Robot }
72*7c3d14c8STreehugger Robot
73*7c3d14c8STreehugger Robot template <class Node, int kReservedBits, int kTabSizeLog>
lock(atomic_uintptr_t * p)74*7c3d14c8STreehugger Robot Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::lock(
75*7c3d14c8STreehugger Robot atomic_uintptr_t *p) {
76*7c3d14c8STreehugger Robot // Uses the pointer lsb as mutex.
77*7c3d14c8STreehugger Robot for (int i = 0;; i++) {
78*7c3d14c8STreehugger Robot uptr cmp = atomic_load(p, memory_order_relaxed);
79*7c3d14c8STreehugger Robot if ((cmp & 1) == 0 &&
80*7c3d14c8STreehugger Robot atomic_compare_exchange_weak(p, &cmp, cmp | 1, memory_order_acquire))
81*7c3d14c8STreehugger Robot return (Node *)cmp;
82*7c3d14c8STreehugger Robot if (i < 10)
83*7c3d14c8STreehugger Robot proc_yield(10);
84*7c3d14c8STreehugger Robot else
85*7c3d14c8STreehugger Robot internal_sched_yield();
86*7c3d14c8STreehugger Robot }
87*7c3d14c8STreehugger Robot }
88*7c3d14c8STreehugger Robot
89*7c3d14c8STreehugger Robot template <class Node, int kReservedBits, int kTabSizeLog>
unlock(atomic_uintptr_t * p,Node * s)90*7c3d14c8STreehugger Robot void StackDepotBase<Node, kReservedBits, kTabSizeLog>::unlock(
91*7c3d14c8STreehugger Robot atomic_uintptr_t *p, Node *s) {
92*7c3d14c8STreehugger Robot DCHECK_EQ((uptr)s & 1, 0);
93*7c3d14c8STreehugger Robot atomic_store(p, (uptr)s, memory_order_release);
94*7c3d14c8STreehugger Robot }
95*7c3d14c8STreehugger Robot
96*7c3d14c8STreehugger Robot template <class Node, int kReservedBits, int kTabSizeLog>
97*7c3d14c8STreehugger Robot typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::handle_type
Put(args_type args,bool * inserted)98*7c3d14c8STreehugger Robot StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args,
99*7c3d14c8STreehugger Robot bool *inserted) {
100*7c3d14c8STreehugger Robot if (inserted) *inserted = false;
101*7c3d14c8STreehugger Robot if (!Node::is_valid(args)) return handle_type();
102*7c3d14c8STreehugger Robot uptr h = Node::hash(args);
103*7c3d14c8STreehugger Robot atomic_uintptr_t *p = &tab[h % kTabSize];
104*7c3d14c8STreehugger Robot uptr v = atomic_load(p, memory_order_consume);
105*7c3d14c8STreehugger Robot Node *s = (Node *)(v & ~1);
106*7c3d14c8STreehugger Robot // First, try to find the existing stack.
107*7c3d14c8STreehugger Robot Node *node = find(s, args, h);
108*7c3d14c8STreehugger Robot if (node) return node->get_handle();
109*7c3d14c8STreehugger Robot // If failed, lock, retry and insert new.
110*7c3d14c8STreehugger Robot Node *s2 = lock(p);
111*7c3d14c8STreehugger Robot if (s2 != s) {
112*7c3d14c8STreehugger Robot node = find(s2, args, h);
113*7c3d14c8STreehugger Robot if (node) {
114*7c3d14c8STreehugger Robot unlock(p, s2);
115*7c3d14c8STreehugger Robot return node->get_handle();
116*7c3d14c8STreehugger Robot }
117*7c3d14c8STreehugger Robot }
118*7c3d14c8STreehugger Robot uptr part = (h % kTabSize) / kPartSize;
119*7c3d14c8STreehugger Robot u32 id = atomic_fetch_add(&seq[part], 1, memory_order_relaxed) + 1;
120*7c3d14c8STreehugger Robot stats.n_uniq_ids++;
121*7c3d14c8STreehugger Robot CHECK_LT(id, kMaxId);
122*7c3d14c8STreehugger Robot id |= part << kPartShift;
123*7c3d14c8STreehugger Robot CHECK_NE(id, 0);
124*7c3d14c8STreehugger Robot CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
125*7c3d14c8STreehugger Robot uptr memsz = Node::storage_size(args);
126*7c3d14c8STreehugger Robot s = (Node *)PersistentAlloc(memsz);
127*7c3d14c8STreehugger Robot stats.allocated += memsz;
128*7c3d14c8STreehugger Robot s->id = id;
129*7c3d14c8STreehugger Robot s->store(args, h);
130*7c3d14c8STreehugger Robot s->link = s2;
131*7c3d14c8STreehugger Robot unlock(p, s);
132*7c3d14c8STreehugger Robot if (inserted) *inserted = true;
133*7c3d14c8STreehugger Robot return s->get_handle();
134*7c3d14c8STreehugger Robot }
135*7c3d14c8STreehugger Robot
136*7c3d14c8STreehugger Robot template <class Node, int kReservedBits, int kTabSizeLog>
137*7c3d14c8STreehugger Robot typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::args_type
Get(u32 id)138*7c3d14c8STreehugger Robot StackDepotBase<Node, kReservedBits, kTabSizeLog>::Get(u32 id) {
139*7c3d14c8STreehugger Robot if (id == 0) {
140*7c3d14c8STreehugger Robot return args_type();
141*7c3d14c8STreehugger Robot }
142*7c3d14c8STreehugger Robot CHECK_EQ(id & (((u32)-1) >> kReservedBits), id);
143*7c3d14c8STreehugger Robot // High kPartBits contain part id, so we need to scan at most kPartSize lists.
144*7c3d14c8STreehugger Robot uptr part = id >> kPartShift;
145*7c3d14c8STreehugger Robot for (int i = 0; i != kPartSize; i++) {
146*7c3d14c8STreehugger Robot uptr idx = part * kPartSize + i;
147*7c3d14c8STreehugger Robot CHECK_LT(idx, kTabSize);
148*7c3d14c8STreehugger Robot atomic_uintptr_t *p = &tab[idx];
149*7c3d14c8STreehugger Robot uptr v = atomic_load(p, memory_order_consume);
150*7c3d14c8STreehugger Robot Node *s = (Node *)(v & ~1);
151*7c3d14c8STreehugger Robot for (; s; s = s->link) {
152*7c3d14c8STreehugger Robot if (s->id == id) {
153*7c3d14c8STreehugger Robot return s->load();
154*7c3d14c8STreehugger Robot }
155*7c3d14c8STreehugger Robot }
156*7c3d14c8STreehugger Robot }
157*7c3d14c8STreehugger Robot return args_type();
158*7c3d14c8STreehugger Robot }
159*7c3d14c8STreehugger Robot
160*7c3d14c8STreehugger Robot template <class Node, int kReservedBits, int kTabSizeLog>
LockAll()161*7c3d14c8STreehugger Robot void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() {
162*7c3d14c8STreehugger Robot for (int i = 0; i < kTabSize; ++i) {
163*7c3d14c8STreehugger Robot lock(&tab[i]);
164*7c3d14c8STreehugger Robot }
165*7c3d14c8STreehugger Robot }
166*7c3d14c8STreehugger Robot
167*7c3d14c8STreehugger Robot template <class Node, int kReservedBits, int kTabSizeLog>
UnlockAll()168*7c3d14c8STreehugger Robot void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() {
169*7c3d14c8STreehugger Robot for (int i = 0; i < kTabSize; ++i) {
170*7c3d14c8STreehugger Robot atomic_uintptr_t *p = &tab[i];
171*7c3d14c8STreehugger Robot uptr s = atomic_load(p, memory_order_relaxed);
172*7c3d14c8STreehugger Robot unlock(p, (Node *)(s & ~1UL));
173*7c3d14c8STreehugger Robot }
174*7c3d14c8STreehugger Robot }
175*7c3d14c8STreehugger Robot
176*7c3d14c8STreehugger Robot } // namespace __sanitizer
177*7c3d14c8STreehugger Robot
178*7c3d14c8STreehugger Robot #endif // SANITIZER_STACKDEPOTBASE_H
179