// 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. #include "src/heap/concurrent-allocator.h" #include "src/common/globals.h" #include "src/execution/isolate.h" #include "src/handles/persistent-handles.h" #include "src/heap/concurrent-allocator-inl.h" #include "src/heap/heap.h" #include "src/heap/local-heap-inl.h" #include "src/heap/local-heap.h" #include "src/heap/marking.h" #include "src/heap/memory-chunk.h" #include "src/heap/parked-scope.h" namespace v8 { namespace internal { void StressConcurrentAllocatorTask::RunInternal() { Heap* heap = isolate_->heap(); LocalHeap local_heap(heap, ThreadKind::kBackground); UnparkedScope unparked_scope(&local_heap); const int kNumIterations = 2000; const int kSmallObjectSize = 10 * kTaggedSize; const int kMediumObjectSize = 8 * KB; const int kLargeObjectSize = static_cast<int>(MemoryChunk::kPageSize - MemoryChunkLayout::ObjectStartOffsetInDataPage()); for (int i = 0; i < kNumIterations; i++) { // Isolate tear down started, stop allocation... if (heap->gc_state() == Heap::TEAR_DOWN) return; AllocationResult result = local_heap.AllocateRaw( kSmallObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, AllocationAlignment::kWordAligned); if (!result.IsRetry()) { heap->CreateFillerObjectAtBackground( result.ToAddress(), kSmallObjectSize, ClearFreedMemoryMode::kDontClearFreedMemory); } else { local_heap.TryPerformCollection(); } result = local_heap.AllocateRaw(kMediumObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, AllocationAlignment::kWordAligned); if (!result.IsRetry()) { heap->CreateFillerObjectAtBackground( result.ToAddress(), kMediumObjectSize, ClearFreedMemoryMode::kDontClearFreedMemory); } else { local_heap.TryPerformCollection(); } result = local_heap.AllocateRaw(kLargeObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, AllocationAlignment::kWordAligned); if (!result.IsRetry()) { heap->CreateFillerObjectAtBackground( result.ToAddress(), kLargeObjectSize, ClearFreedMemoryMode::kDontClearFreedMemory); } else { local_heap.TryPerformCollection(); } local_heap.Safepoint(); } Schedule(isolate_); } // static void StressConcurrentAllocatorTask::Schedule(Isolate* isolate) { auto task = std::make_unique<StressConcurrentAllocatorTask>(isolate); const double kDelayInSeconds = 0.1; V8::GetCurrentPlatform()->CallDelayedOnWorkerThread(std::move(task), kDelayInSeconds); } void ConcurrentAllocator::FreeLinearAllocationArea() { lab_.CloseAndMakeIterable(); } void ConcurrentAllocator::MakeLinearAllocationAreaIterable() { lab_.MakeIterable(); } void ConcurrentAllocator::MarkLinearAllocationAreaBlack() { Address top = lab_.top(); Address limit = lab_.limit(); if (top != kNullAddress && top != limit) { Page::FromAllocationAreaAddress(top)->CreateBlackAreaBackground(top, limit); } } void ConcurrentAllocator::UnmarkLinearAllocationArea() { Address top = lab_.top(); Address limit = lab_.limit(); if (top != kNullAddress && top != limit) { Page::FromAllocationAreaAddress(top)->DestroyBlackAreaBackground(top, limit); } } AllocationResult ConcurrentAllocator::AllocateInLabSlow( int object_size, AllocationAlignment alignment, AllocationOrigin origin) { if (!EnsureLab(origin)) { return AllocationResult::Retry(OLD_SPACE); } AllocationResult allocation = lab_.AllocateRawAligned(object_size, alignment); DCHECK(!allocation.IsRetry()); return allocation; } bool ConcurrentAllocator::EnsureLab(AllocationOrigin origin) { auto result = space_->RawRefillLabBackground( local_heap_, kLabSize, kMaxLabSize, kWordAligned, origin); if (!result) return false; if (local_heap_->heap()->incremental_marking()->black_allocation()) { Address top = result->first; Address limit = top + result->second; Page::FromAllocationAreaAddress(top)->CreateBlackAreaBackground(top, limit); } HeapObject object = HeapObject::FromAddress(result->first); LocalAllocationBuffer saved_lab = std::move(lab_); lab_ = LocalAllocationBuffer::FromResult( local_heap_->heap(), AllocationResult(object), result->second); DCHECK(lab_.IsValid()); if (!lab_.TryMerge(&saved_lab)) { saved_lab.CloseAndMakeIterable(); } return true; } AllocationResult ConcurrentAllocator::AllocateOutsideLab( int object_size, AllocationAlignment alignment, AllocationOrigin origin) { auto result = space_->RawRefillLabBackground(local_heap_, object_size, object_size, alignment, origin); if (!result) return AllocationResult::Retry(OLD_SPACE); HeapObject object = HeapObject::FromAddress(result->first); if (local_heap_->heap()->incremental_marking()->black_allocation()) { local_heap_->heap()->incremental_marking()->MarkBlackBackground( object, object_size); } return AllocationResult(object); } } // namespace internal } // namespace v8