• 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/gc_bitset.h"
23 #include "ecmascript/mem/heap.h"
24 #include "ecmascript/mem/region-inl.h"
25 #include "ecmascript/mem/tlab_allocator-inl.h"
26 
27 namespace panda::ecmascript {
28 constexpr size_t HEAD_SIZE = TaggedObject::TaggedObjectSize();
29 
30 template <typename Callback>
VisitBodyInObj(TaggedObject * root,ObjectSlot start,ObjectSlot end,Callback callback)31 inline bool NonMovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback)
32 {
33     auto hclass = root->SynchronizedGetClass();
34     if (hclass->IsAllTaggedProp()) {
35         return false;
36     }
37     int index = 0;
38     for (ObjectSlot slot = start; slot < end; slot++) {
39         auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
40         auto attr = layout->GetAttr(index++);
41         if (attr.IsTaggedRep()) {
42             callback(slot);
43         }
44     }
45     return true;
46 }
47 
MarkValue(uint32_t threadId,ObjectSlot & slot,Region * rootRegion,bool needBarrier)48 inline void NonMovableMarker::MarkValue(uint32_t threadId, ObjectSlot &slot, Region *rootRegion, bool needBarrier)
49 {
50     JSTaggedValue value(slot.GetTaggedType());
51     if (value.IsHeapObject()) {
52         TaggedObject *obj = nullptr;
53         if (!value.IsWeakForHeapObject()) {
54             obj = value.GetTaggedObject();
55             MarkObject(threadId, obj);
56         } else {
57             RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), rootRegion);
58             obj = value.GetWeakReferentUnChecked();
59         }
60         if (needBarrier) {
61             Region *valueRegion = Region::ObjectAddressToRange(obj);
62             if (valueRegion->InCollectSet()) {
63                 rootRegion->AtomicInsertCrossRegionRSet(slot.SlotAddress());
64             }
65         }
66     }
67 }
68 
MarkObject(uint32_t threadId,TaggedObject * object)69 inline void NonMovableMarker::MarkObject(uint32_t threadId, TaggedObject *object)
70 {
71     Region *objectRegion = Region::ObjectAddressToRange(object);
72 
73     if (!heap_->IsFullMark() && !objectRegion->InYoungSpace()) {
74         return;
75     }
76 
77     if (objectRegion->AtomicMark(object)) {
78         workManager_->Push(threadId, object, objectRegion);
79     }
80 }
81 
HandleRoots(uint32_t threadId,Root type,ObjectSlot slot)82 inline void NonMovableMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
83 {
84     JSTaggedValue value(slot.GetTaggedType());
85     if (value.IsHeapObject()) {
86         MarkObject(threadId, value.GetTaggedObject());
87     }
88 }
89 
HandleRangeRoots(uint32_t threadId,Root type,ObjectSlot start,ObjectSlot end)90 inline void NonMovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
91     ObjectSlot end)
92 {
93     for (ObjectSlot slot = start; slot < end; slot++) {
94         JSTaggedValue value(slot.GetTaggedType());
95         if (value.IsHeapObject()) {
96             if (value.IsWeakForHeapObject()) {
97                 LOG_ECMA_MEM(FATAL) << "Weak Reference in NonMovableMarker roots";
98             }
99             MarkObject(threadId, value.GetTaggedObject());
100         }
101     }
102 }
103 
HandleDerivedRoots(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)104 inline void NonMovableMarker::HandleDerivedRoots([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base,
105                                                  [[maybe_unused]] ObjectSlot derived,
106                                                  [[maybe_unused]] uintptr_t baseOldObject)
107 {
108     // It is only used to update the derived value. The mark of partial GC does not need to update slot
109 }
110 
HandleOldToNewRSet(uint32_t threadId,Region * region)111 inline void NonMovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *region)
112 {
113     region->IterateAllOldToNewBits([this, threadId, &region](void *mem) -> bool {
114         ObjectSlot slot(ToUintPtr(mem));
115         JSTaggedValue value(slot.GetTaggedType());
116         if (value.IsHeapObject()) {
117             if (value.IsWeakForHeapObject()) {
118                 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
119             } else {
120                 MarkObject(threadId, value.GetTaggedObject());
121             }
122         }
123         return true;
124     });
125 }
126 
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)127 inline void NonMovableMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref, Region *objectRegion)
128 {
129     auto value = JSTaggedValue(*ref);
130     Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
131     if (!objectRegion->InYoungSpaceOrCSet() && !valueRegion->InYoungSpaceOrCSet()) {
132         workManager_->PushWeakReference(threadId, ref);
133     }
134 }
135 
136 template <typename Callback>
VisitBodyInObj(TaggedObject * root,ObjectSlot start,ObjectSlot end,Callback callback)137 inline bool MovableMarker::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback)
138 {
139     auto hclass = root->GetClass();
140     if (hclass->IsAllTaggedProp()) {
141         return false;
142     }
143     int index = 0;
144     for (ObjectSlot slot = start; slot < end; slot++) {
145         TaggedObject *dst = hclass->GetLayout().GetTaggedObject();
146         MarkWord markWord(dst);
147         if (markWord.IsForwardingAddress()) {
148             dst = markWord.ToForwardingAddress();
149         }
150         auto layout = LayoutInfo::Cast(dst);
151         auto attr = layout->GetAttr(index++);
152         if (attr.IsTaggedRep()) {
153             callback(slot);
154         }
155     }
156     return true;
157 }
158 
HandleRoots(uint32_t threadId,Root type,ObjectSlot slot)159 inline void MovableMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
160 {
161     JSTaggedValue value(slot.GetTaggedType());
162     if (value.IsHeapObject()) {
163         MarkObject(threadId, value.GetTaggedObject(), slot);
164     }
165 }
166 
HandleRangeRoots(uint32_t threadId,Root type,ObjectSlot start,ObjectSlot end)167 inline void MovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
168     ObjectSlot end)
169 {
170     for (ObjectSlot slot = start; slot < end; slot++) {
171         JSTaggedValue value(slot.GetTaggedType());
172         if (value.IsHeapObject()) {
173             if (value.IsWeakForHeapObject()) {
174                 Region *objectRegion = Region::ObjectAddressToRange(start.SlotAddress());
175                 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), objectRegion);
176             } else {
177                 MarkObject(threadId, value.GetTaggedObject(), slot);
178             }
179         }
180     }
181 }
182 
HandleDerivedRoots(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)183 inline void MovableMarker::HandleDerivedRoots([[maybe_unused]] Root type, ObjectSlot base,
184                                               ObjectSlot derived, uintptr_t baseOldObject)
185 {
186     if (JSTaggedValue(base.GetTaggedType()).IsHeapObject()) {
187         derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject);
188     }
189 }
190 
HandleOldToNewRSet(uint32_t threadId,Region * region)191 inline void MovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *region)
192 {
193     region->IterateAllOldToNewBits([this, threadId, &region](void *mem) -> bool {
194         ObjectSlot slot(ToUintPtr(mem));
195         JSTaggedValue value(slot.GetTaggedType());
196         if (value.IsHeapObject()) {
197             if (value.IsWeakForHeapObject()) {
198                 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
199                 return true;
200             }
201             auto slotStatus = MarkObject(threadId, value.GetTaggedObject(), slot);
202             if (slotStatus == SlotStatus::CLEAR_SLOT) {
203                 return false;
204             }
205         }
206         return true;
207     });
208 }
209 
AllocateDstSpace(uint32_t threadId,size_t size,bool & shouldPromote)210 inline uintptr_t MovableMarker::AllocateDstSpace(uint32_t threadId, size_t size, bool &shouldPromote)
211 {
212     uintptr_t forwardAddress = 0;
213     if (shouldPromote) {
214         forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, COMPRESS_SPACE);
215         if (UNLIKELY(forwardAddress == 0)) {
216             LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
217                                 << " size: " << size;
218             UNREACHABLE();
219         }
220     } else {
221         forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, SEMI_SPACE);
222         if (UNLIKELY(forwardAddress == 0)) {
223             forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, COMPRESS_SPACE);
224             if (UNLIKELY(forwardAddress == 0)) {
225                 LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
226                                     << " size: " << size;
227                 UNREACHABLE();
228             }
229             shouldPromote = true;
230         }
231     }
232     return forwardAddress;
233 }
234 
UpdateForwardAddressIfSuccess(uint32_t threadId,TaggedObject * object,JSHClass * klass,uintptr_t toAddress,size_t size,const MarkWord & markWord,ObjectSlot slot,bool isPromoted)235 inline void MovableMarker::UpdateForwardAddressIfSuccess(uint32_t threadId, TaggedObject *object, JSHClass *klass,
236     uintptr_t toAddress, size_t size, const MarkWord &markWord, ObjectSlot slot, bool isPromoted)
237 {
238     if (memcpy_s(ToVoidPtr(toAddress + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(ToUintPtr(object) + HEAD_SIZE),
239         size - HEAD_SIZE) != EOK) {
240         LOG_FULL(FATAL) << "memcpy_s failed";
241     }
242     workManager_->IncreaseAliveSize(threadId, size);
243     if (isPromoted) {
244         workManager_->IncreasePromotedSize(threadId, size);
245     }
246 
247     *reinterpret_cast<MarkWordType *>(toAddress) = markWord.GetValue();
248     heap_->OnMoveEvent(reinterpret_cast<intptr_t>(object), reinterpret_cast<TaggedObject *>(toAddress), size);
249     if (klass->HasReferenceField()) {
250         workManager_->Push(threadId, reinterpret_cast<TaggedObject *>(toAddress));
251     }
252     slot.Update(reinterpret_cast<TaggedObject *>(toAddress));
253 }
254 
UpdateForwardAddressIfFailed(TaggedObject * object,uintptr_t toAddress,size_t size,ObjectSlot slot)255 inline bool MovableMarker::UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size,
256     ObjectSlot slot)
257 {
258     FreeObject::FillFreeObject(heap_->GetEcmaVM(), toAddress, size);
259     TaggedObject *dst = MarkWord(object).ToForwardingAddress();
260     slot.Update(dst);
261     return Region::ObjectAddressToRange(dst)->InYoungSpace();
262 }
263 
MarkValue(uint32_t threadId,TaggedObject * root,ObjectSlot slot)264 inline void SemiGCMarker::MarkValue(uint32_t threadId, TaggedObject *root, ObjectSlot slot)
265 {
266     JSTaggedValue value(slot.GetTaggedType());
267     if (value.IsHeapObject()) {
268         Region *rootRegion = Region::ObjectAddressToRange(root);
269         if (value.IsWeakForHeapObject()) {
270             RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), rootRegion);
271             return;
272         }
273         auto slotStatus = MarkObject(threadId, value.GetTaggedObject(), slot);
274         if (!rootRegion->InYoungSpace() && slotStatus == SlotStatus::KEEP_SLOT) {
275             SlotNeedUpdate waitUpdate(reinterpret_cast<TaggedObject *>(root), slot);
276             workManager_->PushSlotNeedUpdate(threadId, waitUpdate);
277         }
278     }
279 }
280 
MarkObject(uint32_t threadId,TaggedObject * object,ObjectSlot slot)281 inline SlotStatus SemiGCMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot slot)
282 {
283     Region *objectRegion = Region::ObjectAddressToRange(object);
284     if (!objectRegion->InYoungSpace()) {
285         return SlotStatus::CLEAR_SLOT;
286     }
287 
288     MarkWord markWord(object);
289     if (markWord.IsForwardingAddress()) {
290         TaggedObject *dst = markWord.ToForwardingAddress();
291         slot.Update(dst);
292         Region *valueRegion = Region::ObjectAddressToRange(dst);
293         return valueRegion->InYoungSpace() ? SlotStatus::KEEP_SLOT : SlotStatus::CLEAR_SLOT;
294     }
295     return EvacuateObject(threadId, object, markWord, slot);
296 }
297 
EvacuateObject(uint32_t threadId,TaggedObject * object,const MarkWord & markWord,ObjectSlot slot)298 inline SlotStatus SemiGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord,
299     ObjectSlot slot)
300 {
301     JSHClass *klass = markWord.GetJSHClass();
302     size_t size = klass->SizeFromJSHClass(object);
303     bool isPromoted = ShouldBePromoted(object);
304 
305     uintptr_t forwardAddress = AllocateDstSpace(threadId, size, isPromoted);
306     bool result = Barriers::AtomicSetPrimitive(object, 0, markWord.GetValue(),
307                                                MarkWord::FromForwardingAddress(forwardAddress));
308     if (result) {
309         UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, markWord, slot, isPromoted);
310         return isPromoted ? SlotStatus::CLEAR_SLOT : SlotStatus::KEEP_SLOT;
311     }
312     bool keepSlot = UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
313     return keepSlot ? SlotStatus::KEEP_SLOT : SlotStatus::CLEAR_SLOT;
314 }
315 
ShouldBePromoted(TaggedObject * object)316 inline bool SemiGCMarker::ShouldBePromoted(TaggedObject *object)
317 {
318     Region *region = Region::ObjectAddressToRange(object);
319     return (region->BelowAgeMark() || (region->HasAgeMark() && ToUintPtr(object) < waterLine_));
320 }
321 
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)322 inline void SemiGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref,
323                                               [[maybe_unused]] Region *objectRegion)
324 {
325     auto value = JSTaggedValue(*ref);
326     Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
327     if (valueRegion->InYoungSpace()) {
328         workManager_->PushWeakReference(threadId, ref);
329     }
330 }
331 
MarkValue(uint32_t threadId,ObjectSlot slot)332 inline void CompressGCMarker::MarkValue(uint32_t threadId, ObjectSlot slot)
333 {
334     JSTaggedValue value(slot.GetTaggedType());
335     if (value.IsHeapObject()) {
336         if (value.IsWeakForHeapObject()) {
337             // It is unnecessary to use region pointer in compressGCMarker.
338             RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()));
339             return;
340         }
341         MarkObject(threadId, value.GetTaggedObject(), slot);
342     }
343 }
344 
MarkObject(uint32_t threadId,TaggedObject * object,ObjectSlot slot)345 inline SlotStatus CompressGCMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot slot)
346 {
347     Region *objectRegion = Region::ObjectAddressToRange(object);
348     if (!NeedEvacuate(objectRegion)) {
349         if (objectRegion->AtomicMark(object)) {
350             workManager_->Push(threadId, object);
351         }
352         return SlotStatus::CLEAR_SLOT;
353     }
354 
355     MarkWord markWord(object);
356     if (markWord.IsForwardingAddress()) {
357         TaggedObject *dst = markWord.ToForwardingAddress();
358         slot.Update(dst);
359         return SlotStatus::CLEAR_SLOT;
360     }
361     return EvacuateObject(threadId, object, markWord, slot);
362 }
363 
AllocateReadOnlySpace(size_t size)364 inline uintptr_t CompressGCMarker::AllocateReadOnlySpace(size_t size)
365 {
366     os::memory::LockHolder lock(mutex_);
367     uintptr_t forwardAddress = heap_->GetReadOnlySpace()->Allocate(size);
368     if (UNLIKELY(forwardAddress == 0)) {
369         LOG_ECMA_MEM(FATAL) << "Evacuate Read only Object: alloc failed: "
370                             << " size: " << size;
371         UNREACHABLE();
372     }
373     return forwardAddress;
374 }
375 
AllocateAppSpawnSpace(size_t size)376 inline uintptr_t CompressGCMarker::AllocateAppSpawnSpace(size_t size)
377 {
378     os::memory::LockHolder lock(mutex_);
379     uintptr_t forwardAddress = heap_->GetAppSpawnSpace()->Allocate(size);
380     if (UNLIKELY(forwardAddress == 0)) {
381         LOG_ECMA_MEM(FATAL) << "Evacuate AppSpawn Object: alloc failed: "
382                             << " size: " << size;
383         UNREACHABLE();
384     }
385     return forwardAddress;
386 }
387 
EvacuateObject(uint32_t threadId,TaggedObject * object,const MarkWord & markWord,ObjectSlot slot)388 inline SlotStatus CompressGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord,
389     ObjectSlot slot)
390 {
391     JSHClass *klass = markWord.GetJSHClass();
392     size_t size = klass->SizeFromJSHClass(object);
393     uintptr_t forwardAddress = AllocateForwardAddress(threadId, size, klass, object);
394     bool result = Barriers::AtomicSetPrimitive(object, 0, markWord.GetValue(),
395                                                MarkWord::FromForwardingAddress(forwardAddress));
396     if (result) {
397         UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, markWord, slot);
398         if (isAppSpawn_ && klass->IsString()) {
399             // calculate and set hashcode for read-only ecmastring in advance
400             EcmaStringAccessor(reinterpret_cast<TaggedObject *>(forwardAddress)).GetHashcode();
401         }
402         return SlotStatus::CLEAR_SLOT;
403     }
404     UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
405     return SlotStatus::CLEAR_SLOT;
406 }
407 
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)408 inline void CompressGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref,
409                                                   [[maybe_unused]] Region *objectRegion)
410 {
411     workManager_->PushWeakReference(threadId, ref);
412 }
413 
NeedEvacuate(Region * region)414 inline bool CompressGCMarker::NeedEvacuate(Region *region)
415 {
416     if (isAppSpawn_) {
417         return !region->InHugeObjectSpace()  && !region->InReadOnlySpace() && !region->InNonMovableSpace();
418     }
419     return region->InYoungOrOldSpace();
420 }
421 }  // namespace panda::ecmascript
422 #endif  // ECMASCRIPT_MEM_PARALLEL_MARKER_INL_H
423