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 { // 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 
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 } // LCOV_EXCL_STOP
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()) { // 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
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()) { // 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 
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) { // 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 
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()) { // 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 
VerifyMarkYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const229 void 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 
VerifyEvacuateEden(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const266 void 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 
VerifyEvacuateYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const305 void 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 
VerifyMarkFull(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const344 void 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 
VerifyEvacuateOld([[maybe_unused]]TaggedObject *root, [[maybe_unused]]ObjectSlot slot, [[maybe_unused]]TaggedObject *value) const366 void 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 
VerifyEvacuateFull([[maybe_unused]]TaggedObject *root, [[maybe_unused]]ObjectSlot slot, [[maybe_unused]]TaggedObject *value) const373 void 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 
VerifySharedObjectReference(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const380 void 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 
VerifySharedRSetPostFullGC(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const397 void 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 
operator ()(TaggedObject *obj, JSTaggedValue value)409 void 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 
VerifyAll() const429 void 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 
VerifyRoot() const441 size_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 
VerifyHeap() const474 size_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 
VerifyOldToNewRSet() const483 size_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 
VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const492 void 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 
VerifyMark(Heap *heap)502 void 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 
VerifyEvacuate(Heap *heap)518 void 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 
VerifyAll() const534 void 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 
VerifyMark(bool cm) const546 void 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 
VerifySweep(bool cm) const663 void 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 
VerifyRoot() const776 size_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 
VerifyHeap() const812 size_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 
VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const844 void 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