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