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 #ifndef ECMASCRIPT_MEM_PARALLEL_MARKER_INL_H
17 #define ECMASCRIPT_MEM_PARALLEL_MARKER_INL_H
18
19 #include "ecmascript/mem/parallel_marker.h"
20
21 #include "ecmascript/js_hclass-inl.h"
22 #include "ecmascript/mem/heap.h"
23 #include "ecmascript/mem/parallel_work_helper.h"
24 #include "ecmascript/mem/region-inl.h"
25 #include "ecmascript/mem/tlab_allocator-inl.h"
26 #include "ecmascript/mem/utils.h"
27
28 #include "mem/gc/bitmap.h"
29
30 namespace panda::ecmascript {
31 constexpr int HEAD_SIZE = TaggedObject::TaggedObjectSize();
32
MarkObject(uint32_t threadId,TaggedObject * object)33 inline void NonMovableMarker::MarkObject(uint32_t threadId, TaggedObject *object)
34 {
35 Region *objectRegion = Region::ObjectAddressToRange(object);
36
37 if (!heap_->IsFullMark() && !objectRegion->InYoungGeneration()) {
38 return;
39 }
40
41 auto markBitmap = objectRegion->GetMarkBitmap();
42 ASSERT(markBitmap != nullptr);
43 if (!markBitmap->AtomicTestAndSet(object)) {
44 heap_->GetWorkList()->Push(threadId, object, objectRegion);
45 }
46 }
47
HandleRoots(uint32_t threadId,Root type,ObjectSlot slot)48 inline void NonMovableMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
49 {
50 JSTaggedValue value(slot.GetTaggedType());
51 if (value.IsHeapObject()) {
52 MarkObject(threadId, value.GetTaggedObject());
53 }
54 }
55
HandleRangeRoots(uint32_t threadId,Root type,ObjectSlot start,ObjectSlot end)56 inline void NonMovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
57 ObjectSlot end)
58 {
59 for (ObjectSlot slot = start; slot < end; slot++) {
60 JSTaggedValue value(slot.GetTaggedType());
61 if (value.IsHeapObject()) {
62 if (value.IsWeakForHeapObject()) {
63 Region *objectRegion = Region::ObjectAddressToRange(start.SlotAddress());
64 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), objectRegion);
65 continue;
66 }
67 MarkObject(threadId, value.GetTaggedObject());
68 }
69 }
70 }
71
HandleOldToNewRSet(uint32_t threadId,Region * region)72 inline void NonMovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *region)
73 {
74 auto oldRSet = region->GetOldToNewRememberedSet();
75 if (LIKELY(oldRSet != nullptr)) {
76 oldRSet->IterateOverMarkedChunks([this, threadId, ®ion](void *mem) -> bool {
77 ObjectSlot slot(ToUintPtr(mem));
78 JSTaggedValue value(slot.GetTaggedType());
79 if (value.IsHeapObject()) {
80 if (value.IsWeakForHeapObject()) {
81 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
82 } else {
83 MarkObject(threadId, value.GetTaggedObject());
84 }
85 }
86 return true;
87 });
88 }
89 }
90
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)91 inline void NonMovableMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref, Region *objectRegion)
92 {
93 auto value = JSTaggedValue(*ref);
94 Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
95 if (!objectRegion->InYoungOrCSetGeneration() && !valueRegion->InYoungOrCSetGeneration()) {
96 heap_->GetWorkList()->PushWeakReference(threadId, ref);
97 }
98 }
99
HandleRoots(uint32_t threadId,Root type,ObjectSlot slot)100 inline void MovableMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
101 {
102 JSTaggedValue value(slot.GetTaggedType());
103 if (value.IsHeapObject()) {
104 MarkObject(threadId, value.GetTaggedObject(), slot);
105 }
106 }
107
HandleRangeRoots(uint32_t threadId,Root type,ObjectSlot start,ObjectSlot end)108 inline void MovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
109 ObjectSlot end)
110 {
111 for (ObjectSlot slot = start; slot < end; slot++) {
112 JSTaggedValue value(slot.GetTaggedType());
113 if (value.IsHeapObject()) {
114 if (value.IsWeakForHeapObject()) {
115 Region *objectRegion = Region::ObjectAddressToRange(start.SlotAddress());
116 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), objectRegion);
117 } else {
118 MarkObject(threadId, value.GetTaggedObject(), slot);
119 }
120 }
121 }
122 }
123
HandleOldToNewRSet(uint32_t threadId,Region * region)124 inline void MovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *region)
125 {
126 auto oldRSet = region->GetOldToNewRememberedSet();
127 if (LIKELY(oldRSet != nullptr)) {
128 oldRSet->IterateOverMarkedChunks([this, &oldRSet, threadId, ®ion](void *mem) -> bool {
129 ObjectSlot slot(ToUintPtr(mem));
130 JSTaggedValue value(slot.GetTaggedType());
131 if (value.IsHeapObject()) {
132 if (value.IsWeakForHeapObject()) {
133 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
134 return true;
135 }
136 auto slotStatus = MarkObject(threadId, value.GetTaggedObject(), slot);
137 if (slotStatus == SlotStatus::CLEAR_SLOT) {
138 oldRSet->Clear(ToUintPtr(mem));
139 }
140 }
141 return true;
142 });
143 }
144 }
145
AllocateDstSpace(uint32_t threadId,size_t size,bool & shouldPromote)146 inline uintptr_t MovableMarker::AllocateDstSpace(uint32_t threadId, size_t size, bool &shouldPromote)
147 {
148 uintptr_t forwardAddress = 0;
149 if (shouldPromote) {
150 forwardAddress = heap_->GetWorkList()->GetTlabAllocator(threadId)->Allocate(size, COMPRESS_SPACE);
151 if (UNLIKELY(forwardAddress == 0)) {
152 LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
153 << " size: " << size;
154 UNREACHABLE();
155 }
156 } else {
157 forwardAddress = heap_->GetWorkList()->GetTlabAllocator(threadId)->Allocate(size, SEMI_SPACE);
158 if (UNLIKELY(forwardAddress == 0)) {
159 forwardAddress = heap_->GetWorkList()->GetTlabAllocator(threadId)->Allocate(size, COMPRESS_SPACE);
160 if (UNLIKELY(forwardAddress == 0)) {
161 LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
162 << " size: " << size;
163 UNREACHABLE();
164 }
165 shouldPromote = true;
166 }
167 }
168 return forwardAddress;
169 }
170
UpdateForwardAddressIfSuccess(uint32_t threadId,TaggedObject * object,JSHClass * klass,uintptr_t toAddress,size_t size,const MarkWord & markWord,ObjectSlot slot)171 inline void MovableMarker::UpdateForwardAddressIfSuccess(uint32_t threadId, TaggedObject *object, JSHClass *klass,
172 uintptr_t toAddress, size_t size, const MarkWord &markWord, ObjectSlot slot)
173 {
174 Utils::Copy(ToVoidPtr(toAddress + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(ToUintPtr(object) + HEAD_SIZE),
175 size - HEAD_SIZE);
176 heap_->GetWorkList()->AddAliveSize(threadId, size);
177 *reinterpret_cast<MarkWordType *>(toAddress) = markWord.GetValue();
178 heap_->OnMoveEvent(reinterpret_cast<intptr_t>(object), toAddress);
179 if (klass->HasReferenceField()) {
180 heap_->GetWorkList()->Push(threadId, reinterpret_cast<TaggedObject *>(toAddress));
181 }
182 slot.Update(reinterpret_cast<TaggedObject *>(toAddress));
183 }
184
UpdateForwardAddressIfFailed(TaggedObject * object,uintptr_t toAddress,size_t size,ObjectSlot slot)185 inline bool MovableMarker::UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size,
186 ObjectSlot slot)
187 {
188 FreeObject::FillFreeObject(heap_->GetEcmaVM(), toAddress, size);
189 TaggedObject *dst = MarkWord(object).ToForwardingAddress();
190 slot.Update(dst);
191 return Region::ObjectAddressToRange(dst)->InYoungGeneration();
192 }
193
MarkObject(uint32_t threadId,TaggedObject * object,ObjectSlot slot)194 inline SlotStatus SemiGcMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot slot)
195 {
196 Region *objectRegion = Region::ObjectAddressToRange(object);
197 if (!objectRegion->InYoungGeneration()) {
198 return SlotStatus::CLEAR_SLOT;
199 }
200
201 MarkWord markWord(object);
202 if (markWord.IsForwardingAddress()) {
203 TaggedObject *dst = markWord.ToForwardingAddress();
204 slot.Update(dst);
205 Region *valueRegion = Region::ObjectAddressToRange(dst);
206 return valueRegion->InYoungGeneration() ? SlotStatus::KEEP_SLOT : SlotStatus::CLEAR_SLOT;
207 }
208 return EvacuateObject(threadId, object, markWord, slot);
209 }
210
EvacuateObject(uint32_t threadId,TaggedObject * object,const MarkWord & markWord,ObjectSlot slot)211 inline SlotStatus SemiGcMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord,
212 ObjectSlot slot)
213 {
214 JSHClass *klass = markWord.GetJSHClass();
215 size_t size = klass->SizeFromJSHClass(object);
216 bool isPromoted = ShouldBePromoted(object);
217
218 uintptr_t forwardAddress = AllocateDstSpace(threadId, size, isPromoted);
219 bool result = Barriers::AtomicSetDynPrimitive(object, 0, markWord.GetValue(),
220 MarkWord::FromForwardingAddress(forwardAddress));
221 if (result) {
222 UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, markWord, slot);
223 return isPromoted ? SlotStatus::CLEAR_SLOT : SlotStatus::KEEP_SLOT;
224 }
225 bool keepSlot = UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
226 return keepSlot ? SlotStatus::KEEP_SLOT : SlotStatus::CLEAR_SLOT;
227 }
228
ShouldBePromoted(TaggedObject * object)229 inline bool SemiGcMarker::ShouldBePromoted(TaggedObject *object)
230 {
231 Region *region = Region::ObjectAddressToRange(object);
232 return (region->BelowAgeMark() || (region->HasAgeMark() && ToUintPtr(object) < waterLine_));
233 }
234
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)235 inline void SemiGcMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref,
236 [[maybe_unused]] Region *objectRegion)
237 {
238 auto value = JSTaggedValue(*ref);
239 Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
240 if (valueRegion->InYoungGeneration()) {
241 heap_->GetWorkList()->PushWeakReference(threadId, ref);
242 }
243 }
244
MarkObject(uint32_t threadId,TaggedObject * object,ObjectSlot slot)245 inline SlotStatus CompressGcMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot slot)
246 {
247 Region *objectRegion = Region::ObjectAddressToRange(object);
248 if (!objectRegion->InYoungAndOldGeneration()) {
249 auto markBitmap = objectRegion->GetMarkBitmap();
250 if (!markBitmap->AtomicTestAndSet(object)) {
251 heap_->GetWorkList()->Push(threadId, object);
252 }
253 return SlotStatus::CLEAR_SLOT;
254 }
255
256 MarkWord markWord(object);
257 if (markWord.IsForwardingAddress()) {
258 TaggedObject *dst = markWord.ToForwardingAddress();
259 slot.Update(dst);
260 return SlotStatus::CLEAR_SLOT;
261 }
262 return EvacuateObject(threadId, object, markWord, slot);
263 }
264
EvacuateObject(uint32_t threadId,TaggedObject * object,const MarkWord & markWord,ObjectSlot slot)265 inline SlotStatus CompressGcMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord,
266 ObjectSlot slot)
267 {
268 JSHClass *klass = markWord.GetJSHClass();
269 size_t size = klass->SizeFromJSHClass(object);
270 bool isPromoted = true;
271
272 uintptr_t forwardAddress = AllocateDstSpace(threadId, size, isPromoted);
273 bool result = Barriers::AtomicSetDynPrimitive(object, 0, markWord.GetValue(),
274 MarkWord::FromForwardingAddress(forwardAddress));
275 if (result) {
276 UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, markWord, slot);
277 return SlotStatus::CLEAR_SLOT;
278 }
279 UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
280 return SlotStatus::CLEAR_SLOT;
281 }
282
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)283 inline void CompressGcMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref,
284 [[maybe_unused]] Region *objectRegion)
285 {
286 heap_->GetWorkList()->PushWeakReference(threadId, ref);
287 }
288 } // namespace panda::ecmascript
289 #endif // ECMASCRIPT_MEM_PARALLEL_MARKER_INL_H
290