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