]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/compiler-rt/lib/scudo/standalone/bytemap.h
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / compiler-rt / lib / scudo / standalone / bytemap.h
1 //===-- bytemap.h -----------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef SCUDO_BYTEMAP_H_
10 #define SCUDO_BYTEMAP_H_
11
12 #include "atomic_helpers.h"
13 #include "common.h"
14 #include "mutex.h"
15
16 namespace scudo {
17
18 template <uptr Size> class FlatByteMap {
19 public:
20   void initLinkerInitialized() {
21     Map = reinterpret_cast<u8 *>(map(nullptr, Size, "scudo:bytemap"));
22   }
23   void init() { initLinkerInitialized(); }
24
25   void unmapTestOnly() { unmap(reinterpret_cast<void *>(Map), Size); }
26
27   void set(uptr Index, u8 Value) {
28     DCHECK_LT(Index, Size);
29     DCHECK_EQ(0U, Map[Index]);
30     Map[Index] = Value;
31   }
32   u8 operator[](uptr Index) {
33     DCHECK_LT(Index, Size);
34     return Map[Index];
35   }
36
37 private:
38   u8 *Map;
39 };
40
41 template <uptr Level1Size, uptr Level2Size> class TwoLevelByteMap {
42 public:
43   void initLinkerInitialized() {
44     Level1Map = reinterpret_cast<atomic_uptr *>(
45         map(nullptr, sizeof(atomic_uptr) * Level1Size, "scudo:bytemap"));
46   }
47   void init() {
48     Mutex.init();
49     initLinkerInitialized();
50   }
51
52   void reset() {
53     for (uptr I = 0; I < Level1Size; I++) {
54       u8 *P = get(I);
55       if (!P)
56         continue;
57       unmap(P, Level2Size);
58     }
59     memset(Level1Map, 0, sizeof(atomic_uptr) * Level1Size);
60   }
61
62   void unmapTestOnly() {
63     reset();
64     unmap(reinterpret_cast<void *>(Level1Map),
65           sizeof(atomic_uptr) * Level1Size);
66   }
67
68   uptr size() const { return Level1Size * Level2Size; }
69
70   void set(uptr Index, u8 Value) {
71     DCHECK_LT(Index, Level1Size * Level2Size);
72     u8 *Level2Map = getOrCreate(Index / Level2Size);
73     DCHECK_EQ(0U, Level2Map[Index % Level2Size]);
74     Level2Map[Index % Level2Size] = Value;
75   }
76
77   u8 operator[](uptr Index) const {
78     DCHECK_LT(Index, Level1Size * Level2Size);
79     u8 *Level2Map = get(Index / Level2Size);
80     if (!Level2Map)
81       return 0;
82     return Level2Map[Index % Level2Size];
83   }
84
85 private:
86   u8 *get(uptr Index) const {
87     DCHECK_LT(Index, Level1Size);
88     return reinterpret_cast<u8 *>(
89         atomic_load(&Level1Map[Index], memory_order_acquire));
90   }
91
92   u8 *getOrCreate(uptr Index) {
93     u8 *Res = get(Index);
94     if (!Res) {
95       ScopedLock L(Mutex);
96       if (!(Res = get(Index))) {
97         Res = reinterpret_cast<u8 *>(map(nullptr, Level2Size, "scudo:bytemap"));
98         atomic_store(&Level1Map[Index], reinterpret_cast<uptr>(Res),
99                      memory_order_release);
100       }
101     }
102     return Res;
103   }
104
105   atomic_uptr *Level1Map;
106   HybridMutex Mutex;
107 };
108
109 } // namespace scudo
110
111 #endif // SCUDO_BYTEMAP_H_