• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &region](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, &region](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