| /* |
| * Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license |
| * that can be found in the LICENSE file. |
| */ |
| |
| #ifndef RUNTIME_OBJECT_TRAVERSAL_H |
| #define RUNTIME_OBJECT_TRAVERSAL_H |
| |
| #include <type_traits> |
| |
| #include "Memory.h" |
| #include "Natives.h" |
| #include "ReferenceOps.hpp" |
| #include "Types.h" |
| #include "ObjectOps.hpp" |
| |
| namespace kotlin { |
| |
| // TODO: Consider an iterator/ranges based approaches for traversals. |
| |
| template <typename F> |
| PERFORMANCE_INLINE void traverseClassObjectFields(ObjHeader* object, F process) noexcept(noexcept(process(std::declval<mm::RefFieldAccessor>()))) { |
| const TypeInfo* typeInfo = object->type_info(); |
| RuntimeAssert(typeInfo != theArrayTypeInfo, "Must not be an array of objects"); |
| for (int index = 0; index < typeInfo->objOffsetsCount_; index++) { |
| auto fieldPtr = reinterpret_cast<ObjHeader**>(reinterpret_cast<uintptr_t>(object) + typeInfo->objOffsets_[index]); |
| process(mm::RefFieldAccessor(fieldPtr)); |
| } |
| } |
| |
| template <typename F> |
| PERFORMANCE_INLINE void traverseArrayOfObjectsElements(ArrayHeader* array, F process) noexcept(noexcept(process(std::declval<mm::RefFieldAccessor>()))) { |
| RuntimeAssert(array->type_info() == theArrayTypeInfo, "Must be an array of objects"); |
| for (uint32_t index = 0; index < array->count_; index++) { |
| process(mm::RefFieldAccessor(ArrayAddressOfElementAt(array, index))); |
| } |
| } |
| |
| template <typename F> |
| PERFORMANCE_INLINE void traverseObjectFields(ObjHeader* object, F process) noexcept(noexcept(process(std::declval<mm::RefFieldAccessor>()))) { |
| const TypeInfo* typeInfo = object->type_info(); |
| // Only consider arrays of objects, not arrays of primitives. |
| if (typeInfo != theArrayTypeInfo) { |
| for (int index = 0; index < typeInfo->objOffsetsCount_; index++) { |
| auto fieldPtr = reinterpret_cast<ObjHeader**>(reinterpret_cast<uintptr_t>(object) + typeInfo->objOffsets_[index]); |
| process(mm::RefFieldAccessor(fieldPtr)); |
| } |
| } else { |
| ArrayHeader* array = object->array(); |
| for (uint32_t index = 0; index < array->count_; index++) { |
| process(mm::RefFieldAccessor(ArrayAddressOfElementAt(array, index))); |
| } |
| } |
| } |
| |
| // FIXME explicitly mention no barriers |
| template <typename F> |
| PERFORMANCE_INLINE void traverseReferredObjects(ObjHeader* object, F process) noexcept(noexcept(process(std::declval<ObjHeader*>()))) { |
| traverseObjectFields(object, [&process](auto accessor) noexcept(noexcept(process(std::declval<ObjHeader*>()))) { |
| if (ObjHeader* ref = accessor.direct()) { |
| process(ref); |
| } |
| }); |
| } |
| |
| } // namespace kotlin |
| |
| #endif // RUNTIME_OBJECT_TRAVERSAL_H |