1 /**
2 * Copyright (c) 2021-2025 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_GC_STATIC_GC_MARKER_STATIC_INL_H
17 #define PANDA_RUNTIME_MEM_GC_STATIC_GC_MARKER_STATIC_INL_H
18
19 #include "runtime/mem/gc/gc_marker.h"
20 #include "runtime/mem/gc/workers/gc_workers_task_pool.h"
21
22 namespace ark::mem {
23
24 template <typename Marker>
HandleObject(GCMarkingStackType * objectsStack,const ObjectHeader * object,const Class * cls)25 void GCMarker<Marker, LANG_TYPE_STATIC>::HandleObject(GCMarkingStackType *objectsStack, const ObjectHeader *object,
26 const Class *cls)
27 {
28 while (cls != nullptr) {
29 // Iterate over instance fields
30 uint32_t refNum = cls->GetRefFieldsNum<false>();
31 if (refNum == 0) {
32 cls = cls->GetBase();
33 continue;
34 }
35 uint32_t offset = cls->GetRefFieldsOffset<false>();
36 uint32_t refVolatileNum = cls->GetVolatileRefFieldsNum<false>();
37 for (uint32_t i = 0; i < refVolatileNum; i++, offset += ClassHelper::OBJECT_POINTER_SIZE) {
38 auto *fieldObject = object->GetFieldObject<true>(offset);
39 ValidateObject(object, fieldObject);
40 if (fieldObject != nullptr && AsMarker()->MarkIfNotMarked(fieldObject)) {
41 objectsStack->PushToStack(object, fieldObject);
42 }
43 }
44 for (uint32_t i = refVolatileNum; i < refNum; i++, offset += ClassHelper::OBJECT_POINTER_SIZE) {
45 auto *fieldObject = object->GetFieldObject<false>(offset);
46 ValidateObject(object, fieldObject);
47 if (fieldObject != nullptr && AsMarker()->MarkIfNotMarked(fieldObject)) {
48 objectsStack->PushToStack(object, fieldObject);
49 }
50 }
51 cls = cls->GetBase();
52 }
53 }
54 template <typename Marker>
HandleClass(GCMarkingStackType * objectsStack,const Class * cls)55 void GCMarker<Marker, LANG_TYPE_STATIC>::HandleClass(GCMarkingStackType *objectsStack, const Class *cls)
56 {
57 // Iterate over static fields
58 uint32_t refNum = cls->GetRefFieldsNum<true>();
59 if (refNum > 0) {
60 uint32_t offset = cls->GetRefFieldsOffset<true>();
61 uint32_t refVolatileNum = cls->GetVolatileRefFieldsNum<true>();
62 for (uint32_t i = 0; i < refVolatileNum; i++, offset += ClassHelper::OBJECT_POINTER_SIZE) {
63 auto *fieldObject = cls->GetFieldObject<true>(offset);
64 if (fieldObject != nullptr && AsMarker()->MarkIfNotMarked(fieldObject)) {
65 objectsStack->PushToStack(cls->GetManagedObject(), fieldObject);
66 }
67 }
68 for (uint32_t i = refVolatileNum; i < refNum; i++, offset += ClassHelper::OBJECT_POINTER_SIZE) {
69 auto *fieldObject = cls->GetFieldObject<false>(offset);
70 if (fieldObject != nullptr && AsMarker()->MarkIfNotMarked(fieldObject)) {
71 objectsStack->PushToStack(cls->GetManagedObject(), fieldObject);
72 }
73 }
74 }
75 }
76
77 template <typename Marker>
HandleArrayClass(GCMarkingStackType * objectsStack,const coretypes::Array * arrayObject,const Class * cls)78 void GCMarker<Marker, LANG_TYPE_STATIC>::HandleArrayClass(GCMarkingStackType *objectsStack,
79 const coretypes::Array *arrayObject,
80 [[maybe_unused]] const Class *cls)
81 {
82 LOG(DEBUG, GC) << "Array object: " << GetDebugInfoAboutObject(arrayObject);
83 ArraySizeT arrayLength = arrayObject->GetLength();
84
85 ASSERT(cls->IsObjectArrayClass());
86
87 LOG(DEBUG, GC) << "Iterate over: " << arrayLength << " elements in array";
88 size_t currentPartition = 0;
89 size_t partitionSize = 0;
90 constexpr size_t THRESHOLD_ARRAY_SIZE = 50000U;
91 auto *gc = GetGC();
92 bool useGcWorkers = gc->GetSettings()->ParallelMarkingEnabled();
93 auto taskType = objectsStack->GetTaskType();
94 ASSERT(taskType != GCWorkersTaskTypes::TASK_HUGE_ARRAY_MARKING_REMARK);
95 if (arrayLength >= THRESHOLD_ARRAY_SIZE && useGcWorkers && taskType == GCWorkersTaskTypes::TASK_REMARK) {
96 size_t gcWorkersNum = Runtime::GetOptions().GetTaskmanagerWorkersCount();
97 ASSERT(gcWorkersNum > 0);
98 ArraySizeT arrayPartitionsNumber = gcWorkersNum;
99 partitionSize = arrayLength / arrayPartitionsNumber;
100 auto allocator = gc->GetInternalAllocator();
101 // The rest of the array (last partition till the end of the array) is going to be traversed in current worker
102 for (; currentPartition < arrayPartitionsNumber - 1; ++currentPartition) {
103 auto *newStack = allocator->template New<GCAdaptiveMarkingStack>(
104 gc, useGcWorkers ? gc->GetSettings()->GCRootMarkingStackMaxSize() : 0,
105 useGcWorkers ? gc->GetSettings()->GCWorkersMarkingStackMaxSize() : 0,
106 GCWorkersTaskTypes::TASK_HUGE_ARRAY_MARKING_REMARK);
107 ASSERT(newStack != nullptr);
108 static_cast<GCAdaptiveStack<ObjectHeader *> *>(newStack)->PushToStack(
109 const_cast<coretypes::Array *>(arrayObject));
110 size_t taskStartIndex = currentPartition * partitionSize;
111 void *markingRangeInfo =
112 allocator->template New<std::pair<size_t, size_t>>(taskStartIndex, taskStartIndex + partitionSize);
113 newStack->SetAdditionalMarkingInfo(markingRangeInfo);
114 if (!gc->GetWorkersTaskPool()->AddTask(GCMarkWorkersTask(newStack->GetTaskType(), newStack))) {
115 // Couldn't create a new task. Going to process the rest of the array here
116 allocator->Delete(newStack);
117 break;
118 }
119 }
120 }
121 for (coretypes::ArraySizeT i = currentPartition * partitionSize; i < arrayLength; i++) {
122 auto *arrayElement = arrayObject->Get<ObjectHeader *>(i);
123 if (arrayElement == nullptr) {
124 continue;
125 }
126 #ifndef NDEBUG
127 auto arrayElementCls = arrayElement->ClassAddr<Class>();
128 LOG_IF(arrayElementCls == nullptr, ERROR, GC)
129 << " object's class is nullptr: " << arrayElement << " from array: " << arrayObject;
130 ASSERT(arrayElementCls != nullptr);
131 #endif
132 if (AsMarker()->MarkIfNotMarked(arrayElement)) {
133 objectsStack->PushToStack(arrayObject, arrayElement);
134 }
135 }
136 }
137
138 template <typename Marker>
MarkInstance(GCMarkingStackType * objectsStack,const ObjectHeader * object,const BaseClass * baseCls,const ReferenceCheckPredicateT & refPred)139 void GCMarker<Marker, LANG_TYPE_STATIC>::MarkInstance(GCMarkingStackType *objectsStack, const ObjectHeader *object,
140 const BaseClass *baseCls, const ReferenceCheckPredicateT &refPred)
141 {
142 ASSERT(!baseCls->IsDynamicClass());
143 auto cls = static_cast<const Class *>(baseCls);
144 if (GetGC()->IsReference(cls, object, refPred)) {
145 GetGC()->ProcessReference(objectsStack, cls, object, GC::EmptyReferenceProcessPredicate);
146 } else {
147 MarkInstance(objectsStack, object, baseCls);
148 }
149 }
150
151 template <typename Marker>
MarkInstance(GCMarkingStackType * objectsStack,const ObjectHeader * object,const BaseClass * baseCls)152 void GCMarker<Marker, LANG_TYPE_STATIC>::MarkInstance(GCMarkingStackType *objectsStack, const ObjectHeader *object,
153 const BaseClass *baseCls)
154 {
155 ASSERT(!baseCls->IsDynamicClass());
156 const auto *cls = static_cast<const Class *>(baseCls);
157 if (cls->IsObjectArrayClass()) {
158 auto *arrayObject = static_cast<const ark::coretypes::Array *>(object);
159 HandleArrayClass(objectsStack, arrayObject, cls);
160 } else if (cls->IsClassClass()) {
161 // Handle Class handles static fields only, so we need to Handle regular fields explicitly too
162 auto objectCls = ark::Class::FromClassObject(object);
163 ASSERT(objectCls != nullptr);
164 if (objectCls->IsInitializing() || objectCls->IsInitialized()) {
165 HandleClass(objectsStack, objectCls);
166 }
167 HandleObject(objectsStack, object, cls);
168 } else if (cls->IsInstantiable()) {
169 HandleObject(objectsStack, object, cls);
170 } else {
171 if (!cls->IsPrimitive()) {
172 LOG(FATAL, GC) << "Wrong handling, missed type: " << cls->GetDescriptor();
173 }
174 }
175 }
176
177 } // namespace ark::mem
178
179 #endif // PANDA_RUNTIME_MEM_GC_STATIC_GC_MARKER_STATIC_INL_H
180