// Create a bunch of fake bitmaps since these are required to create image spaces. The bitmaps // do not need to cover the image spaces though. for (size_t i = 0; i < kMaxBitmaps; ++i) {
accounting::ContinuousSpaceBitmap bitmap(
accounting::ContinuousSpaceBitmap::Create( "bitmap", reinterpret_cast<uint8_t*>(static_cast<size_t>(page_size)), page_size));
CHECK(bitmap.IsValid());
live_bitmaps_.push_back(std::move(bitmap));
}
}
MemMap ReserveImage(size_t image_size, /*out*/ std::string* error_str) { // If the image is aligned to the current runtime page size, it will already // be naturally aligned. On the other hand, MayAnonymousAligned() requires // that the requested alignment is higher.
DCHECK_LE(MemMap::GetPageSize(), kElfSegmentAlignment); if (MemMap::GetPageSize() == kElfSegmentAlignment) { return MemMap::MapAnonymous("reserve",
image_size,
PROT_READ | PROT_WRITE, /*low_4gb=*/true,
error_str);
} return MemMap::MapAnonymousAligned("reserve",
image_size,
PROT_READ | PROT_WRITE, /*low_4gb=*/true,
kElfSegmentAlignment,
error_str);
}
private: // Bitmap pool for pre-allocated fake bitmaps. We need to pre-allocate them since we don't want // them to randomly get placed somewhere where we want an image space.
std::vector<accounting::ContinuousSpaceBitmap> live_bitmaps_;
};
class FakeSpace : public space::ContinuousSpace { public:
FakeSpace(uint8_t* begin, uint8_t* end)
: ContinuousSpace("FakeSpace",
space::kGcRetentionPolicyNeverCollect,
begin,
end, /*limit=*/end) {}
EXPECT_EQ(image_header.GetImageSize(), kImageSize);
EXPECT_EQ(static_cast<size_t>(image_header.GetOatFileEnd() - image_header.GetOatFileBegin()),
kImageOatSize);
EXPECT_EQ(image_space->GetOatFile()->Size(), kImageOatSize); // Check that we do not include the oat if there is no space after.
{
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
spaces.AddSpace(image_space.get());
}
EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().Begin()),
image_space->Begin());
EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().End()),
image_space->Limit()); // Add another space and ensure it gets appended.
EXPECT_NE(image_space->Limit(), space.Begin());
{
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
spaces.AddSpace(&space);
}
EXPECT_TRUE(spaces.ContainsSpace(image_space.get()));
EXPECT_TRUE(spaces.ContainsSpace(&space)); // CreateLargestImmuneRegion should have coalesced the two spaces since the oat code after the // image prevents gaps. // Check that we have a continuous region.
EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().Begin()),
image_space->Begin());
EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().End()), space.Limit());
}
// Test [image1][image2][image1 oat][image2 oat][image3] producing a single large immune region.
TEST_F(ImmuneSpacesTest, MultiImage) {
ReserveBitmaps(); // Image 2 needs to be smaller or else it may be chosen for immune region.
constexpr size_t kImage1Size = kElfSegmentAlignment * 17;
constexpr size_t kImage2Size = kElfSegmentAlignment * 13;
constexpr size_t kImage3Size = kElfSegmentAlignment * 3;
constexpr size_t kImage1OatSize = kElfSegmentAlignment * 5;
constexpr size_t kImage2OatSize = kElfSegmentAlignment * 8;
constexpr size_t kImage3OatSize = kElfSegmentAlignment;
constexpr size_t kImageBytes = kImage1Size + kImage2Size + kImage3Size;
constexpr size_t kMemorySize = kImageBytes + kImage1OatSize + kImage2OatSize + kImage3OatSize;
std::string error_str;
MemMap reservation = ReserveImage(kMemorySize, &error_str);
ASSERT_TRUE(reservation.IsValid()) << "Failed to allocate memory region " << error_str;
MemMap image_reservation = reservation.TakeReservedMemory(kImage1Size + kImage2Size);
ASSERT_TRUE(image_reservation.IsValid());
ASSERT_TRUE(reservation.IsValid());
// Check that we do not include the oat if there is no space after.
ImmuneSpaces spaces;
{
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
LOG(INFO) << "Adding space1 " << reinterpret_cast<constvoid*>(space1->Begin());
spaces.AddSpace(space1.get());
LOG(INFO) << "Adding space2 " << reinterpret_cast<constvoid*>(space2->Begin());
spaces.AddSpace(space2.get());
} // There are no more heap bytes, the immune region should only be the first 2 image spaces and // should exclude the image oat files.
EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().Begin()),
space1->Begin());
EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().End()),
space2->Limit());
// Add another space after the oat files, now it should contain the entire memory region.
{
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
LOG(INFO) << "Adding space3 " << reinterpret_cast<constvoid*>(space3->Begin());
spaces.AddSpace(space3.get());
}
EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().Begin()),
space1->Begin());
EXPECT_EQ(reinterpret_cast<uint8_t*>(spaces.GetLargestImmuneRegion().End()),
space3->Limit());
// Add a smaller non-adjacent space and ensure it does not become part of the immune region. // Image size is kImageBytes - kElfSegmentAlignment // Oat size is kElfSegmentAlignment. // Guard pages to ensure it is not adjacent to an existing immune region. // Layout: [guard page][image][oat][guard page]
constexpr size_t kGuardSize = kElfSegmentAlignment;
constexpr size_t kImage4Size = kImageBytes - kElfSegmentAlignment;
constexpr size_t kImage4OatSize = kElfSegmentAlignment;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.