tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }