1 /**
2 * Copyright (c) 2021-2024 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 PANDA_RUNTIME_MEM_OBJECT_HELPERS_INL_H
17 #define PANDA_RUNTIME_MEM_OBJECT_HELPERS_INL_H
18
19 #include "runtime/mem/object_helpers.h"
20 #include "runtime/include/class.h"
21 #include "runtime/include/coretypes/array-inl.h"
22 #include "runtime/include/coretypes/dyn_objects.h"
23 #include "runtime/include/coretypes/string.h"
24 #include "runtime/include/coretypes/class.h"
25 #include "runtime/include/hclass.h"
26
27 namespace ark::mem {
28
IsClassObject(ObjectHeader * obj)29 bool GCStaticObjectHelpers::IsClassObject(ObjectHeader *obj)
30 {
31 return obj->ClassAddr<Class>()->IsClassClass();
32 }
33
34 template <bool INTERRUPTIBLE, typename Handler>
TraverseClass(Class * cls,Handler & handler)35 bool GCStaticObjectHelpers::TraverseClass(Class *cls, Handler &handler)
36 {
37 // Iterate over static fields
38 uint32_t refNum = cls->GetRefFieldsNum<true>();
39 if (refNum == 0) {
40 return true;
41 }
42 uint32_t offset = cls->GetRefFieldsOffset<true>();
43 ObjectHeader *object = cls->GetManagedObject();
44 ASSERT(ToUintPtr(cls) + offset >= ToUintPtr(object));
45 // The offset is relative to the class. Adjust it to make relative to the managed object
46 uint32_t objOffset = ToUintPtr(cls) + offset - ToUintPtr(object);
47 uint32_t refVolatileNum = cls->GetVolatileRefFieldsNum<true>();
48 for (uint32_t i = 0; i < refNum;
49 i++, offset += ClassHelper::OBJECT_POINTER_SIZE, objOffset += ClassHelper::OBJECT_POINTER_SIZE) {
50 bool isVolatile = (i < refVolatileNum);
51 auto *fieldObject = isVolatile ? cls->GetFieldObject<true>(offset) : cls->GetFieldObject<false>(offset);
52 if (fieldObject == nullptr) {
53 continue;
54 }
55 [[maybe_unused]] bool res = handler(object, fieldObject, objOffset, isVolatile);
56 if constexpr (INTERRUPTIBLE) {
57 if (!res) {
58 return false;
59 }
60 }
61 }
62 return true;
63 }
64
65 template <bool INTERRUPTIBLE, typename Handler>
TraverseObject(ObjectHeader * object,Class * cls,Handler & handler)66 bool GCStaticObjectHelpers::TraverseObject(ObjectHeader *object, Class *cls, Handler &handler)
67 {
68 ASSERT(cls != nullptr);
69 ASSERT(!cls->IsDynamicClass());
70 while (cls != nullptr) {
71 // Iterate over instance fields
72 uint32_t refNum = cls->GetRefFieldsNum<false>();
73 if (refNum == 0) {
74 cls = cls->GetBase();
75 continue;
76 }
77
78 uint32_t offset = cls->GetRefFieldsOffset<false>();
79 uint32_t refVolatileNum = cls->GetVolatileRefFieldsNum<false>();
80 for (uint32_t i = 0; i < refNum; i++, offset += ClassHelper::OBJECT_POINTER_SIZE) {
81 bool isVolatile = (i < refVolatileNum);
82 auto *fieldObject =
83 isVolatile ? object->GetFieldObject<true>(offset) : object->GetFieldObject<false>(offset);
84 if (fieldObject == nullptr) {
85 continue;
86 }
87 ValidateObject(object, fieldObject);
88 [[maybe_unused]] bool res = handler(object, fieldObject, offset, isVolatile);
89 if constexpr (!INTERRUPTIBLE) {
90 continue;
91 }
92 if (!res) {
93 return false;
94 }
95 }
96
97 cls = cls->GetBase();
98 }
99 return true;
100 }
101
102 template <bool INTERRUPTIBLE, typename Handler>
TraverseArray(coretypes::Array * array,Class * cls,void * begin,void * end,Handler & handler)103 bool GCStaticObjectHelpers::TraverseArray(coretypes::Array *array, [[maybe_unused]] Class *cls, void *begin, void *end,
104 Handler &handler)
105 {
106 ASSERT(cls != nullptr);
107 ASSERT(!cls->IsDynamicClass());
108 ASSERT(cls->IsObjectArrayClass());
109 ASSERT(IsAligned(ToUintPtr(begin), DEFAULT_ALIGNMENT_IN_BYTES));
110
111 auto *arrayStart = array->GetBase<ObjectPointerType *>();
112 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
113 auto *arrayEnd = arrayStart + array->GetLength();
114 auto *p = begin < arrayStart ? arrayStart : reinterpret_cast<ObjectPointerType *>(begin);
115
116 if (end > arrayEnd) {
117 end = arrayEnd;
118 }
119
120 auto elementSize = coretypes::Array::GetElementSize<ObjectHeader *, false>();
121 auto offset = ToUintPtr(p) - ToUintPtr(array);
122
123 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
124 for (ArraySizeT i = p - arrayStart; p < end; ++p, ++i, offset += elementSize) {
125 auto *arrayElement = array->Get<ObjectHeader *>(i);
126 if (arrayElement != nullptr) {
127 [[maybe_unused]] bool res = handler(array, arrayElement, offset, false);
128 if constexpr (!INTERRUPTIBLE) {
129 continue;
130 }
131 if (!res) {
132 return false;
133 }
134 }
135 }
136
137 return true;
138 }
139
140 template <bool INTERRUPTIBLE, typename Handler>
TraverseAllObjectsWithInfo(ObjectHeader * objectHeader,Handler & handler,void * begin,void * end)141 bool GCStaticObjectHelpers::TraverseAllObjectsWithInfo(ObjectHeader *objectHeader, Handler &handler, void *begin,
142 void *end)
143 {
144 auto *cls = objectHeader->ClassAddr<Class>();
145 ASSERT(cls != nullptr);
146
147 if (cls->IsObjectArrayClass()) {
148 return TraverseArray<INTERRUPTIBLE>(static_cast<coretypes::Array *>(objectHeader), cls, begin, end, handler);
149 }
150 if (cls->IsClassClass()) {
151 auto objectCls = ark::Class::FromClassObject(objectHeader);
152 if (objectCls->IsInitializing() || objectCls->IsInitialized()) {
153 if (!TraverseClass<INTERRUPTIBLE>(objectCls, handler)) {
154 return false;
155 }
156 }
157 }
158 return TraverseObject<INTERRUPTIBLE>(objectHeader, cls, handler);
159 }
160
IsClassObject(ObjectHeader * obj)161 bool GCDynamicObjectHelpers::IsClassObject(ObjectHeader *obj)
162 {
163 return obj->ClassAddr<HClass>()->IsHClass();
164 }
165
166 template <bool INTERRUPTIBLE, typename Handler>
TraverseClass(coretypes::DynClass * dynClass,Handler & handler)167 bool GCDynamicObjectHelpers::TraverseClass(coretypes::DynClass *dynClass, Handler &handler)
168 {
169 size_t hklassSize = dynClass->ClassAddr<HClass>()->GetObjectSize() - sizeof(coretypes::DynClass);
170 size_t bodySize = hklassSize - sizeof(HClass);
171 size_t numOfFields = bodySize / TaggedValue::TaggedTypeSize();
172 for (size_t i = 0; i < numOfFields; i++) {
173 size_t fieldOffset = sizeof(ObjectHeader) + sizeof(HClass) + i * TaggedValue::TaggedTypeSize();
174 auto taggedValue = ObjectAccessor::GetDynValue<TaggedValue>(dynClass, fieldOffset);
175 if (taggedValue.IsHeapObject()) {
176 [[maybe_unused]] bool res = handler(dynClass, taggedValue.GetHeapObject(), fieldOffset, false);
177 if constexpr (!INTERRUPTIBLE) {
178 continue;
179 }
180 if (!res) {
181 return false;
182 }
183 }
184 }
185 return true;
186 }
187
188 template <bool INTERRUPTIBLE, typename Handler>
TraverseObject(ObjectHeader * object,HClass * cls,Handler & handler)189 bool GCDynamicObjectHelpers::TraverseObject(ObjectHeader *object, HClass *cls, Handler &handler)
190 {
191 ASSERT(cls->IsDynamicClass());
192 LOG(DEBUG, GC) << "TraverseObject Current object: " << GetDebugInfoAboutObject(object);
193 // handle object data
194 uint32_t objBodySize = cls->GetObjectSize() - ObjectHeader::ObjectHeaderSize();
195 ASSERT(objBodySize % TaggedValue::TaggedTypeSize() == 0);
196 uint32_t numOfFields = objBodySize / TaggedValue::TaggedTypeSize();
197 size_t dataOffset = ObjectHeader::ObjectHeaderSize();
198 for (uint32_t i = 0; i < numOfFields; i++) {
199 size_t fieldOffset = dataOffset + i * TaggedValue::TaggedTypeSize();
200 if (cls->IsNativeField(fieldOffset)) {
201 continue;
202 }
203 auto taggedValue = ObjectAccessor::GetDynValue<TaggedValue>(object, fieldOffset);
204 if (taggedValue.IsHeapObject()) {
205 [[maybe_unused]] bool res = handler(object, taggedValue.GetHeapObject(), fieldOffset, false);
206 if constexpr (!INTERRUPTIBLE) {
207 continue;
208 }
209 if (!res) {
210 return false;
211 }
212 }
213 }
214 return true;
215 }
216
217 template <bool INTERRUPTIBLE, typename Handler>
TraverseArray(coretypes::Array * array,HClass * cls,void * begin,void * end,Handler & handler)218 bool GCDynamicObjectHelpers::TraverseArray(coretypes::Array *array, [[maybe_unused]] HClass *cls, void *begin,
219 void *end, Handler &handler)
220 {
221 ASSERT(cls != nullptr);
222 ASSERT(cls->IsDynamicClass());
223 ASSERT(cls->IsArray());
224 ASSERT(IsAligned(ToUintPtr(begin), DEFAULT_ALIGNMENT_IN_BYTES));
225
226 auto *arrayStart = array->GetBase<TaggedType *>();
227 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
228 auto *arrayEnd = arrayStart + array->GetLength();
229 auto *p = begin < arrayStart ? arrayStart : reinterpret_cast<TaggedType *>(begin);
230
231 if (end > arrayEnd) {
232 end = arrayEnd;
233 }
234
235 auto elementSize = coretypes::Array::GetElementSize<TaggedType, true>();
236 auto offset = ToUintPtr(p) - ToUintPtr(array);
237 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
238 for (ArraySizeT i = p - arrayStart; p < end; ++p, ++i, offset += elementSize) {
239 TaggedValue arrayElement(array->Get<TaggedType, false, true>(i));
240 if (arrayElement.IsHeapObject()) {
241 [[maybe_unused]] bool res = handler(array, arrayElement.GetHeapObject(), offset, false);
242 if constexpr (!INTERRUPTIBLE) {
243 continue;
244 }
245 if (!res) {
246 return false;
247 }
248 }
249 }
250
251 return true;
252 }
253
254 template <bool INTERRUPTIBLE, typename Handler>
TraverseAllObjectsWithInfo(ObjectHeader * objectHeader,Handler & handler,void * begin,void * end)255 bool GCDynamicObjectHelpers::TraverseAllObjectsWithInfo(ObjectHeader *objectHeader, Handler &handler, void *begin,
256 void *end)
257 {
258 auto *cls = objectHeader->ClassAddr<HClass>();
259 ASSERT(cls != nullptr && cls->IsDynamicClass());
260 if (cls->IsString() || cls->IsNativePointer()) {
261 return true;
262 }
263 if (cls->IsArray()) {
264 return TraverseArray<INTERRUPTIBLE>(static_cast<coretypes::Array *>(objectHeader), cls, begin, end, handler);
265 }
266 if (cls->IsHClass()) {
267 return TraverseClass<INTERRUPTIBLE>(coretypes::DynClass::Cast(objectHeader), handler);
268 }
269
270 return TraverseObject<INTERRUPTIBLE>(objectHeader, cls, handler);
271 }
272
273 } // namespace ark::mem
274
275 #endif // PANDA_RUNTIME_MEM_OBJECT_HELPERS_INL_H
276