1 /* 2 * Copyright (c) 2022 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 ECMASCRIPT_MEM_VISITOR_H 17 #define ECMASCRIPT_MEM_VISITOR_H 18 19 #include <functional> 20 21 #include <ecmascript/mem/slots.h> 22 #include <ecmascript/mem/tagged_object.h> 23 24 namespace panda::ecmascript { 25 enum class Root { 26 ROOT_FRAME, 27 ROOT_HANDLE, 28 ROOT_VM, 29 ROOT_STRING, 30 ROOT_INTERNAL_CALL_PARAMS, 31 }; 32 33 enum class VisitObjectArea { 34 NORMAL, 35 NATIVE_POINTER, 36 IN_OBJECT, 37 RAW_DATA 38 }; 39 40 enum class VisitType : size_t { SEMI_GC_VISIT, OLD_GC_VISIT, SNAPSHOT_VISIT, ALL_VISIT }; 41 enum class VMRootVisitType : uint8_t { MARK, UPDATE_ROOT, VERIFY, HEAP_SNAPSHOT }; 42 43 using RootVisitor = std::function<void(Root type, ObjectSlot p)>; 44 using RootRangeVisitor = std::function<void(Root type, ObjectSlot start, ObjectSlot end)>; 45 using RootBaseAndDerivedVisitor = 46 std::function<void(Root type, ObjectSlot base, ObjectSlot derived, uintptr_t baseOldObject)>; 47 using EcmaObjectRangeVisitor = std::function<void(TaggedObject *root, ObjectSlot start, ObjectSlot end, 48 VisitObjectArea area)>; 49 using WeakRootVisitor = std::function<TaggedObject *(TaggedObject *p)>; 50 51 template <VisitType visitType, size_t size> 52 class PrimitiveObjectBodyIterator { 53 public: IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)54 static inline void IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 55 { 56 if constexpr (visitType == VisitType::ALL_VISIT) { 57 constexpr size_t hclassEnd = sizeof(JSTaggedType); 58 visitor(root, ObjectSlot(ToUintPtr(root)), 59 ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL); 60 if constexpr (size > hclassEnd) { 61 visitor(root, ObjectSlot(ToUintPtr(root) + hclassEnd), 62 ObjectSlot(ToUintPtr(root) + size), VisitObjectArea::RAW_DATA); 63 } 64 } 65 } 66 }; 67 68 template <VisitType visitType, size_t startOffset, size_t endOffset, 69 size_t size, size_t startSize = sizeof(JSTaggedType)> 70 class ObjectBodyIterator { 71 public: 72 template <VisitObjectArea area, bool visitHClass> IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)73 static inline void IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 74 { 75 if constexpr (visitType == VisitType::ALL_VISIT) { 76 if constexpr (visitHClass) { 77 IterateHClass(root, visitor); 78 } 79 IterateBefore(root, visitor); 80 } 81 if constexpr (startOffset < endOffset) { 82 visitor(root, ObjectSlot(ToUintPtr(root) + startOffset), 83 ObjectSlot(ToUintPtr(root) + endOffset), area); 84 } 85 86 if constexpr (visitType == VisitType::ALL_VISIT) { 87 IterateAfter(root, visitor); 88 } 89 } 90 91 static inline void IterateRefBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 92 { 93 IterateBody<VisitObjectArea::NORMAL, true>(root, visitor); 94 } 95 96 static inline void IterateNativeBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 97 { 98 IterateBody<VisitObjectArea::NATIVE_POINTER, true>(root, visitor); 99 } 100 101 static inline void IterateDerivedRefBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 102 { 103 IterateBody<VisitObjectArea::NORMAL, false>(root, visitor); 104 } 105 106 static inline void IterateHClass(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 107 { 108 size_t hclassEnd = sizeof(JSTaggedType); 109 visitor(root, ObjectSlot(ToUintPtr(root)), 110 ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL); 111 } 112 113 static inline void IterateBefore(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 114 { 115 if constexpr (startOffset > startSize) { 116 ASSERT(startOffset != endOffset); 117 IteratorRange(root, visitor, startSize, startOffset); 118 } 119 } 120 IterateAfter(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)121 static inline void IterateAfter(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 122 { 123 if constexpr (size > endOffset) { 124 IteratorRange(root, visitor, endOffset, size); 125 } 126 } 127 IteratorRange(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, size_t start, size_t end)128 static inline void IteratorRange(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, 129 size_t start, size_t end) 130 { 131 visitor(root, ObjectSlot(ToUintPtr(root) + start), 132 ObjectSlot(ToUintPtr(root) + end), VisitObjectArea::RAW_DATA); 133 } 134 }; 135 136 template <VisitType visitType, size_t startOffset> 137 class ArrayBodyIterator { 138 public: IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, size_t refLength, size_t length)139 static inline void IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, 140 size_t refLength, size_t length) 141 { 142 if constexpr (visitType == VisitType::ALL_VISIT) { 143 IterateBefore(root, visitor); 144 } 145 if (LIKELY(refLength != 0)) { 146 size_t endOffset = startOffset + refLength * JSTaggedValue::TaggedTypeSize(); 147 visitor(root, ObjectSlot(ToUintPtr(root) + startOffset), 148 ObjectSlot(ToUintPtr(root) + endOffset), VisitObjectArea::NORMAL); 149 } 150 if constexpr (visitType == VisitType::ALL_VISIT) { 151 IterateAfter(root, visitor, refLength, length); 152 } 153 } 154 IterateBefore(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)155 static inline void IterateBefore(TaggedObject *root, const EcmaObjectRangeVisitor& visitor) 156 { 157 size_t hclassEnd = sizeof(JSTaggedType); 158 ASSERT(startOffset > hclassEnd); 159 visitor(root, ObjectSlot(ToUintPtr(root)), ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL); 160 IteratorRange(root, visitor, hclassEnd, startOffset); 161 } 162 IterateAfter(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, size_t refLength, size_t length)163 static inline void IterateAfter(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, 164 size_t refLength, size_t length) 165 { 166 if (length > refLength) { 167 size_t endOffset = startOffset + refLength * JSTaggedValue::TaggedTypeSize(); 168 size_t size = startOffset + length * JSTaggedValue::TaggedTypeSize(); 169 IteratorRange(root, visitor, endOffset, size); 170 } 171 } 172 IteratorRange(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, size_t start, size_t end)173 static inline void IteratorRange(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, 174 size_t start, size_t end) 175 { 176 visitor(root, ObjectSlot(ToUintPtr(root) + start), 177 ObjectSlot(ToUintPtr(root) + end), VisitObjectArea::RAW_DATA); 178 } 179 }; 180 } // namespace panda::ecmascript 181 #endif // ECMASCRIPT_MEM_VISITOR_H 182