• 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 
MarkObject(uint32_t threadId,TaggedObject * object)30 inline void NonMovableMarker::MarkObject(uint32_t threadId, TaggedObject *object)
31 {
32     Region *objectRegion = Region::ObjectAddressToRange(object);
33 
34     if (!heap_->IsFullMark() && !objectRegion->InYoungSpace()) {
35         return;
36     }
37 
38     if (objectRegion->AtomicMark(object)) {
39         workManager_->Push(threadId, object, objectRegion);
40     }
41 }
42 
HandleRoots(uint32_t threadId,Root type,ObjectSlot slot)43 inline void NonMovableMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
44 {
45     JSTaggedValue value(slot.GetTaggedType());
46     if (value.IsHeapObject()) {
47         MarkObject(threadId, value.GetTaggedObject());
48     }
49 }
50 
HandleRangeRoots(uint32_t threadId,Root type,ObjectSlot start,ObjectSlot end)51 inline void NonMovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
52     ObjectSlot end)
53 {
54     for (ObjectSlot slot = start; slot < end; slot++) {
55         JSTaggedValue value(slot.GetTaggedType());
56         if (value.IsHeapObject()) {
57             if (value.IsWeakForHeapObject()) {
58                 LOG_ECMA_MEM(FATAL) << "Weak Reference in NonMovableMarker roots";
59             }
60             MarkObject(threadId, value.GetTaggedObject());
61         }
62     }
63 }
64 
HandleDerivedRoots(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)65 inline void NonMovableMarker::HandleDerivedRoots([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base,
66                                                  [[maybe_unused]] ObjectSlot derived,
67                                                  [[maybe_unused]] uintptr_t baseOldObject)
68 {
69     // It is only used to update the derived value. The mark of partial GC does not need to update slot
70 }
71 
HandleOldToNewRSet(uint32_t threadId,Region * region)72 inline void NonMovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *region)
73 {
74     region->IterateAllOldToNewBits([this, threadId, &region](void *mem) -> bool {
75         ObjectSlot slot(ToUintPtr(mem));
76         JSTaggedValue value(slot.GetTaggedType());
77         if (value.IsHeapObject()) {
78             if (value.IsInvalidValue()) {
79                 LOG_ECMA_MEM(INFO) << "HandleOldToNew found an invalid value: " << value.GetRawData()
80                                    << " " << slot.GetTaggedType();
81                 return true;
82             }
83             if (value.IsWeakForHeapObject()) {
84                 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
85             } else {
86                 MarkObject(threadId, value.GetTaggedObject());
87             }
88             if (value.GetRawData() != slot.GetTaggedType()) {
89                 LOG_ECMA_MEM(INFO) << "HandleOldToNew mark an overdue value : " << value.GetRawData() << " "
90                                    << slot.GetTaggedType() << " "
91                                    << *reinterpret_cast<JSTaggedType*>(value.GetRawData());
92             }
93         }
94         return true;
95     });
96 }
97 
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)98 inline void NonMovableMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref, Region *objectRegion)
99 {
100     auto value = JSTaggedValue(*ref);
101     Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
102     if (!objectRegion->InYoungSpaceOrCSet() && !valueRegion->InYoungSpaceOrCSet()) {
103         workManager_->PushWeakReference(threadId, ref);
104     }
105 }
106 
HandleRoots(uint32_t threadId,Root type,ObjectSlot slot)107 inline void MovableMarker::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
108 {
109     JSTaggedValue value(slot.GetTaggedType());
110     if (value.IsHeapObject()) {
111         MarkObject(threadId, value.GetTaggedObject(), slot);
112     }
113 }
114 
HandleRangeRoots(uint32_t threadId,Root type,ObjectSlot start,ObjectSlot end)115 inline void MovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
116     ObjectSlot end)
117 {
118     for (ObjectSlot slot = start; slot < end; slot++) {
119         JSTaggedValue value(slot.GetTaggedType());
120         if (value.IsHeapObject()) {
121             if (value.IsWeakForHeapObject()) {
122                 Region *objectRegion = Region::ObjectAddressToRange(start.SlotAddress());
123                 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()), objectRegion);
124             } else {
125                 MarkObject(threadId, value.GetTaggedObject(), slot);
126             }
127         }
128     }
129 }
130 
HandleDerivedRoots(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)131 inline void MovableMarker::HandleDerivedRoots([[maybe_unused]] Root type, ObjectSlot base,
132                                               ObjectSlot derived, uintptr_t baseOldObject)
133 {
134     if (JSTaggedValue(base.GetTaggedType()).IsHeapObject()) {
135         derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject);
136     }
137 }
138 
HandleOldToNewRSet(uint32_t threadId,Region * region)139 inline void MovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *region)
140 {
141     region->IterateAllOldToNewBits([this, threadId, &region](void *mem) -> bool {
142         ObjectSlot slot(ToUintPtr(mem));
143         JSTaggedValue value(slot.GetTaggedType());
144         if (value.IsHeapObject()) {
145             if (value.IsWeakForHeapObject()) {
146                 RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem), region);
147                 return true;
148             }
149             auto slotStatus = MarkObject(threadId, value.GetTaggedObject(), slot);
150             if (slotStatus == SlotStatus::CLEAR_SLOT) {
151                 return false;
152             }
153         }
154         return true;
155     });
156 }
157 
AllocateDstSpace(uint32_t threadId,size_t size,bool & shouldPromote)158 inline uintptr_t MovableMarker::AllocateDstSpace(uint32_t threadId, size_t size, bool &shouldPromote)
159 {
160     uintptr_t forwardAddress = 0;
161     if (shouldPromote) {
162         forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, COMPRESS_SPACE);
163         if (UNLIKELY(forwardAddress == 0)) {
164             LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
165                                 << " size: " << size;
166             UNREACHABLE();
167         }
168     } else {
169         forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, SEMI_SPACE);
170         if (UNLIKELY(forwardAddress == 0)) {
171             forwardAddress = workManager_->GetTlabAllocator(threadId)->Allocate(size, COMPRESS_SPACE);
172             if (UNLIKELY(forwardAddress == 0)) {
173                 LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
174                                     << " size: " << size;
175                 UNREACHABLE();
176             }
177             shouldPromote = true;
178         }
179     }
180     return forwardAddress;
181 }
182 
UpdateForwardAddressIfSuccess(uint32_t threadId,TaggedObject * object,JSHClass * klass,uintptr_t toAddress,size_t size,const MarkWord & markWord,ObjectSlot slot,bool isPromoted)183 inline void MovableMarker::UpdateForwardAddressIfSuccess(uint32_t threadId, TaggedObject *object, JSHClass *klass,
184     uintptr_t toAddress, size_t size, const MarkWord &markWord, ObjectSlot slot, bool isPromoted)
185 {
186     if (memcpy_s(ToVoidPtr(toAddress + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(ToUintPtr(object) + HEAD_SIZE),
187         size - HEAD_SIZE) != EOK) {
188         LOG_FULL(FATAL) << "memcpy_s failed";
189     }
190     workManager_->IncreaseAliveSize(threadId, size);
191     if (isPromoted) {
192         workManager_->IncreasePromotedSize(threadId, size);
193     }
194 
195     *reinterpret_cast<MarkWordType *>(toAddress) = markWord.GetValue();
196     heap_->OnMoveEvent(reinterpret_cast<intptr_t>(object), reinterpret_cast<TaggedObject *>(toAddress), size);
197     if (klass->HasReferenceField()) {
198         workManager_->Push(threadId, reinterpret_cast<TaggedObject *>(toAddress));
199     }
200     slot.Update(reinterpret_cast<TaggedObject *>(toAddress));
201 }
202 
UpdateForwardAddressIfFailed(TaggedObject * object,uintptr_t toAddress,size_t size,ObjectSlot slot)203 inline bool MovableMarker::UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size,
204     ObjectSlot slot)
205 {
206     FreeObject::FillFreeObject(heap_->GetEcmaVM(), toAddress, size);
207     TaggedObject *dst = MarkWord(object).ToForwardingAddress();
208     slot.Update(dst);
209     return Region::ObjectAddressToRange(dst)->InYoungSpace();
210 }
211 
MarkObject(uint32_t threadId,TaggedObject * object,ObjectSlot slot)212 inline SlotStatus SemiGCMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot slot)
213 {
214     Region *objectRegion = Region::ObjectAddressToRange(object);
215     if (!objectRegion->InYoungSpace()) {
216         return SlotStatus::CLEAR_SLOT;
217     }
218 
219     MarkWord markWord(object);
220     if (markWord.IsForwardingAddress()) {
221         TaggedObject *dst = markWord.ToForwardingAddress();
222         slot.Update(dst);
223         Region *valueRegion = Region::ObjectAddressToRange(dst);
224         return valueRegion->InYoungSpace() ? SlotStatus::KEEP_SLOT : SlotStatus::CLEAR_SLOT;
225     }
226     return EvacuateObject(threadId, object, markWord, slot);
227 }
228 
EvacuateObject(uint32_t threadId,TaggedObject * object,const MarkWord & markWord,ObjectSlot slot)229 inline SlotStatus SemiGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord,
230     ObjectSlot slot)
231 {
232     JSHClass *klass = markWord.GetJSHClass();
233     size_t size = klass->SizeFromJSHClass(object);
234     bool isPromoted = ShouldBePromoted(object);
235 
236     uintptr_t forwardAddress = AllocateDstSpace(threadId, size, isPromoted);
237     bool result = Barriers::AtomicSetPrimitive(object, 0, markWord.GetValue(),
238                                                   MarkWord::FromForwardingAddress(forwardAddress));
239     if (result) {
240         UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, markWord, slot, isPromoted);
241         return isPromoted ? SlotStatus::CLEAR_SLOT : SlotStatus::KEEP_SLOT;
242     }
243     bool keepSlot = UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
244     return keepSlot ? SlotStatus::KEEP_SLOT : SlotStatus::CLEAR_SLOT;
245 }
246 
ShouldBePromoted(TaggedObject * object)247 inline bool SemiGCMarker::ShouldBePromoted(TaggedObject *object)
248 {
249     Region *region = Region::ObjectAddressToRange(object);
250     return (region->BelowAgeMark() || (region->HasAgeMark() && ToUintPtr(object) < waterLine_));
251 }
252 
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)253 inline void SemiGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref,
254                                               [[maybe_unused]] Region *objectRegion)
255 {
256     auto value = JSTaggedValue(*ref);
257     Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
258     if (valueRegion->InYoungSpace()) {
259         workManager_->PushWeakReference(threadId, ref);
260     }
261 }
262 
MarkObject(uint32_t threadId,TaggedObject * object,ObjectSlot slot)263 inline SlotStatus CompressGCMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot slot)
264 {
265     Region *objectRegion = Region::ObjectAddressToRange(object);
266     if (!NeedEvacuate(objectRegion)) {
267         if (objectRegion->AtomicMark(object)) {
268             workManager_->Push(threadId, object);
269         }
270         return SlotStatus::CLEAR_SLOT;
271     }
272 
273     MarkWord markWord(object);
274     if (markWord.IsForwardingAddress()) {
275         TaggedObject *dst = markWord.ToForwardingAddress();
276         slot.Update(dst);
277         return SlotStatus::CLEAR_SLOT;
278     }
279     return EvacuateObject(threadId, object, markWord, slot);
280 }
281 
AllocateReadOnlySpace(size_t size)282 inline uintptr_t CompressGCMarker::AllocateReadOnlySpace(size_t size)
283 {
284     os::memory::LockHolder lock(mutex_);
285     uintptr_t forwardAddress = heap_->GetReadOnlySpace()->Allocate(size);
286     if (UNLIKELY(forwardAddress == 0)) {
287         LOG_ECMA_MEM(FATAL) << "Evacuate Read only Object: alloc failed: "
288                             << " size: " << size;
289         UNREACHABLE();
290     }
291     return forwardAddress;
292 }
293 
AllocateAppSpawnSpace(size_t size)294 inline uintptr_t CompressGCMarker::AllocateAppSpawnSpace(size_t size)
295 {
296     os::memory::LockHolder lock(mutex_);
297     uintptr_t forwardAddress = heap_->GetAppSpawnSpace()->Allocate(size);
298     if (UNLIKELY(forwardAddress == 0)) {
299         LOG_ECMA_MEM(FATAL) << "Evacuate AppSpawn Object: alloc failed: "
300                             << " size: " << size;
301         UNREACHABLE();
302     }
303     return forwardAddress;
304 }
305 
EvacuateObject(uint32_t threadId,TaggedObject * object,const MarkWord & markWord,ObjectSlot slot)306 inline SlotStatus CompressGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *object, const MarkWord &markWord,
307     ObjectSlot slot)
308 {
309     JSHClass *klass = markWord.GetJSHClass();
310     size_t size = klass->SizeFromJSHClass(object);
311     uintptr_t forwardAddress = AllocateForwardAddress(threadId, size, klass, object);
312     bool result = Barriers::AtomicSetPrimitive(object, 0, markWord.GetValue(),
313                                                MarkWord::FromForwardingAddress(forwardAddress));
314     if (result) {
315         UpdateForwardAddressIfSuccess(threadId, object, klass, forwardAddress, size, markWord, slot);
316         if (isAppSpawn_ && klass->IsString()) {
317             // calculate and set hashcode for read-only ecmastring in advance
318             EcmaStringAccessor(reinterpret_cast<TaggedObject *>(forwardAddress)).GetHashcode();
319         }
320         return SlotStatus::CLEAR_SLOT;
321     }
322     UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
323     return SlotStatus::CLEAR_SLOT;
324 }
325 
RecordWeakReference(uint32_t threadId,JSTaggedType * ref,Region * objectRegion)326 inline void CompressGCMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref,
327                                                   [[maybe_unused]] Region *objectRegion)
328 {
329     workManager_->PushWeakReference(threadId, ref);
330 }
331 
NeedEvacuate(Region * region)332 inline bool CompressGCMarker::NeedEvacuate(Region *region)
333 {
334     if (isAppSpawn_) {
335         return !region->InHugeObjectSpace()  && !region->InReadOnlySpace() && !region->InNonMovableSpace();
336     }
337     return region->InYoungOrOldSpace();
338 }
339 }  // namespace panda::ecmascript
340 #endif  // ECMASCRIPT_MEM_PARALLEL_MARKER_INL_H
341