1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "runtime/include/mem/allocator-inl.h"
17 #include "runtime/mem/gc/g1/g1-allocator.h"
18 #include "runtime/mem/freelist_allocator-inl.h"
19 #include "runtime/mem/humongous_obj_allocator-inl.h"
20 #include "runtime/mem/pygote_space_allocator-inl.h"
21
22 namespace panda::mem {
23
24 template <MTModeT MTMode>
ObjectAllocatorG1(MemStatsType * mem_stats,bool create_pygote_space_allocator)25 ObjectAllocatorG1<MTMode>::ObjectAllocatorG1(MemStatsType *mem_stats, bool create_pygote_space_allocator)
26 : ObjectAllocatorGenBase(mem_stats, GCCollectMode::GC_ALL, create_pygote_space_allocator)
27 {
28 object_allocator_ = MakePandaUnique<ObjectAllocator>(mem_stats);
29 nonmovable_allocator_ = MakePandaUnique<NonMovableAllocator>(mem_stats, SpaceType::SPACE_TYPE_NON_MOVABLE_OBJECT);
30 humongous_object_allocator_ = MakePandaUnique<HumongousObjectAllocator>(mem_stats);
31 mem_stats_ = mem_stats;
32 }
33
34 template <MTModeT MTMode>
GetRegularObjectMaxSize()35 size_t ObjectAllocatorG1<MTMode>::GetRegularObjectMaxSize()
36 {
37 return ObjectAllocator::GetMaxRegularObjectSize();
38 }
39
40 template <MTModeT MTMode>
GetLargeObjectMaxSize()41 size_t ObjectAllocatorG1<MTMode>::GetLargeObjectMaxSize()
42 {
43 return ObjectAllocator::GetMaxRegularObjectSize();
44 }
45
46 template <MTModeT MTMode>
IsAddressInYoungSpace(uintptr_t address)47 bool ObjectAllocatorG1<MTMode>::IsAddressInYoungSpace(uintptr_t address)
48 {
49 (void)address;
50 return false;
51 }
52
53 template <MTModeT MTMode>
HasYoungSpace()54 bool ObjectAllocatorG1<MTMode>::HasYoungSpace()
55 {
56 return true;
57 }
58
59 template <MTModeT MTMode>
GetYoungSpaceMemRange()60 MemRange ObjectAllocatorG1<MTMode>::GetYoungSpaceMemRange()
61 {
62 return MemRange(0, 1);
63 }
64
65 template <MTModeT MTMode>
CreateNewTLAB(panda::ManagedThread * thread)66 TLAB *ObjectAllocatorG1<MTMode>::CreateNewTLAB([[maybe_unused]] panda::ManagedThread *thread)
67 {
68 return object_allocator_->CreateNewTLAB(thread, TLAB_SIZE);
69 }
70
71 template <MTModeT MTMode>
GetTLABMaxAllocSize()72 size_t ObjectAllocatorG1<MTMode>::GetTLABMaxAllocSize()
73 {
74 return PANDA_TLAB_MAX_ALLOC_SIZE;
75 }
76
77 template <MTModeT MTMode>
IterateOverObjectsInRange(MemRange mem_range,const ObjectVisitor & object_visitor)78 void ObjectAllocatorG1<MTMode>::IterateOverObjectsInRange(MemRange mem_range, const ObjectVisitor &object_visitor)
79 {
80 if (pygote_space_allocator_ != nullptr) {
81 pygote_space_allocator_->IterateOverObjectsInRange(object_visitor, ToVoidPtr(mem_range.GetStartAddress()),
82 ToVoidPtr(mem_range.GetEndAddress()));
83 }
84 humongous_object_allocator_->IterateOverObjectsInRange(object_visitor, ToVoidPtr(mem_range.GetStartAddress()),
85 ToVoidPtr(mem_range.GetEndAddress()));
86 }
87
88 // ObjectAllocatorGen and ObjectAllocatorNoGen should have inheritance relationship
89 template <MTModeT MTMode>
ContainObject(const ObjectHeader * obj) const90 bool ObjectAllocatorG1<MTMode>::ContainObject(const ObjectHeader *obj) const
91 {
92 if (pygote_space_allocator_ != nullptr && pygote_space_allocator_->ContainObject(obj)) {
93 return true;
94 }
95 if (object_allocator_->ContainObject(obj)) {
96 return true;
97 }
98 if (humongous_object_allocator_->ContainObject(obj)) {
99 return true;
100 }
101
102 return false;
103 }
104
105 template <MTModeT MTMode>
IsLive(const ObjectHeader * obj)106 bool ObjectAllocatorG1<MTMode>::IsLive(const ObjectHeader *obj)
107 {
108 if (pygote_space_allocator_ != nullptr && pygote_space_allocator_->ContainObject(obj)) {
109 return pygote_space_allocator_->IsLive(obj);
110 }
111 if (object_allocator_->ContainObject(obj)) {
112 return object_allocator_->IsLive(obj);
113 }
114 if (humongous_object_allocator_->ContainObject(obj)) {
115 return humongous_object_allocator_->IsLive(obj);
116 }
117
118 return false;
119 }
120
121 template <MTModeT MTMode>
Allocate(size_t size,Alignment align,panda::ManagedThread * thread)122 void *ObjectAllocatorG1<MTMode>::Allocate(size_t size, Alignment align, [[maybe_unused]] panda::ManagedThread *thread)
123 {
124 void *mem = nullptr;
125 size_t aligned_size = AlignUp(size, GetAlignmentInBytes(align));
126 if (LIKELY(aligned_size <= REGION_SIZE)) {
127 mem = object_allocator_->Alloc(size, align);
128 } else {
129 mem = AllocateTenured(size);
130 }
131 return mem;
132 }
133
134 template <MTModeT MTMode>
AllocateNonMovable(size_t size,Alignment align,panda::ManagedThread * thread)135 void *ObjectAllocatorG1<MTMode>::AllocateNonMovable(size_t size, Alignment align,
136 [[maybe_unused]] panda::ManagedThread *thread)
137 {
138 // before pygote fork, allocate small non-movable objects in pygote space
139 if (UNLIKELY(IsPygoteAllocEnabled() && pygote_space_allocator_->CanAllocNonMovable(size, align))) {
140 return pygote_space_allocator_->Alloc(size, align);
141 }
142 void *mem = nullptr;
143 size_t aligned_size = AlignUp(size, GetAlignmentInBytes(align));
144 if (aligned_size <= ObjectAllocator::GetMaxRegularObjectSize()) {
145 mem = nonmovable_allocator_->Alloc(aligned_size, align);
146 } else {
147 // We don't need special allocator for this
148 // Humongous objects are non-movable
149 size_t pool_size = std::max(PANDA_DEFAULT_POOL_SIZE, HumongousObjectAllocator::GetMinPoolSize(size));
150 mem = AllocateSafe(size, align, humongous_object_allocator_.get(), pool_size,
151 SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT);
152 }
153 return mem;
154 }
155
156 template <MTModeT MTMode>
AllocateTenured(size_t size)157 void *ObjectAllocatorG1<MTMode>::AllocateTenured(size_t size)
158 {
159 void *mem = nullptr;
160 Alignment align = DEFAULT_ALIGNMENT;
161 size_t aligned_size = AlignUp(size, GetAlignmentInBytes(align));
162 if (aligned_size <= ObjectAllocator::GetMaxRegularObjectSize()) {
163 mem = object_allocator_->Alloc<RegionFlag::IS_OLD>(size, align);
164 } else {
165 size_t pool_size = std::max(PANDA_DEFAULT_POOL_SIZE, HumongousObjectAllocator::GetMinPoolSize(size));
166 mem = AllocateSafe(size, align, humongous_object_allocator_.get(), pool_size,
167 SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT);
168 }
169 return mem;
170 }
171
172 template <MTModeT MTMode>
VisitAndRemoveAllPools(const MemVisitor & mem_visitor)173 void ObjectAllocatorG1<MTMode>::VisitAndRemoveAllPools(const MemVisitor &mem_visitor)
174 {
175 if (pygote_space_allocator_ != nullptr) {
176 pygote_space_allocator_->VisitAndRemoveAllPools(mem_visitor);
177 }
178 object_allocator_->VisitAndRemoveAllPools(mem_visitor);
179 humongous_object_allocator_->VisitAndRemoveAllPools(mem_visitor);
180 }
181
182 template <MTModeT MTMode>
VisitAndRemoveFreePools(const MemVisitor & mem_visitor)183 void ObjectAllocatorG1<MTMode>::VisitAndRemoveFreePools(const MemVisitor &mem_visitor)
184 {
185 if (pygote_space_allocator_ != nullptr) {
186 pygote_space_allocator_->VisitAndRemoveFreePools(mem_visitor);
187 }
188 humongous_object_allocator_->VisitAndRemoveFreePools(mem_visitor);
189 }
190
191 template <MTModeT MTMode>
IterateOverYoungObjects(const ObjectVisitor & object_visitor)192 void ObjectAllocatorG1<MTMode>::IterateOverYoungObjects(const ObjectVisitor &object_visitor)
193 {
194 // Use CompactAllSpecificRegions method to compact young regions.
195 (void)object_visitor;
196 UNREACHABLE();
197 }
198
199 template <MTModeT MTMode>
IterateOverTenuredObjects(const ObjectVisitor & object_visitor)200 void ObjectAllocatorG1<MTMode>::IterateOverTenuredObjects(const ObjectVisitor &object_visitor)
201 {
202 if (pygote_space_allocator_ != nullptr) {
203 pygote_space_allocator_->IterateOverObjects(object_visitor);
204 }
205 object_allocator_->IterateOverObjects(object_visitor);
206 humongous_object_allocator_->IterateOverObjects(object_visitor);
207 }
208
209 template <MTModeT MTMode>
IterateOverObjects(const ObjectVisitor & object_visitor)210 void ObjectAllocatorG1<MTMode>::IterateOverObjects(const ObjectVisitor &object_visitor)
211 {
212 if (pygote_space_allocator_ != nullptr) {
213 pygote_space_allocator_->IterateOverObjects(object_visitor);
214 }
215 object_allocator_->IterateOverObjects(object_visitor);
216 humongous_object_allocator_->IterateOverObjects(object_visitor);
217 }
218
219 template <MTModeT MTMode>
IterateRegularSizeObjects(const ObjectVisitor & object_visitor)220 void ObjectAllocatorG1<MTMode>::IterateRegularSizeObjects(const ObjectVisitor &object_visitor)
221 {
222 object_allocator_->IterateOverObjects(object_visitor);
223 }
224
225 template <MTModeT MTMode>
IterateNonRegularSizeObjects(const ObjectVisitor & object_visitor)226 void ObjectAllocatorG1<MTMode>::IterateNonRegularSizeObjects(const ObjectVisitor &object_visitor)
227 {
228 if (pygote_space_allocator_ != nullptr) {
229 pygote_space_allocator_->IterateOverObjects(object_visitor);
230 }
231 humongous_object_allocator_->IterateOverObjects(object_visitor);
232 }
233
234 template <MTModeT MTMode>
FreeObjectsMovedToPygoteSpace()235 void ObjectAllocatorG1<MTMode>::FreeObjectsMovedToPygoteSpace()
236 {
237 // Clear allocator because we have moved all objects in it to pygote space
238 object_allocator_.reset(new (std::nothrow) ObjectAllocator(mem_stats_));
239 }
240
241 template <MTModeT MTMode>
Collect(const GCObjectVisitor & gc_object_visitor,GCCollectMode collect_mode)242 void ObjectAllocatorG1<MTMode>::Collect(const GCObjectVisitor &gc_object_visitor, GCCollectMode collect_mode)
243 {
244 switch (collect_mode) {
245 case GCCollectMode::GC_MINOR:
246 break;
247 case GCCollectMode::GC_ALL:
248 case GCCollectMode::GC_MAJOR:
249 if (pygote_space_allocator_ != nullptr) {
250 pygote_space_allocator_->Collect(gc_object_visitor);
251 }
252 humongous_object_allocator_->Collect(gc_object_visitor);
253 break;
254 case GCCollectMode::GC_FULL:
255 UNREACHABLE();
256 break;
257 case GC_NONE:
258 UNREACHABLE();
259 break;
260 default:
261 UNREACHABLE();
262 }
263 }
264
265 template <MTModeT MTMode>
ResetYoungAllocator()266 void ObjectAllocatorG1<MTMode>::ResetYoungAllocator()
267 {
268 object_allocator_->ResetAllSpecificRegions<RegionFlag::IS_EDEN>();
269 }
270
271 template <MTModeT MTMode>
IsObjectInNonMovableSpace(const ObjectHeader * obj)272 bool ObjectAllocatorG1<MTMode>::IsObjectInNonMovableSpace(const ObjectHeader *obj)
273 {
274 return nonmovable_allocator_->ContainObject(obj);
275 }
276
277 template class ObjectAllocatorG1<MT_MODE_SINGLE>;
278 template class ObjectAllocatorG1<MT_MODE_MULTI>;
279
280 } // namespace panda::mem
281