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