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 "common_interfaces/heap/heap_visitor.h" 22 #include "ecmascript/mem/slots.h" 23 #include "ecmascript/mem/tagged_object.h" 24 25 namespace panda::ecmascript { 26 enum class Root { 27 ROOT_FRAME, 28 ROOT_HANDLE, 29 ROOT_VM, 30 ROOT_STRING, 31 ROOT_INTERNAL_CALL_PARAMS, 32 }; 33 34 enum class VisitObjectArea { 35 NORMAL, 36 NATIVE_POINTER, 37 IN_OBJECT, 38 RAW_DATA 39 }; 40 41 enum class VisitType : size_t { SEMI_GC_VISIT, OLD_GC_VISIT, SNAPSHOT_VISIT, ALL_VISIT }; 42 enum class VMRootVisitType : uint8_t { MARK, UPDATE_ROOT, VERIFY, HEAP_SNAPSHOT }; 43 44 template <class DerivedVisitor> 45 class BaseObjectVisitor { 46 public: 47 BaseObjectVisitor() = default; 48 virtual ~BaseObjectVisitor() = default; 49 50 NO_MOVE_SEMANTIC(BaseObjectVisitor); 51 NO_COPY_SEMANTIC(BaseObjectVisitor); 52 operator()53 void operator()(BaseObject *rootObject, uintptr_t startAddr, uintptr_t endAddr, VisitObjectArea area) 54 { 55 static_cast<DerivedVisitor*>(this)->VisitObjectRangeImpl(rootObject, startAddr, endAddr, area); 56 } 57 VisitHClass(BaseObject * hclass)58 void VisitHClass(BaseObject *hclass) 59 { 60 static_cast<DerivedVisitor*>(this)->VisitObjectHClassImpl(hclass); 61 } 62 63 // A temporary impl to collect JSWeakMap, need to refactor and fix VisitJSWeakMap(BaseObject * rootObject)64 void VisitJSWeakMap(BaseObject *rootObject) 65 { 66 ASSERT(JSTaggedValue(TaggedObject::Cast(rootObject)).IsJSWeakMap()); 67 static_cast<DerivedVisitor*>(this)->VisitJSWeakMapImpl(rootObject); 68 } 69 VisitObjectRangeImpl(BaseObject * rootObject,uintptr_t startAddr,uintptr_t endAddr,VisitObjectArea area)70 virtual void VisitObjectRangeImpl([[maybe_unused]] BaseObject *rootObject, [[maybe_unused]] uintptr_t startAddr, 71 [[maybe_unused]] uintptr_t endAddr, [[maybe_unused]] VisitObjectArea area) 72 {} 73 VisitObjectHClassImpl(BaseObject * hclass)74 virtual void VisitObjectHClassImpl([[maybe_unused]] BaseObject *hclass) 75 {} 76 VisitJSWeakMapImpl(BaseObject * rootObject)77 virtual void VisitJSWeakMapImpl([[maybe_unused]] BaseObject *rootObject) 78 {} 79 }; 80 81 class RootVisitor { 82 public: 83 RootVisitor() = default; 84 virtual ~RootVisitor() = default; 85 86 NO_MOVE_SEMANTIC(RootVisitor); 87 NO_COPY_SEMANTIC(RootVisitor); 88 89 virtual void VisitRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot slot) = 0; 90 91 virtual void VisitRangeRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot start, 92 [[maybe_unused]] ObjectSlot end) = 0; 93 94 virtual void VisitBaseAndDerivedRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot base, 95 [[maybe_unused]] ObjectSlot derived, [[maybe_unused]] uintptr_t baseOldObject) = 0; 96 }; 97 98 class WeakVisitor { 99 public: 100 WeakVisitor() = default; 101 virtual ~WeakVisitor() = default; 102 103 NO_MOVE_SEMANTIC(WeakVisitor); 104 NO_COPY_SEMANTIC(WeakVisitor); 105 106 virtual bool VisitRoot([[maybe_unused]] Root type, [[maybe_unused]] ObjectSlot slot) = 0; 107 }; 108 109 using WeakRootVisitor = std::function<TaggedObject *(TaggedObject *p)>; 110 111 template <VisitType visitType, size_t size> 112 class PrimitiveObjectBodyIterator { 113 public: 114 template <class DerivedVisitor> IterateBody(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)115 static inline void IterateBody(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 116 { 117 if constexpr (visitType == VisitType::ALL_VISIT) { 118 constexpr size_t hclassEnd = sizeof(JSTaggedType); 119 visitor(root, ToUintPtr(root), 120 ToUintPtr(root) + hclassEnd, VisitObjectArea::NORMAL); 121 if constexpr (size > hclassEnd) { 122 visitor(root, ToUintPtr(root) + hclassEnd, 123 ToUintPtr(root) + size, VisitObjectArea::RAW_DATA); 124 } 125 } 126 } 127 }; 128 129 template <VisitType visitType, size_t startOffset, size_t endOffset, 130 size_t size, size_t startSize = sizeof(JSTaggedType)> 131 class ObjectBodyIterator { 132 public: 133 template <VisitObjectArea area, bool visitHClass, class DerivedVisitor> IterateBody(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)134 static inline void IterateBody(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 135 { 136 if constexpr (visitType == VisitType::ALL_VISIT) { 137 if constexpr (visitHClass) { 138 IterateHClass(root, visitor); 139 } 140 IterateBefore(root, visitor); 141 } 142 if constexpr (startOffset < endOffset) { 143 visitor(root, ToUintPtr(root) + startOffset, 144 ToUintPtr(root) + endOffset, area); 145 } 146 147 if constexpr (visitType == VisitType::ALL_VISIT) { 148 IterateAfter(root, visitor); 149 } 150 } 151 152 template <class DerivedVisitor> IterateRefBody(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)153 static inline void IterateRefBody(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 154 { 155 IterateBody<VisitObjectArea::NORMAL, true>(root, visitor); 156 } 157 158 template <class DerivedVisitor> IterateNativeBody(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)159 static inline void IterateNativeBody(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 160 { 161 IterateBody<VisitObjectArea::NATIVE_POINTER, true>(root, visitor); 162 } 163 164 template <class DerivedVisitor> IterateDerivedRefBody(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)165 static inline void IterateDerivedRefBody(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 166 { 167 IterateBody<VisitObjectArea::NORMAL, false>(root, visitor); 168 } 169 170 template <class DerivedVisitor> IterateHClass(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)171 static inline void IterateHClass(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 172 { 173 visitor.VisitHClass(root->GetClass()); 174 } 175 176 template <class DerivedVisitor> IterateBefore(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)177 static inline void IterateBefore(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 178 { 179 if constexpr (startOffset > startSize) { 180 ASSERT(startOffset != endOffset); 181 IteratorRange(root, visitor, startSize, startOffset); 182 } 183 } 184 185 template <class DerivedVisitor> IterateAfter(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)186 static inline void IterateAfter(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 187 { 188 if constexpr (size > endOffset) { 189 IteratorRange(root, visitor, endOffset, size); 190 } 191 } 192 193 template <class DerivedVisitor> IteratorRange(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor,size_t start,size_t end)194 static inline void IteratorRange(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor, 195 size_t start, size_t end) 196 { 197 visitor(root, ToUintPtr(root) + start, 198 ToUintPtr(root) + end, VisitObjectArea::RAW_DATA); 199 } 200 }; 201 202 template <VisitType visitType, size_t startOffset> 203 class ArrayBodyIterator { 204 public: 205 template <class DerivedVisitor> IterateBody(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor,size_t refLength,size_t length)206 static inline void IterateBody(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor, 207 size_t refLength, size_t length) 208 { 209 if constexpr (visitType == VisitType::ALL_VISIT) { 210 IterateBefore(root, visitor); 211 } 212 if (LIKELY(refLength != 0)) { 213 size_t endOffset = startOffset + refLength * JSTaggedValue::TaggedTypeSize(); 214 visitor(root, ToUintPtr(root) + startOffset, 215 ToUintPtr(root) + endOffset, VisitObjectArea::NORMAL); 216 } 217 if constexpr (visitType == VisitType::ALL_VISIT) { 218 IterateAfter(root, visitor, refLength, length); 219 } 220 } 221 222 template <class DerivedVisitor> IterateBefore(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor)223 static inline void IterateBefore(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor) 224 { 225 size_t hclassEnd = sizeof(JSTaggedType); 226 ASSERT(startOffset > hclassEnd); 227 visitor.VisitHClass(root->GetClass()); 228 IteratorRange(root, visitor, hclassEnd, startOffset); 229 } 230 231 template <class DerivedVisitor> IterateAfter(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor,size_t refLength,size_t length)232 static inline void IterateAfter(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor, 233 size_t refLength, size_t length) 234 { 235 if (length > refLength) { 236 size_t endOffset = startOffset + refLength * JSTaggedValue::TaggedTypeSize(); 237 size_t size = startOffset + length * JSTaggedValue::TaggedTypeSize(); 238 IteratorRange(root, visitor, endOffset, size); 239 } 240 } 241 242 template <class DerivedVisitor> IteratorRange(TaggedObject * root,BaseObjectVisitor<DerivedVisitor> & visitor,size_t start,size_t end)243 static inline void IteratorRange(TaggedObject *root, BaseObjectVisitor<DerivedVisitor> &visitor, 244 size_t start, size_t end) 245 { 246 visitor(root, ToUintPtr(root) + start, 247 ToUintPtr(root) + end, VisitObjectArea::RAW_DATA); 248 } 249 }; 250 } // namespace panda::ecmascript 251 #endif // ECMASCRIPT_MEM_VISITOR_H 252