• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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