1// Copyright 2020 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/heap/concurrent-allocator.h" 6 7#include "src/common/globals.h" 8#include "src/execution/isolate.h" 9#include "src/handles/persistent-handles.h" 10#include "src/heap/concurrent-allocator-inl.h" 11#include "src/heap/heap.h" 12#include "src/heap/local-heap-inl.h" 13#include "src/heap/local-heap.h" 14#include "src/heap/marking.h" 15#include "src/heap/memory-chunk.h" 16#include "src/heap/parked-scope.h" 17 18namespace v8 { 19namespace internal { 20 21void StressConcurrentAllocatorTask::RunInternal() { 22 Heap* heap = isolate_->heap(); 23 LocalHeap local_heap(heap, ThreadKind::kBackground); 24 UnparkedScope unparked_scope(&local_heap); 25 26 const int kNumIterations = 2000; 27 const int kSmallObjectSize = 10 * kTaggedSize; 28 const int kMediumObjectSize = 8 * KB; 29 const int kLargeObjectSize = 30 static_cast<int>(MemoryChunk::kPageSize - 31 MemoryChunkLayout::ObjectStartOffsetInDataPage()); 32 33 for (int i = 0; i < kNumIterations; i++) { 34 // Isolate tear down started, stop allocation... 35 if (heap->gc_state() == Heap::TEAR_DOWN) return; 36 37 AllocationResult result = local_heap.AllocateRaw( 38 kSmallObjectSize, AllocationType::kOld, AllocationOrigin::kRuntime, 39 AllocationAlignment::kTaggedAligned); 40 if (!result.IsFailure()) { 41 heap->CreateFillerObjectAtBackground( 42 result.ToAddress(), kSmallObjectSize, 43 ClearFreedMemoryMode::kDontClearFreedMemory); 44 } else { 45 local_heap.TryPerformCollection(); 46 } 47 48 result = local_heap.AllocateRaw(kMediumObjectSize, AllocationType::kOld, 49 AllocationOrigin::kRuntime, 50 AllocationAlignment::kTaggedAligned); 51 if (!result.IsFailure()) { 52 heap->CreateFillerObjectAtBackground( 53 result.ToAddress(), kMediumObjectSize, 54 ClearFreedMemoryMode::kDontClearFreedMemory); 55 } else { 56 local_heap.TryPerformCollection(); 57 } 58 59 result = local_heap.AllocateRaw(kLargeObjectSize, AllocationType::kOld, 60 AllocationOrigin::kRuntime, 61 AllocationAlignment::kTaggedAligned); 62 if (!result.IsFailure()) { 63 heap->CreateFillerObjectAtBackground( 64 result.ToAddress(), kLargeObjectSize, 65 ClearFreedMemoryMode::kDontClearFreedMemory); 66 } else { 67 local_heap.TryPerformCollection(); 68 } 69 local_heap.Safepoint(); 70 } 71 72 Schedule(isolate_); 73} 74 75// static 76void StressConcurrentAllocatorTask::Schedule(Isolate* isolate) { 77 auto task = std::make_unique<StressConcurrentAllocatorTask>(isolate); 78 const double kDelayInSeconds = 0.1; 79 V8::GetCurrentPlatform()->CallDelayedOnWorkerThread(std::move(task), 80 kDelayInSeconds); 81} 82 83void ConcurrentAllocator::FreeLinearAllocationArea() { 84 // The code page of the linear allocation area needs to be unprotected 85 // because we are going to write a filler into that memory area below. 86 base::Optional<CodePageMemoryModificationScope> optional_scope; 87 if (lab_.IsValid() && space_->identity() == CODE_SPACE) { 88 optional_scope.emplace(MemoryChunk::FromAddress(lab_.top())); 89 } 90 lab_.CloseAndMakeIterable(); 91} 92 93void ConcurrentAllocator::MakeLinearAllocationAreaIterable() { 94 // The code page of the linear allocation area needs to be unprotected 95 // because we are going to write a filler into that memory area below. 96 base::Optional<CodePageMemoryModificationScope> optional_scope; 97 if (lab_.IsValid() && space_->identity() == CODE_SPACE) { 98 optional_scope.emplace(MemoryChunk::FromAddress(lab_.top())); 99 } 100 lab_.MakeIterable(); 101} 102 103void ConcurrentAllocator::MarkLinearAllocationAreaBlack() { 104 Address top = lab_.top(); 105 Address limit = lab_.limit(); 106 107 if (top != kNullAddress && top != limit) { 108 Page::FromAllocationAreaAddress(top)->CreateBlackAreaBackground(top, limit); 109 } 110} 111 112void ConcurrentAllocator::UnmarkLinearAllocationArea() { 113 Address top = lab_.top(); 114 Address limit = lab_.limit(); 115 116 if (top != kNullAddress && top != limit) { 117 Page::FromAllocationAreaAddress(top)->DestroyBlackAreaBackground(top, 118 limit); 119 } 120} 121 122AllocationResult ConcurrentAllocator::AllocateInLabSlow( 123 int object_size, AllocationAlignment alignment, AllocationOrigin origin) { 124 if (!EnsureLab(origin)) { 125 return AllocationResult::Failure(); 126 } 127 128 AllocationResult allocation = lab_.AllocateRawAligned(object_size, alignment); 129 DCHECK(!allocation.IsFailure()); 130 131 return allocation; 132} 133 134bool ConcurrentAllocator::EnsureLab(AllocationOrigin origin) { 135 auto result = space_->RawRefillLabBackground( 136 local_heap_, kLabSize, kMaxLabSize, kTaggedAligned, origin); 137 if (!result) return false; 138 139 if (IsBlackAllocationEnabled()) { 140 Address top = result->first; 141 Address limit = top + result->second; 142 Page::FromAllocationAreaAddress(top)->CreateBlackAreaBackground(top, limit); 143 } 144 145 HeapObject object = HeapObject::FromAddress(result->first); 146 LocalAllocationBuffer saved_lab = std::move(lab_); 147 lab_ = LocalAllocationBuffer::FromResult( 148 space_->heap(), AllocationResult::FromObject(object), result->second); 149 DCHECK(lab_.IsValid()); 150 if (!lab_.TryMerge(&saved_lab)) { 151 saved_lab.CloseAndMakeIterable(); 152 } 153 return true; 154} 155 156AllocationResult ConcurrentAllocator::AllocateOutsideLab( 157 int object_size, AllocationAlignment alignment, AllocationOrigin origin) { 158 auto result = space_->RawRefillLabBackground(local_heap_, object_size, 159 object_size, alignment, origin); 160 if (!result) return AllocationResult::Failure(); 161 162 HeapObject object = HeapObject::FromAddress(result->first); 163 164 if (IsBlackAllocationEnabled()) { 165 owning_heap()->incremental_marking()->MarkBlackBackground(object, 166 object_size); 167 } 168 169 return AllocationResult::FromObject(object); 170} 171 172bool ConcurrentAllocator::IsBlackAllocationEnabled() const { 173 return owning_heap()->incremental_marking()->black_allocation(); 174} 175 176Heap* ConcurrentAllocator::owning_heap() const { return space_->heap(); } 177 178} // namespace internal 179} // namespace v8 180