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