|  | // Copyright 2020 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. | 
|  |  | 
|  | #if !defined(CPPGC_CAGED_HEAP) | 
|  | #error "Must be compiled with caged heap enabled" | 
|  | #endif | 
|  |  | 
|  | #include "src/heap/cppgc/caged-heap.h" | 
|  |  | 
|  | #include "include/cppgc/internal/caged-heap-local-data.h" | 
|  | #include "src/base/bounded-page-allocator.h" | 
|  | #include "src/base/logging.h" | 
|  | #include "src/heap/cppgc/globals.h" | 
|  |  | 
|  | namespace cppgc { | 
|  | namespace internal { | 
|  |  | 
|  | STATIC_ASSERT(api_constants::kCagedHeapReservationSize == | 
|  | kCagedHeapReservationSize); | 
|  | STATIC_ASSERT(api_constants::kCagedHeapReservationAlignment == | 
|  | kCagedHeapReservationAlignment); | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | VirtualMemory ReserveCagedHeap(PageAllocator* platform_allocator) { | 
|  | DCHECK_NOT_NULL(platform_allocator); | 
|  | DCHECK_EQ(0u, | 
|  | kCagedHeapReservationSize % platform_allocator->AllocatePageSize()); | 
|  |  | 
|  | static constexpr size_t kAllocationTries = 4; | 
|  | for (size_t i = 0; i < kAllocationTries; ++i) { | 
|  | void* hint = reinterpret_cast<void*>(RoundDown( | 
|  | reinterpret_cast<uintptr_t>(platform_allocator->GetRandomMmapAddr()), | 
|  | kCagedHeapReservationAlignment)); | 
|  |  | 
|  | VirtualMemory memory(platform_allocator, kCagedHeapReservationSize, | 
|  | kCagedHeapReservationAlignment, hint); | 
|  | if (memory.IsReserved()) return memory; | 
|  | } | 
|  |  | 
|  | FATAL("Fatal process out of memory: Failed to reserve memory for caged heap"); | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | CagedHeap::CagedHeap(HeapBase* heap_base, PageAllocator* platform_allocator) | 
|  | : reserved_area_(ReserveCagedHeap(platform_allocator)) { | 
|  | using CagedAddress = CagedHeap::AllocatorType::Address; | 
|  |  | 
|  | DCHECK_NOT_NULL(heap_base); | 
|  |  | 
|  | CHECK(platform_allocator->SetPermissions( | 
|  | reserved_area_.address(), | 
|  | RoundUp(sizeof(CagedHeapLocalData), platform_allocator->CommitPageSize()), | 
|  | PageAllocator::kReadWrite)); | 
|  |  | 
|  | auto* local_data = | 
|  | new (reserved_area_.address()) CagedHeapLocalData(heap_base); | 
|  | #if defined(CPPGC_YOUNG_GENERATION) | 
|  | local_data->age_table.Reset(platform_allocator); | 
|  | #endif | 
|  | USE(local_data); | 
|  |  | 
|  | const CagedAddress caged_heap_start = | 
|  | RoundUp(reinterpret_cast<CagedAddress>(reserved_area_.address()) + | 
|  | sizeof(CagedHeapLocalData), | 
|  | kPageSize); | 
|  | const size_t local_data_size_with_padding = | 
|  | caged_heap_start - | 
|  | reinterpret_cast<CagedAddress>(reserved_area_.address()); | 
|  |  | 
|  | bounded_allocator_ = std::make_unique<CagedHeap::AllocatorType>( | 
|  | platform_allocator, caged_heap_start, | 
|  | reserved_area_.size() - local_data_size_with_padding, kPageSize); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace cppgc |