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