Line data Source code
1 : // Copyright 2017 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 : #ifndef V8_HEAP_LOCAL_ALLOCATOR_H_
6 : #define V8_HEAP_LOCAL_ALLOCATOR_H_
7 :
8 : #include "src/globals.h"
9 : #include "src/heap/heap.h"
10 : #include "src/heap/spaces.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 : // Allocator encapsulating thread-local allocation. Assumes that all other
16 : // allocations also go through LocalAllocator.
17 200936 : class LocalAllocator {
18 : public:
19 : static const int kLabSize = 32 * KB;
20 : static const int kMaxLabObjectSize = 8 * KB;
21 :
22 200936 : explicit LocalAllocator(Heap* heap)
23 : : heap_(heap),
24 : new_space_(heap->new_space()),
25 : compaction_spaces_(heap),
26 : new_space_lab_(LocalAllocationBuffer::InvalidBuffer()),
27 301404 : lab_allocation_will_fail_(false) {}
28 :
29 : // Needs to be called from the main thread to finalize this LocalAllocator.
30 100468 : void Finalize() {
31 200936 : heap_->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE));
32 100468 : heap_->code_space()->MergeCompactionSpace(
33 200936 : compaction_spaces_.Get(CODE_SPACE));
34 : // Give back remaining LAB space if this LocalAllocator's new space LAB
35 : // sits right next to new space allocation top.
36 100468 : const AllocationInfo info = new_space_lab_.Close();
37 100468 : const Address top = new_space_->top();
38 100468 : if (info.limit() != nullptr && info.limit() == top) {
39 : DCHECK_NOT_NULL(info.top());
40 56045 : *new_space_->allocation_top_address() = info.top();
41 : }
42 100468 : }
43 :
44 136360982 : AllocationResult Allocate(AllocationSpace space, int object_size,
45 : AllocationAlignment alignment) {
46 136360982 : switch (space) {
47 : case NEW_SPACE:
48 77849066 : return AllocateInNewSpace(object_size, alignment);
49 : case OLD_SPACE:
50 58510723 : return compaction_spaces_.Get(OLD_SPACE)->AllocateRaw(object_size,
51 58520190 : alignment);
52 : case CODE_SPACE:
53 1193 : return compaction_spaces_.Get(CODE_SPACE)
54 1193 : ->AllocateRaw(object_size, alignment);
55 : default:
56 0 : UNREACHABLE();
57 : break;
58 : }
59 : }
60 :
61 1178817 : void FreeLast(AllocationSpace space, HeapObject* object, int object_size) {
62 1178817 : switch (space) {
63 : case NEW_SPACE:
64 549469 : FreeLastInNewSpace(object, object_size);
65 549178 : return;
66 : case OLD_SPACE:
67 629348 : FreeLastInOldSpace(object, object_size);
68 629081 : return;
69 : default:
70 : // Only new and old space supported.
71 0 : UNREACHABLE();
72 : break;
73 : }
74 : }
75 :
76 145631 : void AnnounceLockedPage(MemoryChunk* chunk) {
77 145631 : const AllocationSpace space = chunk->owner()->identity();
78 : // There are no allocations on large object and map space and hence we
79 : // cannot announce that we locked a page there.
80 291259 : if (space == LO_SPACE || space == MAP_SPACE) return;
81 :
82 : DCHECK(space != NEW_SPACE);
83 107371 : compaction_spaces_.Get(space)->AnnounceLockedPage(
84 : reinterpret_cast<Page*>(chunk));
85 : }
86 :
87 : private:
88 77856790 : AllocationResult AllocateInNewSpace(int object_size,
89 : AllocationAlignment alignment) {
90 77856790 : if (object_size > kMaxLabObjectSize) {
91 272289 : return new_space_->AllocateRawSynchronized(object_size, alignment);
92 : }
93 77584501 : return AllocateInLAB(object_size, alignment);
94 : }
95 :
96 639557 : inline bool NewLocalAllocationBuffer() {
97 639557 : if (lab_allocation_will_fail_) return false;
98 186061 : LocalAllocationBuffer saved_lab_ = new_space_lab_;
99 : AllocationResult result =
100 186055 : new_space_->AllocateRawSynchronized(kLabSize, kWordAligned);
101 372164 : new_space_lab_ = LocalAllocationBuffer::FromResult(heap_, result, kLabSize);
102 186079 : if (new_space_lab_.IsValid()) {
103 : new_space_lab_.TryMerge(&saved_lab_);
104 : return true;
105 : }
106 206 : new_space_lab_ = saved_lab_;
107 206 : lab_allocation_will_fail_ = true;
108 206 : return false;
109 : }
110 :
111 77595139 : AllocationResult AllocateInLAB(int object_size,
112 : AllocationAlignment alignment) {
113 : AllocationResult allocation;
114 77595139 : if (!new_space_lab_.IsValid() && !NewLocalAllocationBuffer()) {
115 : return AllocationResult::Retry(OLD_SPACE);
116 : }
117 77593495 : allocation = new_space_lab_.AllocateRawAligned(object_size, alignment);
118 77588099 : if (allocation.IsRetry()) {
119 568584 : if (!NewLocalAllocationBuffer()) {
120 : return AllocationResult::Retry(OLD_SPACE);
121 : } else {
122 116540 : allocation = new_space_lab_.AllocateRawAligned(object_size, alignment);
123 116540 : CHECK(!allocation.IsRetry());
124 : }
125 : }
126 77136055 : return allocation;
127 : }
128 :
129 549481 : void FreeLastInNewSpace(HeapObject* object, int object_size) {
130 549481 : if (!new_space_lab_.TryFreeLast(object, object_size)) {
131 : // We couldn't free the last object so we have to write a proper filler.
132 : heap_->CreateFillerObjectAt(object->address(), object_size,
133 12 : ClearRecordedSlots::kNo);
134 : }
135 549481 : }
136 :
137 629356 : void FreeLastInOldSpace(HeapObject* object, int object_size) {
138 1258693 : if (!compaction_spaces_.Get(OLD_SPACE)->TryFreeLast(object, object_size)) {
139 : // We couldn't free the last object so we have to write a proper filler.
140 : heap_->CreateFillerObjectAt(object->address(), object_size,
141 0 : ClearRecordedSlots::kNo);
142 : }
143 629337 : }
144 :
145 : Heap* const heap_;
146 : NewSpace* const new_space_;
147 : CompactionSpaceCollection compaction_spaces_;
148 : LocalAllocationBuffer new_space_lab_;
149 : bool lab_allocation_will_fail_;
150 : };
151 :
152 : } // namespace internal
153 : } // namespace v8
154 :
155 : #endif // V8_HEAP_LOCAL_ALLOCATOR_H_
|