1 /**
2 * Copyright (c) 2021-2025 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 #ifndef PANDA_RUNTIME_MEM_OBJECT_HELPERS_H
16 #define PANDA_RUNTIME_MEM_OBJECT_HELPERS_H
17
18 #include <functional>
19
20 #include "libpandabase/utils/logger.h"
21 #include "libpandabase/mem/mem.h"
22
23 #include "runtime/mem/gc/gc_root_type.h"
24 #include "runtime/include/object_header.h"
25
26 namespace ark {
27 class Class;
28 class HClass;
29 class Field;
30 class ManagedThread;
31 class PandaVM;
32 } // namespace ark
33
34 namespace ark::coretypes {
35 class DynClass;
36 class Array;
37 } // namespace ark::coretypes
38
39 namespace ark::mem {
40
41 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
42 #define LOG_DEBUG_OBJ_HELPERS LOG(DEBUG, GC) << vm->GetGC()->GetLogPrefix()
43
44 class GC;
45
GetObjectSize(const void * mem)46 inline size_t GetObjectSize(const void *mem)
47 {
48 return static_cast<const ObjectHeader *>(mem)->ObjectSize();
49 }
50
51 Logger::Buffer GetDebugInfoAboutObject(const ObjectHeader *header);
52
GetMinimalObjectSize()53 constexpr size_t GetMinimalObjectSize()
54 {
55 return GetAlignedObjectSize(ObjectHeader::ObjectHeaderSize());
56 }
57
58 /**
59 * Validate that object is correct from point of view of GC.
60 * For example it checks that class of the object is not nullptr.
61 * @param from_object object from which we found object by reference
62 * @param object object which we want to validate
63 */
ValidateObject(const ObjectHeader * fromObject,const ObjectHeader * object)64 inline void ValidateObject([[maybe_unused]] const ObjectHeader *fromObject, [[maybe_unused]] const ObjectHeader *object)
65 {
66 #ifndef NDEBUG
67 if (object == nullptr) {
68 return;
69 }
70 // from_object can be null, because sometimes we call Validate when we don't know previous object (for example when
71 // we extract it from stack)
72 if (object->template ClassAddr<BaseClass>() == nullptr) {
73 LOG(ERROR, GC) << " Broken object doesn't have class: " << object << " accessed from object: " << fromObject;
74 UNREACHABLE();
75 }
76 #endif // !NDEBUG
77 }
78
79 /**
80 * Validate that object (which is gc-root) is correct from point of view of GC
81 * See ValidateObject(from_object, object) for further explanation
82 * @param root_type type of the root
83 * @param object object (root) which we want to validate
84 */
ValidateObject(RootType rootType,const ObjectHeader * object)85 inline void ValidateObject([[maybe_unused]] RootType rootType, [[maybe_unused]] const ObjectHeader *object)
86 {
87 #ifndef NDEBUG
88 if (object == nullptr) {
89 return;
90 }
91 ASSERT_DO(object->template ClassAddr<BaseClass>() != nullptr,
92 LOG(FATAL, GC) << " Broken object doesn't have class: " << object << " accessed from root: " << rootType);
93 #endif // !NDEBUG
94 }
95
96 void DumpObject(ObjectHeader *objectHeader, std::basic_ostream<char, std::char_traits<char>> *oStream = &std::cerr);
97
98 void DumpClass(const Class *cls, std::basic_ostream<char, std::char_traits<char>> *oStream = &std::cerr);
99
100 [[nodiscard]] ObjectHeader *GetForwardAddress(const ObjectHeader *objectHeader);
101
102 const char *GetFieldName(const Field &field);
103
104 size_t GetDynClassInstanceSize(coretypes::DynClass *object);
105
106 class GCStaticObjectHelpers {
107 public:
108 /// Check the object is an instance of class
109 static inline bool IsClassObject(ObjectHeader *obj);
110
111 /// Traverse all kinds of object_header and call obj_visitor for each reference field.
112 static void TraverseAllObjects(ObjectHeader *objectHeader,
113 const std::function<void(ObjectHeader *, ObjectHeader *)> &objVisitor);
114
115 /**
116 * Traverse all kinds of object_header and call handler for each reference field.
117 * The handler accepts the object, the reference value, offset to the reference in the object and
118 * the flag whether the field is volatile. Stop traverse if handler return false for any field.
119 * INTERRUPTIBLE means that traverse over objects can be stopped (it is possible when handler may return false)
120 * This template is used to decrease possible performance influence of checking handler's returned value on GC pause
121 * time
122 * Return true if object was fully traversed, otherwise false.
123 */
124 template <bool INTERRUPTIBLE, typename Handler>
125 static bool TraverseAllObjectsWithInfo(ObjectHeader *object, Handler &handler, void *begin = ToVoidPtr(0),
126 void *end = ToVoidPtr(UINTPTR_MAX));
127
128 static void UpdateRefsToMovedObjects(ObjectHeader *object);
129
130 /**
131 * Update a single reference field in the object to the moved value.
132 * Return the moved value.
133 */
134 static ObjectHeader *UpdateRefToMovedObject(ObjectHeader *object, ObjectHeader *ref, uint32_t offset);
135
136 private:
137 template <bool INTERRUPTIBLE, typename Handler>
138 static bool TraverseClass(Class *cls, Handler &handler);
139 template <bool INTERRUPTIBLE, typename Handler>
140 static bool TraverseArray(coretypes::Array *array, Class *cls, void *begin, void *end, Handler &handler);
141 template <bool INTERRUPTIBLE, typename Handler>
142 static bool TraverseObject(ObjectHeader *objectHeader, Class *cls, Handler &handler);
143 };
144
145 class GCDynamicObjectHelpers {
146 public:
147 /// Check the object is an instance of class
148 static inline bool IsClassObject(ObjectHeader *obj);
149
150 /// Traverse all kinds of object_header and call obj_visitor for each reference field.
151 static void TraverseAllObjects(ObjectHeader *objectHeader,
152 const std::function<void(ObjectHeader *, ObjectHeader *)> &objVisitor);
153
154 /**
155 * Traverse all kinds of object_header and call handler for each reference field.
156 * The handler accepts the object, the reference value, offset to the reference in the object and
157 * the flag whether the field is volatile. Stop traverse if handler return false for any field.
158 * INTERRUPTIBLE means that traverse over objects can be stopped (it is possible when handler may return false)
159 * This template is used to decrease possible performance influence of checking handler's returned value on GC pause
160 * time
161 * Return true if object was fully traversed, otherwise false.
162 */
163 template <bool INTERRUPTIBLE, typename Handler>
164 static bool TraverseAllObjectsWithInfo(ObjectHeader *objectHeader, Handler &handler, void *begin = ToVoidPtr(0),
165 void *end = ToVoidPtr(UINTPTR_MAX));
166
167 static void UpdateRefsToMovedObjects(ObjectHeader *object);
168
169 /**
170 * Update a single reference field in the object to the moved value.
171 * Return the moved value.
172 */
173 static ObjectHeader *UpdateRefToMovedObject(ObjectHeader *object, ObjectHeader *ref, uint32_t offset);
174
175 static void RecordDynWeakReference(GC *gc, coretypes::TaggedType *value);
176 static void HandleDynWeakReferences(GC *gc);
177
178 private:
179 template <bool INTERRUPTIBLE, typename Handler>
180 static bool TraverseArray(coretypes::Array *array, HClass *cls, void *begin, void *end, Handler &handler);
181 template <bool INTERRUPTIBLE, typename Handler>
182 static bool TraverseClass(coretypes::DynClass *dynClass, Handler &handler);
183 template <bool INTERRUPTIBLE, typename Handler>
184 static bool TraverseObject(ObjectHeader *objectHeader, HClass *cls, Handler &handler);
185
186 static void UpdateDynArray(PandaVM *vm, coretypes::Array *array, ArraySizeT index, ObjectHeader *objRef);
187
188 static void UpdateDynObjectRef(PandaVM *vm, ObjectHeader *objectHeader, size_t offset, ObjectHeader *fieldObjRef);
189 };
190
191 template <LangTypeT LANG_TYPE>
192 class GCObjectHelpers {
193 };
194
195 template <>
196 class GCObjectHelpers<LANG_TYPE_STATIC> {
197 public:
198 using Value = GCStaticObjectHelpers;
199 };
200
201 template <>
202 class GCObjectHelpers<LANG_TYPE_DYNAMIC> {
203 public:
204 using Value = GCDynamicObjectHelpers;
205 };
206
207 template <LangTypeT LANG_TYPE>
208 using ObjectHelpers = typename GCObjectHelpers<LANG_TYPE>::Value;
209
210 } // namespace ark::mem
211
212 #endif // PANDA_OBJECT_HELPERS_H
213