#include <map>
#include <optional>
#include "src/base/region-allocator.h"
#include "src/execution/isolate.h"
#include "src/heap/heap-inl.h"
#include "src/heap/memory-allocator.h"
#include "src/heap/spaces-inl.h"
#include "src/utils/ostreams.h"
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
class TrackingPageAllocator : public ::v8::PageAllocator { … };
#if !V8_OS_FUCHSIA && !V8_ENABLE_SANDBOX
template <typename TMixin>
class PoolTestMixin : public TMixin {
public:
PoolTestMixin();
~PoolTestMixin() override;
};
class PoolTest : public
WithInternalIsolateMixin<
WithIsolateScopeMixin<
WithIsolateMixin<
PoolTestMixin<
WithDefaultPlatformMixin<
::testing::Test>>>>> {
public:
PoolTest() = default;
~PoolTest() override = default;
PoolTest(const PoolTest&) = delete;
PoolTest& operator=(const PoolTest&) = delete;
static void FreeProcessWidePtrComprCageForTesting() {
IsolateGroup::ReleaseGlobal();
}
static void DoMixinSetUp() {
CHECK_NULL(tracking_page_allocator_);
old_page_allocator_ = GetPlatformPageAllocator();
tracking_page_allocator_ = new TrackingPageAllocator(old_page_allocator_);
CHECK(tracking_page_allocator_->IsEmpty());
CHECK_EQ(old_page_allocator_,
SetPlatformPageAllocatorForTesting(tracking_page_allocator_));
old_sweeping_flag_ = i::v8_flags.concurrent_sweeping;
i::v8_flags.concurrent_sweeping = false;
#ifndef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
FreeProcessWidePtrComprCageForTesting();
#ifdef V8_ENABLE_SANDBOX
GetProcessWideSandbox()->TearDown();
constexpr bool use_guard_regions = false;
CHECK(GetProcessWideSandbox()->Initialize(
tracking_page_allocator_, kSandboxMinimumSize, use_guard_regions));
#endif
IsolateGroup::InitializeOncePerProcess();
#endif
}
static void DoMixinTearDown() {
#ifndef V8_COMPRESS_POINTERS_IN_MULTIPLE_CAGES
FreeProcessWidePtrComprCageForTesting();
#endif
#ifdef V8_ENABLE_SANDBOX
GetProcessWideSandbox()->TearDown();
#endif
i::v8_flags.concurrent_sweeping = old_sweeping_flag_;
CHECK(tracking_page_allocator_->IsEmpty());
CHECK_EQ(tracking_page_allocator_,
SetPlatformPageAllocatorForTesting(old_page_allocator_));
delete tracking_page_allocator_;
tracking_page_allocator_ = nullptr;
}
Heap* heap() { return isolate()->heap(); }
MemoryAllocator* allocator() { return heap()->memory_allocator(); }
MemoryAllocator::Pool* pool() { return allocator()->pool(); }
TrackingPageAllocator* tracking_page_allocator() {
return tracking_page_allocator_;
}
private:
static TrackingPageAllocator* tracking_page_allocator_;
static v8::PageAllocator* old_page_allocator_;
static bool old_sweeping_flag_;
};
TrackingPageAllocator* PoolTest::tracking_page_allocator_ = nullptr;
v8::PageAllocator* PoolTest::old_page_allocator_ = nullptr;
bool PoolTest::old_sweeping_flag_;
template <typename TMixin>
PoolTestMixin<TMixin>::PoolTestMixin() {
PoolTest::DoMixinSetUp();
}
template <typename TMixin>
PoolTestMixin<TMixin>::~PoolTestMixin() {
PoolTest::DoMixinTearDown();
}
TEST_F(PoolTest, UnmapOnTeardown) {
PageMetadata* page =
allocator()->AllocatePage(MemoryAllocator::AllocationMode::kRegular,
static_cast<PagedSpace*>(heap()->old_space()),
Executability::NOT_EXECUTABLE);
Address chunk_address = page->ChunkAddress();
EXPECT_NE(nullptr, page);
const size_t page_size = tracking_page_allocator()->AllocatePageSize();
tracking_page_allocator()->CheckPagePermissions(chunk_address, page_size,
PageAllocator::kReadWrite);
allocator()->Free(MemoryAllocator::FreeMode::kPool, page);
tracking_page_allocator()->CheckPagePermissions(chunk_address, page_size,
PageAllocator::kReadWrite);
pool()->ReleasePooledChunks();
#ifdef V8_COMPRESS_POINTERS
tracking_page_allocator()->CheckPagePermissions(
chunk_address, page_size, PageAllocator::kNoAccess, false);
#else
tracking_page_allocator()->CheckIsFree(chunk_address, page_size);
#endif
}
#endif
}
}