• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "verification.h"
17 
18 #include "ark_collector/ark_collector.h"
19 #include "allocator/region_desc.h"
20 #include "allocator/region_space.h"
21 #include "common/mark_work_stack.h"
22 #include "common/type_def.h"
23 #include "common_components/log/log.h"
24 #include "common_interfaces/objects/base_object.h"
25 #include "common_interfaces/objects/base_state_word.h"
26 #include "common_interfaces/objects/ref_field.h"
27 #include "macros.h"
28 #include "mutator/mutator_manager.h"
29 #include "securec.h"
30 #include "thread/mutator_base.h"
31 #include <iomanip>
32 #include <sstream>
33 #include <unordered_set>
34 
35 /*
36  * Heap Verify:
37  * Checks heap invariants after each GC mark, copy and fix phase. During the check, the world is stopped.
38  * Enabled by default for debug mode. Controlled by gn option `ets_runtime_enable_heap_verify`.
39  *
40  * RB DFX:
41  * Force to use STW GC. Force to use read barrier out of GC.
42  * After GC is finished, set the lowerst bit(WEAK_TAG) of RefField which is not root or doesn't point to pinned objects.
43  * The read barrier is responsible to remove the WEAK_TAG for properly deferencing the object.
44  * Disabled by defualt. Controlled by gn-option `ets_runtime_enable_rb_dfx`.
45  *
46  * Example:
47  * standalone:
48  * python ark.py x64.release --gn-args="ets_runtime_enable_heap_verify=true ets_runtime_enable_rb_dfx=true"
49  * openharmony:
50  * ./build_system.sh --gn-args="ets_runtime_enable_heap_verify=true ets_runtime_enable_rb_dfx=true" ...
51  */
52 
53 namespace common {
54 void VisitRoots(const RefFieldVisitor& visitorFunc);
55 void VisitWeakRoots(const WeakRefFieldVisitor& visitorFunc);
56 
57 #define CONTEXT " at " << __FILE__ << ":" << __LINE__ << std::endl
58 
HexDump(const void * address,size_t length)59 std::string HexDump(const void* address, size_t length)
60 {
61     static constexpr size_t hexDigitsPerByte = 2;
62     static constexpr size_t wordSize = sizeof(uint64_t);
63     static constexpr size_t addressWidth = sizeof(void*) * hexDigitsPerByte;
64 
65     std::ostringstream oss;
66     oss << std::hex << std::setfill('0');
67 
68     const uint8_t* ptr = reinterpret_cast<const uint8_t*>(address);
69 
70     for (size_t i = 0; i < length; i += wordSize) {
71         // Print address
72         oss << "0x" << std::setw(addressWidth) << reinterpret_cast<uintptr_t>(ptr + i) << ": ";
73 
74         // Print content
75         uint64_t word = 0;
76         size_t bytesToRead = std::min(wordSize, length - i);
77         memcpy_s(&word, sizeof(uint64_t), ptr + i, bytesToRead);
78 
79         oss << "0x" << std::setw(wordSize * hexDigitsPerByte) << word << std::endl;
80     }
81 
82     return oss.str();
83 }
84 
GetObjectInfo(const BaseObject * obj)85 std::string GetObjectInfo(const BaseObject* obj)
86 {
87     constexpr size_t defaultInfoLength = 64;
88 
89     std::ostringstream s;
90     s << std::hex << std::endl << ">>> address: 0x" << obj << std::endl;
91 
92     s << "> Raw memory:" << std::endl;
93     if (obj == nullptr) {
94         s << "Skip: nullptr(Ref of nullptr might be a root, or Ref is iterated in region)" << std::endl;
95     } else {
96         s << std::hex << HexDump((void*) obj, defaultInfoLength);
97     }
98 
99     s << "> Region Info:" << std::endl;
100     if (!Heap::IsHeapAddress(obj)) {
101         s << "Skip: Object is not in heap range" << std::endl;
102     } else {
103         auto region = RegionDesc::GetRegionDescAt(reinterpret_cast<MAddress>(obj));
104         s << std::hex << "Type: 0x" << (int) region->GetRegionType() << ", "
105           << "Base: 0x" << region->GetRegionBase() << ", "
106           << "Start: 0x" << region->GetRegionStart() << ", "
107           << "End: 0x" << region->GetRegionEnd() << ", "
108           << "AllocPtr: 0x" << region->GetRegionAllocPtr() << ", "
109           << "MarkingLine: 0x" << region->GetMarkingLine() << ", "
110           << "CopyLine: 0x" << region->GetCopyLine() << std::endl;
111     }
112 
113     return s.str();
114 }
115 
GetRefInfo(const RefField<> & ref)116 std::string GetRefInfo(const RefField<>& ref)
117 {
118     std::ostringstream s;
119     s << std::hex << std::endl << ">>> Ref value: 0x" << ref.GetFieldValue();
120     if (Heap::IsTaggedObject(ref.GetFieldValue())) {
121         s << GetObjectInfo(ref.GetTargetObject()) << std::endl;
122     } else {
123         s << "> Raw memory:" << std::endl
124           << "Skip: primitive" << std::endl;
125     }
126     return s.str();
127 }
128 
IsValidRef(const BaseObject * obj,const RefField<> & ref)129 void IsValidRef(const BaseObject* obj, const RefField<>& ref)
130 {
131     // Maybe we need to check ref later
132     // ...
133 
134     CHECKF(Heap::IsTaggedObject(ref.GetFieldValue()))
135         << CONTEXT
136         << "Object: " << GetObjectInfo(obj) << std::endl
137         << "Ref: " << GetRefInfo(ref) << std::endl;
138 
139     // check referenee
140     auto refObj = ref.GetTargetObject();
141 
142     CHECKF(Heap::IsHeapAddress(refObj))
143         << CONTEXT << std::hex
144         << "Object address: 0x" << reinterpret_cast<MAddress>(refObj) << ","
145         << "Heap range: [0x" << Heap::heapStartAddr_ << ", 0x" << Heap::heapCurrentEnd_ << "]";
146 
147     auto region = RegionDesc::GetRegionDescAt(reinterpret_cast<MAddress>(refObj));
148     CHECKF(region->GetRegionType() != RegionDesc::RegionType::GARBAGE_REGION)
149         << CONTEXT
150         << "Object: " << GetObjectInfo(obj) << std::endl
151         << "Ref: " << GetRefInfo(ref) << std::endl;
152     CHECKF(region->GetRegionType() != RegionDesc::RegionType::FREE_REGION)
153         << CONTEXT
154         << "Object: " << GetObjectInfo(obj) << std::endl
155         << "Ref: " << GetRefInfo(ref) << std::endl;
156 
157     CHECKF(!refObj->IsForwarding() && !refObj->IsForwarded())
158         << CONTEXT
159         << "Object: " << GetObjectInfo(obj) << std::endl
160         << "Ref: " << GetRefInfo(ref) << std::endl;
161 
162     CHECKF(refObj->IsValidObject() != 0)
163         << CONTEXT
164         << "Object: " << GetObjectInfo(obj) << std::endl
165         << "Ref: " << GetRefInfo(ref) << std::endl;
166 
167     CHECKF(refObj->GetSize() != 0)
168         << CONTEXT
169         << "Object: " << GetObjectInfo(obj) << std::endl
170         << "Ref: " << GetRefInfo(ref) << std::endl;
171 }
172 
173 class VerifyVisitor {
174 public:
VerifyRef(const BaseObject * obj,RefField<> & ref)175     void VerifyRef(const BaseObject* obj, RefField<>& ref)
176     {
177         VerifyRefImpl(obj, ref);
178         count_++;
179     }
180 
VerifyRef(const BaseObject * obj,const RefField<> & ref)181     void VerifyRef(const BaseObject* obj, const RefField<>& ref)
182     {
183         VerifyRefImpl(obj, ref);
184         count_++;
185     }
186 
VerifyRefCount() const187     size_t VerifyRefCount() const
188     {
189         return count_;
190     }
191 
192 protected:
VerifyRefImpl(const BaseObject * obj,RefField<> & ref)193     virtual void VerifyRefImpl(const BaseObject* obj, RefField<>& ref)
194     {
195         VerifyRefImpl(obj, static_cast<const RefField<>&>(ref));
196     }
197 
VerifyRefImpl(const BaseObject * obj,const RefField<> & ref)198     virtual void VerifyRefImpl(const BaseObject* obj, const RefField<>& ref)
199     {
200         UNREACHABLE();
201     }
202 
203 private:
204     size_t count_ = 0;
205 };
206 
207 template <bool IsSTWRootVerify = true>
208 class AfterMarkVisitor : public VerifyVisitor {
209 public:
VerifyRefImpl(const BaseObject * obj,const RefField<> & ref)210     void VerifyRefImpl(const BaseObject* obj, const RefField<>& ref) override
211     {
212         IsValidRef(obj, ref);
213 
214         // check remarked objects, so they must be in one of the states below
215         auto refObj = ref.GetTargetObject();
216         RegionDesc *region = RegionDesc::GetRegionDescAt(reinterpret_cast<HeapAddress>(refObj));
217 
218         // if obj is nullptr, this means it is a root object
219         // We expect root objects to be already forwarded: assert(!region->isFromRegion())
220         if (obj == nullptr) {
221             if constexpr (IsSTWRootVerify) {
222                 CHECKF(!region->IsFromRegion())
223                     << CONTEXT << "Object: " << GetObjectInfo(obj) << std::endl
224                     << "Ref: " << GetRefInfo(ref) << std::endl;
225 
226                 return;
227             } else {
228                 CHECKF(!region->IsInToSpace())
229                     << CONTEXT << "Object: " << GetObjectInfo(obj) << std::endl
230                     << "Ref: " << GetRefInfo(ref) << std::endl;
231 
232                 return;
233             }
234         }
235 
236         if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) {
237             CHECKF(RegionSpace::IsResurrectedObject(refObj) ||
238                    RegionSpace::IsMarkedObject(refObj) ||
239                    RegionSpace::IsNewObjectSinceMarking(refObj) ||
240                    !RegionSpace::IsYoungSpaceObject(refObj))
241                 << CONTEXT << "Object: " << GetObjectInfo(obj) << std::endl
242                 << "Ref: " << GetRefInfo(ref) << std::endl;
243         } else {
244             CHECKF(RegionSpace::IsResurrectedObject(refObj) ||
245                    RegionSpace::IsMarkedObject(refObj) ||
246                    RegionSpace::IsNewObjectSinceMarking(refObj))
247                 << CONTEXT << "Object: " << GetObjectInfo(obj) << std::endl
248                 << "Ref: " << GetRefInfo(ref) << std::endl;
249         }
250     }
251 };
252 
253 class AfterForwardVisitor : public VerifyVisitor {
254 public:
VerifyRefImpl(const BaseObject * obj,const RefField<> & ref)255     void VerifyRefImpl(const BaseObject* obj, const RefField<>& ref) override
256     {
257         // check objects in from-space, only alive objects are forwarded
258         auto refObj = ref.GetTargetObject();
259         if (RegionSpace::IsMarkedObject(refObj) || RegionSpace::IsResurrectedObject(refObj)) {
260             CHECKF(refObj->IsForwarded())
261                 << CONTEXT
262                 << "Object: " << GetObjectInfo(obj) << std::endl
263                 << "Ref: " << GetRefInfo(ref) << std::endl;
264 
265             auto toObj = refObj->GetForwardingPointer();
266             IsValidRef(obj, RefField<>(toObj));
267         }
268     }
269 };
270 
271 class AfterFixVisitor : public VerifyVisitor {
272 public:
VerifyRefImpl(const BaseObject * obj,const RefField<> & ref)273     void VerifyRefImpl(const BaseObject* obj, const RefField<>& ref) override
274     {
275         IsValidRef(obj, ref);
276 
277         auto refRegion = RegionDesc::GetRegionDescAt(reinterpret_cast<MAddress>(ref.GetTargetObject()));
278         CHECKF(refRegion->GetRegionType() != RegionDesc::RegionType::FROM_REGION)
279             << CONTEXT
280             << "Object: " << GetObjectInfo(obj) << std::endl
281             << "Ref: " << GetRefInfo(ref) << std::endl;
282     }
283 };
284 
285 class ReadBarrierVisitor : public VerifyVisitor {
286 protected:
287     constexpr static MAddress TAG_RB_DFX_SHIFT = 47;
288     constexpr static MAddress TAG_RB_DFX = 0x1ULL << TAG_RB_DFX_SHIFT;
289 };
290 
291 class ReadBarrierSetter : public ReadBarrierVisitor {
292 public:
VerifyRefImpl(const BaseObject * obj,RefField<> & ref)293     void VerifyRefImpl(const BaseObject* obj, RefField<>& ref) override
294     {
295         if (obj == nullptr) {
296             // skip roots
297             return;
298         }
299 
300         auto regionType =
301             RegionDesc::GetRegionDescAt(reinterpret_cast<MAddress>(ref.GetTargetObject()))->GetRegionType();
302         if (regionType == RegionDesc::RegionType::RECENT_PINNED_REGION ||
303             regionType == RegionDesc::RegionType::FULL_PINNED_REGION ||
304             regionType == RegionDesc::RegionType::FIXED_PINNED_REGION ||
305             regionType == RegionDesc::RegionType::FULL_FIXED_PINNED_REGION) {
306             // Read barrier for pinned objects might be optimized out, so don't set dfx tag
307             return;
308         }
309 
310         auto newRefValue = ref.GetFieldValue() | TAG_RB_DFX;
311         ref.SetFieldValue(newRefValue);
312     }
313 };
314 
315 class ReadBarrierUnsetter : public ReadBarrierVisitor {
316 public:
VerifyRefImpl(const BaseObject * obj,RefField<> & ref)317     void VerifyRefImpl(const BaseObject* obj, RefField<>& ref) override
318     {
319         auto newRefValue = ref.GetFieldValue() & (~TAG_RB_DFX);
320         ref.SetFieldValue(newRefValue);
321     }
322 
GetTargetObject(const RefField<> & ref)323     static BaseObject* GetTargetObject(const RefField<>& ref)
324     {
325         // Get the target object from the reference field, ignoring the read barrier tag
326         BaseObject* targetObj = ref.GetTargetObject();
327         return reinterpret_cast<BaseObject*>(reinterpret_cast<MAddress>(targetObj) & (~TAG_RB_DFX));
328     }
329 };
330 
331 class VerifyIterator {
332 public:
VerifyIterator(RegionSpace & space)333     explicit VerifyIterator(RegionSpace& space) : space_(space) {}
334 
IterateFromSpace(VerifyVisitor & visitor)335     void IterateFromSpace(VerifyVisitor& visitor)
336     {
337         IterateRegionList(space_.GetFromSpace().GetFromRegionList(), visitor);
338     }
339 
IterateRoot(VerifyVisitor & visitor)340     void IterateRoot(VerifyVisitor& visitor)
341     {
342         MarkStack<BaseObject*> roots;
343 
344         RefFieldVisitor refVisitor = [&](RefField<>& ref) { visitor.VerifyRef(nullptr, ref); };
345         VisitRoots(refVisitor);
346     }
347 
IterateWeakRoot(VerifyVisitor & visitor)348     void IterateWeakRoot(VerifyVisitor& visitor)
349     {
350         MarkStack<BaseObject*> roots;
351 
352         WeakRefFieldVisitor refVisitor = [&](RefField<>& ref) {
353             visitor.VerifyRef(nullptr, ref);
354             return true;
355         };
356         VisitWeakRoots(refVisitor);
357     }
358 
359     // By default, IterateRemarked uses the VisitRoots method to traverse GC roots
360     template <void (*VisitRoot)(const RefFieldVisitor &) = VisitRoots>
IterateRemarked(VerifyVisitor & visitor,std::unordered_set<BaseObject * > & markSet,bool forRBDFX=false)361     void IterateRemarked(VerifyVisitor &visitor, std::unordered_set<BaseObject *> &markSet, bool forRBDFX = false)
362     {
363         MarkStack<BaseObject*> markStack;
364         BaseObject* obj = nullptr;
365 
366         auto markFunc = [this, &visitor, &markStack, &markSet, &obj, &forRBDFX](RefField<>& field) {
367             if (!Heap::IsTaggedObject(reinterpret_cast<MAddress>(field.GetFieldValue()))) {
368                 return;
369             }
370 
371             BaseObject* refObj = nullptr;
372             if (forRBDFX) {
373                 refObj = ReadBarrierUnsetter::GetTargetObject(field);
374             } else {
375                 refObj = field.GetTargetObject();
376             }
377             // If it is forwarded, its toVersion must have been traversed during
378             // EnumRoot, so it must have been marked. There is no need for me to
379             // check it, nor to push it into the mark stack.
380             if (refObj->IsForwarded()) {
381                 auto toObj = refObj->GetForwardingPointer();
382                 bool find = markSet.find(toObj) != markSet.end();
383                 CHECKF(find) << "not found to version obj in markSet";
384                 return;
385             }
386 
387             visitor.VerifyRef(obj, field);
388 
389             if (markSet.find(refObj) != markSet.end()) {
390                 return;
391             }
392             markSet.insert(refObj);
393             markStack.push_back(refObj);
394         };
395 
396         VisitRoot(markFunc);
397         while (!markStack.empty()) {
398             obj = markStack.back();
399             markStack.pop_back();
400 
401             obj->ForEachRefField(markFunc);
402         }
403     }
404 
405 private:
IterateRegionList(RegionList & list,VerifyVisitor & visitor)406     void IterateRegionList(RegionList& list, VerifyVisitor& visitor)
407     {
408         list.VisitAllRegions([&](RegionDesc* region) {
409             region->VisitAllObjects([&](BaseObject* obj) { visitor.VerifyRef(nullptr, RefField<>(obj)); });
410         });
411     }
412 
EnumStrongRoots(const std::function<void (RefField<> &)> & markFunc)413     void EnumStrongRoots(const std::function<void(RefField<>&)>& markFunc)
414     {
415         VisitRoots(markFunc);
416     }
417 
Marking(MarkStack<BaseObject * > & markStack)418     void Marking(MarkStack<BaseObject*>& markStack) {}
419 
420     RegionSpace& space_;
421 };
422 
VerifyAfterMarkInternal(RegionSpace & space)423 void WVerify::VerifyAfterMarkInternal(RegionSpace& space)
424 {
425     CHECKF(Heap::GetHeap().GetGCPhase() == GCPhase::GC_PHASE_POST_MARK)
426         << CONTEXT << "Mark verification should be called after PostMarking()";
427 
428     auto iter = VerifyIterator(space);
429     auto verifySTWRoots = AfterMarkVisitor();
430     std::unordered_set<BaseObject*> markSet;
431     iter.IterateRemarked<VisitSTWRoots>(verifySTWRoots, markSet);
432     auto verifyConcurrentRoots = AfterMarkVisitor<false>();
433     iter.IterateRemarked<VisitConcurrentRoots>(verifyConcurrentRoots, markSet);
434 
435     LOG_COMMON(DEBUG) << "[WVerify]: VerifyAfterMark (STWRoots) verified ref count: "
436                       << verifySTWRoots.VerifyRefCount();
437     LOG_COMMON(DEBUG) << "[WVerify]: VerifyAfterMark (ConcurrentRoots) verified ref count: "
438                       << verifyConcurrentRoots.VerifyRefCount();
439 }
440 
VerifyAfterMark(ArkCollector & collector)441 void WVerify::VerifyAfterMark(ArkCollector& collector)
442 {
443 #if !defined(ENABLE_CMC_VERIFY) && defined(NDEBUG)
444     return;
445 #endif
446     RegionSpace& space = reinterpret_cast<RegionSpace&>(collector.GetAllocator());
447     if (!MutatorManager::Instance().WorldStopped()) {
448         STWParam stwParam{"WGC-verify-aftermark"};
449         ScopedStopTheWorld stw(stwParam);
450         VerifyAfterMarkInternal(space);
451     } else {
452         VerifyAfterMarkInternal(space);
453     }
454 }
455 
VerifyAfterForwardInternal(RegionSpace & space)456 void WVerify::VerifyAfterForwardInternal(RegionSpace& space)
457 {
458     CHECKF(Heap::GetHeap().GetGCPhase() == GCPhase::GC_PHASE_COPY)
459         << CONTEXT << "Forward verification should be called after ForwardFromSpace()";
460 
461     auto iter = VerifyIterator(space);
462     auto visitor = AfterForwardVisitor();
463     iter.IterateFromSpace(visitor);
464 
465     LOG_COMMON(DEBUG) << "[WVerify]: VerifyAfterForward verified ref count: " << visitor.VerifyRefCount();
466 }
467 
VerifyAfterForward(ArkCollector & collector)468 void WVerify::VerifyAfterForward(ArkCollector& collector)
469 {
470 #if !defined(ENABLE_CMC_VERIFY) && defined(NDEBUG)
471     return;
472 #endif
473     RegionSpace& space = reinterpret_cast<RegionSpace&>(collector.GetAllocator());
474     if (!MutatorManager::Instance().WorldStopped()) {
475         STWParam stwParam{"WGC-verify-aftermark"};
476         ScopedStopTheWorld stw(stwParam);
477         VerifyAfterForwardInternal(space);
478     } else {
479         VerifyAfterForwardInternal(space);
480     }
481 }
482 
VerifyAfterFixInternal(RegionSpace & space)483 void WVerify::VerifyAfterFixInternal(RegionSpace& space)
484 {
485     CHECKF(Heap::GetHeap().GetGCPhase() == GCPhase::GC_PHASE_FIX)
486         << CONTEXT << "Fix verification should be called after Fix()";
487 
488     auto iter = VerifyIterator(space);
489     auto visitor = AfterFixVisitor();
490 
491     std::unordered_set<BaseObject*> markSet;
492     iter.IterateRemarked(visitor, markSet);
493 
494     LOG_COMMON(DEBUG) << "[WVerify]: VerifyAfterFix verified ref count: " << visitor.VerifyRefCount();
495 }
496 
VerifyAfterFix(ArkCollector & collector)497 void WVerify::VerifyAfterFix(ArkCollector& collector)
498 {
499 #if !defined(ENABLE_CMC_VERIFY) && defined(NDEBUG)
500     return;
501 #endif
502     RegionSpace& space = reinterpret_cast<RegionSpace&>(collector.GetAllocator());
503     if (!MutatorManager::Instance().WorldStopped()) {
504         STWParam stwParam{"WGC-verify-aftermark"};
505         ScopedStopTheWorld stw(stwParam);
506         VerifyAfterFixInternal(space);
507     } else {
508         VerifyAfterFixInternal(space);
509     }
510 }
511 
EnableReadBarrierDFXInternal(RegionSpace & space)512 void WVerify::EnableReadBarrierDFXInternal(RegionSpace& space)
513 {
514     auto iter = VerifyIterator(space);
515     auto setter = ReadBarrierSetter();
516     auto unsetter = ReadBarrierUnsetter();
517 
518     std::unordered_set<BaseObject*> markSet;
519     iter.IterateRemarked(setter, markSet, true);
520     // some slots of heap object are also roots, so we need to unset them
521     iter.IterateRoot(unsetter);
522 }
523 
EnableReadBarrierDFX(ArkCollector & collector)524 void WVerify::EnableReadBarrierDFX(ArkCollector& collector)
525 {
526 #if !defined(ENABLE_CMC_RB_DFX)
527     return;
528 #endif
529     RegionSpace& space = reinterpret_cast<RegionSpace&>(collector.GetAllocator());
530     if (!MutatorManager::Instance().WorldStopped()) {
531         STWParam stwParam{"WGC-verify-enable-rb-dfx"};
532         ScopedStopTheWorld stw(stwParam);
533         EnableReadBarrierDFXInternal(space);
534     } else {
535         EnableReadBarrierDFXInternal(space);
536     }
537 }
538 
DisableReadBarrierDFXInternal(RegionSpace & space)539 void WVerify::DisableReadBarrierDFXInternal(RegionSpace& space)
540 {
541     auto iter = VerifyIterator(space);
542     auto unsetter = ReadBarrierUnsetter();
543 
544     std::unordered_set<BaseObject*> markSet;
545     iter.IterateRemarked(unsetter, markSet, true);
546 }
547 
DisableReadBarrierDFX(ArkCollector & collector)548 void WVerify::DisableReadBarrierDFX(ArkCollector& collector)
549 {
550 #if !defined(ENABLE_CMC_RB_DFX)
551     return;
552 #endif
553     RegionSpace& space = reinterpret_cast<RegionSpace&>(collector.GetAllocator());
554     if (!MutatorManager::Instance().WorldStopped()) {
555         STWParam stwParam{"WGC-verify-disable-rb-dfx"};
556         ScopedStopTheWorld stw(stwParam);
557         DisableReadBarrierDFXInternal(space);
558     } else {
559         DisableReadBarrierDFXInternal(space);
560     }
561 }
562 
563 }  // namespace common
564