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
29 template <typename Handler>
TraverseClass(Class * cls,Handler & handler)30 void GCStaticObjectHelpers::TraverseClass(Class *cls, Handler &handler)
31 {
32 // Iterate over static fields
33 uint32_t ref_num = cls->GetRefFieldsNum<true>();
34 if (ref_num > 0) {
35 uint32_t offset = cls->GetRefFieldsOffset<true>();
36 ObjectHeader *object = cls->GetManagedObject();
37 ASSERT(ToUintPtr(cls) + offset >= ToUintPtr(object));
38 // The offset is relative to the class. Adjust it to make relative to the managed object
39 uint32_t obj_offset = ToUintPtr(cls) + offset - ToUintPtr(object);
40 uint32_t ref_volatile_num = cls->GetVolatileRefFieldsNum<true>();
41 for (uint32_t i = 0; i < ref_num;
42 i++, offset += ClassHelper::OBJECT_POINTER_SIZE, obj_offset += ClassHelper::OBJECT_POINTER_SIZE) {
43 bool is_volatile = (i < ref_volatile_num);
44 auto *field_object = is_volatile ? cls->GetFieldObject<true>(offset) : cls->GetFieldObject<false>(offset);
45 if (field_object == nullptr) {
46 continue;
47 }
48 bool res = handler(object, field_object, obj_offset, is_volatile);
49 if (!res) {
50 return;
51 }
52 }
53 }
54 }
55
56 template <typename Handler>
TraverseObject(ObjectHeader * object,Class * cls,Handler & handler)57 void GCStaticObjectHelpers::TraverseObject(ObjectHeader *object, Class *cls, Handler &handler)
58 {
59 ASSERT(cls != nullptr && !cls->IsDynamicClass());
60 while (cls != nullptr) {
61 // Iterate over instance fields
62 uint32_t ref_num = cls->GetRefFieldsNum<false>();
63 if (ref_num == 0) {
64 cls = cls->GetBase();
65 continue;
66 }
67
68 uint32_t offset = cls->GetRefFieldsOffset<false>();
69 uint32_t ref_volatile_num = cls->GetVolatileRefFieldsNum<false>();
70 for (uint32_t i = 0; i < ref_num; i++, offset += ClassHelper::OBJECT_POINTER_SIZE) {
71 bool is_volatile = (i < ref_volatile_num);
72 auto *field_object =
73 is_volatile ? object->GetFieldObject<true>(offset) : object->GetFieldObject<false>(offset);
74 if (field_object == nullptr) {
75 continue;
76 }
77 ValidateObject(object, field_object);
78 bool res = handler(object, field_object, offset, is_volatile);
79 if (!res) {
80 return;
81 }
82 }
83
84 cls = cls->GetBase();
85 }
86 }
87
88 template <typename Handler>
TraverseArray(coretypes::Array * array,Class * cls,Handler & handler)89 void GCStaticObjectHelpers::TraverseArray(coretypes::Array *array, [[maybe_unused]] Class *cls, Handler &handler)
90 {
91 ASSERT(!cls->IsDynamicClass());
92 ASSERT(cls != nullptr);
93 ASSERT(cls->IsObjectArrayClass());
94 auto array_length = array->GetLength();
95 for (coretypes::array_size_t i = 0; i < array_length; i++) {
96 auto *array_element = array->Get<ObjectHeader *>(i);
97 if (array_element != nullptr) {
98 bool res = handler(array, array_element, array->GetElementOffset<false>(i), false);
99 if (!res) {
100 return;
101 }
102 }
103 }
104 }
105
106 template <typename Handler>
TraverseAllObjectsWithInfo(ObjectHeader * object_header,Handler & handler)107 void GCStaticObjectHelpers::TraverseAllObjectsWithInfo(ObjectHeader *object_header, Handler &handler)
108 {
109 auto *cls = object_header->ClassAddr<Class>();
110 ASSERT(cls != nullptr);
111
112 if (cls->IsObjectArrayClass()) {
113 TraverseArray(static_cast<coretypes::Array *>(object_header), cls, handler);
114 } else {
115 if (cls->IsClassClass()) {
116 auto object_cls = panda::Class::FromClassObject(object_header);
117 if (object_cls->IsInitializing() || object_cls->IsInitialized()) {
118 TraverseClass(object_cls, handler);
119 }
120 }
121 TraverseObject(object_header, cls, handler);
122 }
123 }
124
125 template <typename Handler>
TraverseClass(coretypes::DynClass * dyn_class,Handler & handler)126 void GCDynamicObjectHelpers::TraverseClass(coretypes::DynClass *dyn_class, Handler &handler)
127 {
128 size_t hklass_size = dyn_class->ClassAddr<HClass>()->GetObjectSize() - sizeof(coretypes::DynClass);
129 size_t body_size = hklass_size - sizeof(HClass);
130 size_t num_of_fields = body_size / TaggedValue::TaggedTypeSize();
131 for (size_t i = 0; i < num_of_fields; i++) {
132 size_t field_offset = sizeof(ObjectHeader) + sizeof(HClass) + i * TaggedValue::TaggedTypeSize();
133 auto tagged_value = ObjectAccessor::GetDynValue<TaggedValue>(dyn_class, field_offset);
134 if (tagged_value.IsHeapObject()) {
135 bool res = handler(dyn_class, tagged_value.GetHeapObject(), field_offset, false);
136 if (!res) {
137 return;
138 }
139 }
140 }
141 }
142
143 template <typename Handler>
TraverseObject(ObjectHeader * object,HClass * cls,Handler & handler)144 void GCDynamicObjectHelpers::TraverseObject(ObjectHeader *object, HClass *cls, Handler &handler)
145 {
146 ASSERT(cls->IsDynamicClass());
147 LOG(DEBUG, GC) << "TraverseObject Current object: " << GetDebugInfoAboutObject(object);
148 // handle object data
149 uint32_t obj_body_size = cls->GetObjectSize() - ObjectHeader::ObjectHeaderSize();
150 ASSERT(obj_body_size % TaggedValue::TaggedTypeSize() == 0);
151 uint32_t num_of_fields = obj_body_size / TaggedValue::TaggedTypeSize();
152 size_t data_offset = ObjectHeader::ObjectHeaderSize();
153 for (uint32_t i = 0; i < num_of_fields; i++) {
154 size_t field_offset = data_offset + i * TaggedValue::TaggedTypeSize();
155 if (cls->IsNativeField(field_offset)) {
156 continue;
157 }
158 auto tagged_value = ObjectAccessor::GetDynValue<TaggedValue>(object, field_offset);
159 if (tagged_value.IsHeapObject()) {
160 bool res = handler(object, tagged_value.GetHeapObject(), field_offset, false);
161 if (!res) {
162 return;
163 }
164 }
165 }
166 }
167
168 template <typename Handler>
TraverseArray(coretypes::Array * array,HClass * cls,Handler & handler)169 void GCDynamicObjectHelpers::TraverseArray(coretypes::Array *array, [[maybe_unused]] HClass *cls, Handler &handler)
170 {
171 ASSERT(cls != nullptr);
172 ASSERT(cls->IsDynamicClass());
173
174 ASSERT(cls->IsArray());
175 auto array_length = array->GetLength();
176 for (coretypes::array_size_t i = 0; i < array_length; i++) {
177 TaggedValue array_element(array->Get<TaggedType, false, true>(i));
178 uint32_t offset = array->GetElementOffset<true>(i);
179 if (array_element.IsHeapObject()) {
180 bool res = handler(array, array_element.GetHeapObject(), offset, false);
181 if (!res) {
182 return;
183 }
184 }
185 }
186 }
187
188 template <typename Handler>
TraverseAllObjectsWithInfo(ObjectHeader * object_header,Handler & handler)189 void GCDynamicObjectHelpers::TraverseAllObjectsWithInfo(ObjectHeader *object_header, Handler &handler)
190 {
191 auto *cls = object_header->ClassAddr<HClass>();
192 ASSERT(cls != nullptr && cls->IsDynamicClass());
193 if (cls->IsString() || cls->IsNativePointer()) {
194 return;
195 }
196 if (cls->IsArray()) {
197 TraverseArray(static_cast<coretypes::Array *>(object_header), cls, handler);
198 } else {
199 if (cls->IsHClass()) {
200 TraverseClass(coretypes::DynClass::Cast(object_header), handler);
201 } else {
202 TraverseObject(object_header, cls, handler);
203 }
204 }
205 }
206
207 } // namespace panda::mem
208
209 #endif // PANDA_RUNTIME_MEM_OBJECT_HELPERS_INL_H
210