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
20 namespace panda::ecmascript {
LogErrorForObjSlot(const BaseHeap * heap,const char * headerInfo,TaggedObject * obj,ObjectSlot slot,TaggedObject * value)21 void LogErrorForObjSlot(const BaseHeap *heap, const char *headerInfo, TaggedObject *obj, ObjectSlot slot,
22 TaggedObject *value)
23 { // LCOV_EXCL_START
24 TaggedObject *slotValue = slot.GetTaggedObject();
25 Region *region = Region::ObjectAddressToRange(obj);
26 Region *valueRegion = Region::ObjectAddressToRange(value);
27 Region *slotRegion = Region::ObjectAddressToRange(slotValue);
28 LOG_GC(FATAL) << headerInfo
29 << ": gctype=" << heap->GetGCType()
30 << ", obj address=" << obj
31 << ", obj region=" << region
32 << ", obj space type=" << region->GetSpaceTypeName()
33 << ", obj type=" << JSHClass::DumpJSType(obj->GetClass()->GetObjectType())
34 << ", slot address=" << reinterpret_cast<void*>(slot.SlotAddress())
35 << ", slot value=" << slotValue
36 << ", slot value region=" << slotRegion
37 << ", slot value space type=" << slotRegion->GetSpaceTypeName()
38 << ", slot value type=" << JSHClass::DumpJSType(slotValue->GetClass()->GetObjectType())
39 << ", value address=" << value
40 << ", value region=" << valueRegion
41 << ", value space type=" << valueRegion->GetSpaceTypeName()
42 << ", value type=" << JSHClass::DumpJSType(value->GetClass()->GetObjectType())
43 << ", obj mark bit=" << region->Test(obj)
44 << ", obj slot oldToNew bit=" << region->TestOldToNew(slot.SlotAddress())
45 << ", obj slot value mark bit=" << slotRegion->Test(slotValue)
46 << ", value mark bit=" << valueRegion->Test(value);
47 UNREACHABLE();
48 }
49
LogErrorForObj(const BaseHeap * heap,const char * headerInfo,TaggedObject * obj)50 void LogErrorForObj(const BaseHeap *heap, const char *headerInfo, TaggedObject *obj)
51 {
52 Region *region = Region::ObjectAddressToRange(obj);
53 LOG_GC(FATAL) << headerInfo
54 << ": gctype=" << heap->GetGCType()
55 << ", obj address=" << obj
56 << ", obj value=" << ObjectSlot(ToUintPtr(obj)).GetTaggedObject()
57 << ", obj region=" << region
58 << ", obj space type=" << region->GetSpaceTypeName()
59 << ", obj type=" << JSHClass::DumpJSType(obj->GetClass()->GetObjectType())
60 << ", obj mark bit=" << region->Test(obj);
61 UNREACHABLE();
62 } // LCOV_EXCL_STOP
63
64 // Only used for verify InactiveSemiSpace
VerifyInactiveSemiSpaceMarkedObject(const BaseHeap * heap,void * addr)65 void VerifyObjectVisitor::VerifyInactiveSemiSpaceMarkedObject(const BaseHeap *heap, void *addr)
66 {
67 TaggedObject *object = reinterpret_cast<TaggedObject*>(addr);
68 Region *objectRegion = Region::ObjectAddressToRange(object);
69 if (!objectRegion->InInactiveSemiSpace()) { // LCOV_EXCL_START
70 LogErrorForObj(heap, "Verify InactiveSemiSpaceMarkedObject: Object is not in InactiveSemiSpace.", object);
71 } else {
72 MarkWord word(object);
73 if (!word.IsForwardingAddress()) {
74 LogErrorForObj(heap, "Verify InactiveSemiSpaceMarkedObject: not forwarding address.", object);
75 } else {
76 ObjectSlot slot(ToUintPtr(object));
77 TaggedObject *value = word.ToForwardingAddress();
78 Region *valueRegion = Region::ObjectAddressToRange(value);
79 if (valueRegion->InInactiveSemiSpace()) {
80 LogErrorForObjSlot(heap, "Verify InactiveSemiSpaceMarkedObject: forwarding address, "
81 "but InactiveSemiSpace(FromSpace) Object.", object, slot, value);
82 }
83 }
84 } // LCOV_EXCL_STOP
85 }
86
87 // Verify the object body
VisitAllObjects(TaggedObject * obj)88 void VerifyObjectVisitor::VisitAllObjects(TaggedObject *obj)
89 {
90 auto cb = [this] (ObjectSlot slot, TaggedObject *root) {
91 VerifyObjectSlotLegal(slot, root);
92 };
93 VerifyVisitor verifyVisitor(cb);
94 auto jsHclass = obj->GetClass();
95 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, verifyVisitor);
96 }
97
VerifyObjectSlotLegal(ObjectSlot slot,TaggedObject * object) const98 void VerifyObjectVisitor::VerifyObjectSlotLegal(ObjectSlot slot, TaggedObject *object) const
99 {
100 JSTaggedValue value(slot.GetTaggedType());
101 if (value.IsWeak()) { // LCOV_EXCL_START
102 if (ToUintPtr(value.GetTaggedWeakRef()) < INVALID_THRESHOLD) {
103 LogErrorForObjSlot(heap_, "Heap verify detected an invalid value.",
104 object, slot, value.GetTaggedWeakRef());
105 }
106 if (!heap_->IsAlive(value.GetTaggedWeakRef()) && failCount_ != nullptr) {
107 LogErrorForObjSlot(heap_, "Heap verify detected a dead weak object.",
108 object, slot, value.GetTaggedWeakRef());
109 ++(*failCount_);
110 }
111 } else if (value.IsHeapObject()) {
112 VerifyHeapObjectSlotLegal(slot, value, object);
113 } // LCOV_EXCL_STOP
114 }
115
VerifyHeapObjectSlotLegal(ObjectSlot slot,JSTaggedValue slotValue,TaggedObject * object) const116 void VerifyObjectVisitor::VerifyHeapObjectSlotLegal(ObjectSlot slot,
117 JSTaggedValue slotValue,
118 TaggedObject *object) const
119 {
120 ASSERT(slotValue.IsHeapObject());
121 if (ToUintPtr(slotValue.GetTaggedObject()) < INVALID_THRESHOLD) { // LCOV_EXCL_START
122 LogErrorForObjSlot(heap_, "Heap verify detected an invalid value.",
123 object, slot, slotValue.GetTaggedObject());
124 }
125 if (!heap_->IsAlive(slotValue.GetTaggedObject()) && failCount_ != nullptr) {
126 LogErrorForObjSlot(heap_, "Heap verify detected a dead object.",
127 object, slot, slotValue.GetTaggedObject());
128 ++(*failCount_);
129 } // LCOV_EXCL_STOP
130 switch (verifyKind_) {
131 case VerifyKind::VERIFY_PRE_GC:
132 case VerifyKind::VERIFY_POST_GC:
133 break;
134 case VerifyKind::VERIFY_MARK_YOUNG:
135 VerifyMarkYoung(object, slot, slotValue.GetTaggedObject());
136 break;
137 case VerifyKind::VERIFY_EVACUATE_YOUNG:
138 VerifyEvacuateYoung(object, slot, slotValue.GetTaggedObject());
139 break;
140 case VerifyKind::VERIFY_MARK_FULL:
141 VerifyMarkFull(object, slot, slotValue.GetTaggedObject());
142 break;
143 case VerifyKind::VERIFY_EVACUATE_OLD:
144 VerifyEvacuateOld(object, slot, slotValue.GetTaggedObject());
145 break;
146 case VerifyKind::VERIFY_EVACUATE_FULL:
147 VerifyEvacuateFull(object, slot, slotValue.GetTaggedObject());
148 break;
149 case VerifyKind::VERIFY_SHARED_RSET_POST_FULL_GC:
150 VerifySharedRSetPostFullGC(object, slot, slotValue.GetTaggedObject());
151 break;
152 case VerifyKind::VERIFY_PRE_SHARED_GC:
153 case VerifyKind::VERIFY_POST_SHARED_GC:
154 VerifySharedObjectReference(object, slot, slotValue.GetTaggedObject());
155 break;
156 default: // LCOV_EXCL_START
157 LOG_GC(FATAL) << "unknown verify kind:" << static_cast<size_t>(verifyKind_);
158 UNREACHABLE(); // LCOV_EXCL_STOP
159 }
160 }
161
VerifyMarkYoung(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const162 void VerifyObjectVisitor::VerifyMarkYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
163 {
164 Region *objectRegion = Region::ObjectAddressToRange(object);
165 Region *valueRegion = Region::ObjectAddressToRange(value);
166 ASSERT(!objectRegion->InSharedHeap());
167 if (objectRegion->InGeneralOldSpace() && valueRegion->InYoungSpace()) { // LCOV_EXCL_START
168 if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
169 LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot miss old_to_new bit.", object, slot, value);
170 } else if (!valueRegion->Test(value)) {
171 LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot has old_to_new bit, miss gc_mark bit.",
172 object, slot, value);
173 }
174 }
175 if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
176 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
177 LogErrorForObjSlot(heap_, "Verify MarkYoung: Local object, slot local_to_share bit = 0, "
178 "but SharedHeap object.", object, slot, value);
179 }
180 }
181 if (objectRegion->Test(object)) {
182 if (!objectRegion->InYoungSpace() && !objectRegion->InAppSpawnSpace() &&
183 !objectRegion->InReadOnlySpace()) {
184 LogErrorForObj(heap_, "Verify MarkYoung: Marked object, NOT in Young/AppSpawn/ReadOnly Space", object);
185 }
186 if (valueRegion->InYoungSpace() && !valueRegion->Test(value)) {
187 LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot in YoungSpace, miss gc_mark bit.",
188 object, slot, value);
189 }
190 if (valueRegion->Test(value) &&
191 !(valueRegion->InYoungSpace() || valueRegion->InAppSpawnSpace() || valueRegion->InReadOnlySpace() ||
192 valueRegion->InSharedHeap())) {
193 LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot marked, but NOT in "
194 "Young/AppSpawn/ReadOnly Space.", object, slot, value);
195 }
196 } // LCOV_EXCL_STOP
197 }
198
VerifyEvacuateYoung(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const199 void VerifyObjectVisitor::VerifyEvacuateYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
200 {
201 Region *objectRegion = Region::ObjectAddressToRange(object);
202 Region *valueRegion = Region::ObjectAddressToRange(value);
203
204 if (objectRegion->InGeneralOldSpace()) { // LCOV_EXCL_START
205 if (objectRegion->TestOldToNew(slot.SlotAddress())) {
206 if (!valueRegion->InActiveSemiSpace()) {
207 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 1, "
208 "but NOT ActiveSpace(ToSpace) object.", object, slot, value);
209 }
210 } else {
211 if (valueRegion->InYoungSpace()) {
212 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 0, "
213 "but YoungSpace object.", object, slot, value);
214 }
215 }
216 }
217 if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
218 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
219 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Local object, slot local_to_share bit = 0, "
220 "but SharedHeap object.", object, slot, value);
221 }
222 }
223 if (objectRegion->InActiveSemiSpace()) {
224 if (valueRegion->InInactiveSemiSpace()) {
225 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: ActiveSpace object, slot in InactiveSpace(FromSpace).",
226 object, slot, value);
227 }
228 } // LCOV_EXCL_STOP
229 }
230
VerifyMarkFull(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const231 void VerifyObjectVisitor::VerifyMarkFull(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
232 {
233 Region *objectRegion = Region::ObjectAddressToRange(object);
234 Region *valueRegion = Region::ObjectAddressToRange(value);
235 if (objectRegion->InGeneralOldSpace() && valueRegion->InYoungSpace()) { // LCOV_EXCL_START
236 if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
237 LogErrorForObjSlot(heap_, "Verify MarkFull: Old object, slot miss old_to_new bit.", object, slot, value);
238 }
239 }
240 if (objectRegion->Test(object)) {
241 if (!valueRegion->InSharedHeap() && !valueRegion->Test(value)) {
242 LogErrorForObjSlot(heap_, "Verify MarkFull: Marked object, slot miss gc_mark bit.", object, slot, value);
243 }
244 }
245 if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) {
246 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
247 LogErrorForObjSlot(heap_, "Verify VerifyMarkFull: Local object, slot local_to_share bit = 0, "
248 "but SharedHeap object.", object, slot, value);
249 }
250 } // LCOV_EXCL_STOP
251 }
252
VerifyEvacuateOld(TaggedObject * root,ObjectSlot slot,TaggedObject * value) const253 void VerifyObjectVisitor::VerifyEvacuateOld([[maybe_unused]]TaggedObject *root,
254 [[maybe_unused]]ObjectSlot slot,
255 [[maybe_unused]]TaggedObject *value) const
256 {
257 VerifyEvacuateYoung(root, slot, value);
258 }
259
VerifyEvacuateFull(TaggedObject * root,ObjectSlot slot,TaggedObject * value) const260 void VerifyObjectVisitor::VerifyEvacuateFull([[maybe_unused]]TaggedObject *root,
261 [[maybe_unused]]ObjectSlot slot,
262 [[maybe_unused]]TaggedObject *value) const
263 {
264 VerifyEvacuateYoung(root, slot, value);
265 }
266
VerifySharedObjectReference(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const267 void VerifyObjectVisitor::VerifySharedObjectReference(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
268 {
269 Region *objectRegion = Region::ObjectAddressToRange(object);
270 Region *valueRegion = Region::ObjectAddressToRange(value);
271 if (objectRegion->InSharedHeap()) { // LCOV_EXCL_START
272 if (!valueRegion->InSharedHeap()) {
273 LogErrorForObjSlot(heap_, "Verify SharedObjectReference: Shared object references a local object",
274 object, slot, value);
275 }
276 } else if (valueRegion->InSharedSweepableSpace()) {
277 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
278 LogErrorForObjSlot(heap_, "Verify SharedObjectReference: Local object, slot local_to_share bit = 0, "
279 "but SharedHeap object.", object, slot, value);
280 }
281 } // LCOV_EXCL_STOP
282 }
283
VerifySharedRSetPostFullGC(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const284 void VerifyObjectVisitor::VerifySharedRSetPostFullGC(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
285 {
286 Region *objectRegion = Region::ObjectAddressToRange(object);
287 Region *valueRegion = Region::ObjectAddressToRange(value);
288 if (!objectRegion->InSharedHeap() && valueRegion->InSharedSweepableSpace()) { // LCOV_EXCL_START
289 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) {
290 LogErrorForObjSlot(heap_, "Verify SharedRSetPostFullGC: Local object, slot local_to_share bit = 0, "
291 "but SharedHeap object.", object, slot, value);
292 }
293 } // LCOV_EXCL_STOP
294 }
295
operator ()(TaggedObject * obj,JSTaggedValue value)296 void VerifyObjectVisitor::operator()(TaggedObject *obj, JSTaggedValue value)
297 {
298 ObjectSlot slot(reinterpret_cast<uintptr_t>(obj));
299 if (!value.IsHeapObject()) {
300 LOG_GC(DEBUG) << "Heap object(" << slot.SlotAddress() << ") old to new rset fail: value is "
301 << slot.GetTaggedType();
302 return;
303 }
304
305 TaggedObject *object = value.GetRawTaggedObject();
306 auto region = Region::ObjectAddressToRange(object);
307 if (region->InGeneralOldSpace() && failCount_ != nullptr) { // LCOV_EXCL_START
308 LOG_GC(ERROR) << "Heap object(" << slot.GetTaggedType() << ") old to new rset fail: value("
309 << slot.GetTaggedObject() << "/"
310 << JSHClass::DumpJSType(slot.GetTaggedObject()->GetClass()->GetObjectType())
311 << ")" << " in " << region->GetSpaceTypeName();
312 ++(*failCount_);
313 } // LCOV_EXCL_STOP
314 }
315
VerifyAll() const316 void Verification::VerifyAll() const
317 {
318 [[maybe_unused]] VerifyScope verifyScope(heap_);
319 heap_->GetSweeper()->EnsureAllTaskFinished();
320 size_t result = VerifyRoot();
321 result += VerifyHeap();
322 if (result > 0) { // LCOV_EXCL_START
323 LOG_GC(FATAL) << "Verify (type=" << static_cast<uint8_t>(verifyKind_)
324 << ") corrupted and " << result << " corruptions";
325 } // LCOV_EXCL_STOP
326 }
327
VisitRoot(Root type,ObjectSlot slot)328 void Verification::VerificationRootVisitor::VisitRoot([[maybe_unused]] Root type, ObjectSlot slot)
329 {
330 JSTaggedValue value(slot.GetTaggedType());
331 // Skip verifying shared object in local gc verification.
332 if (value.IsInSharedHeap()) {
333 return;
334 }
335 verification_->VerifyObjectSlot(slot, &failCount_);
336 };
337
VisitRangeRoot(Root type,ObjectSlot start,ObjectSlot end)338 void Verification::VerificationRootVisitor::VisitRangeRoot([[maybe_unused]] Root type, ObjectSlot start,
339 ObjectSlot end)
340 {
341 for (ObjectSlot slot = start; slot < end; slot++) {
342 JSTaggedValue value(slot.GetTaggedType());
343 // Skip verifying shared object in local gc verification.
344 if (value.IsInSharedHeap()) {
345 return;
346 }
347 verification_->VerifyObjectSlot(slot, &failCount_);
348 }
349 };
350
VisitBaseAndDerivedRoot(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)351 void Verification::VerificationRootVisitor::VisitBaseAndDerivedRoot([[maybe_unused]] Root type,
352 [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived, [[maybe_unused]] uintptr_t baseOldObject)
353 {
354 }
355
VerifyRoot() const356 size_t Verification::VerifyRoot() const
357 {
358 size_t failCount = 0;
359 VerificationRootVisitor verificationRootVisitor(this, failCount);
360 ObjectXRay::VisitVMRoots(heap_->GetEcmaVM(), verificationRootVisitor, VMRootVisitType::VERIFY);
361 if (failCount > 0) {
362 LOG_GC(ERROR) << "VerifyRoot detects deadObject count is " << failCount;
363 }
364
365 return failCount;
366 }
367
VerifyHeap() const368 size_t Verification::VerifyHeap() const
369 {
370 size_t failCount = heap_->VerifyHeapObjects(verifyKind_);
371 if (failCount > 0) {
372 LOG_GC(ERROR) << "VerifyHeap detects deadObject count is " << failCount;
373 }
374 return failCount;
375 }
376
VerifyOldToNewRSet() const377 size_t Verification::VerifyOldToNewRSet() const
378 {
379 size_t failCount = heap_->VerifyOldToNewRSet(verifyKind_);
380 if (failCount > 0) {
381 LOG_GC(ERROR) << "VerifyOldToNewRSet detects non new space count is " << failCount;
382 }
383 return failCount;
384 }
385
VerifyObjectSlot(const ObjectSlot & slot,size_t * failCount) const386 void Verification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const
387 {
388 JSTaggedValue value(slot.GetTaggedType());
389 if (value.IsWeak()) {
390 VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedWeakRef());
391 } else if (value.IsHeapObject()) {
392 VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedObject());
393 }
394 }
395
VerifyMark(Heap * heap)396 void Verification::VerifyMark(Heap *heap)
397 {
398 LOG_ECMA(DEBUG) << "start verify mark";
399 switch (heap->GetMarkType()) {
400 case MarkType::MARK_YOUNG:
401 Verification(heap, VerifyKind::VERIFY_MARK_YOUNG).VerifyAll();
402 break;
403 case MarkType::MARK_FULL:
404 Verification(heap, VerifyKind::VERIFY_MARK_FULL).VerifyAll();
405 break;
406 }
407 }
408
VerifyEvacuate(Heap * heap)409 void Verification::VerifyEvacuate(Heap *heap)
410 {
411 LOG_ECMA(DEBUG) << "start verify evacuate and sweep";
412 switch (heap->GetMarkType()) {
413 case MarkType::MARK_YOUNG:
414 Verification(heap, VerifyKind::VERIFY_EVACUATE_YOUNG).VerifyAll();
415 break;
416 case MarkType::MARK_FULL:
417 Verification(heap, VerifyKind::VERIFY_EVACUATE_OLD).VerifyAll();
418 break;
419 }
420 }
421
VerifyAll() const422 void SharedHeapVerification::VerifyAll() const
423 {
424 [[maybe_unused]] VerifyScope verifyScope(sHeap_);
425 sHeap_->GetSweeper()->EnsureAllTaskFinished();
426 size_t result = VerifyRoot();
427 result += VerifyHeap();
428 if (result > 0) { // LCOV_EXCL_START
429 LOG_GC(FATAL) << "Verify (type=" << static_cast<uint8_t>(verifyKind_)
430 << ") corrupted and " << result << " corruptions";
431 } // LCOV_EXCL_STOP
432 }
433
VerifyMark(bool cm) const434 void SharedHeapVerification::VerifyMark(bool cm) const
435 {
436 LOG_GC(DEBUG) << "start verify shared mark";
437 [[maybe_unused]] VerifyScope verifyScope(sHeap_);
438 sHeap_->GetSweeper()->EnsureAllTaskFinished();
439 auto cb1 = [cm] (ObjectSlot slot, TaggedObject *obj) {
440 Region *objectRegion = Region::ObjectAddressToRange(obj);
441 JSTaggedValue value(slot.GetTaggedType());
442 if (value.IsWeak() || !value.IsHeapObject()) {
443 return;
444 }
445 Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
446 if (!valueRegion->InSharedSweepableSpace()) {
447 return;
448 }
449 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { // LCOV_EXCL_START
450 LOG_GC(FATAL) << "verify shared1 " << cm << ':' << slot.SlotAddress()
451 << ' ' << value.GetTaggedObject();
452 UNREACHABLE();
453 }
454 if (!valueRegion->Test(value.GetTaggedObject())) {
455 LOG_GC(FATAL) << "verify shared2 " << cm << ':' << slot.SlotAddress()
456 << ' ' << value.GetTaggedObject();
457 UNREACHABLE();
458 }
459 if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
460 LOG_GC(FATAL) << "verify shared3 " << cm << ':' << slot.SlotAddress()
461 << ' ' << value.GetTaggedObject();
462 UNREACHABLE();
463 } // LCOV_EXCL_STOP
464 };
465 VerifyVisitor verifyVisitor1(cb1);
466 Runtime::GetInstance()->GCIterateThreadList([cm, &verifyVisitor1](JSThread *thread) {
467 auto vm = thread->GetEcmaVM();
468 auto heap = vm->GetHeap();
469 heap->GetSweeper()->EnsureAllTaskFinished();
470 const_cast<Heap*>(heap)->FillBumpPointerForTlab();
471 auto localBuffer = const_cast<Heap*>(heap)->GetMarkingObjectLocalBuffer();
472 if (localBuffer != nullptr) { // LCOV_EXCL_START
473 LOG_GC(FATAL) << "verify shared node not null " << cm << ':' << thread;
474 UNREACHABLE();
475 } // LCOV_EXCL_STOP
476 heap->IterateOverObjects([&verifyVisitor1](TaggedObject *obj) {
477 auto jsHclass = obj->GetClass();
478 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, verifyVisitor1);
479 });
480 });
481 auto cb2 = [cm] (ObjectSlot slot, TaggedObject *obj) {
482 Region *objectRegion = Region::ObjectAddressToRange(obj);
483 if (!objectRegion->Test(obj)) {
484 return;
485 }
486 JSTaggedValue value(slot.GetTaggedType());
487 if (value.IsWeak() || !value.IsHeapObject()) {
488 return;
489 }
490 [[maybe_unused]] Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
491 if (!valueRegion->InSharedHeap()) { // LCOV_EXCL_START
492 LOG_GC(FATAL) << "verify shared4 " << cm << ':' << slot.SlotAddress()
493 << ' ' << value.GetTaggedObject();
494 UNREACHABLE();
495 }
496 if (!valueRegion->InSharedReadOnlySpace()
497 && !valueRegion->Test(value.GetTaggedObject())) {
498 LOG_GC(FATAL) << "verify shared5 " << cm << ':' << slot.SlotAddress()
499 << ' ' << value.GetTaggedObject();
500 UNREACHABLE();
501 }
502 if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
503 LOG_GC(FATAL) << "verify shared6 " << cm << ':' << slot.SlotAddress()
504 << ' ' << value.GetTaggedObject();
505 UNREACHABLE();
506 } // LCOV_EXCL_STOP
507 };
508 VerifyVisitor verifyVisitor2(cb2);
509 sHeap_->IterateOverObjects([&verifyVisitor2](TaggedObject *obj) {
510 auto jsHclass = obj->GetClass();
511 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, verifyVisitor2);
512 });
513 }
514
VerifySweep(bool cm) const515 void SharedHeapVerification::VerifySweep(bool cm) const
516 {
517 LOG_GC(DEBUG) << "start verify shared sweep";
518 [[maybe_unused]] VerifyScope verifyScope(sHeap_);
519 sHeap_->GetSweeper()->EnsureAllTaskFinished();
520 auto cb1 = [cm] (ObjectSlot slot, TaggedObject *obj) {
521 Region *objectRegion = Region::ObjectAddressToRange(obj);
522 JSTaggedValue value(slot.GetTaggedType());
523 if (value.IsWeak() || !value.IsHeapObject()) {
524 return;
525 }
526 Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
527 if (!valueRegion->InSharedSweepableSpace()) {
528 return;
529 }
530 if (!objectRegion->TestLocalToShare(slot.SlotAddress())) { // LCOV_EXCL_START
531 LOG_GC(FATAL) << "verify shared7 " << cm << ':' << slot.SlotAddress()
532 << ' ' << value.GetTaggedObject();
533 UNREACHABLE();
534 }
535 if (valueRegion->InSCollectSet()) {
536 LOG_GC(FATAL) << "verify shared8 " << cm << ':' << slot.SlotAddress()
537 << ' ' << value.GetTaggedObject();
538 UNREACHABLE();
539 }
540 if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
541 LOG_GC(FATAL) << "verify shared9 " << cm << ':' << slot.SlotAddress()
542 << ' ' << value.GetTaggedObject();
543 UNREACHABLE();
544 } // LCOV_EXCL_STOP
545 };
546 VerifyVisitor verifyVisitor1(cb1);
547 Runtime::GetInstance()->GCIterateThreadList([&verifyVisitor1](JSThread *thread) {
548 auto vm = thread->GetEcmaVM();
549 auto heap = vm->GetHeap();
550 heap->GetSweeper()->EnsureAllTaskFinished();
551 const_cast<Heap*>(heap)->FillBumpPointerForTlab();
552 heap->IterateOverObjects([&verifyVisitor1](TaggedObject *obj) {
553 auto jsHclass = obj->GetClass();
554 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, verifyVisitor1);
555 });
556 });
557 auto cb2 = [cm] (ObjectSlot slot, TaggedObject *obj) {
558 [[maybe_unused]] Region *objectRegion = Region::ObjectAddressToRange(obj);
559 if (objectRegion->InSCollectSet()) { // LCOV_EXCL_START
560 LOG_GC(FATAL) << "verify shared10 " << cm << ':' << obj;
561 UNREACHABLE();
562 }
563 JSTaggedValue value(slot.GetTaggedType());
564 if (value.IsWeak() || !value.IsHeapObject()) {
565 return;
566 }
567 [[maybe_unused]] Region *valueRegion = Region::ObjectAddressToRange(value.GetTaggedObject());
568 if (!valueRegion->InSharedHeap()) {
569 LOG_GC(FATAL) << "verify shared11 " << cm << ':' << slot.SlotAddress()
570 << ' ' << value.GetTaggedObject();
571 UNREACHABLE();
572 }
573 if (!valueRegion->InSharedReadOnlySpace() && valueRegion->InSCollectSet()) {
574 LOG_GC(FATAL) << "verify shared12 " << cm << ':' << slot.SlotAddress()
575 << ' ' << value.GetTaggedObject();
576 UNREACHABLE();
577 }
578 if (value.GetTaggedObject()->GetClass()->IsFreeObject()) {
579 LOG_GC(FATAL) << "verify shared13 " << cm << ':' << slot.SlotAddress()
580 << ' ' << value.GetTaggedObject();
581 UNREACHABLE();
582 } // LCOV_EXCL_STOP
583 };
584 VerifyVisitor verifyVisitor2(cb2);
585 sHeap_->IterateOverObjects([&verifyVisitor2](TaggedObject *obj) {
586 auto jsHclass = obj->GetClass();
587
588 ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(obj, jsHclass, verifyVisitor2);
589 });
590 }
591
VisitRoot(Root type,ObjectSlot slot)592 void SharedHeapVerification::VerificationRootVisitor::VisitRoot([[maybe_unused]] Root type, ObjectSlot slot)
593 {
594 sVerification_->VerifyObjectSlot(slot, &failCount_);
595 };
596
VisitRangeRoot(Root type,ObjectSlot start,ObjectSlot end)597 void SharedHeapVerification::VerificationRootVisitor::VisitRangeRoot([[maybe_unused]] Root type, ObjectSlot start,
598 ObjectSlot end)
599 {
600 for (ObjectSlot slot = start; slot < end; slot++) {
601 sVerification_->VerifyObjectSlot(slot, &failCount_);
602 }
603 };
604
VisitBaseAndDerivedRoot(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)605 void SharedHeapVerification::VerificationRootVisitor::VisitBaseAndDerivedRoot([[maybe_unused]] Root type,
606 [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived, [[maybe_unused]] uintptr_t baseOldObject)
607 {
608 }
609
VisitRoot(Root type,ObjectSlot slot)610 void SharedHeapVerification::VerificationSerializeRootVisitor::VisitRoot([[maybe_unused]] Root type, ObjectSlot slot)
611 {
612 JSTaggedValue value(slot.GetTaggedType());
613 if (!sHeap_->IsAlive(value.GetTaggedObject())) {
614 LOG_ECMA(ERROR) << "Serialize Heap verify detected a dead object. " << value.GetTaggedObject();
615 ++failCount_;
616 }
617 };
618
VisitRangeRoot(Root type,ObjectSlot start,ObjectSlot end)619 void SharedHeapVerification::VerificationSerializeRootVisitor::VisitRangeRoot([[maybe_unused]] Root type,
620 [[maybe_unused]] ObjectSlot start, [[maybe_unused]] ObjectSlot end)
621 {
622 }
623
VisitBaseAndDerivedRoot(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)624 void SharedHeapVerification::VerificationSerializeRootVisitor::VisitBaseAndDerivedRoot([[maybe_unused]] Root type,
625 [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived, [[maybe_unused]] uintptr_t baseOldObject)
626 {
627 }
628
VerifyRoot() const629 size_t SharedHeapVerification::VerifyRoot() const
630 {
631 size_t failCount = 0;
632 VerificationRootVisitor verificationRootVisitor(this, failCount);
633 VerificationSerializeRootVisitor verificationSerializeRootVisitor(sHeap_, failCount);
634 Runtime::GetInstance()->IterateSerializeRoot(verificationSerializeRootVisitor);
635 Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
636 ASSERT(!thread->IsInRunningState());
637 auto vm = thread->GetEcmaVM();
638 auto localHeap = const_cast<Heap*>(vm->GetHeap());
639 localHeap->GetSweeper()->EnsureAllTaskFinished();
640 ObjectXRay::VisitVMRoots(vm, verificationRootVisitor, VMRootVisitType::VERIFY);
641 if (failCount > 0) {
642 LOG_GC(ERROR) << "SharedHeap VerifyRoot detects deadObject count is " << failCount;
643 }
644 });
645 return failCount;
646 }
647
VerifyHeap() const648 size_t SharedHeapVerification::VerifyHeap() const
649 {
650 Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
651 ASSERT(!thread->IsInRunningState());
652 const_cast<Heap*>(thread->GetEcmaVM()->GetHeap())->FillBumpPointerForTlab();
653 });
654 size_t failCount = sHeap_->VerifyHeapObjects(verifyKind_);
655 if (failCount > 0) {
656 LOG_GC(ERROR) << "SharedHeap VerifyHeap detects deadObject count is " << failCount;
657 }
658 VerifyKind localVerifyKind = VerifyKind::VERIFY_END;
659 if (verifyKind_ == VerifyKind::VERIFY_PRE_SHARED_GC) {
660 localVerifyKind = VerifyKind::VERIFY_PRE_GC;
661 } else if (verifyKind_ == VerifyKind::VERIFY_POST_SHARED_GC) {
662 localVerifyKind = VerifyKind::VERIFY_POST_GC;
663 }
664
665 Runtime::GetInstance()->GCIterateThreadList([&, localVerifyKind](JSThread *thread) {
666 ASSERT(!thread->IsInRunningState());
667 auto vm = thread->GetEcmaVM();
668 auto localHeap = const_cast<Heap*>(vm->GetHeap());
669 localHeap->GetSweeper()->EnsureAllTaskFinished();
670 if (localVerifyKind != VerifyKind::VERIFY_END) {
671 Verification(localHeap, localVerifyKind).VerifyAll();
672 }
673 if (failCount > 0) {
674 LOG_GC(ERROR) << "SharedHeap VerifyRoot detects deadObject in local heap count is " << failCount;
675 }
676 });
677 return failCount;
678 }
679
VerifyObjectSlot(const ObjectSlot & slot,size_t * failCount) const680 void SharedHeapVerification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const
681 {
682 JSTaggedValue value(slot.GetTaggedType());
683 if (value.IsWeak()) {
684 VerifyObjectVisitor(sHeap_, failCount, verifyKind_)(value.GetTaggedWeakRef());
685 } else if (value.IsHeapObject()) {
686 VerifyObjectVisitor(sHeap_, failCount, verifyKind_)(value.GetTaggedObject());
687 }
688 }
689 } // namespace panda::ecmascript
690