• 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_FULL_GC_INL_H
17 #define ECMASCRIPT_MEM_FULL_GC_INL_H
18 
19 #include "ecmascript/mem/full_gc.h"
20 
21 #include "ecmascript/js_hclass-inl.h"
22 #include "ecmascript/mem/object_xray.h"
23 #include "ecmascript/mem/heap-inl.h"
24 #include "ecmascript/mem/mark_word.h"
25 #include "ecmascript/mem/region-inl.h"
26 #include "ecmascript/mem/work_manager-inl.h"
27 
28 namespace panda::ecmascript {
29 
FullGCRunner(Heap * heap,WorkNodeHolder * workNodeHolder,bool isAppSpawn)30 FullGCRunner::FullGCRunner(Heap *heap, WorkNodeHolder *workNodeHolder, bool isAppSpawn)
31     : heap_(heap), workNodeHolder_(workNodeHolder), isAppSpawn_(isAppSpawn), markRootVisitor_(this),
32       markObjectVisitor_(this), updateLocalToShareRSetVisitor_(this) {}
33 
GetMarkRootVisitor()34 FullGCMarkRootVisitor &FullGCRunner::GetMarkRootVisitor()
35 {
36     return markRootVisitor_;
37 }
38 
GetMarkObjectVisitor()39 FullGCMarkObjectVisitor &FullGCRunner::GetMarkObjectVisitor()
40 {
41     return markObjectVisitor_;
42 }
43 
HandleMarkingSlot(ObjectSlot slot)44 void FullGCRunner::HandleMarkingSlot(ObjectSlot slot)
45 {
46     JSTaggedValue value(slot.GetTaggedType());
47     if (!value.IsHeapObject()) {
48         return;
49     }
50 
51     if (!value.IsWeakForHeapObject()) {
52         TaggedObject *object = value.GetTaggedObject();
53         HandleMarkingSlotObject(slot, object);
54     } else {
55         RecordWeakReference(reinterpret_cast<JSTaggedType *>(slot.SlotAddress()));
56     }
57 }
58 
59 template <class Callback>
VisitBodyInObj(TaggedObject * root,ObjectSlot start,ObjectSlot end,Callback && cb)60 void FullGCRunner::VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback &&cb)
61 {
62     JSHClass *hclass = root->SynchronizedGetClass();
63     ASSERT(!hclass->IsAllTaggedProp());
64     int index = 0;
65     LayoutInfo *layout = LayoutInfo::UncheckCast(hclass->GetLayout().GetTaggedObject());
66     ObjectSlot realEnd = start;
67     realEnd += layout->GetPropertiesCapacity();
68     end = end > realEnd ? realEnd : end;
69     for (ObjectSlot slot = start; slot < end; slot++) {
70         PropertyAttributes attr = layout->GetAttr(index++);
71         if (attr.IsTaggedRep()) {
72             cb(slot);
73         }
74     }
75 }
76 
HandleMarkingSlotObject(ObjectSlot slot,TaggedObject * object)77 void FullGCRunner::HandleMarkingSlotObject(ObjectSlot slot, TaggedObject *object)
78 {
79     Region *objectRegion = Region::ObjectAddressToRange(object);
80     if (!NeedEvacuate(objectRegion)) {
81         if (!objectRegion->InSharedHeap() && objectRegion->AtomicMark(object)) {
82             JSHClass *hclass = object->GetClass();
83             size_t size = hclass->SizeFromJSHClass(object);
84             objectRegion->IncreaseAliveObject(size);
85             PushObject(object);
86         }
87         return;
88     }
89 
90     MarkWord markWord(object);
91     if (markWord.IsForwardingAddress()) {
92         TaggedObject *dst = markWord.ToForwardingAddress();
93         slot.Update(dst);
94         return;
95     }
96     return EvacuateObject(slot, object, markWord);
97 }
98 
NeedEvacuate(Region * region)99 bool FullGCRunner::NeedEvacuate(Region *region)
100 {
101     if (isAppSpawn_) {
102         return !region->InHugeObjectSpace()  && !region->InReadOnlySpace() && !region->InNonMovableSpace() &&
103                !region->InSharedHeap();
104     }
105     return region->InYoungOrOldSpace();
106 }
107 
EvacuateObject(ObjectSlot slot,TaggedObject * object,const MarkWord & markWord)108 void FullGCRunner::EvacuateObject(ObjectSlot slot, TaggedObject *object, const MarkWord &markWord)
109 {
110     JSHClass *klass = markWord.GetJSHClass();
111     size_t size = klass->SizeFromJSHClass(object);
112     uintptr_t forwardAddress = AllocateForwardAddress(size);
113     RawCopyObject(ToUintPtr(object), forwardAddress, size, markWord);
114 
115     MarkWordType oldValue = markWord.GetValue();
116     MarkWordType result = Barriers::AtomicSetPrimitive(object, 0, oldValue,
117                                                        MarkWord::FromForwardingAddress(forwardAddress));
118     if (result == oldValue) {
119         TaggedObject *toObject = reinterpret_cast<TaggedObject*>(forwardAddress);
120         UpdateForwardAddressIfSuccess(slot, object, klass, size, toObject);
121         Region *region = Region::ObjectAddressToRange(object);
122         if (region->HasLocalToShareRememberedSet()) {
123             ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(toObject, klass, updateLocalToShareRSetVisitor_);
124         }
125         return;
126     }
127     ASSERT(MarkWord::IsForwardingAddress(result));
128     UpdateForwardAddressIfFailed(slot, size, forwardAddress, MarkWord::ToForwardingAddress(result));
129 }
130 
AllocateForwardAddress(size_t size)131 uintptr_t FullGCRunner::AllocateForwardAddress(size_t size)
132 {
133     if (!isAppSpawn_) {
134         return AllocateDstSpace(size);
135     }
136     return AllocateAppSpawnSpace(size);
137 }
138 
AllocateDstSpace(size_t size)139 uintptr_t FullGCRunner::AllocateDstSpace(size_t size)
140 {
141     uintptr_t forwardAddress = workNodeHolder_->GetTlabAllocator()->Allocate(size, COMPRESS_SPACE);
142     if (UNLIKELY(forwardAddress == 0)) {
143         LOG_ECMA_MEM(FATAL) << "EvacuateObject alloc failed: " << " size: " << size;
144         UNREACHABLE();
145     }
146     return forwardAddress;
147 }
148 
AllocateAppSpawnSpace(size_t size)149 uintptr_t FullGCRunner::AllocateAppSpawnSpace(size_t size)
150 {
151     uintptr_t forwardAddress = heap_->GetAppSpawnSpace()->AllocateSync(size);
152     if (UNLIKELY(forwardAddress == 0)) {
153         LOG_ECMA_MEM(FATAL) << "Evacuate AppSpawn Object: alloc failed: "
154                             << " size: " << size;
155         UNREACHABLE();
156     }
157     return forwardAddress;
158 }
159 
RawCopyObject(uintptr_t fromAddress,uintptr_t toAddress,size_t size,const MarkWord & markWord)160 void FullGCRunner::RawCopyObject(uintptr_t fromAddress, uintptr_t toAddress, size_t size, const MarkWord &markWord)
161 {
162     size_t copySize = size - HEAD_SIZE;
163     errno_t res = memcpy_s(ToVoidPtr(toAddress + HEAD_SIZE), copySize, ToVoidPtr(fromAddress + HEAD_SIZE), copySize);
164     if (res != EOK) {
165         LOG_FULL(FATAL) << "memcpy_s failed " << res;
166     }
167     *reinterpret_cast<MarkWordType *>(toAddress) = markWord.GetValue();
168 }
169 
UpdateForwardAddressIfSuccess(ObjectSlot slot,TaggedObject * object,JSHClass * klass,size_t size,TaggedObject * toAddress)170 void FullGCRunner::UpdateForwardAddressIfSuccess(ObjectSlot slot, TaggedObject *object, JSHClass *klass, size_t size,
171     TaggedObject *toAddress)
172 {
173     workNodeHolder_->IncreaseAliveSize(size);
174 
175     heap_->OnMoveEvent(reinterpret_cast<uintptr_t>(object), toAddress, size);
176     if (klass->HasReferenceField()) {
177         PushObject(toAddress);
178     }
179     slot.Update(toAddress);
180 }
181 
UpdateForwardAddressIfFailed(ObjectSlot slot,size_t size,uintptr_t toAddress,TaggedObject * dst)182 void FullGCRunner::UpdateForwardAddressIfFailed(ObjectSlot slot, size_t size, uintptr_t toAddress, TaggedObject *dst)
183 {
184     FreeObject::FillFreeObject(heap_, toAddress, size);
185     slot.Update(dst);
186 }
187 
PushObject(TaggedObject * object)188 void FullGCRunner::PushObject(TaggedObject *object)
189 {
190     workNodeHolder_->Push(object);
191 }
192 
RecordWeakReference(JSTaggedType * weak)193 void FullGCRunner::RecordWeakReference(JSTaggedType *weak)
194 {
195     workNodeHolder_->PushWeakReference(weak);
196 }
197 
FullGCMarkRootVisitor(FullGCRunner * runner)198 FullGCMarkRootVisitor::FullGCMarkRootVisitor(FullGCRunner *runner) : runner_(runner) {}
199 
VisitRoot(Root type,ObjectSlot slot)200 void FullGCMarkRootVisitor::VisitRoot([[maybe_unused]] Root type, ObjectSlot slot)
201 {
202     JSTaggedValue value(slot.GetTaggedType());
203     if (value.IsHeapObject()) {
204         ASSERT(!value.IsWeak());
205         runner_->HandleMarkingSlotObject(slot, value.GetTaggedObject());
206     }
207 }
208 
VisitRangeRoot(Root type,ObjectSlot start,ObjectSlot end)209 void FullGCMarkRootVisitor::VisitRangeRoot([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end)
210 {
211     for (ObjectSlot slot = start; slot < end; slot++) {
212         JSTaggedValue value(slot.GetTaggedType());
213         if (value.IsHeapObject()) {
214             ASSERT(!value.IsWeak());
215             runner_->HandleMarkingSlotObject(slot, value.GetTaggedObject());
216         }
217     }
218 }
219 
VisitBaseAndDerivedRoot(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)220 void FullGCMarkRootVisitor::VisitBaseAndDerivedRoot([[maybe_unused]] Root type, ObjectSlot base, ObjectSlot derived,
221                                                     uintptr_t baseOldObject)
222 {
223     if (JSTaggedValue(base.GetTaggedType()).IsHeapObject()) {
224         derived.Update(base.GetTaggedType() + derived.GetTaggedType() - baseOldObject);
225     }
226 }
227 
FullGCMarkObjectVisitor(FullGCRunner * runner)228 FullGCMarkObjectVisitor::FullGCMarkObjectVisitor(FullGCRunner *runner) : runner_(runner) {}
229 
VisitObjectRangeImpl(TaggedObject * root,ObjectSlot start,ObjectSlot end,VisitObjectArea area)230 void FullGCMarkObjectVisitor::VisitObjectRangeImpl(TaggedObject *root, ObjectSlot start, ObjectSlot end,
231                                                    VisitObjectArea area)
232 {
233     if (UNLIKELY(area == VisitObjectArea::IN_OBJECT)) {
234         runner_->VisitBodyInObj(root, start, end, [this](ObjectSlot slot) {
235             runner_->HandleMarkingSlot(slot);
236         });
237         return;
238     }
239     for (ObjectSlot slot = start; slot < end; slot++) {
240         runner_->HandleMarkingSlot(slot);
241     }
242 }
243 
VisitHClassSlot(ObjectSlot slot,TaggedObject * hclass)244 void FullGCMarkObjectVisitor::VisitHClassSlot(ObjectSlot slot, TaggedObject *hclass)
245 {
246     ASSERT(hclass->GetClass()->IsHClass());
247     runner_->HandleMarkingSlotObject(slot, hclass);
248 }
249 
FullGCUpdateLocalToShareRSetVisitor(FullGCRunner * runner)250 FullGCUpdateLocalToShareRSetVisitor::FullGCUpdateLocalToShareRSetVisitor(FullGCRunner *runner) : runner_(runner) {}
251 
VisitObjectRangeImpl(TaggedObject * root,ObjectSlot start,ObjectSlot end,VisitObjectArea area)252 void FullGCUpdateLocalToShareRSetVisitor::VisitObjectRangeImpl(TaggedObject *root, ObjectSlot start, ObjectSlot end,
253                                                                VisitObjectArea area)
254 {
255     Region *rootRegion = Region::ObjectAddressToRange(root);
256     ASSERT(!rootRegion->InSharedHeap());
257     if (UNLIKELY(area == VisitObjectArea::IN_OBJECT)) {
258         runner_->VisitBodyInObj(root, start, end, [this, rootRegion](ObjectSlot slot) {
259             SetLocalToShareRSet(slot, rootRegion);
260         });
261         return;
262     }
263     for (ObjectSlot slot = start; slot < end; slot++) {
264         SetLocalToShareRSet(slot, rootRegion);
265     }
266 }
267 
SetLocalToShareRSet(ObjectSlot slot,Region * rootRegion)268 void FullGCUpdateLocalToShareRSetVisitor::SetLocalToShareRSet(ObjectSlot slot, Region *rootRegion)
269 {
270     ASSERT(!rootRegion->InSharedHeap());
271     JSTaggedType value = slot.GetTaggedType();
272     if (!JSTaggedValue(value).IsHeapObject()) {
273         return;
274     }
275 
276     Region *valueRegion = Region::ObjectAddressToRange(value);
277     if (valueRegion->InSharedSweepableSpace()) {
278         rootRegion->AtomicInsertLocalToShareRSet(slot.SlotAddress());
279     }
280 }
281 
282 }  // namespace panda::ecmascript
283 #endif  // ECMASCRIPT_MEM_FULL_GC_INL_H