1 //===-- sanitizer_allocator_bytemap.h ---------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Part of the Sanitizer Allocator.
12 //===----------------------------------------------------------------------===//
13 #ifndef SANITIZER_ALLOCATOR_H
14 #error This file must be included inside sanitizer_allocator.h
17 // Maps integers in rage [0, kSize) to u8 values.
18 template <u64 kSize, typename AddressSpaceViewTy = LocalAddressSpaceView>
21 using AddressSpaceView = AddressSpaceViewTy;
23 internal_memset(map_, 0, sizeof(map_));
26 void set(uptr idx, u8 val) {
28 CHECK_EQ(0U, map_[idx]);
31 u8 operator[] (uptr idx) {
33 // FIXME: CHECK may be too expensive here.
40 // TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values.
41 // It is implemented as a two-dimensional array: array of kSize1 pointers
42 // to kSize2-byte arrays. The secondary arrays are mmaped on demand.
43 // Each value is initially zero and can be set to something else only once.
44 // Setting and getting values from multiple threads is safe w/o extra locking.
45 template <u64 kSize1, u64 kSize2,
46 typename AddressSpaceViewTy = LocalAddressSpaceView,
47 class MapUnmapCallback = NoOpMapUnmapCallback>
48 class TwoLevelByteMap {
50 using AddressSpaceView = AddressSpaceViewTy;
52 internal_memset(map1_, 0, sizeof(map1_));
56 void TestOnlyUnmap() {
57 for (uptr i = 0; i < kSize1; i++) {
60 MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2);
61 UnmapOrDie(p, kSize2);
65 uptr size() const { return kSize1 * kSize2; }
66 uptr size1() const { return kSize1; }
67 uptr size2() const { return kSize2; }
69 void set(uptr idx, u8 val) {
70 CHECK_LT(idx, kSize1 * kSize2);
71 u8 *map2 = GetOrCreate(idx / kSize2);
72 CHECK_EQ(0U, map2[idx % kSize2]);
73 map2[idx % kSize2] = val;
76 u8 operator[] (uptr idx) const {
77 CHECK_LT(idx, kSize1 * kSize2);
78 u8 *map2 = Get(idx / kSize2);
80 auto value_ptr = AddressSpaceView::Load(&map2[idx % kSize2]);
85 u8 *Get(uptr idx) const {
86 CHECK_LT(idx, kSize1);
87 return reinterpret_cast<u8 *>(
88 atomic_load(&map1_[idx], memory_order_acquire));
91 u8 *GetOrCreate(uptr idx) {
94 SpinMutexLock l(&mu_);
95 if (!(res = Get(idx))) {
96 res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap");
97 MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2);
98 atomic_store(&map1_[idx], reinterpret_cast<uptr>(res),
99 memory_order_release);
105 atomic_uintptr_t map1_[kSize1];