tor-browser

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

AtomicBitfields.h (21825B)


      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 #ifndef mozilla_AtomicBitfields_h
      8 #define mozilla_AtomicBitfields_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/MacroArgs.h"
     12 #include "mozilla/MacroForEach.h"
     13 
     14 #include <cstdint>
     15 #include <type_traits>
     16 
     17 #ifdef __wasi__
     18 #  include "mozilla/WasiAtomic.h"
     19 #else
     20 #  include <atomic>
     21 #endif  // __wasi__
     22 
     23 namespace mozilla {
     24 
     25 // Creates a series of atomic bitfields.
     26 //
     27 // |aBitfields| is the name of the underlying storage for the bitfields.
     28 // |aBitFieldsSize| is the size of the underlying storage (8, 16, 32, or 64).
     29 //
     30 // Bitfields are specified as a triplet of (type, name, size), which mirrors
     31 // the way you declare native C++ bitfields (bool mMyField1: 1). Trailing
     32 // commas are not supported in the list of bitfields.
     33 //
     34 // Signed integer types are not supported by this Macro to avoid dealing with
     35 // packing/unpacking the sign bit and C++'s general messiness around signed
     36 // integer representations not being fully defined.
     37 //
     38 // You cannot request a single field that's the
     39 // size of the the entire bitfield storage. Just use a normal atomic integer!
     40 //
     41 //
     42 // ========================== SEMANTICS AND SAFETY ============================
     43 //
     44 // All fields are default-initialized to 0.
     45 //
     46 // In debug builds, storing a value to a bitfield that's larger than its bits
     47 // can fit will trigger an assertion. In release builds, the value will just be
     48 // masked off.
     49 //
     50 // If you request anything unsupported by this macro it should result in
     51 // a compile-time error (either a static assert or just weird macro errors).
     52 // For instance, this macro will statically prevent using more bits than
     53 // |aBitFieldsSize|, so specifying the size is just to prevent accidentally
     54 // making the storage bigger.
     55 //
     56 // Each field will get a Load$NAME and Store$Name method which will atomically
     57 // load and store the requested value with a Sequentially Consistent memory
     58 // order (to be on the safe side). Storing a field requires a compare-exchange,
     59 // so a thread may get stalled if there's a lot of contention on the bitfields.
     60 //
     61 //
     62 // ============================== MOTIVATION ==================================
     63 //
     64 // You might be wondering: why would I need atomic bitfields? Well as it turns
     65 // out, bitfields and concurrency mess a lot of people up!
     66 //
     67 // CPUs don't have operations to write to a handful of bits -- they generally
     68 // only have the precision of a byte. So when you use C++'s native bitfields,
     69 // the compiler generates code to mask and shift the values in for you. This
     70 // means writing to a single field will actually overwrite all the other
     71 // bitfields that are packed in with it!
     72 //
     73 // In single-threaded code this is fine; the old values are loaded and written
     74 // back by the compiler's generated code. But in concurrent code, it means
     75 // that accessing two different fields can be an unexpected Data Race (which is
     76 // Undefined Behavior!).
     77 //
     78 // By using MOZ_ATOMIC_BITFIELDS, you protect yourself from these Data Races,
     79 // and don't have to worry about writes getting lost.
     80 //
     81 //
     82 // ================================ EXAMPLE ===================================
     83 //
     84 //   #include "mozilla/AtomicBitfields.h"
     85 //   #include <stdint.h>
     86 //
     87 //
     88 //   struct MyType {
     89 //     MOZ_ATOMIC_BITFIELDS(mAtomicFields, 8, (
     90 //      (bool, IsDownloaded, 1),
     91 //      (uint32_t, SomeData, 2),
     92 //      (uint8_t, OtherData, 5)
     93 //     ))
     94 //
     95 //     int32_t aNormalInteger;
     96 //
     97 //     explicit MyType(uint32_t aSomeData): aNormalInteger(7) {
     98 //       StoreSomeData(aSomeData);
     99 //       // Other bitfields were already default initialized to 0/false
    100 //     }
    101 //   };
    102 //
    103 //
    104 //   int main() {
    105 //     MyType val(3);
    106 //
    107 //     if (!val.LoadIsDownloaded()) {
    108 //       val.StoreOtherData(2);
    109 //       val.StoreIsDownloaded(true);
    110 //     }
    111 //   }
    112 //
    113 //
    114 // ============================== GENERATED ===================================
    115 //
    116 // This macro is a real mess to read because, well, it's a macro. So for the
    117 // sake of anyone who has to review or modify its internals, here's a rough
    118 // sketch of what the above example would expand to:
    119 //
    120 //   struct MyType {
    121 //     // The actual storage of the bitfields, initialized to 0.
    122 //     std::atomic_uint8_t mAtomicFields{0};
    123 //
    124 //     // How many bits were actually used (in this case, all of them).
    125 //     static const size_t mAtomicFields_USED_BITS = 8;
    126 //
    127 //     // The offset values for each field.
    128 //     static const size_t mAtomicFieldsIsDownloaded = 0;
    129 //     static const size_t mAtomicFieldsSomeData = 1;
    130 //     static const size_t mAtomicFieldsOtherData = 3;
    131 //
    132 //     // Quick safety guard to prevent capacity overflow.
    133 //     static_assert(mAtomicFields_USED_BITS <= 8);
    134 //
    135 //     // Asserts that fields are reasonable.
    136 //     static_assert(8>1, "mAtomicFields: MOZ_ATOMIC_BITFIELDS field too big");
    137 //     static_assert(std::is_unsigned<bool>(), "mAtomicFields:
    138 //     MOZ_ATOMIC_BITFIELDS doesn't support signed payloads");
    139 //     // ...and so on
    140 //
    141 //     // Load/Store methods for all the fields.
    142 //
    143 //     bool LoadIsDownloaded() { ... }
    144 //     void StoreIsDownloaded(bool aValue) { ... }
    145 //
    146 //     uint32_t LoadSomeData() { ... }
    147 //     void StoreSomeData(uint32_t aValue) { ... }
    148 //
    149 //     uint8_t LoadOtherData() { ... }
    150 //     void StoreOtherData(uint8_t aValue) { ... }
    151 //
    152 //
    153 //     // Remainder of the struct body continues normally.
    154 //     int32_t aNormalInteger;
    155 //     explicit MyType(uint32_t aSomeData): aNormalInteger(7) {
    156 //       StoreSomeData(aSomeData);
    157 //       // Other bitfields were already default initialized to 0/false.
    158 //     }
    159 //   }
    160 //
    161 // Also if you're wondering why there's so many MOZ_CONCAT's -- it's because
    162 // the preprocessor sometimes gets confused if we use ## on certain arguments.
    163 // MOZ_CONCAT reliably kept the preprocessor happy, sorry it's so ugly!
    164 //
    165 //
    166 // ==================== FIXMES / FUTURE WORK ==================================
    167 //
    168 // * It would be nice if LoadField could be IsField for booleans.
    169 //
    170 // * For the case of setting something to all 1's or 0's, we can use
    171 //   |fetch_or| or |fetch_and| instead of |compare_exchange_weak|. Is this
    172 //   worth providing? (Possibly for 1-bit boolean fields?)
    173 //
    174 // * Try harder to hide the atomic/enum/array internals from
    175 //   the outer struct?
    176 //
    177 #define MOZ_ATOMIC_BITFIELDS(aBitfields, aBitfieldsSize, aFields)             \
    178  std::atomic_uint##aBitfieldsSize##_t aBitfields{0};                         \
    179                                                                              \
    180  static const size_t MOZ_CONCAT(aBitfields, _USED_BITS) =                    \
    181      MOZ_FOR_EACH_SEPARATED(MOZ_ATOMIC_BITFIELDS_FIELD_SIZE, (+), (),        \
    182                             aFields);                                        \
    183                                                                              \
    184  MOZ_ROLL_EACH(MOZ_ATOMIC_BITFIELDS_OFFSET_HELPER1, (aBitfields, ), aFields) \
    185                                                                              \
    186  static_assert(MOZ_CONCAT(aBitfields, _USED_BITS) <= aBitfieldsSize,         \
    187                #aBitfields ": Maximum bits (" #aBitfieldsSize                \
    188                            ") exceeded for MOZ_ATOMIC_BITFIELDS instance");  \
    189                                                                              \
    190  MOZ_FOR_EACH(MOZ_ATOMIC_BITFIELDS_FIELD_HELPER,                             \
    191               (aBitfields, aBitfieldsSize, ), aFields)
    192 
    193 // Just a helper to unpack the head of the list.
    194 #define MOZ_ATOMIC_BITFIELDS_OFFSET_HELPER1(aBitfields, aFields) \
    195  MOZ_ATOMIC_BITFIELDS_OFFSET_HELPER2(aBitfields, MOZ_ARG_1 aFields, aFields);
    196 
    197 // Just a helper to unpack the name and call the real function.
    198 #define MOZ_ATOMIC_BITFIELDS_OFFSET_HELPER2(aBitfields, aField, aFields) \
    199  MOZ_ATOMIC_BITFIELDS_OFFSET(aBitfields, MOZ_ARG_2 aField, aFields)
    200 
    201 // To compute the offset of a field, why sum up all the offsets after it
    202 // (inclusive) and subtract that from the total sum itself. We do this to swap
    203 // the rolling sum that |MOZ_ROLL_EACH| gets us from descending to ascending.
    204 #define MOZ_ATOMIC_BITFIELDS_OFFSET(aBitfields, aFieldName, aFields)    \
    205  static const size_t MOZ_CONCAT(aBitfields, aFieldName) =              \
    206      MOZ_CONCAT(aBitfields, _USED_BITS) -                              \
    207      (MOZ_FOR_EACH_SEPARATED(MOZ_ATOMIC_BITFIELDS_FIELD_SIZE, (+), (), \
    208                              aFields));
    209 
    210 // Just a more clearly named way of unpacking the size.
    211 #define MOZ_ATOMIC_BITFIELDS_FIELD_SIZE(aArgs) MOZ_ARG_3 aArgs
    212 
    213 // Just a helper to unpack the tuple and call the real function.
    214 #define MOZ_ATOMIC_BITFIELDS_FIELD_HELPER(aBitfields, aBitfieldsSize, aArgs) \
    215  MOZ_ATOMIC_BITFIELDS_FIELD(aBitfields, aBitfieldsSize, MOZ_ARG_1 aArgs,    \
    216                             MOZ_ARG_2 aArgs, MOZ_ARG_3 aArgs)
    217 
    218 // We need to disable this with coverity because it doesn't like checking that
    219 // booleans are < 2 (because they always are).
    220 #ifdef __COVERITY__
    221 #  define MOZ_ATOMIC_BITFIELDS_STORE_GUARD(aValue, aFieldSize)
    222 #else
    223 #  define MOZ_ATOMIC_BITFIELDS_STORE_GUARD(aValue, aFieldSize) \
    224    MOZ_ASSERT(((uint64_t)aValue) < (1ull << aFieldSize),      \
    225               "Stored value exceeded capacity of bitfield!")
    226 #endif
    227 
    228 // Generates the Load and Store methods for each field.
    229 //
    230 // Some comments here because inline macro comments are a pain in the neck:
    231 //
    232 // Most of the locals are forward declared to minimize messy macroified
    233 // type declaration. Also a lot of locals are used to try to make things
    234 // a little more clear, while also avoiding integer promotion issues.
    235 // This is why some locals are literally just copying a value we already have:
    236 // to force it to the right size.
    237 //
    238 // There's an annoying overflow case where a bitfields instance has a field
    239 // that is the same size as the bitfields. Rather than trying to handle that,
    240 // we just static_assert against it.
    241 //
    242 //
    243 // BITMATH EXPLAINED:
    244 //
    245 // For |Load$Name|:
    246 //
    247 //    mask = ((1 << fieldSize) - 1) << offset
    248 //
    249 // If you subtract 1 from a value with 1 bit set you get all 1's below that bit.
    250 // This is perfect for ANDing out |fieldSize| bits. We shift by |offset| to get
    251 // it in the right place.
    252 //
    253 //    value = (aBitfields.load() & mask) >> offset
    254 //
    255 // This sets every bit we're not interested in to 0. Shifting the result by
    256 // |offset| converts the value back to its native format, ready to be cast
    257 // up to an integer type.
    258 //
    259 //
    260 // For |Store$Name|:
    261 //
    262 //    packedValue = (resizedValue << offset) & mask
    263 //
    264 // This converts a native value to the packed format. If the value is in bounds,
    265 // the AND will do nothing. If it's out of bounds (not checked in release),
    266 // then it will cause the value to wrap around by modulo 2^aFieldSize, just like
    267 // a normal uint.
    268 //
    269 //    clearedValue = oldValue & ~mask;
    270 //
    271 // This clears the bits where our field is stored on our bitfield storage by
    272 // ANDing it with an inverted (NOTed) mask.
    273 //
    274 //    newValue = clearedValue | packedValue;
    275 //
    276 // Once we have |packedValue| and |clearedValue| they just need to be ORed
    277 // together to merge the new field value with the old values of all the other
    278 // fields.
    279 //
    280 // This last step is done in a while loop because someone else can modify
    281 // the bits before we have a chance to. If we didn't guard against this,
    282 // our write would undo the write the other thread did. |compare_exchange_weak|
    283 // is specifically designed to handle this. We give it what we expect the
    284 // current value to be, and what we want it to be. If someone else modifies
    285 // the bitfields before us, then we will reload the value and try again.
    286 //
    287 // Note that |compare_exchange_weak| writes back the actual value to the
    288 // "expected" argument (it's passed by-reference), so we don't need to do
    289 // another load in the body of the loop when we fail to write our result.
    290 #define MOZ_ATOMIC_BITFIELDS_FIELD(aBitfields, aBitfieldsSize, aFieldType, \
    291                                   aFieldName, aFieldSize)                 \
    292  static_assert(aBitfieldsSize > aFieldSize,                               \
    293                #aBitfields ": MOZ_ATOMIC_BITFIELDS field too big");       \
    294  static_assert(std::is_unsigned<aFieldType>(), #aBitfields                \
    295                ": MOZ_ATOMIC_BITFIELDS doesn't support signed payloads"); \
    296                                                                           \
    297  aFieldType MOZ_CONCAT(Load, aFieldName)() const {                        \
    298    uint##aBitfieldsSize##_t fieldSize, mask, masked, value;               \
    299    size_t offset = MOZ_CONCAT(aBitfields, aFieldName);                    \
    300    fieldSize = aFieldSize;                                                \
    301    mask = ((1ull << fieldSize) - 1ull) << offset;                         \
    302    masked = aBitfields.load() & mask;                                     \
    303    value = (masked >> offset);                                            \
    304    return value;                                                          \
    305  }                                                                        \
    306                                                                           \
    307  void MOZ_CONCAT(Store, aFieldName)(aFieldType aValue) {                  \
    308    MOZ_ATOMIC_BITFIELDS_STORE_GUARD(aValue, aFieldSize);                  \
    309    uint##aBitfieldsSize##_t fieldSize, mask, resizedValue, packedValue,   \
    310        oldValue, clearedValue, newValue;                                  \
    311    size_t offset = MOZ_CONCAT(aBitfields, aFieldName);                    \
    312    fieldSize = aFieldSize;                                                \
    313    mask = ((1ull << fieldSize) - 1ull) << offset;                         \
    314    resizedValue = aValue;                                                 \
    315    packedValue = (resizedValue << offset) & mask;                         \
    316    oldValue = aBitfields.load();                                          \
    317    do {                                                                   \
    318      clearedValue = oldValue & ~mask;                                     \
    319      newValue = clearedValue | packedValue;                               \
    320    } while (!aBitfields.compare_exchange_weak(oldValue, newValue));       \
    321  }
    322 
    323 // OK SO THIS IS A GROSS HACK. GCC 10.2 (and below) has a bug[1] where it
    324 // doesn't allow a static array to reference itself in its initializer, so we
    325 // need to create a hacky way to produce a rolling sum of all the offsets.
    326 //
    327 // To do this, we make a tweaked version of |MOZ_FOR_EACH| which instead of
    328 // passing just one argument to |aMacro| it passes the remaining values of
    329 // |aArgs|.
    330 //
    331 // This allows us to expand an input (a, b, c, d) quadratically to:
    332 //
    333 // int sum1 = a + b + c + d;
    334 // int sum2 = b + c + d;
    335 // int sum3 = c + d;
    336 // int sum4 = d;
    337 //
    338 // So all of this is a copy-paste of |MOZ_FOR_EACH| except the definition
    339 // of |MOZ_FOR_EACH_HELPER| no longer extracts an argument with |MOZ_ARG_1|.
    340 // Also this is restricted to 32 arguments just to reduce footprint a little.
    341 //
    342 // If the GCC bug is ever fixed, then this hack can be removed, and we can
    343 // use the non-quadratic version that was originally written[2]. In case
    344 // that link dies, a brief summary of that implementation:
    345 //
    346 // * Associate each field with an index by creating an `enum class` with
    347 //   entries for each field (an existing gecko patten).
    348 //
    349 // * Calculate offsets with a constexpr static array whose initializer
    350 //   self-referentially adds the contents of the previous index to the
    351 //   compute the current one.
    352 //
    353 // * Index into this array with the enum.
    354 //
    355 // [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97234
    356 // [2]: https://phabricator.services.mozilla.com/D91622?id=346499
    357 #define MOZ_ROLL_EACH_EXPAND_HELPER(...) __VA_ARGS__
    358 #define MOZ_ROLL_EACH_GLUE(a, b) a b
    359 #define MOZ_ROLL_EACH_SEPARATED(aMacro, aSeparator, aFixedArgs, aArgs)       \
    360  MOZ_ROLL_EACH_GLUE(MOZ_PASTE_PREFIX_AND_ARG_COUNT(                         \
    361                         MOZ_ROLL_EACH_, MOZ_ROLL_EACH_EXPAND_HELPER aArgs), \
    362                     (aMacro, aSeparator, aFixedArgs, aArgs))
    363 #define MOZ_ROLL_EACH(aMacro, aFixedArgs, aArgs) \
    364  MOZ_ROLL_EACH_SEPARATED(aMacro, (), aFixedArgs, aArgs)
    365 
    366 #define MOZ_ROLL_EACH_HELPER_GLUE(a, b) a b
    367 #define MOZ_ROLL_EACH_HELPER(aMacro, aFixedArgs, aArgs) \
    368  MOZ_ROLL_EACH_HELPER_GLUE(aMacro,                     \
    369                            (MOZ_ROLL_EACH_EXPAND_HELPER aFixedArgs aArgs))
    370 
    371 #define MOZ_ROLL_EACH_0(m, s, fa, a)
    372 #define MOZ_ROLL_EACH_1(m, s, fa, a) MOZ_ROLL_EACH_HELPER(m, fa, a)
    373 #define MOZ_ROLL_EACH_2(m, s, fa, a) \
    374  MOZ_ROLL_EACH_HELPER(m, fa, a)     \
    375  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_1(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    376 #define MOZ_ROLL_EACH_3(m, s, fa, a) \
    377  MOZ_ROLL_EACH_HELPER(m, fa, a)     \
    378  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_2(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    379 #define MOZ_ROLL_EACH_4(m, s, fa, a) \
    380  MOZ_ROLL_EACH_HELPER(m, fa, a)     \
    381  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_3(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    382 #define MOZ_ROLL_EACH_5(m, s, fa, a) \
    383  MOZ_ROLL_EACH_HELPER(m, fa, a)     \
    384  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_4(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    385 #define MOZ_ROLL_EACH_6(m, s, fa, a) \
    386  MOZ_ROLL_EACH_HELPER(m, fa, a)     \
    387  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_5(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    388 #define MOZ_ROLL_EACH_7(m, s, fa, a) \
    389  MOZ_ROLL_EACH_HELPER(m, fa, a)     \
    390  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_6(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    391 #define MOZ_ROLL_EACH_8(m, s, fa, a) \
    392  MOZ_ROLL_EACH_HELPER(m, fa, a)     \
    393  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_7(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    394 #define MOZ_ROLL_EACH_9(m, s, fa, a) \
    395  MOZ_ROLL_EACH_HELPER(m, fa, a)     \
    396  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_8(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    397 #define MOZ_ROLL_EACH_10(m, s, fa, a) \
    398  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    399  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_9(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    400 #define MOZ_ROLL_EACH_11(m, s, fa, a) \
    401  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    402  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_10(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    403 #define MOZ_ROLL_EACH_12(m, s, fa, a) \
    404  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    405  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_11(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    406 #define MOZ_ROLL_EACH_13(m, s, fa, a) \
    407  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    408  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_12(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    409 #define MOZ_ROLL_EACH_14(m, s, fa, a) \
    410  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    411  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_13(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    412 #define MOZ_ROLL_EACH_15(m, s, fa, a) \
    413  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    414  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_14(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    415 #define MOZ_ROLL_EACH_16(m, s, fa, a) \
    416  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    417  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_15(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    418 #define MOZ_ROLL_EACH_17(m, s, fa, a) \
    419  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    420  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_16(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    421 #define MOZ_ROLL_EACH_18(m, s, fa, a) \
    422  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    423  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_17(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    424 #define MOZ_ROLL_EACH_19(m, s, fa, a) \
    425  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    426  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_18(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    427 #define MOZ_ROLL_EACH_20(m, s, fa, a) \
    428  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    429  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_19(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    430 #define MOZ_ROLL_EACH_21(m, s, fa, a) \
    431  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    432  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_20(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    433 #define MOZ_ROLL_EACH_22(m, s, fa, a) \
    434  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    435  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_21(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    436 #define MOZ_ROLL_EACH_23(m, s, fa, a) \
    437  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    438  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_22(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    439 #define MOZ_ROLL_EACH_24(m, s, fa, a) \
    440  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    441  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_23(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    442 #define MOZ_ROLL_EACH_25(m, s, fa, a) \
    443  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    444  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_24(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    445 #define MOZ_ROLL_EACH_26(m, s, fa, a) \
    446  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    447  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_25(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    448 #define MOZ_ROLL_EACH_27(m, s, fa, a) \
    449  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    450  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_26(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    451 #define MOZ_ROLL_EACH_28(m, s, fa, a) \
    452  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    453  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_27(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    454 #define MOZ_ROLL_EACH_29(m, s, fa, a) \
    455  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    456  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_28(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    457 #define MOZ_ROLL_EACH_30(m, s, fa, a) \
    458  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    459  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_29(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    460 #define MOZ_ROLL_EACH_31(m, s, fa, a) \
    461  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    462  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_30(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    463 #define MOZ_ROLL_EACH_32(m, s, fa, a) \
    464  MOZ_ROLL_EACH_HELPER(m, fa, a)      \
    465  MOZ_ROLL_EACH_EXPAND_HELPER s MOZ_ROLL_EACH_31(m, s, fa, (MOZ_ARGS_AFTER_1 a))
    466 }  // namespace mozilla
    467 #endif /* mozilla_AtomicBitfields_h */