• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/mem/verification.h"
17 
18 #include "ecmascript/js_tagged_value-inl.h"
19 #include "ecmascript/mem/slots.h"
20 #include "ecmascript/mem/visitor.h"
21 #include "ecmascript/mem/concurrent_sweeper.h"
22 
23 namespace panda::ecmascript {
LogErrorForObjSlot(const Heap * heap,const char * headerInfo,TaggedObject * obj,ObjectSlot slot,TaggedObject * value)24 void LogErrorForObjSlot(const Heap *heap, const char *headerInfo, TaggedObject *obj, ObjectSlot slot,
25                         TaggedObject *value)
26 {
27     TaggedObject *slotValue = slot.GetTaggedObject();
28     Region *region = Region::ObjectAddressToRange(obj);
29     Region *valueRegion = Region::ObjectAddressToRange(value);
30     Region *slotRegion = Region::ObjectAddressToRange(slotValue);
31     LOG_GC(FATAL) << headerInfo
32                   << ": gctype=" << heap->GetGCType()
33                   << ", obj address=" << obj
34                   << ", obj region=" << region
35                   << ", obj space type=" << region->GetSpaceTypeName()
36                   << ", obj type=" << JSHClass::DumpJSType(obj->GetClass()->GetObjectType())
37                   << ", slot address=" << reinterpret_cast<void*>(slot.SlotAddress())
38                   << ", slot value=" << slotValue
39                   << ", slot value region=" << slotRegion
40                   << ", slot value space type=" << slotRegion->GetSpaceTypeName()
41                   << ", slot value type=" << JSHClass::DumpJSType(slotValue->GetClass()->GetObjectType())
42                   << ", value address=" << value
43                   << ", value region=" << valueRegion
44                   << ", value space type=" << valueRegion->GetSpaceTypeName()
45                   << ", value type=" << JSHClass::DumpJSType(value->GetClass()->GetObjectType())
46                   << ", obj mark bit=" << region->Test(obj)
47                   << ", obj slot olwToNew bit=" << region->TestOldToNew(slot.SlotAddress())
48                   << ", obj slot value mark bit=" << slotRegion->Test(slotValue)
49                   << ", value mark bit=" << valueRegion->Test(value);
50     UNREACHABLE();
51 }
52 
LogErrorForObj(const Heap * heap,const char * headerInfo,TaggedObject * obj)53 void LogErrorForObj(const Heap *heap, const char *headerInfo, TaggedObject *obj)
54 {
55     Region *region = Region::ObjectAddressToRange(obj);
56     LOG_GC(FATAL) << headerInfo
57                   << ": gctype=" << heap->GetGCType()
58                   << ", obj address=" << obj
59                   << ", obj value=" << ObjectSlot(ToUintPtr(obj)).GetTaggedObject()
60                   << ", obj region=" << region
61                   << ", obj space type=" << region->GetSpaceTypeName()
62                   << ", obj type=" << JSHClass::DumpJSType(obj->GetClass()->GetObjectType())
63                   << ", obj mark bit=" << region->Test(obj);
64     UNREACHABLE();
65 }
66 
67 // Only used for verify InactiveSemiSpace
VerifyInactiveSemiSpaceMarkedObject(const Heap * heap,void * addr)68 void VerifyObjectVisitor::VerifyInactiveSemiSpaceMarkedObject(const Heap *heap, void *addr)
69 {
70     TaggedObject *object = reinterpret_cast<TaggedObject*>(addr);
71     Region *objectRegion = Region::ObjectAddressToRange(object);
72     if (!objectRegion->InInactiveSemiSpace()) {
73         LogErrorForObj(heap, "Verify InactiveSemiSpaceMarkedObject: Object is not in InactiveSemiSpace.", object);
74     } else {
75         MarkWord word(object);
76         if (!word.IsForwardingAddress()) {
77             LogErrorForObj(heap, "Verify InactiveSemiSpaceMarkedObject: not forwarding address.", object);
78         } else {
79             ObjectSlot slot(ToUintPtr(object));
80             TaggedObject *value = word.ToForwardingAddress();
81             Region *valueRegion = Region::ObjectAddressToRange(value);
82             if (valueRegion->InInactiveSemiSpace()) {
83                 LogErrorForObjSlot(heap, "Verify InactiveSemiSpaceMarkedObject: forwarding address, "
84                     "but InactiveSemiSpace(FromSpace) Object.", object, slot, value);
85             }
86         }
87     }
88 }
89 
90 // Verify the object body
VisitAllObjects(TaggedObject * obj)91 void VerifyObjectVisitor::VisitAllObjects(TaggedObject *obj)
92 {
93     auto jsHclass = obj->GetClass();
94     objXRay_.VisitObjectBody<VisitType::OLD_GC_VISIT>(
95         obj, jsHclass, [this](TaggedObject *root, ObjectSlot start, ObjectSlot end,
96                               VisitObjectArea area) {
97             if (area == VisitObjectArea::IN_OBJECT) {
98                 auto hclass = root->GetClass();
99                 ASSERT(!hclass->IsAllTaggedProp());
100                 int index = 0;
101                 for (ObjectSlot slot = start; slot < end; slot++) {
102                     auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
103                     auto attr = layout->GetAttr(index++);
104                     if (attr.IsTaggedRep()) {
105                         VerifyObjectSlotLegal(slot, root);
106                     }
107                 }
108                 return;
109             }
110             for (ObjectSlot slot = start; slot < end; slot++) {
111                 VerifyObjectSlotLegal(slot, root);
112             }
113         });
114 }
115 
VerifyObjectSlotLegal(ObjectSlot slot,TaggedObject * object) const116 void VerifyObjectVisitor::VerifyObjectSlotLegal(ObjectSlot slot, TaggedObject *object) const
117 {
118     JSTaggedValue value(slot.GetTaggedType());
119     if (value.IsWeak()) {
120         if (ToUintPtr(value.GetTaggedWeakRef()) < INVALID_THRESHOLD) {
121             LogErrorForObjSlot(heap_, "Heap verify detected an invalid value.",
122                 object, slot, value.GetTaggedWeakRef());
123         }
124         if (!heap_->IsAlive(value.GetTaggedWeakRef())) {
125             LogErrorForObjSlot(heap_, "Heap verify detected a dead weak object.",
126                 object, slot, value.GetTaggedWeakRef());
127             ++(*failCount_);
128         }
129     } else if (value.IsHeapObject()) {
130         if (ToUintPtr(value.GetTaggedObject()) < INVALID_THRESHOLD) {
131             LogErrorForObjSlot(heap_, "Heap verify detected an invalid value.",
132                 object, slot, value.GetTaggedObject());
133         }
134         if (!heap_->IsAlive(value.GetTaggedObject())) {
135             LogErrorForObjSlot(heap_, "Heap verify detected a dead object.",
136                 object, slot, value.GetTaggedObject());
137             ++(*failCount_);
138         }
139         switch (verifyKind_) {
140             case VerifyKind::VERIFY_PRE_GC:
141             case VerifyKind::VERIFY_POST_GC:
142                 break;
143             case VerifyKind::VERIFY_CONCURRENT_MARK_YOUNG:
144                 VerifyMarkYoung(object, slot, value.GetTaggedObject());
145                 break;
146             case VerifyKind::VERIFY_EVACUATE_YOUNG:
147                 VerifyEvacuateYoung(object, slot, value.GetTaggedObject());
148                 break;
149             case VerifyKind::VERIFY_CONCURRENT_MARK_FULL:
150                 VerifyMarkFull(object, slot, value.GetTaggedObject());
151                 break;
152             case VerifyKind::VERIFY_EVACUATE_OLD:
153                 VerifyEvacuateOld(object, slot, value.GetTaggedObject());
154                 break;
155             case VerifyKind::VERIFY_EVACUATE_FULL:
156                 VerifyEvacuateFull(object, slot, value.GetTaggedObject());
157                 break;
158             default:
159                 LOG_GC(FATAL) << "unknown verify kind:" << static_cast<size_t>(verifyKind_);
160                 UNREACHABLE();
161         }
162     }
163 }
164 
VerifyMarkYoung(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const165 void VerifyObjectVisitor::VerifyMarkYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
166 {
167     Region *objectRegion = Region::ObjectAddressToRange(object);
168     Region *valueRegion = Region::ObjectAddressToRange(value);
169     if (!objectRegion->InYoungSpace() && valueRegion->InYoungSpace()) {
170         if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
171             LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot miss old_to_new bit.", object, slot, value);
172         } else if (!valueRegion->Test(value)) {
173             LogErrorForObjSlot(heap_, "Verify MarkYoung: Old object, slot has old_to_new bit, miss gc_mark bit.",
174                 object, slot, value);
175         }
176     }
177     if (objectRegion->Test(object)) {
178         if (!objectRegion->InYoungSpace() && !objectRegion->InAppSpawnSpace() && !objectRegion->InReadOnlySpace()) {
179             LogErrorForObj(heap_, "Verify MarkYoung: Marked object, NOT in Young/AppSpawn/ReadOnly Space", object);
180         }
181         if (valueRegion->InYoungSpace() && !valueRegion->Test(value)) {
182             LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot in YoungSpace, miss gc_mark bit.",
183                 object, slot, value);
184         }
185         if (valueRegion->Test(value) && !(valueRegion->InYoungSpace() || valueRegion->InAppSpawnSpace() ||
186                                           valueRegion->InReadOnlySpace())) {
187             LogErrorForObjSlot(heap_, "Verify MarkYoung: Marked object, slot marked, but NOT in "
188                 "Young/AppSpawn/ReadOnly Space.", object, slot, value);
189         }
190     }
191 }
192 
VerifyEvacuateYoung(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const193 void VerifyObjectVisitor::VerifyEvacuateYoung(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
194 {
195     Region *objectRegion = Region::ObjectAddressToRange(object);
196     Region *valueRegion = Region::ObjectAddressToRange(value);
197     if (!objectRegion->InYoungSpace()) {
198         if (objectRegion->TestOldToNew(slot.SlotAddress())) {
199             if (!valueRegion->InActiveSemiSpace()) {
200                 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 1, "
201                     "but NOT ActiveSpace(ToSpace) object.", object, slot, value);
202             }
203         } else {
204             if (valueRegion->InYoungSpace()) {
205                 LogErrorForObjSlot(heap_, "Verify EvacuateYoung: Old object, slot old_to_new bit = 0, "
206                     "but YoungSpace object.", object, slot, value);
207             }
208         }
209     }
210     if (objectRegion->InActiveSemiSpace()) {
211         if (valueRegion->InInactiveSemiSpace()) {
212             LogErrorForObjSlot(heap_, "Verify EvacuateYoung: ActiveSpace object, slot in InactiveSpace(FromSpace).",
213                 object, slot, value);
214         }
215     }
216 }
217 
VerifyMarkFull(TaggedObject * object,ObjectSlot slot,TaggedObject * value) const218 void VerifyObjectVisitor::VerifyMarkFull(TaggedObject *object, ObjectSlot slot, TaggedObject *value) const
219 {
220     Region *objectRegion = Region::ObjectAddressToRange(object);
221     Region *valueRegion = Region::ObjectAddressToRange(value);
222     if (!objectRegion->InYoungSpace() && valueRegion->InYoungSpace()) {
223         if (!objectRegion->TestOldToNew(slot.SlotAddress())) {
224             LogErrorForObjSlot(heap_, "Verify MarkFull: Old object, slot miss old_to_new bit.", object, slot, value);
225         }
226     }
227     if (objectRegion->Test(object)) {
228         if (!valueRegion->Test(value)) {
229             LogErrorForObjSlot(heap_, "Verify MarkFull: Marked object, slot miss gc_mark bit.", object, slot, value);
230         }
231     }
232 }
233 
VerifyEvacuateOld(TaggedObject * root,ObjectSlot slot,TaggedObject * value) const234 void VerifyObjectVisitor::VerifyEvacuateOld([[maybe_unused]]TaggedObject *root,
235                                             [[maybe_unused]]ObjectSlot slot,
236                                             [[maybe_unused]]TaggedObject *value) const
237 {
238     VerifyEvacuateYoung(root, slot, value);
239 }
240 
VerifyEvacuateFull(TaggedObject * root,ObjectSlot slot,TaggedObject * value) const241 void VerifyObjectVisitor::VerifyEvacuateFull([[maybe_unused]]TaggedObject *root,
242                                              [[maybe_unused]]ObjectSlot slot,
243                                              [[maybe_unused]]TaggedObject *value) const
244 {
245     VerifyEvacuateYoung(root, slot, value);
246 }
247 
operator ()(TaggedObject * obj,JSTaggedValue value)248 void VerifyObjectVisitor::operator()(TaggedObject *obj, JSTaggedValue value)
249 {
250     ObjectSlot slot(reinterpret_cast<uintptr_t>(obj));
251     if (!value.IsHeapObject()) {
252         LOG_GC(DEBUG) << "Heap object(" << slot.SlotAddress() << ") old to new rset fail: value is "
253                       << slot.GetTaggedType();
254         return;
255     }
256 
257     TaggedObject *object = value.GetRawTaggedObject();
258     auto region = Region::ObjectAddressToRange(object);
259     if (!region->InYoungSpace()) {
260         LOG_GC(ERROR) << "Heap object(" << slot.GetTaggedType() << ") old to new rset fail: value("
261                       << slot.GetTaggedObject() << "/"
262                       << JSHClass::DumpJSType(slot.GetTaggedObject()->GetClass()->GetObjectType())
263                       << ")" << " in " << region->GetSpaceTypeName();
264         ++(*failCount_);
265     }
266 }
267 
VerifyAll() const268 void Verification::VerifyAll() const
269 {
270     [[maybe_unused]] VerifyScope verifyScope(heap_);
271     heap_->GetSweeper()->EnsureAllTaskFinished();
272     size_t result = VerifyRoot();
273     result += VerifyHeap();
274     if (result > 0) {
275         LOG_GC(FATAL) << "Verify (type=" << static_cast<uint8_t>(verifyKind_)
276                       << ") corrupted and " << result << " corruptions";
277     }
278 }
279 
VerifyRoot() const280 size_t Verification::VerifyRoot() const
281 {
282     size_t failCount = 0;
283     RootVisitor visitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot slot) {
284         VerifyObjectSlot(slot, &failCount);
285     };
286     RootRangeVisitor rangeVisitor = [this, &failCount]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) {
287         for (ObjectSlot slot = start; slot < end; slot++) {
288             VerifyObjectSlot(slot, &failCount);
289         }
290     };
291     RootBaseAndDerivedVisitor derivedVisitor =
292         []([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, [[maybe_unused]] ObjectSlot derived,
293            [[maybe_unused]] uintptr_t baseOldObject) {
294     };
295     objXRay_.VisitVMRoots(visitor, rangeVisitor, derivedVisitor);
296     if (failCount > 0) {
297         LOG_GC(ERROR) << "VerifyRoot detects deadObject count is " << failCount;
298     }
299 
300     return failCount;
301 }
302 
VerifyHeap() const303 size_t Verification::VerifyHeap() const
304 {
305     size_t failCount = heap_->VerifyHeapObjects(verifyKind_);
306     if (failCount > 0) {
307         LOG_GC(ERROR) << "VerifyHeap detects deadObject count is " << failCount;
308     }
309     return failCount;
310 }
311 
VerifyOldToNewRSet() const312 size_t Verification::VerifyOldToNewRSet() const
313 {
314     size_t failCount = heap_->VerifyOldToNewRSet(verifyKind_);
315     if (failCount > 0) {
316         LOG_GC(ERROR) << "VerifyOldToNewRSet detects non new space count is " << failCount;
317     }
318     return failCount;
319 }
320 
VerifyObjectSlot(const ObjectSlot & slot,size_t * failCount) const321 void Verification::VerifyObjectSlot(const ObjectSlot &slot, size_t *failCount) const
322 {
323     JSTaggedValue value(slot.GetTaggedType());
324     if (value.IsWeak()) {
325         VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedWeakRef());
326     } else if (value.IsHeapObject()) {
327         VerifyObjectVisitor(heap_, failCount, verifyKind_)(value.GetTaggedObject());
328     }
329 }
330 }  // namespace panda::ecmascript
331