• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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_SHARED_HEAP_SHARED_GC_MARKER_INL_H
17 #define ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_MARKER_INL_H
18 
19 #include "ecmascript/mem/shared_heap/shared_gc_marker.h"
20 
21 #include "ecmascript/js_hclass-inl.h"
22 #include "ecmascript/mem/heap-inl.h"
23 #include "ecmascript/mem/region-inl.h"
24 #include "ecmascript/mem/tlab_allocator-inl.h"
25 #include "ecmascript/runtime.h"
26 
27 namespace panda::ecmascript {
MarkObject(uint32_t threadId,TaggedObject * object,ObjectSlot & slot)28 inline void SharedGCMarker::MarkObject(uint32_t threadId, TaggedObject *object, [[maybe_unused]] ObjectSlot &slot)
29 {
30     Region *objectRegion = Region::ObjectAddressToRange(object);
31     ASSERT(objectRegion->InSharedHeap());
32     if (!objectRegion->InSharedReadOnlySpace() && objectRegion->AtomicMark(object)) {
33         ASSERT(objectRegion->InSharedSweepableSpace());
34         sWorkManager_->Push(threadId, object);
35     }
36 }
37 
MarkObjectFromJSThread(WorkNode * & localBuffer,TaggedObject * object)38 inline void SharedGCMarkerBase::MarkObjectFromJSThread(WorkNode *&localBuffer, TaggedObject *object)
39 {
40     Region *objectRegion = Region::ObjectAddressToRange(object);
41     ASSERT(objectRegion->InSharedHeap());
42     if (!objectRegion->InSharedReadOnlySpace() && objectRegion->AtomicMark(object)) {
43         sWorkManager_->PushToLocalMarkingBuffer(localBuffer, object);
44     }
45 }
46 
MarkValue(uint32_t threadId,ObjectSlot & slot)47 inline void SharedGCMarker::MarkValue(uint32_t threadId, ObjectSlot &slot)
48 {
49     JSTaggedValue value(slot.GetTaggedType());
50     if (value.IsInSharedSweepableSpace()) {
51         if (!value.IsWeakForHeapObject()) {
52             MarkObject(threadId, value.GetTaggedObject(), slot);
53         } else {
54             RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()));
55         }
56     }
57 }
58 
HandleRoots(uint32_t threadId,Root type,ObjectSlot slot)59 inline void SharedGCMarkerBase::HandleRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
60 {
61     JSTaggedValue value(slot.GetTaggedType());
62     if (value.IsInSharedSweepableSpace()) {
63         MarkObject(threadId, value.GetTaggedObject(), slot);
64     }
65 }
66 
HandleLocalRoots(uint32_t threadId,Root type,ObjectSlot slot)67 inline void SharedGCMarkerBase::HandleLocalRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot slot)
68 {
69     JSTaggedValue value(slot.GetTaggedType());
70     if (value.IsInSharedSweepableSpace()) {
71         MarkObject(threadId, value.GetTaggedObject(), slot);
72     }
73 }
74 
HandleLocalRangeRoots(uint32_t threadId,Root type,ObjectSlot start,ObjectSlot end)75 inline void SharedGCMarkerBase::HandleLocalRangeRoots(uint32_t threadId, [[maybe_unused]] Root type, ObjectSlot start,
76     ObjectSlot end)
77 {
78     for (ObjectSlot slot = start; slot < end; slot++) {
79         JSTaggedValue value(slot.GetTaggedType());
80         if (value.IsInSharedSweepableSpace()) {
81             if (value.IsWeakForHeapObject()) {
82                 LOG_ECMA_MEM(FATAL) << "Weak Reference in SharedGCMarker roots";
83             }
84             MarkObject(threadId, value.GetTaggedObject(), slot);
85         }
86     }
87 }
88 
HandleLocalDerivedRoots(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)89 void SharedGCMarker::HandleLocalDerivedRoots([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base,
90                                              [[maybe_unused]] ObjectSlot derived,
91                                              [[maybe_unused]] uintptr_t baseOldObject)
92 {
93     // It is only used to update the derived value. The mark of share GC does not need to update slot
94 }
95 
HandleLocalDerivedRoots(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)96 void SharedGCMovableMarker::HandleLocalDerivedRoots([[maybe_unused]] Root type, ObjectSlot base,
97                                                     ObjectSlot derived, uintptr_t baseOldObject)
98 {
99     if (JSTaggedValue(base.GetTaggedType()).IsHeapObject()) {
100         derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject);
101     }
102 }
103 
104 template <typename Callback>
VisitBodyInObj(TaggedObject * root,ObjectSlot start,ObjectSlot end,Callback callback)105 ARK_INLINE bool SharedGCMarkerBase::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end,
106                                                    Callback callback)
107 {
108     auto hclass = root->SynchronizedGetClass();
109     int index = 0;
110     auto layout = LayoutInfo::UncheckCast(hclass->GetLayout().GetTaggedObject());
111     ObjectSlot realEnd = start;
112     realEnd += layout->GetPropertiesCapacity();
113     end = end > realEnd ? realEnd : end;
114     for (ObjectSlot slot = start; slot < end; slot++) {
115         auto attr = layout->GetAttr(index++);
116         if (attr.IsTaggedRep()) {
117             callback(slot);
118         }
119     }
120     return true;
121 }
122 
RecordWeakReference(uint32_t threadId,JSTaggedType * slot)123 inline void SharedGCMarkerBase::RecordWeakReference(uint32_t threadId, JSTaggedType *slot)
124 {
125     sWorkManager_->PushWeakReference(threadId, slot);
126 }
127 
RecordObject(JSTaggedValue value,uint32_t threadId,void * mem)128 inline void SharedGCMarkerBase::RecordObject(JSTaggedValue value, uint32_t threadId, void *mem)
129 {
130     if (value.IsWeakForHeapObject()) {
131         RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem));
132     } else {
133         ObjectSlot slot(ToUintPtr(mem));
134         MarkObject(threadId, value.GetTaggedObject(), slot);
135     }
136 }
137 
138 template<SharedMarkType markType>
GetVisitor(JSTaggedValue value,uint32_t threadId,void * mem)139 inline bool SharedGCMarkerBase::GetVisitor(JSTaggedValue value, uint32_t threadId, void *mem)
140 {
141     if (value.IsInSharedSweepableSpace()) {
142         if constexpr (markType == SharedMarkType::CONCURRENT_MARK_INITIAL_MARK) {
143             // For now if record weak references from local to share in marking root, the slots
144             // may be invalid due to LocalGC, so just mark them as strong-reference.
145             ObjectSlot slot(ToUintPtr(mem));
146             MarkObject(threadId, value.GetHeapObject(), slot);
147         } else {
148             static_assert(markType == SharedMarkType::NOT_CONCURRENT_MARK);
149             RecordObject(value, threadId, mem);
150         }
151         return true;
152     }
153     return false;
154 }
155 
156 template<SharedMarkType markType>
GenerateRSetVisitor(uint32_t threadId)157 inline auto SharedGCMarkerBase::GenerateRSetVisitor(uint32_t threadId)
158 {
159     auto visitor = [this, threadId](void *mem) -> bool {
160         ObjectSlot slot(ToUintPtr(mem));
161         JSTaggedValue value(slot.GetTaggedType());
162         return GetVisitor<markType>(value, threadId, mem);
163     };
164     return visitor;
165 }
166 
167 template<SharedMarkType markType>
ProcessVisitorOfDoMark(uint32_t threadId)168 inline void SharedGCMarkerBase::ProcessVisitorOfDoMark(uint32_t threadId)
169 {
170     auto rSetVisitor = GenerateRSetVisitor<markType>(threadId);
171     auto visitor = [rSetVisitor](Region *region, RememberedSet *rSet) {
172         rSet->IterateAllMarkedBits(ToUintPtr(region), rSetVisitor);
173     };
174     for (RSetWorkListHandler *handler : rSetHandlers_) {
175         ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::ProcessRSet");
176         handler->ProcessAll(visitor);
177         // To ensure the accuracy of the state range, notify finished is executed on js thread and deamon thread.
178         // Reentrant does not cause exceptions because all the values are set to false.
179         NotifyThreadProcessRsetFinished(handler->GetOwnerThreadUnsafe());
180     }
181 }
182 
183 template<SharedMarkType markType>
DoMark(uint32_t threadId)184 inline void SharedGCMarkerBase::DoMark(uint32_t threadId)
185 {
186     if constexpr (markType != SharedMarkType::CONCURRENT_MARK_REMARK) {
187         ProcessVisitorOfDoMark<markType>(threadId);
188     }
189     ProcessMarkStack(threadId);
190 }
191 
MarkObjectOfProcessVisitor(void * mem,WorkNode * & localBuffer)192 inline bool SharedGCMarkerBase::MarkObjectOfProcessVisitor(void *mem, WorkNode *&localBuffer)
193 {
194     ObjectSlot slot(ToUintPtr(mem));
195     JSTaggedValue value(slot.GetTaggedType());
196     if (value.IsInSharedSweepableSpace()) {
197         // For now if record weak references from local to share in marking root, the slots
198         // may be invalid due to LocalGC, so just mark them as strong-reference.
199         MarkObjectFromJSThread(localBuffer, value.GetHeapObject());
200         return true;
201     }
202 
203     // clear bit.
204     return false;
205 }
206 
ProcessVisitor(RSetWorkListHandler * handler)207 inline void SharedGCMarkerBase::ProcessVisitor(RSetWorkListHandler *handler)
208 {
209     WorkNode *&localBuffer = handler->GetHeap()->GetMarkingObjectLocalBuffer();
210     auto rSetVisitor = [this, &localBuffer](void *mem) -> bool {
211         return MarkObjectOfProcessVisitor(mem, localBuffer);
212     };
213     auto visitor = [rSetVisitor](Region *region, RememberedSet *rSet) {
214         rSet->IterateAllMarkedBits(ToUintPtr(region), rSetVisitor);
215     };
216     handler->ProcessAll(visitor);
217 }
218 
ProcessThenMergeBackRSetFromBoundJSThread(RSetWorkListHandler * handler)219 inline void SharedGCMarkerBase::ProcessThenMergeBackRSetFromBoundJSThread(RSetWorkListHandler *handler)
220 {
221     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SharedGCMarker::ProcessRSet");
222     ASSERT(JSThread::GetCurrent() == handler->GetHeap()->GetEcmaVM()->GetJSThread());
223     ASSERT(JSThread::GetCurrent()->IsInRunningState());
224     ProcessVisitor(handler);
225     handler->WaitFinishedThenMergeBack();
226 }
227 
NotifyThreadProcessRsetStart(JSThread * localThread)228 inline void SharedGCMarkerBase::NotifyThreadProcessRsetStart(JSThread *localThread)
229 {
230     // This method is called within the GCIterateThreadList method,
231     // so the thread lock problem does not need to be considered.
232     ASSERT(localThread != nullptr);
233     localThread->SetProcessingLocalToSharedRset(true);
234 }
235 
NotifyThreadProcessRsetFinished(JSThread * localThread)236 inline void SharedGCMarkerBase::NotifyThreadProcessRsetFinished(JSThread *localThread)
237 {
238     // The localThread may have been released or reused.
239     Runtime::GetInstance()->GCIterateThreadList([localThread](JSThread *thread) {
240         if (localThread == thread) {
241             thread->SetProcessingLocalToSharedRset(false);
242             return;
243         }
244     });
245 }
246 
MarkObject(uint32_t threadId,TaggedObject * object,ObjectSlot & slot)247 void SharedGCMovableMarker::MarkObject(uint32_t threadId, TaggedObject *object, ObjectSlot &slot)
248 {
249     Region *objectRegion = Region::ObjectAddressToRange(object);
250     ASSERT(objectRegion->InSharedHeap());
251     if (!NeedEvacuate(objectRegion)) {
252         if (!objectRegion->InSharedReadOnlySpace() && objectRegion->AtomicMark(object)) {
253             auto hclass = object->GetClass();
254             auto size = hclass->SizeFromJSHClass(object);
255             objectRegion->IncreaseAliveObject(size);
256             sWorkManager_->Push(threadId, object);
257         }
258         return;
259     }
260 
261     MarkWord markWord(object);
262     if (markWord.IsForwardingAddress()) {
263         TaggedObject *dst = markWord.ToForwardingAddress();
264         slot.Update(dst);
265         return;
266     }
267     return EvacuateObject(threadId, object, markWord, slot);
268 }
269 
MarkValue(uint32_t threadId,ObjectSlot & slot)270 void SharedGCMovableMarker::MarkValue(uint32_t threadId, ObjectSlot &slot)
271 {
272     JSTaggedValue value(slot.GetTaggedType());
273     if (value.IsInSharedSweepableSpace()) {
274         if (!value.IsWeakForHeapObject()) {
275             MarkObject(threadId, value.GetTaggedObject(), slot);
276         } else {
277             RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()));
278         }
279     }
280 }
281 
NeedEvacuate(Region * region)282 bool SharedGCMovableMarker::NeedEvacuate(Region *region)
283 {
284     return region->InSharedOldSpace();
285 }
286 
EvacuateObject(uint32_t threadId,TaggedObject * object,const MarkWord & markWord,ObjectSlot slot)287 void SharedGCMovableMarker::EvacuateObject(uint32_t threadId, TaggedObject *object,
288     const MarkWord &markWord, ObjectSlot slot)
289 {
290     JSHClass *klass = markWord.GetJSHClass();
291     size_t size = klass->SizeFromJSHClass(object);
292     uintptr_t forwardAddress = AllocateForwardAddress(threadId, size);
293     RawCopyObject(ToUintPtr(object), forwardAddress, size, markWord);
294 
295     auto oldValue = markWord.GetValue();
296     auto result = Barriers::AtomicSetPrimitive(object, 0, oldValue,
297                                                MarkWord::FromForwardingAddress(forwardAddress));
298     if (result == oldValue) {
299         UpdateForwardAddressIfSuccess(threadId, klass, forwardAddress, size, slot);
300         return;
301     }
302     UpdateForwardAddressIfFailed(object, forwardAddress, size, slot);
303 }
304 
AllocateDstSpace(uint32_t threadId,size_t size)305 uintptr_t SharedGCMovableMarker::AllocateDstSpace(uint32_t threadId, size_t size)
306 {
307     uintptr_t forwardAddress = 0;
308     forwardAddress = sWorkManager_->GetTlabAllocator(threadId)->Allocate(size, SHARED_COMPRESS_SPACE);
309     if (UNLIKELY(forwardAddress == 0)) {
310         LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: "
311                             << " size: " << size;
312         UNREACHABLE();
313     }
314     return forwardAddress;
315 }
316 
RawCopyObject(uintptr_t fromAddress,uintptr_t toAddress,size_t size,const MarkWord & markWord)317 inline void SharedGCMovableMarker::RawCopyObject(uintptr_t fromAddress, uintptr_t toAddress, size_t size,
318     const MarkWord &markWord)
319 {
320     if (memcpy_s(ToVoidPtr(toAddress + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(fromAddress + HEAD_SIZE),
321         size - HEAD_SIZE) != EOK) {
322         LOG_FULL(FATAL) << "memcpy_s failed";
323     }
324     *reinterpret_cast<MarkWordType *>(toAddress) = markWord.GetValue();
325 }
326 
UpdateForwardAddressIfSuccess(uint32_t threadId,JSHClass * klass,uintptr_t toAddress,size_t size,ObjectSlot slot)327 void SharedGCMovableMarker::UpdateForwardAddressIfSuccess(uint32_t threadId, JSHClass *klass, uintptr_t toAddress,
328     size_t size, ObjectSlot slot)
329 {
330     sWorkManager_->IncreaseAliveSize(threadId, size);
331     if (klass->HasReferenceField()) {
332         sWorkManager_->Push(threadId, reinterpret_cast<TaggedObject *>(toAddress));
333     }
334     slot.Update(reinterpret_cast<TaggedObject *>(toAddress));
335 }
336 
UpdateForwardAddressIfFailed(TaggedObject * object,uintptr_t toAddress,size_t size,ObjectSlot slot)337 void SharedGCMovableMarker::UpdateForwardAddressIfFailed(TaggedObject *object, uintptr_t toAddress, size_t size,
338     ObjectSlot slot)
339 {
340     FreeObject::FillFreeObject(sHeap_, toAddress, size);
341     TaggedObject *dst = MarkWord(object).ToForwardingAddress();
342     slot.Update(dst);
343 }
344 
AllocateForwardAddress(uint32_t threadId,size_t size)345 uintptr_t SharedGCMovableMarker::AllocateForwardAddress(uint32_t threadId, size_t size)
346 {
347     return AllocateDstSpace(threadId, size);
348 }
349 }  // namespace panda::ecmascript
350 #endif  // ECMASCRIPT_MEM_SHARED_HEAP_SHARED_GC_MARKER_INL_H
351