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