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