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
24namespace panda::ecmascript {
25enum class Root {
26    ROOT_FRAME,
27    ROOT_HANDLE,
28    ROOT_VM,
29    ROOT_STRING,
30    ROOT_INTERNAL_CALL_PARAMS,
31};
32
33enum class VisitObjectArea {
34    NORMAL,
35    NATIVE_POINTER,
36    IN_OBJECT,
37    RAW_DATA
38};
39
40enum class VisitType : size_t { SEMI_GC_VISIT, OLD_GC_VISIT, SNAPSHOT_VISIT, ALL_VISIT };
41enum class VMRootVisitType : uint8_t { MARK, UPDATE_ROOT, VERIFY, HEAP_SNAPSHOT };
42
43using RootVisitor = std::function<void(Root type, ObjectSlot p)>;
44using RootRangeVisitor = std::function<void(Root type, ObjectSlot start, ObjectSlot end)>;
45using RootBaseAndDerivedVisitor =
46    std::function<void(Root type, ObjectSlot base, ObjectSlot derived, uintptr_t baseOldObject)>;
47using EcmaObjectRangeVisitor = std::function<void(TaggedObject *root, ObjectSlot start, ObjectSlot end,
48                                                  VisitObjectArea area)>;
49using WeakRootVisitor = std::function<TaggedObject *(TaggedObject *p)>;
50
51template <VisitType visitType, size_t size>
52class PrimitiveObjectBodyIterator {
53public:
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
68template <VisitType visitType, size_t startOffset, size_t endOffset,
69          size_t size, size_t startSize = sizeof(JSTaggedType)>
70class ObjectBodyIterator {
71public:
72    template <VisitObjectArea area, bool visitHClass>
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
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
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
136template <VisitType visitType, size_t startOffset>
137class ArrayBodyIterator {
138public:
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
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
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
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