• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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