diff options
Diffstat (limited to 'mfbt/tests/TestAtomicBitfields.cpp')
-rw-r--r-- | mfbt/tests/TestAtomicBitfields.cpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/mfbt/tests/TestAtomicBitfields.cpp b/mfbt/tests/TestAtomicBitfields.cpp new file mode 100644 index 0000000000..237dbde538 --- /dev/null +++ b/mfbt/tests/TestAtomicBitfields.cpp @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" +#include "mozilla/AtomicBitfields.h" + +// This is a big macro mess, so let's summarize what's in here right up front: +// +// |TestDocumentationExample| is intended to be a copy-paste of the example +// in the macro's documentation, to make sure it's correct. +// +// +// |TestJammedWithFlags| tests using every bit of the type for bool flags. +// 64-bit isn't tested due to macro limitations. +// +// +// |TestLopsided| tests an instance with the following configuration: +// +// * a 1-bit boolean +// * an (N-1)-bit uintN_t +// +// It tests both orderings of these fields. +// +// Hopefully these are enough to cover all the nasty boundary conditions +// (that still compile). + +// ==================== TestDocumentationExample ======================== + +struct MyType { + MOZ_ATOMIC_BITFIELDS(mAtomicFields, 8, + ((bool, IsDownloaded, 1), (uint32_t, SomeData, 2), + (uint8_t, OtherData, 5))) + + int32_t aNormalInteger; + + explicit MyType(uint32_t aSomeData) : aNormalInteger(7) { + StoreSomeData(aSomeData); + // Other bitfields were already default initialized to 0/false + } +}; + +void TestDocumentationExample() { + MyType val(3); + + if (!val.LoadIsDownloaded()) { + val.StoreOtherData(2); + val.StoreIsDownloaded(true); + } +} + +// ====================== TestJammedWithFlags ========================= + +#define TIMES_8(aFunc, aSeparator, aArgs) \ + MOZ_FOR_EACH_SEPARATED(aFunc, aSeparator, aArgs, (1, 2, 3, 4, 5, 6, 7, 8)) +#define TIMES_16(aFunc, aSeparator, aArgs) \ + MOZ_FOR_EACH_SEPARATED( \ + aFunc, aSeparator, aArgs, \ + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) +#define TIMES_32(aFunc, aSeparator, aArgs) \ + MOZ_FOR_EACH_SEPARATED( \ + aFunc, aSeparator, aArgs, \ + (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, \ + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)) + +#define CHECK_BOOL(aIndex) \ + MOZ_ASSERT(val.LoadFlag##aIndex() == false); \ + val.StoreFlag##aIndex(true); \ + MOZ_ASSERT(val.LoadFlag##aIndex() == true); \ + val.StoreFlag##aIndex(false); \ + MOZ_ASSERT(val.LoadFlag##aIndex() == false); + +#define GENERATE_TEST_JAMMED_WITH_FLAGS(aSize) \ + void TestJammedWithFlags##aSize() { \ + JammedWithFlags##aSize val; \ + TIMES_##aSize(CHECK_BOOL, (;), ()); \ + } + +#define TEST_JAMMED_WITH_FLAGS(aSize) TestJammedWithFlags##aSize(); + +// ========================= TestLopsided =========================== + +#define GENERATE_TEST_LOPSIDED_FUNC(aSide, aSize) \ + void TestLopsided##aSide##aSize() { \ + Lopsided##aSide##aSize val; \ + MOZ_ASSERT(val.LoadHappyLittleBit() == false); \ + MOZ_ASSERT(val.LoadLargeAndInCharge() == 0); \ + val.StoreHappyLittleBit(true); \ + MOZ_ASSERT(val.LoadHappyLittleBit() == true); \ + MOZ_ASSERT(val.LoadLargeAndInCharge() == 0); \ + val.StoreLargeAndInCharge(1); \ + MOZ_ASSERT(val.LoadHappyLittleBit() == true); \ + MOZ_ASSERT(val.LoadLargeAndInCharge() == 1); \ + val.StoreLargeAndInCharge(0); \ + MOZ_ASSERT(val.LoadHappyLittleBit() == true); \ + MOZ_ASSERT(val.LoadLargeAndInCharge() == 0); \ + uint##aSize##_t size = aSize; \ + uint##aSize##_t int_max = (~(1ull << (size - 1))) - 1; \ + val.StoreLargeAndInCharge(int_max); \ + MOZ_ASSERT(val.LoadHappyLittleBit() == true); \ + MOZ_ASSERT(val.LoadLargeAndInCharge() == int_max); \ + val.StoreHappyLittleBit(false); \ + MOZ_ASSERT(val.LoadHappyLittleBit() == false); \ + MOZ_ASSERT(val.LoadLargeAndInCharge() == int_max); \ + val.StoreLargeAndInCharge(int_max); \ + MOZ_ASSERT(val.LoadHappyLittleBit() == false); \ + MOZ_ASSERT(val.LoadLargeAndInCharge() == int_max); \ + } + +#define GENERATE_TEST_LOPSIDED(aSize) \ + struct LopsidedA##aSize { \ + MOZ_ATOMIC_BITFIELDS(mAtomicFields, aSize, \ + ((bool, HappyLittleBit, 1), \ + (uint##aSize##_t, LargeAndInCharge, ((aSize)-1)))) \ + }; \ + struct LopsidedB##aSize { \ + MOZ_ATOMIC_BITFIELDS(mAtomicFields, aSize, \ + ((uint##aSize##_t, LargeAndInCharge, ((aSize)-1)), \ + (bool, HappyLittleBit, 1))) \ + }; \ + GENERATE_TEST_LOPSIDED_FUNC(A, aSize); \ + GENERATE_TEST_LOPSIDED_FUNC(B, aSize); + +#define TEST_LOPSIDED(aSize) \ + TestLopsidedA##aSize(); \ + TestLopsidedB##aSize(); + +// ==================== generate and run the tests ====================== + +// There's an unknown bug in clang-cl-9 (used for win64-ccov) that makes +// generating these with the TIMES_N macro not work. So these are written out +// explicitly to unbork CI. +struct JammedWithFlags8 { + MOZ_ATOMIC_BITFIELDS(mAtomicFields, 8, + ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1), + (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1), + (bool, Flag7, 1), (bool, Flag8, 1))) +}; + +struct JammedWithFlags16 { + MOZ_ATOMIC_BITFIELDS(mAtomicFields, 16, + ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1), + (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1), + (bool, Flag7, 1), (bool, Flag8, 1), (bool, Flag9, 1), + (bool, Flag10, 1), (bool, Flag11, 1), (bool, Flag12, 1), + (bool, Flag13, 1), (bool, Flag14, 1), (bool, Flag15, 1), + (bool, Flag16, 1))) +}; + +struct JammedWithFlags32 { + MOZ_ATOMIC_BITFIELDS(mAtomicFields, 32, + ((bool, Flag1, 1), (bool, Flag2, 1), (bool, Flag3, 1), + (bool, Flag4, 1), (bool, Flag5, 1), (bool, Flag6, 1), + (bool, Flag7, 1), (bool, Flag8, 1), (bool, Flag9, 1), + (bool, Flag10, 1), (bool, Flag11, 1), (bool, Flag12, 1), + (bool, Flag13, 1), (bool, Flag14, 1), (bool, Flag15, 1), + (bool, Flag16, 1), (bool, Flag17, 1), (bool, Flag18, 1), + (bool, Flag19, 1), (bool, Flag20, 1), (bool, Flag21, 1), + (bool, Flag22, 1), (bool, Flag23, 1), (bool, Flag24, 1), + (bool, Flag25, 1), (bool, Flag26, 1), (bool, Flag27, 1), + (bool, Flag28, 1), (bool, Flag29, 1), (bool, Flag30, 1), + (bool, Flag31, 1), (bool, Flag32, 1))) +}; + +GENERATE_TEST_JAMMED_WITH_FLAGS(8) +GENERATE_TEST_JAMMED_WITH_FLAGS(16) +GENERATE_TEST_JAMMED_WITH_FLAGS(32) +// MOZ_FOR_EACH_64 doesn't exist :( + +GENERATE_TEST_LOPSIDED(8) +GENERATE_TEST_LOPSIDED(16) +GENERATE_TEST_LOPSIDED(32) +GENERATE_TEST_LOPSIDED(64) + +int main() { + TestDocumentationExample(); + + TEST_JAMMED_WITH_FLAGS(8); + TEST_JAMMED_WITH_FLAGS(16); + TEST_JAMMED_WITH_FLAGS(32); + + TEST_LOPSIDED(8); + TEST_LOPSIDED(16); + TEST_LOPSIDED(32); + TEST_LOPSIDED(64); + return 0; +} |