• 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 #include <algorithm>
16 
17 #include "runtime/mem/object_helpers-inl.h"
18 #include "runtime/include/coretypes/dyn_objects.h"
19 #include "runtime/include/hclass.h"
20 #include "runtime/include/class.h"
21 #include "runtime/include/coretypes/array-inl.h"
22 #include "runtime/include/coretypes/string.h"
23 
24 #include "runtime/include/coretypes/class.h"
25 #include "runtime/include/thread.h"
26 #include "runtime/include/panda_vm.h"
27 #include "runtime/mem/gc/dynamic/gc_dynamic_data.h"
28 
29 namespace panda::mem {
30 
31 using DynClass = coretypes::DynClass;
32 using TaggedValue = coretypes::TaggedValue;
33 using TaggedType = coretypes::TaggedType;
34 
GetObjectSize(const void * mem)35 size_t GetObjectSize(const void *mem)
36 {
37     ASSERT(mem != nullptr);
38     auto *obj_header = static_cast<const ObjectHeader *>(mem);
39     auto base_cls = obj_header->ClassAddr<BaseClass>();
40 
41     size_t object_size;
42     if (base_cls->IsDynamicClass()) {
43         auto *klass = static_cast<HClass *>(base_cls);
44         if (klass->IsString()) {
45             auto *string_object = static_cast<const coretypes::String *>(obj_header);
46             object_size = string_object->ObjectSize();
47         } else if (klass->IsArray()) {
48             auto *array_object = static_cast<const coretypes::Array *>(obj_header);
49             object_size = sizeof(coretypes::Array) + array_object->GetLength() * TaggedValue::TaggedTypeSize();
50         } else {
51             object_size = base_cls->GetObjectSize();
52         }
53     } else {
54         object_size = obj_header->ObjectSize();
55     }
56     return object_size;
57 }
58 
GetDebugInfoAboutObject(const ObjectHeader * header)59 PandaString GetDebugInfoAboutObject(const ObjectHeader *header)
60 {
61     PandaStringStream ss;
62     ss << "( " << header->ClassAddr<Class>()->GetDescriptor() << " " << std::hex << header << " " << std::dec
63        << GetObjectSize(header) << " bytes) mword = " << std::hex << header->AtomicGetMark().GetValue();
64     return ss.str();
65 }
66 
DumpObject(ObjectHeader * object_header,std::basic_ostream<char,std::char_traits<char>> * o_stream)67 void DumpObject([[maybe_unused]] ObjectHeader *object_header,
68                 std::basic_ostream<char, std::char_traits<char>> *o_stream)
69 {
70     auto *cls = object_header->ClassAddr<Class>();
71     ASSERT(cls != nullptr);
72     *o_stream << "Dump object object_header = " << std::hex << object_header << ", cls = " << std::hex << cls->GetName()
73               << std::endl;
74 
75     if (cls->IsArrayClass()) {
76         auto array = static_cast<coretypes::Array *>(object_header);
77         *o_stream << "Array " << std::hex << object_header << " " << cls->GetComponentType()->GetName()
78                   << " length = " << std::dec << array->GetLength() << std::endl;
79         return;
80     }
81 
82     while (cls != nullptr) {
83         Span<Field> fields = cls->GetInstanceFields();
84         *o_stream << "Dump object: " << std::hex << object_header << std::endl;
85         if (cls->GetName() == "java.lang.String") {
86             auto *str_object = static_cast<panda::coretypes::String *>(object_header);
87             if (str_object->GetLength() > 0 && !str_object->IsUtf16()) {
88                 *o_stream << "length = " << std::dec << str_object->GetLength() << std::endl;
89                 constexpr size_t BUFF_SIZE = 256;
90                 std::array<char, BUFF_SIZE> buff {0};
91                 strncpy_s(&buff[0], BUFF_SIZE, reinterpret_cast<const char *>(str_object->GetDataMUtf8()),
92                           static_cast<size_t>(str_object->GetLength()));
93                 *o_stream << "String data: " << &buff[0] << std::endl;
94             }
95         }
96         for (Field &field : fields) {
97             *o_stream << "\tfield \"" << GetFieldName(field) << "\" ";
98             size_t offset = field.GetOffset();
99             panda_file::Type::TypeId type_id = field.GetType().GetId();
100             if (type_id == panda_file::Type::TypeId::REFERENCE) {
101                 ObjectHeader *field_object = object_header->GetFieldObject(offset);
102                 if (field_object != nullptr) {
103                     *o_stream << std::hex << field_object << std::endl;
104                 } else {
105                     *o_stream << "NULL" << std::endl;
106                 }
107             } else if (type_id != panda_file::Type::TypeId::VOID) {
108                 *o_stream << std::dec;
109                 switch (type_id) {
110                     case panda_file::Type::TypeId::U1: {
111                         auto val = object_header->GetFieldPrimitive<bool>(offset);
112                         *o_stream << val << std::endl;
113                     } break;
114                     case panda_file::Type::TypeId::I8: {
115                         auto val = object_header->GetFieldPrimitive<int8_t>(offset);
116                         *o_stream << val << std::endl;
117                     } break;
118                     case panda_file::Type::TypeId::U8: {
119                         auto val = object_header->GetFieldPrimitive<uint8_t>(offset);
120                         *o_stream << val << std::endl;
121                     } break;
122                     case panda_file::Type::TypeId::I16: {
123                         auto val = object_header->GetFieldPrimitive<int16_t>(offset);
124                         *o_stream << val << std::endl;
125                     } break;
126                     case panda_file::Type::TypeId::U16: {
127                         auto val = object_header->GetFieldPrimitive<uint16_t>(offset);
128                         *o_stream << val << std::endl;
129                     } break;
130                     case panda_file::Type::TypeId::I32: {
131                         auto val = object_header->GetFieldPrimitive<int32_t>(offset);
132                         *o_stream << val << std::endl;
133                     } break;
134                     case panda_file::Type::TypeId::U32: {
135                         auto val = object_header->GetFieldPrimitive<uint32_t>(offset);
136                         *o_stream << val << std::endl;
137                     } break;
138                     case panda_file::Type::TypeId::F32: {
139                         auto val = object_header->GetFieldPrimitive<float>(offset);
140                         *o_stream << val << std::endl;
141                     } break;
142                     case panda_file::Type::TypeId::F64: {
143                         auto val = object_header->GetFieldPrimitive<double>(offset);
144                         *o_stream << val << std::endl;
145                     } break;
146                     case panda_file::Type::TypeId::I64: {
147                         auto val = object_header->GetFieldPrimitive<int64_t>(offset);
148                         *o_stream << val << std::endl;
149                     } break;
150                     case panda_file::Type::TypeId::U64: {
151                         auto val = object_header->GetFieldPrimitive<uint64_t>(offset);
152                         *o_stream << val << std::endl;
153                     } break;
154                     default:
155                         LOG(FATAL, COMMON) << "Error at object dump - wrong type id";
156                 }
157             }
158         }
159         cls = cls->GetBase();
160     }
161 }
162 
DumpClass(Class * cls,std::basic_ostream<char,std::char_traits<char>> * o_stream)163 void DumpClass(Class *cls, std::basic_ostream<char, std::char_traits<char>> *o_stream)
164 {
165     if (UNLIKELY(cls == nullptr)) {
166         return;
167     }
168     std::function<void(Class *, ObjectHeader *, const Field *, ObjectHeader *)> field_dump(
169         [o_stream]([[maybe_unused]] Class *kls, [[maybe_unused]] ObjectHeader *obj, const Field *field,
170                    ObjectHeader *field_object) {
171             *o_stream << "field = " << GetFieldName(*field) << std::hex << " " << field_object << std::endl;
172         });
173     // Dump class static fields
174     *o_stream << "Dump class: addr = " << std::hex << cls << ", cls = " << cls->GetDescriptor() << std::endl;
175     *o_stream << "Dump static fields:" << std::endl;
176     const Span<Field> &fields = cls->GetStaticFields();
177     ObjectHeader *cls_object = cls->GetManagedObject();
178     TraverseFields(fields, cls, cls_object, field_dump);
179     *o_stream << "Dump cls object fields:" << std::endl;
180     DumpObject(cls_object);
181 }
182 
GetForwardAddress(ObjectHeader * object_header)183 ObjectHeader *GetForwardAddress(ObjectHeader *object_header)
184 {
185     ASSERT(object_header->IsForwarded());
186     MarkWord mark_word = object_header->AtomicGetMark();
187     MarkWord::markWordSize addr = mark_word.GetForwardingAddress();
188     return reinterpret_cast<ObjectHeader *>(addr);
189 }
190 
GetFieldName(const Field & field)191 const char *GetFieldName(const Field &field)
192 {
193     static const char *empty_string = "";
194     bool is_proxy = field.GetClass()->IsProxy();
195     // For proxy class it is impossible to get field name in standard manner
196     if (!is_proxy) {
197         return reinterpret_cast<const char *>(field.GetName().data);
198     }
199     return empty_string;
200 }
201 
TraverseAllObjects(ObjectHeader * object_header,const std::function<void (ObjectHeader *,ObjectHeader *)> & obj_visitor)202 void GCDynamicObjectHelpers::TraverseAllObjects(ObjectHeader *object_header,
203                                                 const std::function<void(ObjectHeader *, ObjectHeader *)> &obj_visitor)
204 {
205     auto *cls = object_header->ClassAddr<HClass>();
206     ASSERT(cls != nullptr);
207     if (cls->IsString() || cls->IsNativePointer()) {
208         return;
209     }
210     if (cls->IsArray()) {
211         std::function<void(ObjectHeader *, const array_size_t, ObjectHeader *)> arr_fn(
212             [&obj_visitor]([[maybe_unused]] ObjectHeader *arr_object_header, [[maybe_unused]] const array_size_t INDEX,
213                            ObjectHeader *object_reference) { obj_visitor(arr_object_header, object_reference); });
214         TraverseArray(object_header, cls, arr_fn);
215     } else {
216         std::function<void(ObjectHeader *, size_t, ObjectHeader *, bool)> dyn_obj_proxy(
217             [&obj_visitor](ObjectHeader *obj_header, [[maybe_unused]] size_t offset, ObjectHeader *obj_reference,
218                            [[maybe_unused]] bool is_update_classword) { obj_visitor(obj_header, obj_reference); });
219         TraverseObject(object_header, cls, dyn_obj_proxy);
220     }
221 }
222 
RecordDynWeakReference(GC * gc,coretypes::TaggedType * value)223 void GCDynamicObjectHelpers::RecordDynWeakReference(GC *gc, coretypes::TaggedType *value)
224 {
225     GCExtensionData *data = gc->GetExtensionData();
226     ASSERT(data != nullptr);
227     ASSERT(data->GetLangType() == LANG_TYPE_DYNAMIC);
228     static_cast<GCDynamicData *>(data)->GetDynWeakReferences()->push(value);
229 }
230 
HandleDynWeakReferences(GC * gc)231 void GCDynamicObjectHelpers::HandleDynWeakReferences(GC *gc)
232 {
233     GCExtensionData *data = gc->GetExtensionData();
234     ASSERT(data != nullptr);
235     ASSERT(data->GetLangType() == LANG_TYPE_DYNAMIC);
236     auto *weak_refs = static_cast<GCDynamicData *>(data)->GetDynWeakReferences();
237     while (!weak_refs->empty()) {
238         coretypes::TaggedType *object_pointer = weak_refs->top();
239         weak_refs->pop();
240         TaggedValue value(*object_pointer);
241         if (value.IsUndefined()) {
242             continue;
243         }
244         ASSERT(value.IsWeak());
245         ObjectHeader *object = value.GetWeakReferent();
246         /* Note: If it is in young GC, the weak reference whose referent is in tenured space will not be marked. The */
247         /*       weak reference whose referent is in young space will be moved into the tenured space or reset in    */
248         /*       CollecYoungAndMove. If the weak referent here is not moved in young GC, it should be cleared.       */
249         if (gc->GetGCPhase() == GCPhase::GC_PHASE_MARK_YOUNG) {
250             if (gc->GetObjectAllocator()->IsAddressInYoungSpace(ToUintPtr(object)) && !gc->IsMarked(object)) {
251                 *object_pointer = TaggedValue::Undefined().GetRawData();
252             }
253         } else {
254             /* Note: When it is in tenured GC, we check whether the referent has been marked. */
255             if (!gc->IsMarked(object)) {
256                 *object_pointer = TaggedValue::Undefined().GetRawData();
257             }
258         }
259     }
260 }
261 
TraverseAllObjects(ObjectHeader * object_header,const std::function<void (ObjectHeader *,ObjectHeader *)> & obj_visitor)262 void GCStaticObjectHelpers::TraverseAllObjects(ObjectHeader *object_header,
263                                                const std::function<void(ObjectHeader *, ObjectHeader *)> &obj_visitor)
264 {
265     auto *cls = object_header->ClassAddr<Class>();
266     // If create new object when visiting card table, the ClassAddr of the new object may be null
267     if (cls == nullptr) {
268         return;
269     }
270 
271     if (cls->IsObjectArrayClass()) {
272         TraverseArray(object_header, cls, ArrayElementVisitor(obj_visitor));
273     } else {
274         if (cls->IsClassClass()) {
275             auto object_cls = panda::Class::FromClassObject(object_header);
276             if (object_cls->IsInitializing() || object_cls->IsInitialized()) {
277                 TraverseClass(object_cls, ClassFieldVisitor(obj_visitor));
278             }
279         }
280         TraverseObject(object_header, cls, ObjectFieldVisitor(obj_visitor));
281     }
282 }
283 
UpdateRefsToMovedObjects(PandaVM * vm,ObjectHeader * object,BaseClass * base_cls)284 void GCStaticObjectHelpers::UpdateRefsToMovedObjects(PandaVM *vm, ObjectHeader *object, BaseClass *base_cls)
285 {
286     ASSERT(!base_cls->IsDynamicClass());
287     auto *cls = static_cast<Class *>(base_cls);
288     if (cls->IsObjectArrayClass()) {
289         LOG_DEBUG_OBJ_HELPERS << " IsObjArrayClass";
290         TraverseArray(object, cls, [vm](ObjectHeader *obj, array_size_t index, ObjectHeader *element) {
291             MarkWord mark_word = element->GetMark();  // no need atomic because stw
292             if (mark_word.GetState() == MarkWord::ObjectState::STATE_GC) {
293                 // update element without write barrier
294                 auto array_object = static_cast<coretypes::Array *>(obj);
295                 MarkWord::markWordSize addr = mark_word.GetForwardingAddress();
296                 LOG_DEBUG_OBJ_HELPERS << "  update obj ref for array  " << std::hex << obj << " index =  " << index
297                                       << " from " << array_object->Get<ObjectHeader *>(index) << " to " << addr;
298                 array_object->Set<ObjectHeader *, false>(index, reinterpret_cast<ObjectHeader *>(addr));
299             }
300         });
301     } else {
302         LOG_DEBUG_OBJ_HELPERS << " IsObject";
303         TraverseObject(
304             object, cls, [vm](ObjectHeader *obj, ObjectHeader *field_object, uint32_t field_offset, bool is_volatile) {
305                 MarkWord mark_word = field_object->GetMark();  // no need atomic because stw
306                 if (mark_word.GetState() == MarkWord::ObjectState::STATE_GC) {
307                     // update instance field without write barrier
308                     MarkWord::markWordSize addr = mark_word.GetForwardingAddress();
309                     LOG_DEBUG_OBJ_HELPERS << "  update obj ref for object " << std::hex << obj << " from "
310                                           << field_object << " to " << addr;
311                     if (is_volatile) {
312                         obj->SetFieldObject<true, false>(field_offset, reinterpret_cast<ObjectHeader *>(addr));
313                     } else {
314                         obj->SetFieldObject<false, false>(field_offset, reinterpret_cast<ObjectHeader *>(addr));
315                     }
316                 }
317             });
318         if (!cls->IsClassClass()) {
319             return;
320         }
321 
322         auto object_cls = panda::Class::FromClassObject(object);
323         if (!object_cls->IsInitializing() && !object_cls->IsInitialized()) {
324             return;
325         }
326 
327         TraverseClass(
328             object_cls, [](Class *object_kls, ObjectHeader *field_object, uint32_t field_offset, bool is_volatile) {
329                 MarkWord mark_word = field_object->GetMark();  // no need atomic because stw
330                 if (mark_word.GetState() == MarkWord::ObjectState::STATE_GC) {
331                     // update static field without write barrier
332                     MarkWord::markWordSize addr = mark_word.GetForwardingAddress();
333                     if (is_volatile) {
334                         object_kls->SetFieldObject<true, false>(field_offset, reinterpret_cast<ObjectHeader *>(addr));
335                     } else {
336                         object_kls->SetFieldObject<false, false>(field_offset, reinterpret_cast<ObjectHeader *>(addr));
337                     }
338                 }
339             });
340     }
341 }
342 
UpdateRefsToMovedObjects(PandaVM * vm,ObjectHeader * object,BaseClass * base_cls)343 void GCDynamicObjectHelpers::UpdateRefsToMovedObjects(PandaVM *vm, ObjectHeader *object, BaseClass *base_cls)
344 {
345     ASSERT(base_cls->IsDynamicClass());
346     auto *cls = static_cast<HClass *>(base_cls);
347     if (cls->IsNativePointer() || cls->IsString()) {
348         return;
349     }
350     if (cls->IsArray()) {
351         LOG_DEBUG_OBJ_HELPERS << " IsDynamicArrayClass";
352         auto update_array_callback = [vm](ObjectHeader *obj, array_size_t index, ObjectHeader *obj_ref) {
353             UpdateDynArray(vm, obj, index, obj_ref);
354         };
355         TraverseArray(object, cls, update_array_callback);
356     } else {
357         LOG_DEBUG_OBJ_HELPERS << " IsDynamicObject";
358         auto update_object_callback = [vm](ObjectHeader *obj, size_t offset, ObjectHeader *field_obj_ref,
359                                            bool is_update_classword) {
360             UpdateDynObjectRef(vm, obj, offset, field_obj_ref, is_update_classword);
361         };
362         TraverseObject(object, cls, update_object_callback);
363     }
364 }
365 
UpdateDynArray(PandaVM * vm,ObjectHeader * object,array_size_t index,ObjectHeader * obj_ref)366 void GCDynamicObjectHelpers::UpdateDynArray(PandaVM *vm, ObjectHeader *object, array_size_t index,
367                                             ObjectHeader *obj_ref)
368 {
369     TaggedValue value(obj_ref);
370     bool is_dyn_weak = value.IsWeak();
371     if (is_dyn_weak) {
372         obj_ref = value.GetWeakReferent();
373     }
374 
375     MarkWord mark_word = obj_ref->AtomicGetMark();
376     if (mark_word.GetState() == MarkWord::ObjectState::STATE_GC) {
377         auto arr = static_cast<coretypes::Array *>(object);
378         MarkWord::markWordSize addr = mark_word.GetForwardingAddress();
379         LOG_DEBUG_OBJ_HELPERS << "  update obj ref for array  " << std::hex << object << " index =  " << index
380                               << " from " << std::hex << arr->Get<ObjectHeader *>(index) << " to " << addr;
381         auto *field_object = reinterpret_cast<ObjectHeader *>(addr);
382         if (is_dyn_weak) {
383             field_object = TaggedValue(field_object).CreateAndGetWeakRef().GetRawHeapObject();
384         }
385         size_t offset = TaggedValue::TaggedTypeSize() * index;
386         ObjectAccessor::SetDynObject<true>(vm->GetAssociatedThread(), arr->GetData(), offset, field_object);
387     }
388 }
389 
UpdateDynObjectRef(PandaVM * vm,ObjectHeader * object,size_t offset,ObjectHeader * field_obj_ref,bool is_update_classword)390 void GCDynamicObjectHelpers::UpdateDynObjectRef(PandaVM *vm, ObjectHeader *object, size_t offset,
391                                                 ObjectHeader *field_obj_ref, bool is_update_classword)
392 {
393     TaggedValue value(field_obj_ref);
394     bool is_dyn_weak = value.IsWeak();
395     if (is_dyn_weak) {
396         field_obj_ref = value.GetWeakReferent();
397     }
398     MarkWord mark_word = field_obj_ref->AtomicGetMark();
399     if (mark_word.GetState() == MarkWord::ObjectState::STATE_GC) {
400         MarkWord::markWordSize addr = mark_word.GetForwardingAddress();
401         LOG_DEBUG_OBJ_HELPERS << "  update obj ref for object " << std::hex << object << " from "
402                               << ObjectAccessor::GetDynValue<ObjectHeader *>(object, offset) << " to " << addr;
403         auto *h_class = field_obj_ref->ClassAddr<HClass>();
404         if (is_update_classword && h_class->IsHClass()) {
405             addr += ObjectHeader::ObjectHeaderSize();
406         }
407         auto *field_object = reinterpret_cast<ObjectHeader *>(addr);
408         if (is_dyn_weak) {
409             field_object = TaggedValue(field_object).CreateAndGetWeakRef().GetRawHeapObject();
410         }
411         ObjectAccessor::SetDynObject(vm->GetAssociatedThread(), object, offset, field_object);
412     }
413 }
414 
415 }  // namespace panda::mem
416