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
21namespace panda::ecmascript {
22void LogErrorForObjSlot(const BaseHeap *heap, const char *headerInfo, TaggedObject *obj, ObjectSlot slot,
23                        TaggedObject *value)
24{ // LCOV_EXCL_START
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
52void 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} // LCOV_EXCL_STOP
65
66// Only used for verify InactiveSemiSpace
67void 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()) { // LCOV_EXCL_START
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    } // LCOV_EXCL_STOP
87}
88
89// Verify the object body
90void 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
115void VerifyObjectVisitor::VerifyObjectSlotLegal(ObjectSlot slot, TaggedObject *object) const
116{
117    JSTaggedValue value(slot.GetTaggedType());
118    if (value.IsWeak()) { // LCOV_EXCL_START
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    } // LCOV_EXCL_STOP
131}
132
133void VerifyObjectVisitor::VerifyHeapObjectSlotLegal(ObjectSlot slot,
134                                                    JSTaggedValue slotValue,
135                                                    TaggedObject *object) const
136{
137    ASSERT(slotValue.IsHeapObject());
138    if (ToUintPtr(slotValue.GetTaggedObject()) < INVALID_THRESHOLD) { // LCOV_EXCL_START
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    } // LCOV_EXCL_STOP
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: // LCOV_EXCL_START
180            LOG_GC(FATAL) << "unknown verify kind:" << static_cast<size_t>(verifyKind_);
181            UNREACHABLE(); // LCOV_EXCL_STOP
182    }
183}
184
185void 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()) { // LCOV_EXCL_START
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()
213                && !objectRegion->InReadOnlySpace()) {
214            LogErrorForObj(heap_, "Verify MarkYoung: Marked object, NOT in Eden Space", object);
215        }
216        if (valueRegion->InEdenSpace() && !valueRegion->Test(value)) {
217            LogErrorForObjSlot(heap_, "Verify MarkEden: Marked object, slot in EdenSpace, miss gc_mark bit.",
218                object, slot, value);
219        }
220        if (valueRegion->Test(value) && !(valueRegion->InEdenSpace() || valueRegion->InAppSpawnSpace()
221                || valueRegion->InReadOnlySpace() || valueRegion->InSharedHeap())) {
222            LogErrorForObjSlot(heap_, "Verify MarkEden: Marked object, slot marked, but NOT in Eden Space.",
223                object, slot, value);
224        }
225    } // LCOV_EXCL_STOP
226}
227
228
229void VerifyObjectVisitor::VerifyMarkYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
230{
231    Region *objectRegion = Region::ObjectAddressToRange(object);
232    Region *valueRegion = Region::ObjectAddressToRange(value);
233    ASSERT(!objectRegion->InSharedHeap());
234    if (objectRegion->InGeneralOldSpace() && valueRegion->InGeneralNewSpace()) { // LCOV_EXCL_START
235        if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
236            LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot miss old_to_new bit.", object, slot, value);
237        } else if (!valueRegion->Test(value)) {
238            LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot has old_to_new bit, miss gc_mark bit.",
239                object, slot, value);
240        }
241    }
242    if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
243        if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
244            LogErrorForObjSlot(heap_, "Verify MarkYoung: Local object, slot local_to_share bit = 0, "
245                "but SharedHeap object.", object, slot, value);
246        }
247    }
248    if (objectRegion->Test(object)) {
249        if (!objectRegion->InGeneralNewSpace() && !objectRegion->InAppSpawnSpace() &&
250            !objectRegion->InReadOnlySpace()) {
251            LogErrorForObj(heap_, "Verify MarkYoung: Marked object, NOT in Young/AppSpawn/ReadOnly Space", object);
252        }
253        if (valueRegion->InGeneralNewSpace() && !valueRegion->Test(value)) {
254            LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot in YoungSpace, miss gc_mark bit.",
255                object, slot, value);
256        }
257        if (valueRegion->Test(value) &&
258            !(valueRegion->InYoungSpace() || valueRegion->InAppSpawnSpace() || valueRegion->InReadOnlySpace() ||
259              valueRegion->InSharedHeap() || valueRegion->InEdenSpace())) {
260            LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot marked, but NOT in "
261                "Young/AppSpawn/ReadOnly Space.", object, slot, value);
262        }
263    } // LCOV_EXCL_STOP
264}
265
266void VerifyObjectVisitor::VerifyEvacuateEden(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
267{
268    Region *objectRegion = Region::ObjectAddressToRange(object);
269    Region *valueRegion = Region::ObjectAddressToRange(value);
270    if (objectRegion->InGeneralOldSpace()) { // LCOV_EXCL_START
271        if (objectRegion->TestOldToNew(slot.SlotAddress())) {
272            if (!valueRegion->InActiveSemiSpace()) {
273                if (valueRegion->InEdenSpace()) {
274                    LogErrorForObjSlot(heap_, "Verify EvacuateEden: Old object, slot old_to_new bit = 1, "
275                        "but in EdenSpace object.", object, slot, value);
276                }
277                LogErrorForObjSlot(heap_, "Verify EvacuateEden: Old object, slot old_to_new bit = 1, "
278                    "but NOT ActiveSpace(ToSpace) object.", object, slot, value);
279            }
280        } else {
281            if (valueRegion->InGeneralNewSpace()) {
282                LogErrorForObjSlot(heap_, "Verify EvacuateEden: Old object, slot old_to_new bit = 0, "
283                    "but YoungSpace object.", object, slot, value);
284            }
285        }
286    }
287    if (objectRegion->InYoungSpace()) {
288        if (objectRegion->TestNewToEden(slot.SlotAddress())) {
289            if (!valueRegion->InEdenSpace()) {
290                LogErrorForObjSlot(heap_, "Verify EvacuateEden: Young object, slot young_to_eden bit = 1, "
291                    "but NOT Eden object.", object, slot, value);
292            } else {
293                LogErrorForObjSlot(heap_, "Verify EvacuateEden: Young object, slot young_to_eden bit = 1, "
294                    "but Eden object.", object, slot, value);
295            }
296        } else {
297            if (valueRegion->InEdenSpace()) {
298                LogErrorForObjSlot(heap_, "Verify EvacuateEden: Young object, slot young_to_eden bit = 0, "
299                    "but Eden object.", object, slot, value);
300            }
301        }
302    } // LCOV_EXCL_STOP
303}
304
305void VerifyObjectVisitor::VerifyEvacuateYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
306{
307    Region *objectRegion = Region::ObjectAddressToRange(object);
308    Region *valueRegion = Region::ObjectAddressToRange(value);
309
310    if (objectRegion->InGeneralOldSpace()) { // LCOV_EXCL_START
311        if (objectRegion->TestOldToNew(slot.SlotAddress())) {
312            if (!valueRegion->InActiveSemiSpace()) {
313                if (valueRegion->InEdenSpace()) {
314                    LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 1, "
315                        "but in EdenSpace object.", object, slot, value);
316                }
317                LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 1, "
318                    "but NOT ActiveSpace(ToSpace) object.", object, slot, value);
319            }
320        } else {
321            if (valueRegion->InGeneralNewSpace()) {
322                LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 0, "
323                    "but YoungSpace object.", object, slot, value);
324            }
325        }
326    }
327    if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
328        if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
329            LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Local object, slot local_to_share bit = 0, "
330                "but SharedHeap object.", object, slot, value);
331        }
332    }
333    if (objectRegion->InActiveSemiSpace()) {
334        if (valueRegion->InInactiveSemiSpace()) {
335            LogErrorForObjSlot(heap_, "Verify EvacuateYoung: ActiveSpace object, slot in InactiveSpace(FromSpace).",
336                object, slot, value);
337        } else if (valueRegion->InEdenSpace()) {
338            LogErrorForObjSlot(heap_, "Verify EvacuateYoung: ActiveSpace object, slot in EdenSpace.",
339                object, slot, value);
340        }
341    } // LCOV_EXCL_STOP
342}
343
344void VerifyObjectVisitor::VerifyMarkFull(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
345{
346    Region *objectRegion = Region::ObjectAddressToRange(object);
347    Region *valueRegion = Region::ObjectAddressToRange(value);
348    if (objectRegion->InGeneralOldSpace() && valueRegion->InGeneralNewSpace()) { // LCOV_EXCL_START
349        if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
350            LogErrorForObjSlot(heap_, "Verify MarkFull: Old object, slot miss old_to_new bit.", object, slot, value);
351        }
352    }
353    if (objectRegion->Test(object)) {
354        if (!valueRegion->InSharedHeap() && !valueRegion->Test(value)) {
355            LogErrorForObjSlot(heap_, "Verify MarkFull: Marked object, slot miss gc_mark bit.", object, slot, value);
356        }
357    }
358    if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
359        if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
360            LogErrorForObjSlot(heap_, "Verify VerifyMarkFull: Local object, slot local_to_share bit = 0, "
361                "but SharedHeap object.", object, slot, value);
362        }
363    } // LCOV_EXCL_STOP
364}
365
366void VerifyObjectVisitor::VerifyEvacuateOld([[maybe_unused]]TaggedObject *root,
367                                            [[maybe_unused]]ObjectSlot slot,
368                                            [[maybe_unused]]TaggedObject *value) const
369{
370    VerifyEvacuateYoung(root, slot, value);
371}
372
373void VerifyObjectVisitor::VerifyEvacuateFull([[maybe_unused]]TaggedObject *root,
374                                             [[maybe_unused]]ObjectSlot slot,
375                                             [[maybe_unused]]TaggedObject *value) const
376{
377    VerifyEvacuateYoung(root, slot, value);
378}
379
380void VerifyObjectVisitor::VerifySharedObjectReference(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
381{
382    Region *objectRegion = Region::ObjectAddressToRange(object);
383    Region *valueRegion = Region::ObjectAddressToRange(value);
384    if (objectRegion->InSharedHeap()) { // LCOV_EXCL_START
385        if (!valueRegion->InSharedHeap()) {
386            LogErrorForObjSlot(heap_, "Verify SharedObjectReference: Shared object references a local object",
387                object, slot, value);
388        }
389    } else if (valueRegion->InSharedSweepableSpace()) {
390        if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
391            LogErrorForObjSlot(heap_, "Verify SharedObjectReference: Local object, slot local_to_share bit = 0, "
392                "but SharedHeap object.", object, slot, value);
393        }
394    } // LCOV_EXCL_STOP
395}
396
397void VerifyObjectVisitor::VerifySharedRSetPostFullGC(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
398{
399    Region *objectRegion = Region::ObjectAddressToRange(object);
400    Region *valueRegion = Region::ObjectAddressToRange(value);
401    if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { // LCOV_EXCL_START
402        if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
403            LogErrorForObjSlot(heap_, "Verify SharedRSetPostFullGC: Local object, slot local_to_share bit = 0, "
404                "but SharedHeap object.", object, slot, value);
405        }
406    } // LCOV_EXCL_STOP
407}
408
409void VerifyObjectVisitor::operator()(TaggedObject *obj, JSTaggedValue value)
410{
411    ObjectSlot slot(reinterpret_cast<uintptr_t>(obj));
412    if (!value.IsHeapObject()) {
413        LOG_GC(DEBUG) << "Heap object(" << slot.SlotAddress() << ") old to new rset fail: value is "
414                      << slot.GetTaggedType();
415        return;
416    }
417
418    TaggedObject *object = value.GetRawTaggedObject();
419    auto region = Region::ObjectAddressToRange(object);
420    if (region->InGeneralOldSpace()) { // LCOV_EXCL_START
421        LOG_GC(ERROR) << "Heap object(" << slot.GetTaggedType() << ") old to new rset fail: value("
422                      << slot.GetTaggedObject() << "/"
423                      << JSHClass::DumpJSType(slot.GetTaggedObject()->GetClass()->GetObjectType())
424                      << ")" << " in " << region->GetSpaceTypeName();
425        ++(*failCount_);
426    } // LCOV_EXCL_STOP
427}
428
429void Verification::VerifyAll() const
430{
431    [[maybe_unused]] VerifyScope verifyScope(heap_);
432    heap_->GetSweeper()->EnsureAllTaskFinished();
433    size_t result = VerifyRoot();
434    result += VerifyHeap();
435    if (result > 0) { // LCOV_EXCL_START
436        LOG_GC(FATAL) << "Verify (type=" << static_cast<uint8_t>(verifyKind_)
437                      << ") corrupted and " << result << " corruptions";
438    } // LCOV_EXCL_STOP
439}
440
441size_t Verification::VerifyRoot() const
442{
443    size_t failCount = 0;
444    RootVisitor visitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) {
445        JSTaggedValue value(slot.GetTaggedType());
446        // Skip verifying shared object in local gc verification.
447        if (value.IsInSharedHeap()) {
448            return;
449        }
450        VerifyObjectSlot(slot, &failCount);
451    };
452    RootRangeVisitor rangeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) {
453        for (ObjectSlot slot = start; slot < end; slot++) {
454            JSTaggedValue value(slot.GetTaggedType());
455            // Skip verifying shared object in local gc verification.
456            if (value.IsInSharedHeap()) {
457                return;
458            }
459            VerifyObjectSlot(slot, &failCount);
460        }
461    };
462    RootBaseAndDerivedVisitor derivedVisitor =
463        []([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived,
464           [[maybe_unused]] uintptr_t baseOldObject) {
465    };
466    ObjectXRay::VisitVMRoots(heap_->GetEcmaVM(), visitor, rangeVisitor, derivedVisitor, VMRootVisitType::VERIFY);
467    if (failCount > 0) {
468        LOG_GC(ERROR) << "VerifyRoot detects deadObject count is " << failCount;
469    }
470
471    return failCount;
472}
473
474size_t Verification::VerifyHeap() const
475{
476    size_t failCount = heap_->VerifyHeapObjects(verifyKind_);
477    if (failCount > 0) {
478        LOG_GC(ERROR) << "VerifyHeap detects deadObject count is " << failCount;
479    }
480    return failCount;
481}
482
483size_t Verification::VerifyOldToNewRSet() const
484{
485    size_t failCount = heap_->VerifyOldToNewRSet(verifyKind_);
486    if (failCount > 0) {
487        LOG_GC(ERROR) << "VerifyOldToNewRSet detects non new space count is " << failCount;
488    }
489    return failCount;
490}
491
492void Verification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const
493{
494    JSTaggedValue value(slot.GetTaggedType());
495    if (value.IsWeak()) {
496        VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedWeakRef());
497    } else if (value.IsHeapObject()) {
498        VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedObject());
499    }
500}
501
502void Verification::VerifyMark(Heap *heap)
503{
504    LOG_ECMA(DEBUG) << "start verify mark";
505    switch (heap->GetMarkType()) {
506        case MarkType::MARK_EDEN:
507            Verification(heap, VerifyKind::VERIFY_MARK_EDEN).VerifyAll();
508            break;
509        case MarkType::MARK_YOUNG:
510            Verification(heap, VerifyKind::VERIFY_MARK_YOUNG).VerifyAll();
511            break;
512        case MarkType::MARK_FULL:
513            Verification(heap, VerifyKind::VERIFY_MARK_FULL).VerifyAll();
514            break;
515    }
516}
517
518void Verification::VerifyEvacuate(Heap *heap)
519{
520    LOG_ECMA(DEBUG) << "start verify evacuate and sweep";
521    switch (heap->GetMarkType()) {
522        case MarkType::MARK_EDEN:
523            Verification(heap, VerifyKind::VERIFY_EVACUATE_EDEN).VerifyAll();
524            break;
525        case MarkType::MARK_YOUNG:
526            Verification(heap, VerifyKind::VERIFY_EVACUATE_YOUNG).VerifyAll();
527            break;
528        case MarkType::MARK_FULL:
529            Verification(heap, VerifyKind::VERIFY_EVACUATE_OLD).VerifyAll();
530            break;
531    }
532}
533
534void SharedHeapVerification::VerifyAll() const
535{
536    [[maybe_unused]] VerifyScope verifyScope(sHeap_);
537    sHeap_->GetSweeper()->EnsureAllTaskFinished();
538    size_t result = VerifyRoot();
539    result += VerifyHeap();
540    if (result > 0) { // LCOV_EXCL_START
541        LOG_GC(FATAL) << "Verify (type=" << static_cast<uint8_t>(verifyKind_)
542                      << ") corrupted and " << result << " corruptions";
543    } // LCOV_EXCL_STOP
544}
545
546void SharedHeapVerification::VerifyMark(bool cm) const
547{
548    LOG_GC(DEBUG) << "start verify shared mark";
549    [[maybe_unused]] VerifyScope verifyScope(sHeap_);
550    sHeap_->GetSweeper()->EnsureAllTaskFinished();
551    Runtime::GetInstance()->GCIterateThreadList([cm](JSThread *thread) {
552        auto vm = thread->GetEcmaVM();
553        auto heap = vm->GetHeap();
554        heap->GetSweeper()->EnsureAllTaskFinished();
555        const_cast<Heap*>(heap)->FillBumpPointerForTlab();
556        auto localBuffer = const_cast<Heap*>(heap)->GetMarkingObjectLocalBuffer();
557        if (localBuffer != nullptr) { // LCOV_EXCL_START
558            LOG_GC(FATAL) << "verify shared node not null " << cm << ':' << thread;
559            UNREACHABLE();
560        } // LCOV_EXCL_STOP
561        heap->IterateOverObjects([cm](TaggedObject *obj) {
562            auto jsHclass = obj->GetClass();
563            auto f = [cm] (ObjectSlot slot, TaggedObject *obj) {
564                Region *objectRegion = Region::ObjectAddressToRange(obj);
565                JSTaggedValue value(slot.GetTaggedType());
566                if (value.IsWeak() || !value.IsHeapObject()) {
567                    return;
568                }
569                Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
570                if (!valueRegion->InSharedSweepableSpace()) {
571                    return;
572                }
573                if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { // LCOV_EXCL_START
574                    LOG_GC(FATAL) << "verify shared1 " << cm << ':' << slot.SlotAddress()
575                                  << ' ' << value.GetTaggedObject();
576                    UNREACHABLE();
577                }
578                if (!valueRegion->Test(value.GetTaggedObject())) {
579                    LOG_GC(FATAL) << "verify shared2 " << cm << ':' << slot.SlotAddress()
580                                  << ' ' << value.GetTaggedObject();
581                    UNREACHABLE();
582                }
583                if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
584                    LOG_GC(FATAL) << "verify shared3 " << cm << ':' << slot.SlotAddress()
585                                  << ' ' << value.GetTaggedObject();
586                    UNREACHABLE();
587                } // LCOV_EXCL_STOP
588            };
589            ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
590                obj, jsHclass, [f](TaggedObject *root, ObjectSlot start, ObjectSlot end,
591                                VisitObjectArea area) {
592                if (area == VisitObjectArea::IN_OBJECT) {
593                    auto hclass = root->GetClass();
594                    ASSERT(!hclass->IsAllTaggedProp());
595                    int index = 0;
596                    for (ObjectSlot slot = start; slot < end; slot++) {
597                        auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
598                        auto attr = layout->GetAttr(index++);
599                        if (attr.IsTaggedRep()) {
600                            f(slot, root);
601                        }
602                    }
603                    return;
604                }
605                for (ObjectSlot slot = start; slot < end; slot++) {
606                    f(slot, root);
607                }
608            });
609        });
610    });
611    sHeap_->IterateOverObjects([cm](TaggedObject *obj) {
612        auto jsHclass = obj->GetClass();
613        auto f = [cm] (ObjectSlot slot, TaggedObject *obj) {
614            Region *objectRegion = Region::ObjectAddressToRange(obj);
615            if (!objectRegion->Test(obj)) {
616                return;
617            }
618            JSTaggedValue value(slot.GetTaggedType());
619            if (value.IsWeak() || !value.IsHeapObject()) {
620                return;
621            }
622            [[maybe_unused]] Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
623            if (!valueRegion->InSharedHeap()) { // LCOV_EXCL_START
624                LOG_GC(FATAL) << "verify shared4 " << cm << ':' << slot.SlotAddress()
625                              << ' ' << value.GetTaggedObject();
626                UNREACHABLE();
627            }
628            if (!valueRegion->InSharedReadOnlySpace()
629                    && !valueRegion->Test(value.GetTaggedObject())) {
630                LOG_GC(FATAL) << "verify shared5 " << cm << ':' << slot.SlotAddress()
631                              << ' ' << value.GetTaggedObject();
632                UNREACHABLE();
633            }
634            if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
635                LOG_GC(FATAL) << "verify shared6 " << cm << ':' << slot.SlotAddress()
636                              << ' ' << value.GetTaggedObject();
637                UNREACHABLE();
638            } // LCOV_EXCL_STOP
639        };
640        ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
641            obj, jsHclass, [f](TaggedObject *root, ObjectSlot start, ObjectSlot end,
642                               VisitObjectArea area) {
643            if (area == VisitObjectArea::IN_OBJECT) {
644                auto hclass = root->GetClass();
645                ASSERT(!hclass->IsAllTaggedProp());
646                int index = 0;
647                for (ObjectSlot slot = start; slot < end; slot++) {
648                    auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
649                    auto attr = layout->GetAttr(index++);
650                    if (attr.IsTaggedRep()) {
651                        f(slot, root);
652                    }
653                }
654                return;
655            }
656            for (ObjectSlot slot = start; slot < end; slot++) {
657                f(slot, root);
658            }
659        });
660    });
661}
662
663void SharedHeapVerification::VerifySweep(bool cm) const
664{
665    LOG_GC(DEBUG) << "start verify shared sweep";
666    [[maybe_unused]] VerifyScope verifyScope(sHeap_);
667    sHeap_->GetSweeper()->EnsureAllTaskFinished();
668    Runtime::GetInstance()->GCIterateThreadList([cm](JSThread *thread) {
669        auto vm = thread->GetEcmaVM();
670        auto heap = vm->GetHeap();
671        heap->GetSweeper()->EnsureAllTaskFinished();
672        const_cast<Heap*>(heap)->FillBumpPointerForTlab();
673        heap->IterateOverObjects([cm](TaggedObject *obj) {
674            auto jsHclass = obj->GetClass();
675            auto f = [cm] (ObjectSlot slot, TaggedObject *obj) {
676                Region *objectRegion = Region::ObjectAddressToRange(obj);
677                JSTaggedValue value(slot.GetTaggedType());
678                if (value.IsWeak() || !value.IsHeapObject()) {
679                    return;
680                }
681                Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
682                if (!valueRegion->InSharedSweepableSpace()) {
683                    return;
684                }
685                if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { // LCOV_EXCL_START
686                    LOG_GC(FATAL) << "verify shared7 " << cm << ':' << slot.SlotAddress()
687                                  << ' ' << value.GetTaggedObject();
688                    UNREACHABLE();
689                }
690                if (!valueRegion->Test(value.GetTaggedObject())) {
691                    LOG_GC(FATAL) << "verify shared8 " << cm << ':' << slot.SlotAddress()
692                                  << ' ' << value.GetTaggedObject();
693                    UNREACHABLE();
694                }
695                if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
696                    LOG_GC(FATAL) << "verify shared9 " << cm << ':' << slot.SlotAddress()
697                                  << ' ' << value.GetTaggedObject();
698                    UNREACHABLE();
699                } // LCOV_EXCL_STOP
700            };
701            ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
702                obj, jsHclass, [f](TaggedObject *root, ObjectSlot start, ObjectSlot end,
703                                VisitObjectArea area) {
704                if (area == VisitObjectArea::IN_OBJECT) {
705                    auto hclass = root->GetClass();
706                    ASSERT(!hclass->IsAllTaggedProp());
707                    int index = 0;
708                    for (ObjectSlot slot = start; slot < end; slot++) {
709                        auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
710                        auto attr = layout->GetAttr(index++);
711                        if (attr.IsTaggedRep()) {
712                            f(slot, root);
713                        }
714                    }
715                    return;
716                }
717                for (ObjectSlot slot = start; slot < end; slot++) {
718                    f(slot, root);
719                }
720            });
721        });
722    });
723    sHeap_->IterateOverObjects([cm](TaggedObject *obj) {
724        auto jsHclass = obj->GetClass();
725        auto f = [cm] (ObjectSlot slot, TaggedObject *obj) {
726            [[maybe_unused]] Region *objectRegion = Region::ObjectAddressToRange(obj);
727            if (!objectRegion->Test(obj)) { // LCOV_EXCL_START
728                LOG_GC(FATAL) << "verify shared10 " << cm << ':' << obj;
729                UNREACHABLE();
730            }
731            JSTaggedValue value(slot.GetTaggedType());
732            if (value.IsWeak() || !value.IsHeapObject()) {
733                return;
734            }
735            [[maybe_unused]] Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
736            if (!valueRegion->InSharedHeap()) {
737                LOG_GC(FATAL) << "verify shared11 " << cm << ':' << slot.SlotAddress()
738                              << ' ' << value.GetTaggedObject();
739                UNREACHABLE();
740            }
741            if (!valueRegion->InSharedReadOnlySpace()
742                    && !valueRegion->Test(value.GetTaggedObject())) {
743                LOG_GC(FATAL) << "verify shared12 " << cm << ':' << slot.SlotAddress()
744                              << ' ' << value.GetTaggedObject();
745                UNREACHABLE();
746            }
747            if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
748                LOG_GC(FATAL) << "verify shared13 " << cm << ':' << slot.SlotAddress()
749                              << ' ' << value.GetTaggedObject();
750                UNREACHABLE();
751            } // LCOV_EXCL_STOP
752        };
753        ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(
754            obj, jsHclass, [f](TaggedObject *root, ObjectSlot start, ObjectSlot end,
755                                VisitObjectArea area) {
756            if (area == VisitObjectArea::IN_OBJECT) {
757                auto hclass = root->GetClass();
758                ASSERT(!hclass->IsAllTaggedProp());
759                int index = 0;
760                for (ObjectSlot slot = start; slot < end; slot++) {
761                    auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
762                    auto attr = layout->GetAttr(index++);
763                    if (attr.IsTaggedRep()) {
764                        f(slot, root);
765                    }
766                }
767                return;
768            }
769            for (ObjectSlot slot = start; slot < end; slot++) {
770                f(slot, root);
771            }
772        });
773    });
774}
775
776size_t SharedHeapVerification::VerifyRoot() const
777{
778    size_t failCount = 0;
779    RootVisitor visitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) {
780        VerifyObjectSlot(slot, &failCount);
781    };
782    RootRangeVisitor rangeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) {
783        for (ObjectSlot slot = start; slot < end; slot++) {
784            VerifyObjectSlot(slot, &failCount);
785        }
786    };
787    RootBaseAndDerivedVisitor derivedVisitor =
788        []([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived,
789           [[maybe_unused]] uintptr_t baseOldObject) {
790    };
791    RootVisitor serializeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) {
792        JSTaggedValue value(slot.GetTaggedType());
793        if (!sHeap_->IsAlive(value.GetTaggedObject())) {
794            LOG_ECMA(ERROR) << "Serialize Heap verify detected a dead object. " << value.GetTaggedObject();
795            ++failCount;
796        }
797    };
798    Runtime::GetInstance()->IterateSerializeRoot(serializeVisitor);
799    Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
800        ASSERT(!thread->IsInRunningState());
801        auto vm = thread->GetEcmaVM();
802        auto localHeap = const_cast<Heap*>(vm->GetHeap());
803        localHeap->GetSweeper()->EnsureAllTaskFinished();
804        ObjectXRay::VisitVMRoots(vm, visitor, rangeVisitor, derivedVisitor, VMRootVisitType::VERIFY);
805        if (failCount > 0) {
806            LOG_GC(ERROR) << "SharedHeap VerifyRoot detects deadObject count is " << failCount;
807        }
808    });
809    return failCount;
810}
811
812size_t SharedHeapVerification::VerifyHeap() const
813{
814    Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
815        ASSERT(!thread->IsInRunningState());
816        const_cast<Heap*>(thread->GetEcmaVM()->GetHeap())->FillBumpPointerForTlab();
817    });
818    size_t failCount = sHeap_->VerifyHeapObjects(verifyKind_);
819    if (failCount > 0) {
820        LOG_GC(ERROR) << "SharedHeap VerifyHeap detects deadObject count is " << failCount;
821    }
822    VerifyKind localVerifyKind = VerifyKind::VERIFY_END;
823    if (verifyKind_ == VerifyKind::VERIFY_PRE_SHARED_GC) {
824        localVerifyKind = VerifyKind::VERIFY_PRE_GC;
825    } else if (verifyKind_ == VerifyKind::VERIFY_POST_SHARED_GC) {
826        localVerifyKind = VerifyKind::VERIFY_POST_GC;
827    }
828
829    Runtime::GetInstance()->GCIterateThreadList([&, localVerifyKind](JSThread *thread) {
830        ASSERT(!thread->IsInRunningState());
831        auto vm = thread->GetEcmaVM();
832        auto localHeap = const_cast<Heap*>(vm->GetHeap());
833        localHeap->GetSweeper()->EnsureAllTaskFinished();
834        if (localVerifyKind != VerifyKind::VERIFY_END) {
835            Verification(localHeap, localVerifyKind).VerifyAll();
836        }
837        if (failCount > 0) {
838            LOG_GC(ERROR) << "SharedHeap VerifyRoot detects deadObject in local heap count is " << failCount;
839        }
840    });
841    return failCount;
842}
843
844void SharedHeapVerification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const
845{
846    JSTaggedValue value(slot.GetTaggedType());
847    if (value.IsWeak()) {
848        VerifyObjectVisitor(sHeap_, failCount, verifyKind_)(value.GetTaggedWeakRef());
849    } else if (value.IsHeapObject()) {
850        VerifyObjectVisitor(sHeap_, failCount, verifyKind_)(value.GetTaggedObject());
851    }
852}
853}  // namespace panda::ecmascript
854