| // Copyright 2015 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/heap/spaces.h" |
| #include "test/unittests/heap/bitmap-test-utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| const uint32_t kBlackCell = 0xAAAAAAAA; |
| const uint32_t kWhiteCell = 0x00000000; |
| const uint32_t kBlackByte = 0xAA; |
| const uint32_t kWhiteByte = 0x00; |
| |
| template <typename T> |
| using BitmapTest = TestWithBitmap<T>; |
| |
| TYPED_TEST_SUITE(BitmapTest, BitmapTypes); |
| |
| using NonAtomicBitmapTest = |
| TestWithBitmap<ConcurrentBitmap<AccessMode::NON_ATOMIC>>; |
| |
| TEST_F(NonAtomicBitmapTest, IsZeroInitialized) { |
| // We require all tests to start from a zero-initialized bitmap. Manually |
| // verify this invariant here. |
| for (size_t i = 0; i < Bitmap::kSize; i++) { |
| EXPECT_EQ(raw_bitmap()[i], kWhiteByte); |
| } |
| } |
| |
| TEST_F(NonAtomicBitmapTest, Cells) { |
| auto bm = bitmap(); |
| bm->cells()[1] = kBlackCell; |
| uint8_t* raw = raw_bitmap(); |
| int second_cell_base = Bitmap::kBytesPerCell; |
| for (size_t i = 0; i < Bitmap::kBytesPerCell; i++) { |
| EXPECT_EQ(raw[second_cell_base + i], kBlackByte); |
| } |
| } |
| |
| TEST_F(NonAtomicBitmapTest, CellsCount) { |
| size_t last_cell_index = bitmap()->CellsCount() - 1; |
| bitmap()->cells()[last_cell_index] = kBlackCell; |
| // Manually verify on raw memory. |
| uint8_t* raw = raw_bitmap(); |
| for (size_t i = 0; i < Bitmap::kSize; i++) { |
| // Last cell should be set. |
| if (i >= (Bitmap::kSize - Bitmap::kBytesPerCell)) { |
| EXPECT_EQ(raw[i], kBlackByte); |
| } else { |
| EXPECT_EQ(raw[i], kWhiteByte); |
| } |
| } |
| } |
| |
| TEST_F(NonAtomicBitmapTest, IsClean) { |
| auto bm = bitmap(); |
| EXPECT_TRUE(bm->IsClean()); |
| bm->cells()[0] = kBlackCell; |
| EXPECT_FALSE(bm->IsClean()); |
| } |
| |
| TYPED_TEST(BitmapTest, Clear) { |
| auto bm = this->bitmap(); |
| for (size_t i = 0; i < Bitmap::kSize; i++) { |
| this->raw_bitmap()[i] = 0xFFu; |
| } |
| bm->Clear(); |
| for (size_t i = 0; i < Bitmap::kSize; i++) { |
| EXPECT_EQ(this->raw_bitmap()[i], 0); |
| } |
| } |
| |
| TYPED_TEST(BitmapTest, MarkAllBits) { |
| auto bm = this->bitmap(); |
| bm->MarkAllBits(); |
| for (size_t i = 0; i < Bitmap::kSize; i++) { |
| EXPECT_EQ(this->raw_bitmap()[i], 0xFF); |
| } |
| } |
| |
| TYPED_TEST(BitmapTest, ClearRange1) { |
| auto bm = this->bitmap(); |
| bm->cells()[0] = kBlackCell; |
| bm->cells()[1] = kBlackCell; |
| bm->cells()[2] = kBlackCell; |
| bm->ClearRange(0, Bitmap::kBitsPerCell + Bitmap::kBitsPerCell / 2); |
| EXPECT_EQ(bm->cells()[0], kWhiteCell); |
| EXPECT_EQ(bm->cells()[1], 0xAAAA0000); |
| EXPECT_EQ(bm->cells()[2], kBlackCell); |
| } |
| |
| TYPED_TEST(BitmapTest, ClearRange2) { |
| auto bm = this->bitmap(); |
| bm->cells()[0] = kBlackCell; |
| bm->cells()[1] = kBlackCell; |
| bm->cells()[2] = kBlackCell; |
| bm->ClearRange(Bitmap::kBitsPerCell, |
| Bitmap::kBitsPerCell + Bitmap::kBitsPerCell / 2); |
| EXPECT_EQ(bm->cells()[0], kBlackCell); |
| EXPECT_EQ(bm->cells()[1], 0xAAAA0000); |
| EXPECT_EQ(bm->cells()[2], kBlackCell); |
| } |
| |
| TYPED_TEST(BitmapTest, SetAndClearRange) { |
| auto bm = this->bitmap(); |
| for (int i = 0; i < 3; i++) { |
| bm->SetRange(i, Bitmap::kBitsPerCell + i); |
| CHECK_EQ(bm->cells()[0], 0xFFFFFFFFu << i); |
| CHECK_EQ(bm->cells()[1], (1u << i) - 1); |
| bm->ClearRange(i, Bitmap::kBitsPerCell + i); |
| CHECK_EQ(bm->cells()[0], 0x0u); |
| CHECK_EQ(bm->cells()[1], 0x0u); |
| } |
| } |
| |
| // AllBitsSetInRange() and AllBitsClearInRange() are only used when verifying |
| // the heap on the main thread so they don't have atomic implementations. |
| TEST_F(NonAtomicBitmapTest, ClearMultipleRanges) { |
| auto bm = this->bitmap(); |
| |
| bm->SetRange(0, Bitmap::kBitsPerCell * 3); |
| CHECK(bm->AllBitsSetInRange(0, Bitmap::kBitsPerCell)); |
| |
| bm->ClearRange(Bitmap::kBitsPerCell / 2, Bitmap::kBitsPerCell); |
| bm->ClearRange(Bitmap::kBitsPerCell, |
| Bitmap::kBitsPerCell + Bitmap::kBitsPerCell / 2); |
| bm->ClearRange(Bitmap::kBitsPerCell * 2 + 8, Bitmap::kBitsPerCell * 2 + 16); |
| bm->ClearRange(Bitmap::kBitsPerCell * 2 + 24, Bitmap::kBitsPerCell * 3); |
| |
| CHECK_EQ(bm->cells()[0], 0xFFFFu); |
| CHECK(bm->AllBitsSetInRange(0, Bitmap::kBitsPerCell / 2)); |
| CHECK( |
| bm->AllBitsClearInRange(Bitmap::kBitsPerCell / 2, Bitmap::kBitsPerCell)); |
| |
| CHECK_EQ(bm->cells()[1], 0xFFFF0000u); |
| CHECK(bm->AllBitsClearInRange( |
| Bitmap::kBitsPerCell, Bitmap::kBitsPerCell + Bitmap::kBitsPerCell / 2)); |
| CHECK(bm->AllBitsSetInRange(Bitmap::kBitsPerCell + Bitmap::kBitsPerCell / 2, |
| Bitmap::kBitsPerCell * 2)); |
| |
| CHECK_EQ(bm->cells()[2], 0xFF00FFu); |
| CHECK(bm->AllBitsSetInRange( |
| Bitmap::kBitsPerCell * 2, |
| Bitmap::kBitsPerCell * 2 + Bitmap::kBitsPerCell / 4)); |
| CHECK(bm->AllBitsClearInRange( |
| Bitmap::kBitsPerCell * 2 + Bitmap::kBitsPerCell / 4, |
| Bitmap::kBitsPerCell * 2 + Bitmap::kBitsPerCell / 2)); |
| CHECK(bm->AllBitsSetInRange( |
| Bitmap::kBitsPerCell * 2 + Bitmap::kBitsPerCell / 2, |
| Bitmap::kBitsPerCell * 2 + Bitmap::kBitsPerCell / 2 + |
| Bitmap::kBitsPerCell / 4)); |
| CHECK(bm->AllBitsClearInRange(Bitmap::kBitsPerCell * 2 + |
| Bitmap::kBitsPerCell / 2 + |
| Bitmap::kBitsPerCell / 4, |
| Bitmap::kBitsPerCell * 3)); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |