1 /**
2 * Copyright (c) 2024 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 #ifndef PANDA_RUNTIME_MEM_NEW_OBJECT_HELPERS_INL_H
17 #define PANDA_RUNTIME_MEM_NEW_OBJECT_HELPERS_INL_H
18
19 #include "runtime/mem/object-references-iterator.h"
20 #include "runtime/include/coretypes/array-inl.h"
21 #include "runtime/include/class-inl.h"
22
23 namespace ark::mem {
24 class ObjectArrayIterator {
25 public:
26 template <typename T, bool INTERRUPTIBLE, typename Handler>
27 static bool Iterate(coretypes::Array *array, Handler *handler);
28
29 template <typename T, bool INTERRUPTIBLE, typename Handler>
30 static bool Iterate(coretypes::Array *array, Handler *handler, void *begin, void *end);
31 };
32
33 template <typename T, bool INTERRUPTIBLE, typename Handler>
Iterate(coretypes::Array * array,Handler * handler)34 bool ObjectArrayIterator::Iterate(coretypes::Array *array, Handler *handler)
35 {
36 auto *arrayStart = array->GetBase<T *>();
37 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
38 auto *arrayEnd = arrayStart + array->GetLength();
39
40 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
41 for (auto *p = arrayStart; p < arrayEnd; ++p) {
42 [[maybe_unused]] auto cont = handler->ProcessObjectPointer(p);
43 if constexpr (INTERRUPTIBLE) {
44 if (!cont) {
45 return false;
46 }
47 }
48 }
49
50 return true;
51 }
52
53 template <typename T, bool INTERRUPTIBLE, typename Handler>
Iterate(coretypes::Array * array,Handler * handler,void * begin,void * end)54 bool ObjectArrayIterator::Iterate(coretypes::Array *array, Handler *handler, void *begin, void *end)
55 {
56 ASSERT(IsAligned(ToUintPtr(begin), DEFAULT_ALIGNMENT_IN_BYTES));
57
58 auto *arrayStart = array->GetBase<T *>();
59 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
60 auto *arrayEnd = arrayStart + array->GetLength();
61 auto *p = begin < arrayStart ? arrayStart : reinterpret_cast<T *>(begin);
62
63 if (end > arrayEnd) {
64 end = arrayEnd;
65 }
66
67 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
68 for (; p < end; ++p) {
69 [[maybe_unused]] auto cont = handler->ProcessObjectPointer(p);
70 if constexpr (INTERRUPTIBLE) {
71 if (!cont) {
72 return false;
73 }
74 }
75 }
76
77 return true;
78 }
79
80 template <bool INTERRUPTIBLE, typename Handler>
Iterate(ObjectHeader * obj,Handler * handler,void * begin,void * end)81 bool ObjectIterator<LANG_TYPE_STATIC>::Iterate(ObjectHeader *obj, Handler *handler, void *begin, void *end)
82 {
83 auto *cls = obj->ClassAddr<Class>();
84 ASSERT(cls != nullptr);
85 return Iterate<INTERRUPTIBLE>(cls, obj, handler, begin, end);
86 }
87
88 template <typename Handler>
IterateAndDiscoverReferences(GC * gc,ObjectHeader * obj,Handler * handler)89 bool ObjectIterator<LANG_TYPE_STATIC>::IterateAndDiscoverReferences(GC *gc, ObjectHeader *obj, Handler *handler)
90 {
91 auto *cls = obj->ClassAddr<Class>();
92 ASSERT(cls != nullptr);
93
94 if (gc->IsReference(cls, obj, [gc](auto *o) { return gc->InGCSweepRange(o); })) {
95 gc->ProcessReferenceForSinglePassCompaction(
96 cls, obj, [handler](void *o) { handler->ProcessObjectPointer(reinterpret_cast<ObjectPointerType *>(o)); });
97 return true;
98 }
99
100 return Iterate<false>(cls, obj, handler);
101 }
102
103 template <typename Handler>
IterateAndDiscoverReferences(GC * gc,ObjectHeader * obj,Handler * handler,void * begin,void * end)104 bool ObjectIterator<LANG_TYPE_STATIC>::IterateAndDiscoverReferences(GC *gc, ObjectHeader *obj, Handler *handler,
105 void *begin, void *end)
106 {
107 auto *cls = obj->ClassAddr<Class>();
108 ASSERT(cls != nullptr);
109
110 if (gc->IsReference(cls, obj, [gc](auto *o) { return gc->InGCSweepRange(o); })) {
111 gc->ProcessReferenceForSinglePassCompaction(
112 cls, obj, [handler](void *o) { handler->ProcessObjectPointer(reinterpret_cast<ObjectPointerType *>(o)); });
113 return true;
114 }
115
116 return Iterate<false>(cls, obj, handler, begin, end);
117 }
118
119 template <bool INTERRUPTIBLE, typename Handler>
Iterate(Class * cls,ObjectHeader * obj,Handler * handler)120 bool ObjectIterator<LANG_TYPE_STATIC>::Iterate(Class *cls, ObjectHeader *obj, Handler *handler)
121 {
122 if (cls->IsObjectArrayClass()) {
123 return ObjectArrayIterator::Iterate<ObjectPointerType, INTERRUPTIBLE>(static_cast<coretypes::Array *>(obj),
124 handler);
125 }
126 if (cls->IsClassClass()) {
127 auto *objectClass = ark::Class::FromClassObject(obj);
128 if (objectClass->IsInitializing() || objectClass->IsInitialized()) {
129 if (!IterateClassReferences<INTERRUPTIBLE>(objectClass, handler)) {
130 return false;
131 }
132 }
133 }
134
135 return IterateObjectReferences<INTERRUPTIBLE>(obj, cls, handler);
136 }
137
138 template <bool INTERRUPTIBLE, typename Handler>
Iterate(Class * cls,ObjectHeader * obj,Handler * handler,void * begin,void * end)139 bool ObjectIterator<LANG_TYPE_STATIC>::Iterate(Class *cls, ObjectHeader *obj, Handler *handler, void *begin, void *end)
140 {
141 if (cls->IsObjectArrayClass()) {
142 return ObjectArrayIterator::Iterate<ObjectPointerType, INTERRUPTIBLE>(static_cast<coretypes::Array *>(obj),
143 handler, begin, end);
144 }
145 if (cls->IsClassClass()) {
146 auto *objectClass = ark::Class::FromClassObject(obj);
147 if (objectClass->IsInitializing() || objectClass->IsInitialized()) {
148 if (!IterateClassReferences<INTERRUPTIBLE>(objectClass, handler, begin, end)) {
149 return false;
150 }
151 }
152 }
153
154 if (obj >= begin && !cls->IsVariableSize() && ToUintPtr(obj) + cls->GetObjectSize() <= ToUintPtr(end)) {
155 return IterateObjectReferences<INTERRUPTIBLE>(obj, cls, handler);
156 }
157
158 return IterateObjectReferences<INTERRUPTIBLE>(obj, cls, handler, begin, end);
159 }
160
161 template <bool INTERRUPTIBLE, typename Handler>
IterateClassReferences(Class * cls,Handler * handler)162 bool ObjectIterator<LANG_TYPE_STATIC>::IterateClassReferences(Class *cls, Handler *handler)
163 {
164 auto refNum = cls->GetRefFieldsNum<true>();
165 if (refNum > 0) {
166 auto offset = cls->GetRefFieldsOffset<true>();
167 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
168 auto *refStart = reinterpret_cast<ObjectPointerType *>(ToUintPtr(cls) + offset);
169 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
170 auto *refEnd = refStart + refNum;
171 return IterateRange<INTERRUPTIBLE>(refStart, refEnd, handler);
172 }
173 return true;
174 }
175
176 template <bool INTERRUPTIBLE, typename Handler>
IterateClassReferences(Class * cls,Handler * handler,void * begin,void * end)177 bool ObjectIterator<LANG_TYPE_STATIC>::IterateClassReferences(Class *cls, Handler *handler, void *begin, void *end)
178 {
179 auto refNum = cls->GetRefFieldsNum<true>();
180 if (refNum > 0) {
181 auto offset = cls->GetRefFieldsOffset<true>();
182 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
183 auto *refStart = reinterpret_cast<ObjectPointerType *>(ToUintPtr(cls) + offset);
184 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
185 auto *refEnd = refStart + refNum;
186 return IterateRange<INTERRUPTIBLE>(refStart, refEnd, handler, begin, end);
187 }
188 return true;
189 }
190
191 template <bool INTERRUPTIBLE, typename Handler>
IterateObjectReferences(ObjectHeader * object,Class * objClass,Handler * handler)192 bool ObjectIterator<LANG_TYPE_STATIC>::IterateObjectReferences(ObjectHeader *object, Class *objClass, Handler *handler)
193 {
194 ASSERT(objClass != nullptr);
195 ASSERT(!objClass->IsDynamicClass());
196 auto *cls = objClass;
197 while (cls != nullptr) {
198 auto refNum = cls->GetRefFieldsNum<false>();
199 if (refNum == 0) {
200 cls = cls->GetBase();
201 continue;
202 }
203
204 auto offset = cls->GetRefFieldsOffset<false>();
205 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
206 auto *refStart = reinterpret_cast<ObjectPointerType *>(ToUintPtr(object) + offset);
207 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
208 auto *refEnd = refStart + refNum;
209 ASSERT_PRINT(ToUintPtr(refEnd) <= ToUintPtr(object) + objClass->GetObjectSize(),
210 "cls " << objClass->GetName() << " obj " << object << " size " << objClass->GetObjectSize()
211 << " refs " << refStart << ".." << refEnd);
212 [[maybe_unused]] auto cont = IterateRange<INTERRUPTIBLE>(refStart, refEnd, handler);
213 if constexpr (INTERRUPTIBLE) {
214 if (!cont) {
215 return false;
216 }
217 }
218
219 cls = cls->GetBase();
220 }
221 return true;
222 }
223
224 template <bool INTERRUPTIBLE, typename Handler>
IterateObjectReferences(ObjectHeader * object,Class * cls,Handler * handler,void * begin,void * end)225 bool ObjectIterator<LANG_TYPE_STATIC>::IterateObjectReferences(ObjectHeader *object, Class *cls, Handler *handler,
226 void *begin, void *end)
227 {
228 ASSERT(cls != nullptr);
229 ASSERT(!cls->IsDynamicClass());
230 while (cls != nullptr) {
231 auto refNum = cls->GetRefFieldsNum<false>();
232 if (refNum == 0) {
233 cls = cls->GetBase();
234 continue;
235 }
236
237 auto offset = cls->GetRefFieldsOffset<false>();
238 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
239 auto *refStart = reinterpret_cast<ObjectPointerType *>(ToUintPtr(object) + offset);
240 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
241 auto *refEnd = refStart + refNum;
242 [[maybe_unused]] auto cont = IterateRange<INTERRUPTIBLE>(refStart, refEnd, handler, begin, end);
243 if constexpr (INTERRUPTIBLE) {
244 if (!cont) {
245 return false;
246 }
247 }
248
249 cls = cls->GetBase();
250 }
251 return true;
252 }
253
254 template <bool INTERRUPTIBLE, typename Handler>
IterateRange(ObjectPointerType * refStart,const ObjectPointerType * refEnd,Handler * handler)255 bool ObjectIterator<LANG_TYPE_STATIC>::IterateRange(ObjectPointerType *refStart, const ObjectPointerType *refEnd,
256 Handler *handler)
257 {
258 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
259 for (auto *p = refStart; p < refEnd; p++) {
260 [[maybe_unused]] auto cont = handler->ProcessObjectPointer(p);
261 if constexpr (INTERRUPTIBLE) {
262 if (!cont) {
263 return false;
264 }
265 }
266 }
267 return true;
268 }
269
270 template <bool INTERRUPTIBLE, typename Handler>
IterateRange(ObjectPointerType * refStart,ObjectPointerType * refEnd,Handler * handler,void * begin,void * end)271 bool ObjectIterator<LANG_TYPE_STATIC>::IterateRange(ObjectPointerType *refStart, ObjectPointerType *refEnd,
272 Handler *handler, void *begin, void *end)
273 {
274 auto *p = begin < refStart ? refStart : reinterpret_cast<ObjectPointerType *>(begin);
275 if (end > refEnd) {
276 end = refEnd;
277 }
278 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
279 for (; p < end; p++) {
280 [[maybe_unused]] auto cont = handler->ProcessObjectPointer(p);
281 if constexpr (INTERRUPTIBLE) {
282 if (!cont) {
283 return false;
284 }
285 }
286 }
287 return true;
288 }
289
290 template <bool INTERRUPTIBLE, typename Handler>
Iterate(ObjectHeader * obj,Handler * handler,void * begin,void * end)291 bool ObjectIterator<LANG_TYPE_DYNAMIC>::Iterate(ObjectHeader *obj, Handler *handler, void *begin, void *end)
292 {
293 auto *cls = obj->ClassAddr<HClass>();
294 ASSERT(cls != nullptr && cls->IsDynamicClass());
295 return Iterate<INTERRUPTIBLE>(cls, obj, handler, begin, end);
296 }
297
298 template <typename Handler>
IterateAndDiscoverReferences(GC * gc,ObjectHeader * obj,Handler * handler)299 bool ObjectIterator<LANG_TYPE_DYNAMIC>::IterateAndDiscoverReferences(GC *gc, ObjectHeader *obj, Handler *handler)
300 {
301 auto *cls = obj->ClassAddr<HClass>();
302 ASSERT(cls != nullptr && cls->IsDynamicClass());
303
304 if (gc->IsReference(cls, obj, [gc](auto *o) { return gc->InGCSweepRange(o); })) {
305 gc->ProcessReferenceForSinglePassCompaction(
306 cls, obj, [handler](void *o) { handler->ProcessObjectPointer(reinterpret_cast<TaggedType *>(o)); });
307 return true;
308 }
309
310 return Iterate<false>(cls, obj, handler);
311 }
312
313 template <typename Handler>
IterateAndDiscoverReferences(GC * gc,ObjectHeader * obj,Handler * handler,void * begin,void * end)314 bool ObjectIterator<LANG_TYPE_DYNAMIC>::IterateAndDiscoverReferences(GC *gc, ObjectHeader *obj, Handler *handler,
315 void *begin, void *end)
316 {
317 auto *cls = obj->ClassAddr<HClass>();
318 ASSERT(cls != nullptr && cls->IsDynamicClass());
319
320 if (gc->IsReference(cls, obj, [gc](auto *o) { return gc->InGCSweepRange(o); })) {
321 gc->ProcessReferenceForSinglePassCompaction(
322 cls, obj, [handler](void *o) { handler->ProcessObjectPointer(reinterpret_cast<TaggedType *>(o)); });
323 return true;
324 }
325
326 return Iterate<false>(cls, obj, handler, begin, end);
327 }
328
329 template <bool INTERRUPTIBLE, typename Handler>
Iterate(HClass * cls,ObjectHeader * obj,Handler * handler)330 bool ObjectIterator<LANG_TYPE_DYNAMIC>::Iterate(HClass *cls, ObjectHeader *obj, Handler *handler)
331 {
332 if (cls->IsString() || cls->IsNativePointer()) {
333 return true;
334 }
335 if (cls->IsArray()) {
336 return ObjectArrayIterator::Iterate<TaggedType, INTERRUPTIBLE>(static_cast<coretypes::Array *>(obj), handler);
337 }
338 if (cls->IsHClass()) {
339 return IterateClassReferences<INTERRUPTIBLE>(coretypes::DynClass::Cast(obj), handler);
340 }
341
342 return IterateObjectReferences<INTERRUPTIBLE>(obj, cls, handler);
343 }
344
345 template <bool INTERRUPTIBLE, typename Handler>
Iterate(HClass * cls,ObjectHeader * obj,Handler * handler,void * begin,void * end)346 bool ObjectIterator<LANG_TYPE_DYNAMIC>::Iterate(HClass *cls, ObjectHeader *obj, Handler *handler, void *begin,
347 void *end)
348 {
349 if (cls->IsString() || cls->IsNativePointer()) {
350 return true;
351 }
352 if (cls->IsArray()) {
353 return ObjectArrayIterator::Iterate<TaggedType, INTERRUPTIBLE>(static_cast<coretypes::Array *>(obj), handler,
354 begin, end);
355 }
356 if (cls->IsHClass()) {
357 return IterateClassReferences<INTERRUPTIBLE>(coretypes::DynClass::Cast(obj), handler, begin, end);
358 }
359
360 return IterateObjectReferences<INTERRUPTIBLE>(obj, cls, handler, begin, end);
361 }
362
363 template <bool INTERRUPTIBLE, typename Handler>
IterateClassReferences(coretypes::DynClass * dynClass,Handler * handler)364 bool ObjectIterator<LANG_TYPE_DYNAMIC>::IterateClassReferences(coretypes::DynClass *dynClass, Handler *handler)
365 {
366 auto hklassSize = dynClass->ClassAddr<HClass>()->GetObjectSize() - sizeof(coretypes::DynClass);
367 auto bodySize = hklassSize - sizeof(HClass);
368 auto numOfFields = bodySize / TaggedValue::TaggedTypeSize();
369 auto fieldOffset = sizeof(ObjectHeader) + sizeof(HClass);
370 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
371 auto *fieldStart = reinterpret_cast<TaggedType *>(ToUintPtr(dynClass) + fieldOffset);
372 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
373 auto *fieldEnd = fieldStart + numOfFields;
374 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
375 for (auto *p = fieldStart; p < fieldEnd; p++) {
376 [[maybe_unused]] auto cont = handler->ProcessObjectPointer(p);
377 if constexpr (INTERRUPTIBLE) {
378 if (!cont) {
379 return false;
380 }
381 }
382 }
383 return true;
384 }
385
386 template <bool INTERRUPTIBLE, typename Handler>
IterateClassReferences(coretypes::DynClass * dynClass,Handler * handler,void * begin,void * end)387 bool ObjectIterator<LANG_TYPE_DYNAMIC>::IterateClassReferences(coretypes::DynClass *dynClass, Handler *handler,
388 void *begin, void *end)
389 {
390 auto hklassSize = dynClass->ClassAddr<HClass>()->GetObjectSize() - sizeof(coretypes::DynClass);
391 auto bodySize = hklassSize - sizeof(HClass);
392 auto numOfFields = bodySize / TaggedValue::TaggedTypeSize();
393 auto fieldOffset = sizeof(ObjectHeader) + sizeof(HClass);
394 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
395 auto *fieldStart = reinterpret_cast<TaggedType *>(ToUintPtr(dynClass) + fieldOffset);
396 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
397 auto *fieldEnd = fieldStart + numOfFields;
398 auto *p = begin < fieldStart ? fieldStart : reinterpret_cast<TaggedType *>(begin);
399 if (end > fieldEnd) {
400 end = fieldEnd;
401 }
402 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
403 for (; p < end; p++) {
404 [[maybe_unused]] auto cont = handler->ProcessObjectPointer(p);
405 if constexpr (INTERRUPTIBLE) {
406 if (!cont) {
407 return false;
408 }
409 }
410 }
411 return true;
412 }
413
414 template <bool INTERRUPTIBLE, typename Handler>
IterateObjectReferences(ObjectHeader * object,HClass * cls,Handler * handler)415 bool ObjectIterator<LANG_TYPE_DYNAMIC>::IterateObjectReferences(ObjectHeader *object, HClass *cls, Handler *handler)
416 {
417 ASSERT(cls->IsDynamicClass());
418 LOG(DEBUG, GC) << "TraverseObject Current object: " << GetDebugInfoAboutObject(object);
419 auto objBodySize = cls->GetObjectSize() - ObjectHeader::ObjectHeaderSize();
420 ASSERT(objBodySize % TaggedValue::TaggedTypeSize() == 0);
421 auto numOfFields = objBodySize / TaggedValue::TaggedTypeSize();
422 auto dataOffset = ObjectHeader::ObjectHeaderSize();
423 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
424 auto *fieldStart = reinterpret_cast<TaggedType *>(ToUintPtr(object) + dataOffset);
425 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
426 auto *fieldEnd = fieldStart + numOfFields;
427 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
428 for (auto *p = fieldStart; p < fieldEnd; p++) {
429 if (cls->IsNativeField(ToUintPtr(p) - ToUintPtr(object))) {
430 continue;
431 }
432 [[maybe_unused]] auto cont = handler->ProcessObjectPointer(p);
433 if constexpr (INTERRUPTIBLE) {
434 if (!cont) {
435 return false;
436 }
437 }
438 }
439 return true;
440 }
441
442 template <bool INTERRUPTIBLE, typename Handler>
IterateObjectReferences(ObjectHeader * object,HClass * cls,Handler * handler,void * begin,void * end)443 bool ObjectIterator<LANG_TYPE_DYNAMIC>::IterateObjectReferences(ObjectHeader *object, HClass *cls, Handler *handler,
444 void *begin, void *end)
445 {
446 ASSERT(cls->IsDynamicClass());
447 LOG(DEBUG, GC) << "TraverseObject Current object: " << GetDebugInfoAboutObject(object);
448 auto objBodySize = cls->GetObjectSize() - ObjectHeader::ObjectHeaderSize();
449 ASSERT(objBodySize % TaggedValue::TaggedTypeSize() == 0);
450 auto numOfFields = objBodySize / TaggedValue::TaggedTypeSize();
451 auto dataOffset = ObjectHeader::ObjectHeaderSize();
452 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
453 auto *fieldStart = reinterpret_cast<TaggedType *>(ToUintPtr(object) + dataOffset);
454 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
455 auto *fieldEnd = fieldStart + numOfFields;
456 auto *p = begin < fieldStart ? fieldStart : reinterpret_cast<TaggedType *>(begin);
457 if (end > fieldEnd) {
458 end = fieldEnd;
459 }
460 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
461 for (; p < end; p++) {
462 if (cls->IsNativeField(ToUintPtr(p) - ToUintPtr(object))) {
463 continue;
464 }
465 [[maybe_unused]] auto cont = handler->ProcessObjectPointer(p);
466 if constexpr (INTERRUPTIBLE) {
467 if (!cont) {
468 return false;
469 }
470 }
471 }
472 return true;
473 }
474 } // namespace ark::mem
475
476 #endif // PANDA_RUNTIME_MEM_NEW_OBJECT_HELPERS_INL_H
477