1 /*
2 * Copyright (c) 2021 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 class ClassFieldVisitor {
30 public:
ClassFieldVisitor(const ObjectVisitorEx & visitor)31 explicit ClassFieldVisitor(const ObjectVisitorEx &visitor) : visitor_(visitor) {}
operator()32 ALWAYS_INLINE void operator()([[maybe_unused]] Class *cls, ObjectHeader *field_object,
33 [[maybe_unused]] uint32_t offset, [[maybe_unused]] bool is_volatile) const
34 {
35 return visitor_(cls->GetManagedObject(), field_object);
36 }
37
38 virtual ~ClassFieldVisitor() = default;
39
40 NO_COPY_SEMANTIC(ClassFieldVisitor);
41 NO_MOVE_SEMANTIC(ClassFieldVisitor);
42
43 private:
44 const ObjectVisitorEx &visitor_;
45 };
46
47 class ObjectFieldVisitor {
48 public:
ObjectFieldVisitor(const ObjectVisitorEx & visitor)49 explicit ObjectFieldVisitor(const ObjectVisitorEx &visitor) : visitor_(visitor) {}
operator()50 ALWAYS_INLINE void operator()([[maybe_unused]] ObjectHeader *object, ObjectHeader *field_object,
51 [[maybe_unused]] uint32_t offset, [[maybe_unused]] bool is_volatile) const
52 {
53 return visitor_(object, field_object);
54 }
55
56 virtual ~ObjectFieldVisitor() = default;
57
58 NO_COPY_SEMANTIC(ObjectFieldVisitor);
59 NO_MOVE_SEMANTIC(ObjectFieldVisitor);
60
61 private:
62 const ObjectVisitorEx &visitor_;
63 };
64
65 class ArrayElementVisitor {
66 public:
ArrayElementVisitor(const ObjectVisitorEx & visitor)67 explicit ArrayElementVisitor(const ObjectVisitorEx &visitor) : visitor_(visitor) {}
operator()68 ALWAYS_INLINE void operator()([[maybe_unused]] ObjectHeader *array_object,
69 [[maybe_unused]] array_size_t element_index, ObjectHeader *element_object) const
70 {
71 return visitor_(array_object, element_object);
72 }
73
74 virtual ~ArrayElementVisitor() = default;
75
76 NO_COPY_SEMANTIC(ArrayElementVisitor);
77 NO_MOVE_SEMANTIC(ArrayElementVisitor);
78
79 private:
80 const ObjectVisitorEx &visitor_;
81 };
82
83 template <typename FieldVisitor>
TraverseFields(const Span<Field> & fields,Class * cls,ObjectHeader * object_header,const FieldVisitor & field_visitor)84 void TraverseFields(const Span<Field> &fields, Class *cls, ObjectHeader *object_header,
85 const FieldVisitor &field_visitor)
86 {
87 for (const Field &field : fields) {
88 LOG(DEBUG, GC) << " current field \"" << GetFieldName(field) << "\"";
89 size_t offset = field.GetOffset();
90 panda_file::Type::TypeId type_id = field.GetType().GetId();
91 if (type_id == panda_file::Type::TypeId::REFERENCE) {
92 ObjectHeader *field_object = object_header->GetFieldObject(offset);
93 if (field_object != nullptr) {
94 LOG(DEBUG, GC) << " field val = " << std::hex << field_object;
95 field_visitor(cls, object_header, &field, field_object);
96 } else {
97 LOG(DEBUG, GC) << " field val = nullptr";
98 }
99 }
100 }
101 }
102
103 template <typename FieldVisitor>
TraverseClass(Class * cls,const FieldVisitor & field_visitor)104 void TraverseClass(Class *cls, const FieldVisitor &field_visitor)
105 {
106 // Iterate over static fields
107 uint32_t ref_num = cls->GetRefFieldsNum<true>();
108 if (ref_num > 0) {
109 uint32_t offset = cls->GetRefFieldsOffset<true>();
110 uint32_t ref_volatile_num = cls->GetVolatileRefFieldsNum<true>();
111 for (uint32_t i = 0; i < ref_num; i++, offset += ClassHelper::OBJECT_POINTER_SIZE) {
112 bool is_volatile = (i < ref_volatile_num);
113 auto *field_object = is_volatile ? cls->GetFieldObject<true>(offset) : cls->GetFieldObject<false>(offset);
114 if (field_object != nullptr) {
115 field_visitor(cls, field_object, offset, is_volatile);
116 }
117 }
118 }
119 }
120
121 template <typename FieldVisitor>
TraverseObject(ObjectHeader * object,BaseClass * base_cls,const FieldVisitor & field_visitor)122 void GCStaticObjectHelpers::TraverseObject(ObjectHeader *object, BaseClass *base_cls, const FieldVisitor &field_visitor)
123 {
124 ASSERT(!base_cls->IsDynamicClass());
125 auto *cls = static_cast<Class *>(base_cls);
126 while (cls != nullptr) {
127 // Iterate over instance fields
128 uint32_t ref_num = cls->GetRefFieldsNum<false>();
129 if (ref_num > 0) {
130 uint32_t offset = cls->GetRefFieldsOffset<false>();
131 uint32_t ref_volatile_num = cls->GetVolatileRefFieldsNum<false>();
132 for (uint32_t i = 0; i < ref_num; i++, offset += ClassHelper::OBJECT_POINTER_SIZE) {
133 bool is_volatile = (i < ref_volatile_num);
134 auto *field_object =
135 is_volatile ? object->GetFieldObject<true>(offset) : object->GetFieldObject<false>(offset);
136 if (field_object != nullptr) {
137 field_visitor(object, field_object, offset, is_volatile);
138 }
139 }
140 }
141 cls = cls->GetBase();
142 }
143 }
144
145 template <typename ElementVisitor>
TraverseArray(ObjectHeader * object,BaseClass * base_cls,const ElementVisitor & array_element_visitor)146 void GCStaticObjectHelpers::TraverseArray(ObjectHeader *object, BaseClass *base_cls,
147 const ElementVisitor &array_element_visitor)
148 {
149 ASSERT(!base_cls->IsDynamicClass());
150 [[maybe_unused]] auto *cls = static_cast<Class *>(base_cls);
151 ASSERT(cls != nullptr);
152 ASSERT(cls->IsObjectArrayClass());
153 auto *array_object = static_cast<coretypes::Array *>(object);
154 auto array_length = array_object->GetLength();
155 for (coretypes::array_size_t i = 0; i < array_length; i++) {
156 auto *array_element = array_object->Get<ObjectHeader *>(i);
157 if (array_element != nullptr) {
158 array_element_visitor(object, i, array_element);
159 }
160 }
161 }
162
163 template <typename FieldVisitor>
TraverseObject(ObjectHeader * object,BaseClass * base_cls,const FieldVisitor & field_visitor)164 void GCDynamicObjectHelpers::TraverseObject(ObjectHeader *object, BaseClass *base_cls,
165 const FieldVisitor &field_visitor)
166 {
167 ASSERT(base_cls->IsDynamicClass());
168 auto *cls = static_cast<HClass *>(base_cls);
169 ASSERT(cls != nullptr);
170 LOG(DEBUG, GC) << "TraverseObject Current object: " << GetDebugInfoAboutObject(object);
171 // check dynclass
172 if (cls->IsHClass()) {
173 auto dyn_class = coretypes::DynClass::Cast(object);
174 auto klass = dyn_class->GetHClass();
175
176 auto dynclass_dynclass = static_cast<coretypes::DynClass *>(cls->GetManagedObject());
177 ASSERT(dynclass_dynclass != nullptr);
178 size_t klass_size = dynclass_dynclass->GetHClass()->GetObjectSize() - sizeof(coretypes::DynClass);
179
180 uintptr_t start_addr = reinterpret_cast<uintptr_t>(klass) + sizeof(HClass);
181 int num_of_fields = static_cast<int>((klass_size - sizeof(HClass)) / TaggedValue::TaggedTypeSize());
182 for (int i = 0; i < num_of_fields; i++) {
183 auto *field_addr = reinterpret_cast<TaggedType *>(start_addr + i * TaggedValue::TaggedTypeSize());
184 TaggedValue tagged_value(*field_addr);
185 if (tagged_value.IsHeapObject()) {
186 ObjectHeader *ref_object_header = tagged_value.GetRawHeapObject();
187 size_t offset = ObjectHeader::ObjectHeaderSize() + sizeof(HClass) + i * TaggedValue::TaggedTypeSize();
188 field_visitor(object, offset, ref_object_header, false);
189 }
190 }
191 } else {
192 // handle dynobject dyn_class
193 size_t offset_class_word = ObjectHeader::GetClassOffset();
194 ObjectHeader *dyn_class = cls->GetManagedObject();
195 field_visitor(object, offset_class_word, dyn_class, true);
196
197 // handle object data
198 auto obj_body_size = cls->GetObjectSize() - ObjectHeader::ObjectHeaderSize();
199 ASSERT(obj_body_size % TaggedValue::TaggedTypeSize() == 0);
200 int num_of_fields = static_cast<int>(obj_body_size / TaggedValue::TaggedTypeSize());
201 size_t addr = reinterpret_cast<uintptr_t>(object) + ObjectHeader::ObjectHeaderSize();
202 for (int i = 0; i < num_of_fields; i++) {
203 auto *field_addr = reinterpret_cast<TaggedType *>(addr + i * TaggedValue::TaggedTypeSize());
204 TaggedValue tagged_value(*field_addr);
205 if (tagged_value.IsHeapObject()) {
206 ObjectHeader *ref_object_header = tagged_value.GetRawHeapObject();
207 size_t offset = ObjectHeader::ObjectHeaderSize() + i * TaggedValue::TaggedTypeSize();
208 field_visitor(object, offset, ref_object_header, false);
209 }
210 }
211 }
212 }
213
214 template <typename ElementVisitor>
TraverseArray(ObjectHeader * object,BaseClass * base_cls,const ElementVisitor & array_element_visitor)215 void GCDynamicObjectHelpers::TraverseArray(ObjectHeader *object, BaseClass *base_cls,
216 const ElementVisitor &array_element_visitor)
217 {
218 ASSERT(base_cls->IsDynamicClass());
219 [[maybe_unused]] auto *cls = static_cast<HClass *>(base_cls);
220 ASSERT(cls != nullptr);
221
222 ASSERT(cls->IsArray());
223 auto *array_object = static_cast<coretypes::Array *>(object);
224 auto array_length = array_object->GetLength();
225 for (coretypes::array_size_t i = 0; i < array_length; i++) {
226 TaggedValue array_element(array_object->Get<TaggedType, false, true>(i));
227 if (array_element.IsHeapObject()) {
228 array_element_visitor(object, i, array_element.GetRawHeapObject());
229 }
230 }
231 }
232
233 } // namespace panda::mem
234
235 #endif // PANDA_RUNTIME_MEM_OBJECT_HELPERS_INL_H_
236