// Copyright 2018 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/init/isolate-allocator.h" #include "src/base/bounded-page-allocator.h" #include "src/common/ptr-compr.h" #include "src/execution/isolate.h" #include "src/utils/utils.h" namespace v8 { namespace internal { IsolateAllocator::IsolateAllocator(IsolateAllocationMode mode) { #if V8_TARGET_ARCH_64_BIT if (mode == IsolateAllocationMode::kInV8Heap) { Address heap_reservation_address = InitReservation(); CommitPagesForIsolate(heap_reservation_address); return; } #endif // V8_TARGET_ARCH_64_BIT // Allocate Isolate in C++ heap. CHECK_EQ(mode, IsolateAllocationMode::kInCppHeap); page_allocator_ = GetPlatformPageAllocator(); isolate_memory_ = ::operator new(sizeof(Isolate)); DCHECK(!reservation_.IsReserved()); } IsolateAllocator::~IsolateAllocator() { if (reservation_.IsReserved()) { // The actual memory will be freed when the |reservation_| will die. return; } // The memory was allocated in C++ heap. ::operator delete(isolate_memory_); } #if V8_TARGET_ARCH_64_BIT Address IsolateAllocator::InitReservation() { v8::PageAllocator* platform_page_allocator = GetPlatformPageAllocator(); // Reserve a 4Gb region so that the middle is 4Gb aligned. // The VirtualMemory API does not support such an constraint so we have to // implement it manually here. size_t reservation_size = kPtrComprHeapReservationSize; size_t base_alignment = kPtrComprIsolateRootAlignment; const int kMaxAttempts = 3; for (int attempt = 0; attempt < kMaxAttempts; ++attempt) { Address hint = RoundDown(reinterpret_cast
( platform_page_allocator->GetRandomMmapAddr()), base_alignment) + kPtrComprIsolateRootBias; // Within this reservation there will be a sub-region with proper alignment. VirtualMemory padded_reservation(platform_page_allocator, reservation_size * 2, reinterpret_cast(hint)); if (!padded_reservation.IsReserved()) break; // Find such a sub-region inside the reservation that it's middle is // |base_alignment|-aligned. Address address = RoundUp(padded_reservation.address() + kPtrComprIsolateRootBias, base_alignment) - kPtrComprIsolateRootBias; CHECK(padded_reservation.InVM(address, reservation_size)); #if defined(V8_OS_FUCHSIA) // Fuchsia does not respect given hints so as a workaround we will use // overreserved address space region instead of trying to re-reserve // a subregion. if (padded_reservation.InVM(address, reservation_size)) { reservation_ = std::move(padded_reservation); return address; } #else // Now free the padded reservation and immediately try to reserve an exact // region at aligned address. We have to do this dancing because the // reservation address requirement is more complex than just a certain // alignment and not all operating systems support freeing parts of reserved // address space regions. padded_reservation.Free(); VirtualMemory reservation(platform_page_allocator, reservation_size, reinterpret_cast(address)); if (!reservation.IsReserved()) break; // The reservation could still be somewhere else but we can accept it // if the reservation has the required alignment. Address aligned_address = RoundUp(reservation.address() + kPtrComprIsolateRootBias, base_alignment) - kPtrComprIsolateRootBias; if (reservation.address() == aligned_address) { reservation_ = std::move(reservation); CHECK_EQ(reservation_.size(), reservation_size); return aligned_address; } #endif } V8::FatalProcessOutOfMemory(nullptr, "Failed to reserve memory for new V8 Isolate"); return kNullAddress; } void IsolateAllocator::CommitPagesForIsolate(Address heap_address) { CHECK(reservation_.InVM(heap_address, kPtrComprHeapReservationSize)); Address isolate_root = heap_address + kPtrComprIsolateRootBias; CHECK(IsAligned(isolate_root, kPtrComprIsolateRootAlignment)); v8::PageAllocator* platform_page_allocator = GetPlatformPageAllocator(); // Simplify BoundedPageAllocator's life by configuring it to use same page // size as the Heap will use (MemoryChunk::kPageSize). size_t page_size = RoundUp(size_t{1} << kPageSizeBits, platform_page_allocator->AllocatePageSize()); page_allocator_instance_ = base::make_unique( platform_page_allocator, heap_address, kPtrComprHeapReservationSize, page_size); page_allocator_ = page_allocator_instance_.get(); Address isolate_address = isolate_root - Isolate::isolate_root_bias(); Address isolate_end = isolate_address + sizeof(Isolate); // Inform the bounded page allocator about reserved pages. { Address reserved_region_address = RoundDown(isolate_address, page_size); size_t reserved_region_size = RoundUp(isolate_end, page_size) - reserved_region_address; CHECK(page_allocator_instance_->AllocatePagesAt( reserved_region_address, reserved_region_size, PageAllocator::Permission::kNoAccess)); } // Commit pages where the Isolate will be stored. { size_t commit_page_size = platform_page_allocator->CommitPageSize(); Address committed_region_address = RoundDown(isolate_address, commit_page_size); size_t committed_region_size = RoundUp(isolate_end, commit_page_size) - committed_region_address; // We are using |reservation_| directly here because |page_allocator_| has // bigger commit page size than we actually need. CHECK(reservation_.SetPermissions(committed_region_address, committed_region_size, PageAllocator::kReadWrite)); if (Heap::ShouldZapGarbage()) { for (Address address = committed_region_address; address < committed_region_size; address += kSystemPointerSize) { base::Memory
(address) = static_cast
(kZapValue); } } } isolate_memory_ = reinterpret_cast(isolate_address); } #endif // V8_TARGET_ARCH_64_BIT } // namespace internal } // namespace v8