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