// 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 using BitmapTest = TestWithBitmap; TYPED_TEST_SUITE(BitmapTest, BitmapTypes); using NonAtomicBitmapTest = TestWithBitmap>; 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