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