[heap] Fix mark bits for partially compacted pages.

See bug report.

R=ulan@chromium.org
BUG=chromium:538567
LOG=N

Review URL: https://codereview.chromium.org/1393293002

Cr-Commit-Position: refs/heads/master@{#31179}
This commit is contained in:
mlippautz 2015-10-08 06:49:19 -07:00 committed by Commit bot
parent 9d2e21775c
commit 3feba64470
4 changed files with 136 additions and 1 deletions

View File

@ -3349,6 +3349,12 @@ bool MarkCompactCollector::EvacuateLiveObjectsFromPage(
HeapObject* target_object = nullptr;
AllocationResult allocation = target_space->AllocateRaw(size, alignment);
if (!allocation.To(&target_object)) {
// We need to abort compaction for this page. Make sure that we reset
// the mark bits for objects that have already been migrated.
if (i > 0) {
p->markbits()->ClearRange(p->AddressToMarkbitIndex(p->area_start()),
p->AddressToMarkbitIndex(object_addr));
}
return false;
}

View File

@ -165,6 +165,10 @@ class Bitmap {
return index >> kBitsPerCellLog2;
}
V8_INLINE static uint32_t IndexInCell(uint32_t index) {
return index & kBitIndexMask;
}
INLINE(static uint32_t CellToIndex(uint32_t index)) {
return index << kBitsPerCellLog2;
}
@ -184,7 +188,7 @@ class Bitmap {
}
inline MarkBit MarkBitFromIndex(uint32_t index) {
MarkBit::CellType mask = 1 << (index & kBitIndexMask);
MarkBit::CellType mask = 1u << IndexInCell(index);
MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2);
return MarkBit(cell, mask);
}
@ -256,6 +260,23 @@ class Bitmap {
}
return true;
}
// Clears all bits starting from {cell_base_index} up to and excluding
// {index}. Note that {cell_base_index} is required to be cell aligned.
void ClearRange(uint32_t cell_base_index, uint32_t index) {
DCHECK_EQ(IndexInCell(cell_base_index), 0);
DCHECK_GE(index, cell_base_index);
uint32_t start_cell_index = IndexToCell(cell_base_index);
uint32_t end_cell_index = IndexToCell(index);
DCHECK_GE(end_cell_index, start_cell_index);
// Clear all cells till the cell containing the last index.
for (uint32_t i = start_cell_index; i < end_cell_index; i++) {
cells()[i] = 0;
}
// Clear all bits in the last cell till the last bit before index.
uint32_t clear_mask = ~((1u << IndexInCell(index)) - 1);
cells()[end_cell_index] &= clear_mask;
}
};

View File

@ -0,0 +1,107 @@
// 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 "testing/gtest/include/gtest/gtest.h"
namespace {
using v8::internal::Bitmap;
class BitmapTest : public ::testing::Test {
public:
static const uint32_t kBlackCell;
static const uint32_t kWhiteCell;
static const uint32_t kBlackByte;
static const uint32_t kWhiteByte;
BitmapTest() : memory_(new uint8_t[Bitmap::kSize]) {
memset(memory_, 0, Bitmap::kSize);
}
virtual ~BitmapTest() { delete[] memory_; }
Bitmap* bitmap() { return reinterpret_cast<Bitmap*>(memory_); }
uint8_t* raw_bitmap() { return memory_; }
private:
uint8_t* memory_;
};
const uint32_t BitmapTest::kBlackCell = 0xAAAAAAAA;
const uint32_t BitmapTest::kWhiteCell = 0x00000000;
const uint32_t BitmapTest::kBlackByte = 0xAA;
const uint32_t BitmapTest::kWhiteByte = 0x00;
TEST_F(BitmapTest, 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(BitmapTest, Cells) {
Bitmap* 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(BitmapTest, CellsCount) {
int 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(BitmapTest, IsClean) {
Bitmap* bm = bitmap();
EXPECT_TRUE(bm->IsClean());
bm->cells()[0] = kBlackCell;
EXPECT_FALSE(bm->IsClean());
}
TEST_F(BitmapTest, ClearRange1) {
Bitmap* bm = 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);
}
TEST_F(BitmapTest, ClearRange2) {
Bitmap* bm = 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);
}
} // namespace

View File

@ -103,6 +103,7 @@
'libplatform/default-platform-unittest.cc',
'libplatform/task-queue-unittest.cc',
'libplatform/worker-thread-unittest.cc',
'heap/bitmap-unittest.cc',
'heap/gc-idle-time-handler-unittest.cc',
'heap/memory-reducer-unittest.cc',
'heap/heap-unittest.cc',