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 class RootVisitor { 44 public: 45 RootVisitor() = default; 46 virtual ~RootVisitor() = default; 47 48 NO_MOVE_SEMANTIC(RootVisitor); 49 NO_COPY_SEMANTIC(RootVisitor); 50 51 virtual void VisitRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot slot) = 0; 52 53 virtual void VisitRangeRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot start, 54 [[maybe_unused]] ObjectSlot end) = 0; 55 56 virtual void VisitBaseAndDerivedRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, 57 [[maybe_unused]] ObjectSlot derived, [[maybe_unused]] uintptr_t baseOldObject) = 0; 58 }; 59 using WeakRootVisitor = std::function<TaggedObject *(TaggedObject *p)>; 60 61 template <class DerivedVisitor> 62 class EcmaObjectRangeVisitor { 63 public: 64 EcmaObjectRangeVisitor() = default; 65 virtual ~EcmaObjectRangeVisitor() = default; 66 67 NO_MOVE_SEMANTIC(EcmaObjectRangeVisitor); 68 NO_COPY_SEMANTIC(EcmaObjectRangeVisitor); 69 operator()70 void operator()(TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) 71 { 72 static_cast<DerivedVisitor*>(this)->VisitObjectRangeImpl(root, start, end, area); 73 } 74 VisitHClass(TaggedObject * hclass)75 void VisitHClass(TaggedObject *hclass) 76 { 77 static_cast<DerivedVisitor*>(this)->VisitObjectHClassImpl(hclass); 78 } 79 VisitObjectRangeImpl(TaggedObject * root,ObjectSlot start,ObjectSlot end,VisitObjectArea area)80 virtual void VisitObjectRangeImpl([[maybe_unused]] TaggedObject *root, [[maybe_unused]] ObjectSlot start, 81 [[maybe_unused]] ObjectSlot end, [[maybe_unused]] VisitObjectArea area) 82 { 83 UNREACHABLE(); 84 } 85 VisitObjectHClassImpl(TaggedObject * hclass)86 virtual void VisitObjectHClassImpl([[maybe_unused]] TaggedObject *hclass) 87 { 88 UNREACHABLE(); 89 } 90 }; 91 92 template <VisitType visitType, size_t size> 93 class PrimitiveObjectBodyIterator { 94 public: 95 template<class DerivedVisitor> IterateBody(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)96 static inline void IterateBody(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 97 { 98 if constexpr (visitType == VisitType::ALL_VISIT) { 99 constexpr size_t hclassEnd = sizeof(JSTaggedType); 100 visitor(root, ObjectSlot(ToUintPtr(root)), 101 ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL); 102 if constexpr (size > hclassEnd) { 103 visitor(root, ObjectSlot(ToUintPtr(root) + hclassEnd), 104 ObjectSlot(ToUintPtr(root) + size), VisitObjectArea::RAW_DATA); 105 } 106 } 107 } 108 }; 109 110 template <VisitType visitType, size_t startOffset, size_t endOffset, 111 size_t size, size_t startSize = sizeof(JSTaggedType)> 112 class ObjectBodyIterator { 113 public: 114 template <VisitObjectArea area, bool visitHClass, class DerivedVisitor> IterateBody(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)115 static inline void IterateBody(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 116 { 117 if constexpr (visitType == VisitType::ALL_VISIT) { 118 if constexpr (visitHClass) { 119 IterateHClass(root, visitor); 120 } 121 IterateBefore(root, visitor); 122 } 123 if constexpr (startOffset < endOffset) { 124 visitor(root, ObjectSlot(ToUintPtr(root) + startOffset), 125 ObjectSlot(ToUintPtr(root) + endOffset), area); 126 } 127 128 if constexpr (visitType == VisitType::ALL_VISIT) { 129 IterateAfter(root, visitor); 130 } 131 } 132 133 template <class DerivedVisitor> IterateRefBody(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)134 static inline void IterateRefBody(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 135 { 136 IterateBody<VisitObjectArea::NORMAL, true>(root, visitor); 137 } 138 139 template <class DerivedVisitor> IterateNativeBody(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)140 static inline void IterateNativeBody(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 141 { 142 IterateBody<VisitObjectArea::NATIVE_POINTER, true>(root, visitor); 143 } 144 145 template <class DerivedVisitor> IterateDerivedRefBody(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)146 static inline void IterateDerivedRefBody(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 147 { 148 IterateBody<VisitObjectArea::NORMAL, false>(root, visitor); 149 } 150 151 template <class DerivedVisitor> IterateHClass(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)152 static inline void IterateHClass(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 153 { 154 size_t hclassEnd = sizeof(JSTaggedType); 155 visitor(root, ObjectSlot(ToUintPtr(root)), 156 ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL); 157 } 158 159 template <class DerivedVisitor> IterateBefore(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)160 static inline void IterateBefore(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 161 { 162 if constexpr (startOffset > startSize) { 163 ASSERT(startOffset != endOffset); 164 IteratorRange(root, visitor, startSize, startOffset); 165 } 166 } 167 168 template <class DerivedVisitor> IterateAfter(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)169 static inline void IterateAfter(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 170 { 171 if constexpr (size > endOffset) { 172 IteratorRange(root, visitor, endOffset, size); 173 } 174 } 175 176 template <class DerivedVisitor> IteratorRange(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor,size_t start,size_t end)177 static inline void IteratorRange(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor, 178 size_t start, size_t end) 179 { 180 visitor(root, ObjectSlot(ToUintPtr(root) + start), 181 ObjectSlot(ToUintPtr(root) + end), VisitObjectArea::RAW_DATA); 182 } 183 }; 184 185 template <VisitType visitType, size_t startOffset> 186 class ArrayBodyIterator { 187 public: 188 template <class DerivedVisitor> IterateBody(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor,size_t refLength,size_t length)189 static inline void IterateBody(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor, 190 size_t refLength, size_t length) 191 { 192 if constexpr (visitType == VisitType::ALL_VISIT) { 193 IterateBefore(root, visitor); 194 } 195 if (LIKELY(refLength != 0)) { 196 size_t endOffset = startOffset + refLength * JSTaggedValue::TaggedTypeSize(); 197 visitor(root, ObjectSlot(ToUintPtr(root) + startOffset), 198 ObjectSlot(ToUintPtr(root) + endOffset), VisitObjectArea::NORMAL); 199 } 200 if constexpr (visitType == VisitType::ALL_VISIT) { 201 IterateAfter(root, visitor, refLength, length); 202 } 203 } 204 205 template <class DerivedVisitor> IterateBefore(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor)206 static inline void IterateBefore(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor) 207 { 208 size_t hclassEnd = sizeof(JSTaggedType); 209 ASSERT(startOffset > hclassEnd); 210 visitor(root, ObjectSlot(ToUintPtr(root)), ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL); 211 IteratorRange(root, visitor, hclassEnd, startOffset); 212 } 213 214 template <class DerivedVisitor> IterateAfter(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor,size_t refLength,size_t length)215 static inline void IterateAfter(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor, 216 size_t refLength, size_t length) 217 { 218 if (length > refLength) { 219 size_t endOffset = startOffset + refLength * JSTaggedValue::TaggedTypeSize(); 220 size_t size = startOffset + length * JSTaggedValue::TaggedTypeSize(); 221 IteratorRange(root, visitor, endOffset, size); 222 } 223 } 224 225 template <class DerivedVisitor> IteratorRange(TaggedObject * root,EcmaObjectRangeVisitor<DerivedVisitor> & visitor,size_t start,size_t end)226 static inline void IteratorRange(TaggedObject *root, EcmaObjectRangeVisitor<DerivedVisitor> &visitor, 227 size_t start, size_t end) 228 { 229 visitor(root, ObjectSlot(ToUintPtr(root) + start), 230 ObjectSlot(ToUintPtr(root) + end), VisitObjectArea::RAW_DATA); 231 } 232 }; 233 } // namespace panda::ecmascript 234 #endif // ECMASCRIPT_MEM_VISITOR_H 235