TestAtomicBitfields.cpp (8280B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/Assertions.h" 8 #include "mozilla/AtomicBitfields.h" 9 10 // This is a big macro mess, so let's summarize what's in here right up front: 11 // 12 // |TestDocumentationExample| is intended to be a copy-paste of the example 13 // in the macro's documentation, to make sure it's correct. 14 // 15 // 16 // |TestJammedWithFlags| tests using every bit of the type for bool flags. 17 // 64-bit isn't tested due to macro limitations. 18 // 19 // 20 // |TestLopsided| tests an instance with the following configuration: 21 // 22 // * a 1-bit boolean 23 // * an (N-1)-bit uintN_t 24 // 25 // It tests both orderings of these fields. 26 // 27 // Hopefully these are enough to cover all the nasty boundary conditions 28 // (that still compile). 29 30 // ==================== TestDocumentationExample ======================== 31 32 struct MyType { 33 MOZ_ATOMIC_BITFIELDS(mAtomicFields, 8, 34 ((bool, IsDownloaded, 1), (uint32_t, SomeData, 2), 35 (uint8_t, OtherData, 5))) 36 37 int32_t aNormalInteger; 38 39 explicit MyType(uint32_t aSomeData) : aNormalInteger(7) { 40 StoreSomeData(aSomeData); 41 // Other bitfields were already default initialized to 0/false 42 } 43 }; 44 45 void TestDocumentationExample() { 46 MyType val(3); 47 48 if (!val.LoadIsDownloaded()) { 49 val.StoreOtherData(2); 50 val.StoreIsDownloaded(true); 51 } 52 } 53 54 // ====================== TestJammedWithFlags ========================= 55 56 #define TIMES_8(aFunc, aSeparator, aArgs) \ 57 MOZ_FOR_EACH_SEPARATED(aFunc, aSeparator, aArgs, (1, 2, 3, 4, 5, 6, 7, 8)) 58 #define TIMES_16(aFunc, aSeparator, aArgs) \ 59 MOZ_FOR_EACH_SEPARATED( \ 60 aFunc, aSeparator, aArgs, \ 61 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) 62 #define TIMES_32(aFunc, aSeparator, aArgs) \ 63 MOZ_FOR_EACH_SEPARATED( \ 64 aFunc, aSeparator, aArgs, \ 65 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, \ 66 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)) 67 68 #define CHECK_BOOL(aIndex) \ 69 MOZ_RELEASE_ASSERT(val.LoadFlag##aIndex() == false); \ 70 val.StoreFlag##aIndex(true); \ 71 MOZ_RELEASE_ASSERT(val.LoadFlag##aIndex() == true); \ 72 val.StoreFlag##aIndex(false); \ 73 MOZ_RELEASE_ASSERT(val.LoadFlag##aIndex() == false); 74 75 #define GENERATE_TEST_JAMMED_WITH_FLAGS(aSize) \ 76 void TestJammedWithFlags##aSize() { \ 77 JammedWithFlags##aSize val; \ 78 TIMES_##aSize(CHECK_BOOL, (;), ()); \ 79 } 80 81 #define TEST_JAMMED_WITH_FLAGS(aSize) TestJammedWithFlags##aSize(); 82 83 // ========================= TestLopsided =========================== 84 85 #define GENERATE_TEST_LOPSIDED_FUNC(aSide, aSize) \ 86 void TestLopsided##aSide##aSize() { \ 87 Lopsided##aSide##aSize val; \ 88 MOZ_RELEASE_ASSERT(val.LoadHappyLittleBit() == false); \ 89 MOZ_RELEASE_ASSERT(val.LoadLargeAndInCharge() == 0); \ 90 val.StoreHappyLittleBit(true); \ 91 MOZ_RELEASE_ASSERT(val.LoadHappyLittleBit() == true); \ 92 MOZ_RELEASE_ASSERT(val.LoadLargeAndInCharge() == 0); \ 93 val.StoreLargeAndInCharge(1); \ 94 MOZ_RELEASE_ASSERT(val.LoadHappyLittleBit() == true); \ 95 MOZ_RELEASE_ASSERT(val.LoadLargeAndInCharge() == 1); \ 96 val.StoreLargeAndInCharge(0); \ 97 MOZ_RELEASE_ASSERT(val.LoadHappyLittleBit() == true); \ 98 MOZ_RELEASE_ASSERT(val.LoadLargeAndInCharge() == 0); \ 99 uint##aSize##_t size = aSize; \ 100 uint##aSize##_t int_max = (~(1ull << (size - 1))) - 1; \ 101 val.StoreLargeAndInCharge(int_max); \ 102 MOZ_RELEASE_ASSERT(val.LoadHappyLittleBit() == true); \ 103 MOZ_RELEASE_ASSERT(val.LoadLargeAndInCharge() == int_max); \ 104 val.StoreHappyLittleBit(false); \ 105 MOZ_RELEASE_ASSERT(val.LoadHappyLittleBit() == false); \ 106 MOZ_RELEASE_ASSERT(val.LoadLargeAndInCharge() == int_max); \ 107 val.StoreLargeAndInCharge(int_max); \ 108 MOZ_RELEASE_ASSERT(val.LoadHappyLittleBit() == false); \ 109 MOZ_RELEASE_ASSERT(val.LoadLargeAndInCharge() == int_max); \ 110 } 111 112 #define GENERATE_TEST_LOPSIDED(aSize) \ 113 struct LopsidedA##aSize { \ 114 MOZ_ATOMIC_BITFIELDS(mAtomicFields, aSize, \ 115 ((bool, HappyLittleBit, 1), \ 116 (uint##aSize##_t, LargeAndInCharge, ((aSize) - 1)))) \ 117 }; \ 118 struct LopsidedB##aSize { \ 119 MOZ_ATOMIC_BITFIELDS(mAtomicFields, aSize, \ 120 ((uint##aSize##_t, LargeAndInCharge, ((aSize) - 1)), \ 121 (bool, HappyLittleBit, 1))) \ 122 }; \ 123 GENERATE_TEST_LOPSIDED_FUNC(A, aSize); \ 124 GENERATE_TEST_LOPSIDED_FUNC(B, aSize); 125 126 #define TEST_LOPSIDED(aSize) \ 127 TestLopsidedA##aSize(); \ 128 TestLopsidedB##aSize(); 129 130 // ==================== generate and run the tests ====================== 131 132 // There's an unknown bug in clang-cl-9 (used for win64-ccov) that makes 133 // generating these with the TIMES_N macro not work. So these are written out 134 // explicitly to unbork CI. 135 struct JammedWithFlags8 { 136 MOZ_ATOMIC_BITFIELDS(mAtomicFields, 8, 137 ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1), 138 (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1), 139 (bool, Flag7, 1), (bool, Flag8, 1))) 140 }; 141 142 struct JammedWithFlags16 { 143 MOZ_ATOMIC_BITFIELDS(mAtomicFields, 16, 144 ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1), 145 (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1), 146 (bool, Flag7, 1), (bool, Flag8, 1), (bool, Flag9, 1), 147 (bool, Flag10, 1), (bool, Flag11, 1), (bool, Flag12, 1), 148 (bool, Flag13, 1), (bool, Flag14, 1), (bool, Flag15, 1), 149 (bool, Flag16, 1))) 150 }; 151 152 struct JammedWithFlags32 { 153 MOZ_ATOMIC_BITFIELDS(mAtomicFields, 32, 154 ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1), 155 (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1), 156 (bool, Flag7, 1), (bool, Flag8, 1), (bool, Flag9, 1), 157 (bool, Flag10, 1), (bool, Flag11, 1), (bool, Flag12, 1), 158 (bool, Flag13, 1), (bool, Flag14, 1), (bool, Flag15, 1), 159 (bool, Flag16, 1), (bool, Flag17, 1), (bool, Flag18, 1), 160 (bool, Flag19, 1), (bool, Flag20, 1), (bool, Flag21, 1), 161 (bool, Flag22, 1), (bool, Flag23, 1), (bool, Flag24, 1), 162 (bool, Flag25, 1), (bool, Flag26, 1), (bool, Flag27, 1), 163 (bool, Flag28, 1), (bool, Flag29, 1), (bool, Flag30, 1), 164 (bool, Flag31, 1), (bool, Flag32, 1))) 165 }; 166 167 GENERATE_TEST_JAMMED_WITH_FLAGS(8) 168 GENERATE_TEST_JAMMED_WITH_FLAGS(16) 169 GENERATE_TEST_JAMMED_WITH_FLAGS(32) 170 // MOZ_FOR_EACH_64 doesn't exist :( 171 172 GENERATE_TEST_LOPSIDED(8) 173 GENERATE_TEST_LOPSIDED(16) 174 GENERATE_TEST_LOPSIDED(32) 175 GENERATE_TEST_LOPSIDED(64) 176 177 int main() { 178 TestDocumentationExample(); 179 180 TEST_JAMMED_WITH_FLAGS(8); 181 TEST_JAMMED_WITH_FLAGS(16); 182 TEST_JAMMED_WITH_FLAGS(32); 183 184 TEST_LOPSIDED(8); 185 TEST_LOPSIDED(16); 186 TEST_LOPSIDED(32); 187 TEST_LOPSIDED(64); 188 return 0; 189 }