• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 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 panda::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                 if (!res) {
91                     return false;
92                 }
93             }
94         }
95 
96         cls = cls->GetBase();
97     }
98     return true;
99 }
100 
101 template <bool INTERRUPTIBLE, typename Handler>
TraverseArray(coretypes::Array * array,Class * cls,void * begin,void * end,Handler & handler)102 bool GCStaticObjectHelpers::TraverseArray(coretypes::Array *array, [[maybe_unused]] Class *cls, void *begin, void *end,
103                                           Handler &handler)
104 {
105     ASSERT(cls != nullptr);
106     ASSERT(!cls->IsDynamicClass());
107     ASSERT(cls->IsObjectArrayClass());
108     ASSERT(IsAligned(ToUintPtr(begin), DEFAULT_ALIGNMENT_IN_BYTES));
109 
110     auto *arrayStart = array->GetBase<ObjectPointerType *>();
111     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
112     auto *arrayEnd = arrayStart + array->GetLength();
113     auto *p = begin < arrayStart ? arrayStart : reinterpret_cast<ObjectPointerType *>(begin);
114 
115     if (end > arrayEnd) {
116         end = arrayEnd;
117     }
118 
119     auto elementSize = coretypes::Array::GetElementSize<ObjectHeader *, false>();
120     auto offset = ToUintPtr(p) - ToUintPtr(array);
121 
122     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
123     for (ArraySizeT i = p - arrayStart; p < end; ++p, ++i, offset += elementSize) {
124         auto *arrayElement = array->Get<ObjectHeader *>(i);
125         if (arrayElement != nullptr) {
126             [[maybe_unused]] bool res = handler(array, arrayElement, offset, false);
127             if constexpr (INTERRUPTIBLE) {
128                 if (!res) {
129                     return false;
130                 }
131             }
132         }
133     }
134 
135     return true;
136 }
137 
138 template <bool INTERRUPTIBLE, typename Handler>
TraverseAllObjectsWithInfo(ObjectHeader * objectHeader,Handler & handler,void * begin,void * end)139 bool GCStaticObjectHelpers::TraverseAllObjectsWithInfo(ObjectHeader *objectHeader, Handler &handler, void *begin,
140                                                        void *end)
141 {
142     auto *cls = objectHeader->ClassAddr<Class>();
143     ASSERT(cls != nullptr);
144 
145     if (cls->IsObjectArrayClass()) {
146         return TraverseArray<INTERRUPTIBLE>(static_cast<coretypes::Array *>(objectHeader), cls, begin, end, handler);
147     }
148     if (cls->IsClassClass()) {
149         auto objectCls = panda::Class::FromClassObject(objectHeader);
150         if (objectCls->IsInitializing() || objectCls->IsInitialized()) {
151             if (!TraverseClass<INTERRUPTIBLE>(objectCls, handler)) {
152                 return false;
153             }
154         }
155     }
156     return TraverseObject<INTERRUPTIBLE>(objectHeader, cls, handler);
157 }
158 
IsClassObject(ObjectHeader * obj)159 bool GCDynamicObjectHelpers::IsClassObject(ObjectHeader *obj)
160 {
161     return obj->ClassAddr<HClass>()->IsHClass();
162 }
163 
164 template <bool INTERRUPTIBLE, typename Handler>
TraverseClass(coretypes::DynClass * dynClass,Handler & handler)165 bool GCDynamicObjectHelpers::TraverseClass(coretypes::DynClass *dynClass, Handler &handler)
166 {
167     size_t hklassSize = dynClass->ClassAddr<HClass>()->GetObjectSize() - sizeof(coretypes::DynClass);
168     size_t bodySize = hklassSize - sizeof(HClass);
169     size_t numOfFields = bodySize / TaggedValue::TaggedTypeSize();
170     for (size_t i = 0; i < numOfFields; i++) {
171         size_t fieldOffset = sizeof(ObjectHeader) + sizeof(HClass) + i * TaggedValue::TaggedTypeSize();
172         auto taggedValue = ObjectAccessor::GetDynValue<TaggedValue>(dynClass, fieldOffset);
173         if (taggedValue.IsHeapObject()) {
174             [[maybe_unused]] bool res = handler(dynClass, taggedValue.GetHeapObject(), fieldOffset, false);
175             if constexpr (INTERRUPTIBLE) {
176                 if (!res) {
177                     return false;
178                 }
179             }
180         }
181     }
182     return true;
183 }
184 
185 template <bool INTERRUPTIBLE, typename Handler>
TraverseObject(ObjectHeader * object,HClass * cls,Handler & handler)186 bool GCDynamicObjectHelpers::TraverseObject(ObjectHeader *object, HClass *cls, Handler &handler)
187 {
188     ASSERT(cls->IsDynamicClass());
189     LOG(DEBUG, GC) << "TraverseObject Current object: " << GetDebugInfoAboutObject(object);
190     // handle object data
191     uint32_t objBodySize = cls->GetObjectSize() - ObjectHeader::ObjectHeaderSize();
192     ASSERT(objBodySize % TaggedValue::TaggedTypeSize() == 0);
193     uint32_t numOfFields = objBodySize / TaggedValue::TaggedTypeSize();
194     size_t dataOffset = ObjectHeader::ObjectHeaderSize();
195     for (uint32_t i = 0; i < numOfFields; i++) {
196         size_t fieldOffset = dataOffset + i * TaggedValue::TaggedTypeSize();
197         if (cls->IsNativeField(fieldOffset)) {
198             continue;
199         }
200         auto taggedValue = ObjectAccessor::GetDynValue<TaggedValue>(object, fieldOffset);
201         if (taggedValue.IsHeapObject()) {
202             [[maybe_unused]] bool res = handler(object, taggedValue.GetHeapObject(), fieldOffset, false);
203             if constexpr (INTERRUPTIBLE) {
204                 if (!res) {
205                     return false;
206                 }
207             }
208         }
209     }
210     return true;
211 }
212 
213 template <bool INTERRUPTIBLE, typename Handler>
TraverseArray(coretypes::Array * array,HClass * cls,void * begin,void * end,Handler & handler)214 bool GCDynamicObjectHelpers::TraverseArray(coretypes::Array *array, [[maybe_unused]] HClass *cls, void *begin,
215                                            void *end, Handler &handler)
216 {
217     ASSERT(cls != nullptr);
218     ASSERT(cls->IsDynamicClass());
219     ASSERT(cls->IsArray());
220     ASSERT(IsAligned(ToUintPtr(begin), DEFAULT_ALIGNMENT_IN_BYTES));
221 
222     auto *arrayStart = array->GetBase<TaggedType *>();
223     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
224     auto *arrayEnd = arrayStart + array->GetLength();
225     auto *p = begin < arrayStart ? arrayStart : reinterpret_cast<TaggedType *>(begin);
226 
227     if (end > arrayEnd) {
228         end = arrayEnd;
229     }
230 
231     auto elementSize = coretypes::Array::GetElementSize<TaggedType, true>();
232     auto offset = ToUintPtr(p) - ToUintPtr(array);
233     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
234     for (ArraySizeT i = p - arrayStart; p < end; ++p, ++i, offset += elementSize) {
235         TaggedValue arrayElement(array->Get<TaggedType, false, true>(i));
236         if (arrayElement.IsHeapObject()) {
237             [[maybe_unused]] bool res = handler(array, arrayElement.GetHeapObject(), offset, false);
238             if constexpr (INTERRUPTIBLE) {
239                 if (!res) {
240                     return false;
241                 }
242             }
243         }
244     }
245 
246     return true;
247 }
248 
249 template <bool INTERRUPTIBLE, typename Handler>
TraverseAllObjectsWithInfo(ObjectHeader * objectHeader,Handler & handler,void * begin,void * end)250 bool GCDynamicObjectHelpers::TraverseAllObjectsWithInfo(ObjectHeader *objectHeader, Handler &handler, void *begin,
251                                                         void *end)
252 {
253     auto *cls = objectHeader->ClassAddr<HClass>();
254     ASSERT(cls != nullptr && cls->IsDynamicClass());
255     if (cls->IsString() || cls->IsNativePointer()) {
256         return true;
257     }
258     if (cls->IsArray()) {
259         return TraverseArray<INTERRUPTIBLE>(static_cast<coretypes::Array *>(objectHeader), cls, begin, end, handler);
260     }
261     if (cls->IsHClass()) {
262         return TraverseClass<INTERRUPTIBLE>(coretypes::DynClass::Cast(objectHeader), handler);
263     }
264 
265     return TraverseObject<INTERRUPTIBLE>(objectHeader, cls, handler);
266 }
267 
268 }  // namespace panda::mem
269 
270 #endif  // PANDA_RUNTIME_MEM_OBJECT_HELPERS_INL_H
271