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