1 /*
2 * Copyright (c) 2021 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 #include "ecmascript/mem/verification.h"
17
18 #include "ecmascript/mem/shared_heap/shared_concurrent_sweeper.h"
19 #include "ecmascript/runtime.h"
20
21 namespace panda::ecmascript {
LogErrorForObjSlot(const BaseHeap * heap,const char * headerInfo,TaggedObject * obj,ObjectSlot slot,TaggedObject * value)22 void LogErrorForObjSlot(const BaseHeap *heap, const char *headerInfo, TaggedObject *obj, ObjectSlot slot,
23 TaggedObject *value)
24 {
25 TaggedObject *slotValue = slot.GetTaggedObject();
26 Region *region = Region::ObjectAddressToRange(obj);
27 Region *valueRegion = Region::ObjectAddressToRange(value);
28 Region *slotRegion = Region::ObjectAddressToRange(slotValue);
29 LOG_GC(FATAL) << headerInfo
30 << ": gctype=" << heap->GetGCType()
31 << ", obj address=" << obj
32 << ", obj region=" << region
33 << ", obj space type=" << region->GetSpaceTypeName()
34 << ", obj type=" << JSHClass::DumpJSType(obj->GetClass()->GetObjectType())
35 << ", slot address=" << reinterpret_cast<void*>(slot.SlotAddress())
36 << ", slot value=" << slotValue
37 << ", slot value region=" << slotRegion
38 << ", slot value space type=" << slotRegion->GetSpaceTypeName()
39 << ", slot value type=" << JSHClass::DumpJSType(slotValue->GetClass()->GetObjectType())
40 << ", value address=" << value
41 << ", value region=" << valueRegion
42 << ", value space type=" << valueRegion->GetSpaceTypeName()
43 << ", value type=" << JSHClass::DumpJSType(value->GetClass()->GetObjectType())
44 << ", obj mark bit=" << region->Test(obj)
45 << ", obj slot oldToNew bit=" << region->TestOldToNew(slot.SlotAddress())
46 << ", obj slot newToEden bit=" << region->TestNewToEden(slot.SlotAddress())
47 << ", obj slot value mark bit=" << slotRegion->Test(slotValue)
48 << ", value mark bit=" << valueRegion->Test(value);
49 UNREACHABLE();
50 }
51
LogErrorForObj(const BaseHeap * heap,const char * headerInfo,TaggedObject * obj)52 void LogErrorForObj(const BaseHeap *heap, const char *headerInfo, TaggedObject *obj)
53 {
54 Region *region = Region::ObjectAddressToRange(obj);
55 LOG_GC(FATAL) << headerInfo
56 << ": gctype=" << heap->GetGCType()
57 << ", obj address=" << obj
58 << ", obj value=" << ObjectSlot(ToUintPtr(obj)).GetTaggedObject()
59 << ", obj region=" << region
60 << ", obj space type=" << region->GetSpaceTypeName()
61 << ", obj type=" << JSHClass::DumpJSType(obj->GetClass()->GetObjectType())
62 << ", obj mark bit=" << region->Test(obj);
63 UNREACHABLE();
64 }
65
66 // Only used for verify InactiveSemiSpace
VerifyInactiveSemiSpaceMarkedObject(const BaseHeap * heap,void * addr)67 void VerifyObjectVisitor::VerifyInactiveSemiSpaceMarkedObject(const BaseHeap *heap, void *addr)
68 {
69 TaggedObject *object = reinterpret_cast<TaggedObject*>(addr);
70 Region *objectRegion = Region::ObjectAddressToRange(object);
71 if (!objectRegion->InInactiveSemiSpace()) {
72 LogErrorForObj(heap, "Verify InactiveSemiSpaceMarkedObject: Object is not in InactiveSemiSpace.", object);
73 } else {
74 MarkWord word(object);
75 if (!word.IsForwardingAddress()) {
76 LogErrorForObj(heap, "Verify InactiveSemiSpaceMarkedObject: not forwarding address.", object);
77 } else {
78 ObjectSlot slot(ToUintPtr(object));
79 TaggedObject *value = word.ToForwardingAddress();
80 Region *valueRegion = Region::ObjectAddressToRange(value);
81 if (valueRegion->InInactiveSemiSpace()) {
82 LogErrorForObjSlot(heap, "Verify InactiveSemiSpaceMarkedObject: forwarding address, "
83 "but InactiveSemiSpace(FromSpace) Object.", object, slot, value);
84 }
85 }
86 }
87 }
88
89 // Verify the object body
VisitAllObjects(TaggedObject * obj)90 void VerifyObjectVisitor::VisitAllObjects(TaggedObject *obj)
91 {
92 auto jsHclass = obj->GetClass();
93 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
94 obj, jsHclass, [this](TaggedObject *root, ObjectSlot start, ObjectSlot end,
95 VisitObjectArea area) {
96 if (area == VisitObjectArea::IN_OBJECT) {
97 auto hclass = root->GetClass();
98 ASSERT(!hclass->IsAllTaggedProp());
99 int index = 0;
100 for (ObjectSlot slot = start; slot < end; slot++) {
101 auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
102 auto attr = layout->GetAttr(index++);
103 if (attr.IsTaggedRep()) {
104 VerifyObjectSlotLegal(slot, root);
105 }
106 }
107 return;
108 }
109 for (ObjectSlot slot = start; slot < end; slot++) {
110 VerifyObjectSlotLegal(slot, root);
111 }
112 });
113 }
114
VerifyObjectSlotLegal(ObjectSlot slot,TaggedObject * object) const115 void VerifyObjectVisitor::VerifyObjectSlotLegal(ObjectSlot slot, TaggedObject *object) const
116 {
117 JSTaggedValue value(slot.GetTaggedType());
118 if (value.IsWeak()) {
119 if (ToUintPtr(value.GetTaggedWeakRef()) < INVALID_THRESHOLD) {
120 LogErrorForObjSlot(heap_, "Heap verify detected an invalid value.",
121 object, slot, value.GetTaggedWeakRef());
122 }
123 if (!heap_->IsAlive(value.GetTaggedWeakRef())) {
124 LogErrorForObjSlot(heap_, "Heap verify detected a dead weak object.",
125 object, slot, value.GetTaggedWeakRef());
126 ++(*failCount_);
127 }
128 } else if (value.IsHeapObject()) {
129 VerifyHeapObjectSlotLegal(slot, value, object);
130 }
131 }
132
VerifyHeapObjectSlotLegal(ObjectSlot slot,JSTaggedValue slotValue,TaggedObject * object) const133 void VerifyObjectVisitor::VerifyHeapObjectSlotLegal(ObjectSlot slot,
134 JSTaggedValue slotValue,
135 TaggedObject *object) const
136 {
137 ASSERT(slotValue.IsHeapObject());
138 if (ToUintPtr(slotValue.GetTaggedObject()) < INVALID_THRESHOLD) {
139 LogErrorForObjSlot(heap_, "Heap verify detected an invalid value.",
140 object, slot, slotValue.GetTaggedObject());
141 }
142 if (!heap_->IsAlive(slotValue.GetTaggedObject())) {
143 LogErrorForObjSlot(heap_, "Heap verify detected a dead object.",
144 object, slot, slotValue.GetTaggedObject());
145 ++(*failCount_);
146 }
147 switch (verifyKind_) {
148 case VerifyKind::VERIFY_PRE_GC:
149 case VerifyKind::VERIFY_POST_GC:
150 break;
151 case VerifyKind::VERIFY_MARK_EDEN:
152 VerifyMarkEden(object, slot, slotValue.GetTaggedObject());
153 break;
154 case VerifyKind::VERIFY_EVACUATE_EDEN:
155 VerifyEvacuateEden(object, slot, slotValue.GetTaggedObject());
156 break;
157 case VerifyKind::VERIFY_MARK_YOUNG:
158 VerifyMarkYoung(object, slot, slotValue.GetTaggedObject());
159 break;
160 case VerifyKind::VERIFY_EVACUATE_YOUNG:
161 VerifyEvacuateYoung(object, slot, slotValue.GetTaggedObject());
162 break;
163 case VerifyKind::VERIFY_MARK_FULL:
164 VerifyMarkFull(object, slot, slotValue.GetTaggedObject());
165 break;
166 case VerifyKind::VERIFY_EVACUATE_OLD:
167 VerifyEvacuateOld(object, slot, slotValue.GetTaggedObject());
168 break;
169 case VerifyKind::VERIFY_EVACUATE_FULL:
170 VerifyEvacuateFull(object, slot, slotValue.GetTaggedObject());
171 break;
172 case VerifyKind::VERIFY_SHARED_RSET_POST_FULL_GC:
173 VerifySharedRSetPostFullGC(object, slot, slotValue.GetTaggedObject());
174 break;
175 case VerifyKind::VERIFY_PRE_SHARED_GC:
176 case VerifyKind::VERIFY_POST_SHARED_GC:
177 VerifySharedObjectReference(object, slot, slotValue.GetTaggedObject());
178 break;
179 default:
180 LOG_GC(FATAL) << "unknown verify kind:" << static_cast<size_t>(verifyKind_);
181 UNREACHABLE();
182 }
183 }
184
VerifyMarkEden(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const185 void VerifyObjectVisitor::VerifyMarkEden(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
186 {
187 Region *objectRegion = Region::ObjectAddressToRange(object);
188 Region *valueRegion = Region::ObjectAddressToRange(value);
189 JSTaggedValue value1(object);
190 JSTaggedValue value2(value);
191 if (objectRegion->InGeneralOldSpace() && valueRegion->InEdenSpace()) {
192 if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
193 LogErrorForObjSlot(heap_, "Verify MarkEden: Old object, slot miss old_to_new bit.", object, slot, value);
194 } else if (!valueRegion->Test(value)) {
195 LogErrorForObjSlot(heap_, "Verify MarkEden: Old object, slot has old_to_new bit, miss gc_mark bit.",
196 object, slot, value);
197 }
198 }
199
200 if (objectRegion->InYoungSpace() && valueRegion->InEdenSpace()) {
201 if (!objectRegion->TestNewToEden(slot.SlotAddress())) {
202 value1.D();
203 value2.D();
204 LogErrorForObjSlot(heap_, "Verify MarkEden: Young object, slot miss new_to_eden bit.", object, slot, value);
205 } else if (!valueRegion->Test(value)) {
206 LogErrorForObjSlot(heap_, "Verify MarkEden: Young object, slot has new_to_eden bit, miss gc_mark bit.",
207 object, slot, value);
208 }
209 }
210
211 if (objectRegion->Test(object)) {
212 if (!objectRegion->InEdenSpace() && !objectRegion->InAppSpawnSpace() && !objectRegion->InReadOnlySpace()) {
213 LogErrorForObj(heap_, "Verify MarkYoung: Marked object, NOT in Eden Space", object);
214 }
215 if (valueRegion->InEdenSpace() && !valueRegion->Test(value)) {
216 LogErrorForObjSlot(heap_, "Verify MarkEden: Marked object, slot in EdenSpace, miss gc_mark bit.",
217 object, slot, value);
218 }
219 if (valueRegion->Test(value) && !(valueRegion->InEdenSpace() || valueRegion->InAppSpawnSpace() ||
220 valueRegion->InReadOnlySpace() || valueRegion->InSharedHeap())) {
221 LogErrorForObjSlot(heap_, "Verify MarkEden: Marked object, slot marked, but NOT in Eden Space.",
222 object, slot, value);
223 }
224 }
225 }
226
227
VerifyMarkYoung(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const228 void VerifyObjectVisitor::VerifyMarkYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
229 {
230 Region *objectRegion = Region::ObjectAddressToRange(object);
231 Region *valueRegion = Region::ObjectAddressToRange(value);
232 ASSERT(!objectRegion->InSharedHeap());
233 if (objectRegion->InGeneralOldSpace() && valueRegion->InGeneralNewSpace()) {
234 if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
235 LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot miss old_to_new bit.", object, slot, value);
236 } else if (!valueRegion->Test(value)) {
237 LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot has old_to_new bit, miss gc_mark bit.",
238 object, slot, value);
239 }
240 }
241 if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
242 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
243 LogErrorForObjSlot(heap_, "Verify MarkYoung: Local object, slot local_to_share bit = 0, "
244 "but SharedHeap object.", object, slot, value);
245 }
246 }
247 if (objectRegion->Test(object)) {
248 if (!objectRegion->InGeneralNewSpace() && !objectRegion->InAppSpawnSpace() &&
249 !objectRegion->InReadOnlySpace()) {
250 LogErrorForObj(heap_, "Verify MarkYoung: Marked object, NOT in Young/AppSpawn/ReadOnly Space", object);
251 }
252 if (valueRegion->InGeneralNewSpace() && !valueRegion->Test(value)) {
253 LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot in YoungSpace, miss gc_mark bit.",
254 object, slot, value);
255 }
256 if (valueRegion->Test(value) &&
257 !(valueRegion->InYoungSpace() || valueRegion->InAppSpawnSpace() || valueRegion->InReadOnlySpace() ||
258 valueRegion->InSharedHeap() || valueRegion->InEdenSpace())) {
259 LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot marked, but NOT in "
260 "Young/AppSpawn/ReadOnly Space.", object, slot, value);
261 }
262 }
263 }
264
VerifyEvacuateEden(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const265 void VerifyObjectVisitor::VerifyEvacuateEden(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
266 {
267 Region *objectRegion = Region::ObjectAddressToRange(object);
268 Region *valueRegion = Region::ObjectAddressToRange(value);
269 if (objectRegion->InGeneralOldSpace()) {
270 if (objectRegion->TestOldToNew(slot.SlotAddress())) {
271 if (!valueRegion->InActiveSemiSpace()) {
272 if (valueRegion->InEdenSpace()) {
273 LogErrorForObjSlot(heap_, "Verify EvacuateEden: Old object, slot old_to_new bit = 1, "
274 "but in EdenSpace object.", object, slot, value);
275 }
276 LogErrorForObjSlot(heap_, "Verify EvacuateEden: Old object, slot old_to_new bit = 1, "
277 "but NOT ActiveSpace(ToSpace) object.", object, slot, value);
278 }
279 } else {
280 if (valueRegion->InGeneralNewSpace()) {
281 LogErrorForObjSlot(heap_, "Verify EvacuateEden: Old object, slot old_to_new bit = 0, "
282 "but YoungSpace object.", object, slot, value);
283 }
284 }
285 }
286 if (objectRegion->InYoungSpace()) {
287 if (objectRegion->TestNewToEden(slot.SlotAddress())) {
288 if (!valueRegion->InEdenSpace()) {
289 LogErrorForObjSlot(heap_, "Verify EvacuateEden: Young object, slot young_to_eden bit = 1, "
290 "but NOT Eden object.", object, slot, value);
291 } else {
292 LogErrorForObjSlot(heap_, "Verify EvacuateEden: Young object, slot young_to_eden bit = 1, "
293 "but Eden object.", object, slot, value);
294 }
295 } else {
296 if (valueRegion->InEdenSpace()) {
297 LogErrorForObjSlot(heap_, "Verify EvacuateEden: Young object, slot young_to_eden bit = 0, "
298 "but Eden object.", object, slot, value);
299 }
300 }
301 }
302 }
303
VerifyEvacuateYoung(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const304 void VerifyObjectVisitor::VerifyEvacuateYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
305 {
306 Region *objectRegion = Region::ObjectAddressToRange(object);
307 Region *valueRegion = Region::ObjectAddressToRange(value);
308
309 if (objectRegion->InGeneralOldSpace()) {
310 if (objectRegion->TestOldToNew(slot.SlotAddress())) {
311 if (!valueRegion->InActiveSemiSpace()) {
312 if (valueRegion->InEdenSpace()) {
313 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 1, "
314 "but in EdenSpace object.", object, slot, value);
315 }
316 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 1, "
317 "but NOT ActiveSpace(ToSpace) object.", object, slot, value);
318 }
319 } else {
320 if (valueRegion->InGeneralNewSpace()) {
321 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 0, "
322 "but YoungSpace object.", object, slot, value);
323 }
324 }
325 }
326 if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
327 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
328 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Local object, slot local_to_share bit = 0, "
329 "but SharedHeap object.", object, slot, value);
330 }
331 }
332 if (objectRegion->InActiveSemiSpace()) {
333 if (valueRegion->InInactiveSemiSpace()) {
334 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: ActiveSpace object, slot in InactiveSpace(FromSpace).",
335 object, slot, value);
336 } else if (valueRegion->InEdenSpace()) {
337 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: ActiveSpace object, slot in EdenSpace.",
338 object, slot, value);
339 }
340 }
341 }
342
VerifyMarkFull(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const343 void VerifyObjectVisitor::VerifyMarkFull(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
344 {
345 Region *objectRegion = Region::ObjectAddressToRange(object);
346 Region *valueRegion = Region::ObjectAddressToRange(value);
347 if (objectRegion->InGeneralOldSpace() && valueRegion->InGeneralNewSpace()) {
348 if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
349 LogErrorForObjSlot(heap_, "Verify MarkFull: Old object, slot miss old_to_new bit.", object, slot, value);
350 }
351 }
352 if (objectRegion->Test(object)) {
353 if (!valueRegion->InSharedHeap() && !valueRegion->Test(value)) {
354 LogErrorForObjSlot(heap_, "Verify MarkFull: Marked object, slot miss gc_mark bit.", object, slot, value);
355 }
356 }
357 if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
358 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
359 LogErrorForObjSlot(heap_, "Verify VerifyMarkFull: Local object, slot local_to_share bit = 0, "
360 "but SharedHeap object.", object, slot, value);
361 }
362 }
363 }
364
VerifyEvacuateOld(TaggedObject * root,ObjectSlot slot,TaggedObject * value) const365 void VerifyObjectVisitor::VerifyEvacuateOld([[maybe_unused]]TaggedObject *root,
366 [[maybe_unused]]ObjectSlot slot,
367 [[maybe_unused]]TaggedObject *value) const
368 {
369 VerifyEvacuateYoung(root, slot, value);
370 }
371
VerifyEvacuateFull(TaggedObject * root,ObjectSlot slot,TaggedObject * value) const372 void VerifyObjectVisitor::VerifyEvacuateFull([[maybe_unused]]TaggedObject *root,
373 [[maybe_unused]]ObjectSlot slot,
374 [[maybe_unused]]TaggedObject *value) const
375 {
376 VerifyEvacuateYoung(root, slot, value);
377 }
378
VerifySharedObjectReference(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const379 void VerifyObjectVisitor::VerifySharedObjectReference(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
380 {
381 Region *objectRegion = Region::ObjectAddressToRange(object);
382 Region *valueRegion = Region::ObjectAddressToRange(value);
383 if (objectRegion->InSharedHeap()) {
384 if (!valueRegion->InSharedHeap()) {
385 LogErrorForObjSlot(heap_, "Verify SharedObjectReference: Shared object references a local object",
386 object, slot, value);
387 }
388 } else if (valueRegion->InSharedSweepableSpace()) {
389 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
390 LogErrorForObjSlot(heap_, "Verify SharedObjectReference: Local object, slot local_to_share bit = 0, "
391 "but SharedHeap object.", object, slot, value);
392 }
393 }
394 }
395
VerifySharedRSetPostFullGC(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const396 void VerifyObjectVisitor::VerifySharedRSetPostFullGC(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
397 {
398 Region *objectRegion = Region::ObjectAddressToRange(object);
399 Region *valueRegion = Region::ObjectAddressToRange(value);
400 if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
401 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
402 LogErrorForObjSlot(heap_, "Verify SharedRSetPostFullGC: Local object, slot local_to_share bit = 0, "
403 "but SharedHeap object.", object, slot, value);
404 }
405 }
406 }
407
operator ()(TaggedObject * obj,JSTaggedValue value)408 void VerifyObjectVisitor::operator()(TaggedObject *obj, JSTaggedValue value)
409 {
410 ObjectSlot slot(reinterpret_cast<uintptr_t>(obj));
411 if (!value.IsHeapObject()) {
412 LOG_GC(DEBUG) << "Heap object(" << slot.SlotAddress() << ") old to new rset fail: value is "
413 << slot.GetTaggedType();
414 return;
415 }
416
417 TaggedObject *object = value.GetRawTaggedObject();
418 auto region = Region::ObjectAddressToRange(object);
419 if (region->InGeneralOldSpace()) {
420 LOG_GC(ERROR) << "Heap object(" << slot.GetTaggedType() << ") old to new rset fail: value("
421 << slot.GetTaggedObject() << "/"
422 << JSHClass::DumpJSType(slot.GetTaggedObject()->GetClass()->GetObjectType())
423 << ")" << " in " << region->GetSpaceTypeName();
424 ++(*failCount_);
425 }
426 }
427
VerifyAll() const428 void Verification::VerifyAll() const
429 {
430 [[maybe_unused]] VerifyScope verifyScope(heap_);
431 heap_->GetSweeper()->EnsureAllTaskFinished();
432 size_t result = VerifyRoot();
433 result += VerifyHeap();
434 if (result > 0) {
435 LOG_GC(FATAL) << "Verify (type=" << static_cast<uint8_t>(verifyKind_)
436 << ") corrupted and " << result << " corruptions";
437 }
438 }
439
VerifyRoot() const440 size_t Verification::VerifyRoot() const
441 {
442 size_t failCount = 0;
443 RootVisitor visitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) {
444 JSTaggedValue value(slot.GetTaggedType());
445 // Skip verifying shared object in local gc verification.
446 if (value.IsInSharedHeap()) {
447 return;
448 }
449 VerifyObjectSlot(slot, &failCount);
450 };
451 RootRangeVisitor rangeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) {
452 for (ObjectSlot slot = start; slot < end; slot++) {
453 JSTaggedValue value(slot.GetTaggedType());
454 // Skip verifying shared object in local gc verification.
455 if (value.IsInSharedHeap()) {
456 return;
457 }
458 VerifyObjectSlot(slot, &failCount);
459 }
460 };
461 RootBaseAndDerivedVisitor derivedVisitor =
462 []([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived,
463 [[maybe_unused]] uintptr_t baseOldObject) {
464 };
465 ObjectXRay::VisitVMRoots(heap_->GetEcmaVM(), visitor, rangeVisitor, derivedVisitor, VMRootVisitType::VERIFY);
466 if (failCount > 0) {
467 LOG_GC(ERROR) << "VerifyRoot detects deadObject count is " << failCount;
468 }
469
470 return failCount;
471 }
472
VerifyHeap() const473 size_t Verification::VerifyHeap() const
474 {
475 size_t failCount = heap_->VerifyHeapObjects(verifyKind_);
476 if (failCount > 0) {
477 LOG_GC(ERROR) << "VerifyHeap detects deadObject count is " << failCount;
478 }
479 return failCount;
480 }
481
VerifyOldToNewRSet() const482 size_t Verification::VerifyOldToNewRSet() const
483 {
484 size_t failCount = heap_->VerifyOldToNewRSet(verifyKind_);
485 if (failCount > 0) {
486 LOG_GC(ERROR) << "VerifyOldToNewRSet detects non new space count is " << failCount;
487 }
488 return failCount;
489 }
490
VerifyObjectSlot(const ObjectSlot & slot,size_t * failCount) const491 void Verification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const
492 {
493 JSTaggedValue value(slot.GetTaggedType());
494 if (value.IsWeak()) {
495 VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedWeakRef());
496 } else if (value.IsHeapObject()) {
497 VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedObject());
498 }
499 }
500
VerifyMark(Heap * heap)501 void Verification::VerifyMark(Heap *heap)
502 {
503 LOG_ECMA(DEBUG) << "start verify mark";
504 switch (heap->GetMarkType()) {
505 case MarkType::MARK_EDEN:
506 Verification(heap, VerifyKind::VERIFY_MARK_EDEN).VerifyAll();
507 break;
508 case MarkType::MARK_YOUNG:
509 Verification(heap, VerifyKind::VERIFY_MARK_YOUNG).VerifyAll();
510 break;
511 case MarkType::MARK_FULL:
512 Verification(heap, VerifyKind::VERIFY_MARK_FULL).VerifyAll();
513 break;
514 }
515 }
516
VerifyEvacuate(Heap * heap)517 void Verification::VerifyEvacuate(Heap *heap)
518 {
519 LOG_ECMA(DEBUG) << "start verify evacuate and sweep";
520 switch (heap->GetMarkType()) {
521 case MarkType::MARK_EDEN:
522 Verification(heap, VerifyKind::VERIFY_EVACUATE_EDEN).VerifyAll();
523 break;
524 case MarkType::MARK_YOUNG:
525 Verification(heap, VerifyKind::VERIFY_EVACUATE_YOUNG).VerifyAll();
526 break;
527 case MarkType::MARK_FULL:
528 Verification(heap, VerifyKind::VERIFY_EVACUATE_OLD).VerifyAll();
529 break;
530 }
531 }
532
VerifyAll() const533 void SharedHeapVerification::VerifyAll() const
534 {
535 [[maybe_unused]] VerifyScope verifyScope(sHeap_);
536 sHeap_->GetSweeper()->EnsureAllTaskFinished();
537 size_t result = VerifyRoot();
538 result += VerifyHeap();
539 if (result > 0) {
540 LOG_GC(FATAL) << "Verify (type=" << static_cast<uint8_t>(verifyKind_)
541 << ") corrupted and " << result << " corruptions";
542 }
543 }
544
VerifyMark(bool cm) const545 void SharedHeapVerification::VerifyMark(bool cm) const
546 {
547 LOG_GC(DEBUG) << "start verify shared mark";
548 [[maybe_unused]] VerifyScope verifyScope(sHeap_);
549 sHeap_->GetSweeper()->EnsureAllTaskFinished();
550 Runtime::GetInstance()->GCIterateThreadList([cm](JSThread *thread) {
551 auto vm = thread->GetEcmaVM();
552 auto heap = vm->GetHeap();
553 heap->GetSweeper()->EnsureAllTaskFinished();
554 const_cast<Heap*>(heap)->FillBumpPointerForTlab();
555 auto localBuffer = const_cast<Heap*>(heap)->GetMarkingObjectLocalBuffer();
556 if (localBuffer != nullptr) {
557 LOG_GC(FATAL) << "verify shared node not null " << cm << ':' << thread;
558 UNREACHABLE();
559 }
560 heap->IterateOverObjects([cm](TaggedObject *obj) {
561 auto jsHclass = obj->GetClass();
562 auto f = [cm] (ObjectSlot slot, TaggedObject *obj) {
563 Region *objectRegion = Region::ObjectAddressToRange(obj);
564 JSTaggedValue value(slot.GetTaggedType());
565 if (value.IsWeak() || !value.IsHeapObject()) {
566 return;
567 }
568 Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
569 if (!valueRegion->InSharedSweepableSpace()) {
570 return;
571 }
572 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
573 LOG_GC(FATAL) << "verify shared1 " << cm << ':' << slot.SlotAddress()
574 << ' ' << value.GetTaggedObject();
575 UNREACHABLE();
576 }
577 if (!valueRegion->Test(value.GetTaggedObject())) {
578 LOG_GC(FATAL) << "verify shared2 " << cm << ':' << slot.SlotAddress()
579 << ' ' << value.GetTaggedObject();
580 UNREACHABLE();
581 }
582 if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
583 LOG_GC(FATAL) << "verify shared3 " << cm << ':' << slot.SlotAddress()
584 << ' ' << value.GetTaggedObject();
585 UNREACHABLE();
586 }
587 };
588 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
589 obj, jsHclass, [f](TaggedObject *root, ObjectSlot start, ObjectSlot end,
590 VisitObjectArea area) {
591 if (area == VisitObjectArea::IN_OBJECT) {
592 auto hclass = root->GetClass();
593 ASSERT(!hclass->IsAllTaggedProp());
594 int index = 0;
595 for (ObjectSlot slot = start; slot < end; slot++) {
596 auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
597 auto attr = layout->GetAttr(index++);
598 if (attr.IsTaggedRep()) {
599 f(slot, root);
600 }
601 }
602 return;
603 }
604 for (ObjectSlot slot = start; slot < end; slot++) {
605 f(slot, root);
606 }
607 });
608 });
609 });
610 sHeap_->IterateOverObjects([cm](TaggedObject *obj) {
611 auto jsHclass = obj->GetClass();
612 auto f = [cm] (ObjectSlot slot, TaggedObject *obj) {
613 Region *objectRegion = Region::ObjectAddressToRange(obj);
614 if (!objectRegion->Test(obj)) {
615 return;
616 }
617 JSTaggedValue value(slot.GetTaggedType());
618 if (value.IsWeak() || !value.IsHeapObject()) {
619 return;
620 }
621 [[maybe_unused]] Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
622 if (!valueRegion->InSharedHeap()) {
623 LOG_GC(FATAL) << "verify shared4 " << cm << ':' << slot.SlotAddress()
624 << ' ' << value.GetTaggedObject();
625 UNREACHABLE();
626 }
627 if (!valueRegion->InSharedReadOnlySpace() && !valueRegion->Test(value.GetTaggedObject())) {
628 LOG_GC(FATAL) << "verify shared5 " << cm << ':' << slot.SlotAddress()
629 << ' ' << value.GetTaggedObject();
630 UNREACHABLE();
631 }
632 if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
633 LOG_GC(FATAL) << "verify shared6 " << cm << ':' << slot.SlotAddress()
634 << ' ' << value.GetTaggedObject();
635 UNREACHABLE();
636 }
637 };
638 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
639 obj, jsHclass, [f](TaggedObject *root, ObjectSlot start, ObjectSlot end,
640 VisitObjectArea area) {
641 if (area == VisitObjectArea::IN_OBJECT) {
642 auto hclass = root->GetClass();
643 ASSERT(!hclass->IsAllTaggedProp());
644 int index = 0;
645 for (ObjectSlot slot = start; slot < end; slot++) {
646 auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
647 auto attr = layout->GetAttr(index++);
648 if (attr.IsTaggedRep()) {
649 f(slot, root);
650 }
651 }
652 return;
653 }
654 for (ObjectSlot slot = start; slot < end; slot++) {
655 f(slot, root);
656 }
657 });
658 });
659 }
660
VerifySweep(bool cm) const661 void SharedHeapVerification::VerifySweep(bool cm) const
662 {
663 LOG_GC(DEBUG) << "start verify shared sweep";
664 [[maybe_unused]] VerifyScope verifyScope(sHeap_);
665 sHeap_->GetSweeper()->EnsureAllTaskFinished();
666 Runtime::GetInstance()->GCIterateThreadList([cm](JSThread *thread) {
667 auto vm = thread->GetEcmaVM();
668 auto heap = vm->GetHeap();
669 heap->GetSweeper()->EnsureAllTaskFinished();
670 const_cast<Heap*>(heap)->FillBumpPointerForTlab();
671 heap->IterateOverObjects([cm](TaggedObject *obj) {
672 auto jsHclass = obj->GetClass();
673 auto f = [cm] (ObjectSlot slot, TaggedObject *obj) {
674 Region *objectRegion = Region::ObjectAddressToRange(obj);
675 JSTaggedValue value(slot.GetTaggedType());
676 if (value.IsWeak() || !value.IsHeapObject()) {
677 return;
678 }
679 Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
680 if (!valueRegion->InSharedSweepableSpace()) {
681 return;
682 }
683 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
684 LOG_GC(FATAL) << "verify shared7 " << cm << ':' << slot.SlotAddress()
685 << ' ' << value.GetTaggedObject();
686 UNREACHABLE();
687 }
688 if (!valueRegion->Test(value.GetTaggedObject())) {
689 LOG_GC(FATAL) << "verify shared8 " << cm << ':' << slot.SlotAddress()
690 << ' ' << value.GetTaggedObject();
691 UNREACHABLE();
692 }
693 if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
694 LOG_GC(FATAL) << "verify shared9 " << cm << ':' << slot.SlotAddress()
695 << ' ' << value.GetTaggedObject();
696 UNREACHABLE();
697 }
698 };
699 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
700 obj, jsHclass, [f](TaggedObject *root, ObjectSlot start, ObjectSlot end,
701 VisitObjectArea area) {
702 if (area == VisitObjectArea::IN_OBJECT) {
703 auto hclass = root->GetClass();
704 ASSERT(!hclass->IsAllTaggedProp());
705 int index = 0;
706 for (ObjectSlot slot = start; slot < end; slot++) {
707 auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
708 auto attr = layout->GetAttr(index++);
709 if (attr.IsTaggedRep()) {
710 f(slot, root);
711 }
712 }
713 return;
714 }
715 for (ObjectSlot slot = start; slot < end; slot++) {
716 f(slot, root);
717 }
718 });
719 });
720 });
721 sHeap_->IterateOverObjects([cm](TaggedObject *obj) {
722 auto jsHclass = obj->GetClass();
723 auto f = [cm] (ObjectSlot slot, TaggedObject *obj) {
724 [[maybe_unused]] Region *objectRegion = Region::ObjectAddressToRange(obj);
725 if (!objectRegion->Test(obj)) {
726 LOG_GC(FATAL) << "verify shared10 " << cm << ':' << obj;
727 UNREACHABLE();
728 }
729 JSTaggedValue value(slot.GetTaggedType());
730 if (value.IsWeak() || !value.IsHeapObject()) {
731 return;
732 }
733 [[maybe_unused]] Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
734 if (!valueRegion->InSharedHeap()) {
735 LOG_GC(FATAL) << "verify shared11 " << cm << ':' << slot.SlotAddress()
736 << ' ' << value.GetTaggedObject();
737 UNREACHABLE();
738 }
739 if (!valueRegion->InSharedReadOnlySpace() && !valueRegion->Test(value.GetTaggedObject())) {
740 LOG_GC(FATAL) << "verify shared12 " << cm << ':' << slot.SlotAddress()
741 << ' ' << value.GetTaggedObject();
742 UNREACHABLE();
743 }
744 if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
745 LOG_GC(FATAL) << "verify shared13 " << cm << ':' << slot.SlotAddress()
746 << ' ' << value.GetTaggedObject();
747 UNREACHABLE();
748 }
749 };
750 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
751 obj, jsHclass, [f](TaggedObject *root, ObjectSlot start, ObjectSlot end,
752 VisitObjectArea area) {
753 if (area == VisitObjectArea::IN_OBJECT) {
754 auto hclass = root->GetClass();
755 ASSERT(!hclass->IsAllTaggedProp());
756 int index = 0;
757 for (ObjectSlot slot = start; slot < end; slot++) {
758 auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
759 auto attr = layout->GetAttr(index++);
760 if (attr.IsTaggedRep()) {
761 f(slot, root);
762 }
763 }
764 return;
765 }
766 for (ObjectSlot slot = start; slot < end; slot++) {
767 f(slot, root);
768 }
769 });
770 });
771 }
772
VerifyRoot() const773 size_t SharedHeapVerification::VerifyRoot() const
774 {
775 size_t failCount = 0;
776 RootVisitor visitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) {
777 VerifyObjectSlot(slot, &failCount);
778 };
779 RootRangeVisitor rangeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) {
780 for (ObjectSlot slot = start; slot < end; slot++) {
781 VerifyObjectSlot(slot, &failCount);
782 }
783 };
784 RootBaseAndDerivedVisitor derivedVisitor =
785 []([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived,
786 [[maybe_unused]] uintptr_t baseOldObject) {
787 };
788 RootVisitor serializeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) {
789 JSTaggedValue value(slot.GetTaggedType());
790 if (!sHeap_->IsAlive(value.GetTaggedObject())) {
791 LOG_ECMA(ERROR) << "Serialize Heap verify detected a dead object. " << value.GetTaggedObject();
792 ++failCount;
793 }
794 };
795 Runtime::GetInstance()->IterateSerializeRoot(serializeVisitor);
796 Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
797 ASSERT(!thread->IsInRunningState());
798 auto vm = thread->GetEcmaVM();
799 auto localHeap = const_cast<Heap*>(vm->GetHeap());
800 localHeap->GetSweeper()->EnsureAllTaskFinished();
801 ObjectXRay::VisitVMRoots(vm, visitor, rangeVisitor, derivedVisitor, VMRootVisitType::VERIFY);
802 if (failCount > 0) {
803 LOG_GC(ERROR) << "SharedHeap VerifyRoot detects deadObject count is " << failCount;
804 }
805 });
806 return failCount;
807 }
808
VerifyHeap() const809 size_t SharedHeapVerification::VerifyHeap() const
810 {
811 Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
812 ASSERT(!thread->IsInRunningState());
813 const_cast<Heap*>(thread->GetEcmaVM()->GetHeap())->FillBumpPointerForTlab();
814 });
815 size_t failCount = sHeap_->VerifyHeapObjects(verifyKind_);
816 if (failCount > 0) {
817 LOG_GC(ERROR) << "SharedHeap VerifyHeap detects deadObject count is " << failCount;
818 }
819 VerifyKind localVerifyKind = VerifyKind::VERIFY_END;
820 if (verifyKind_ == VerifyKind::VERIFY_PRE_SHARED_GC) {
821 localVerifyKind = VerifyKind::VERIFY_PRE_GC;
822 } else if (verifyKind_ == VerifyKind::VERIFY_POST_SHARED_GC) {
823 localVerifyKind = VerifyKind::VERIFY_POST_GC;
824 }
825
826 Runtime::GetInstance()->GCIterateThreadList([&, localVerifyKind](JSThread *thread) {
827 ASSERT(!thread->IsInRunningState());
828 auto vm = thread->GetEcmaVM();
829 auto localHeap = const_cast<Heap*>(vm->GetHeap());
830 localHeap->GetSweeper()->EnsureAllTaskFinished();
831 if (localVerifyKind != VerifyKind::VERIFY_END) {
832 Verification(localHeap, localVerifyKind).VerifyAll();
833 }
834 if (failCount > 0) {
835 LOG_GC(ERROR) << "SharedHeap VerifyRoot detects deadObject in local heap count is " << failCount;
836 }
837 });
838 return failCount;
839 }
840
VerifyObjectSlot(const ObjectSlot & slot,size_t * failCount) const841 void SharedHeapVerification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const
842 {
843 JSTaggedValue value(slot.GetTaggedType());
844 if (value.IsWeak()) {
845 VerifyObjectVisitor(sHeap_, failCount, verifyKind_)(value.GetTaggedWeakRef());
846 } else if (value.IsHeapObject()) {
847 VerifyObjectVisitor(sHeap_, failCount, verifyKind_)(value.GetTaggedObject());
848 }
849 }
850 } // namespace panda::ecmascript
851