1 /**
2 * Copyright (c) 2023 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_GC_WORKERS_TASKS_H
17 #define PANDA_RUNTIME_MEM_GC_GC_WORKERS_TASKS_H
18
19 #include "runtime/mem/gc/g1/ref_updater.h"
20 #include "runtime/mem/gc/gc_root.h"
21 #include "runtime/thread_pool_queue.h"
22 #include "libpandabase/utils/range.h"
23
24 namespace panda::mem {
25
26 enum class GCWorkersTaskTypes : uint32_t {
27 TASK_EMPTY,
28 TASK_MARKING,
29 TASK_REMARK,
30 TASK_FULL_MARK,
31 TASK_REGION_COMPACTING,
32 TASK_RETURN_FREE_PAGES_TO_OS,
33 TASK_UPDATE_REMSET_REFS,
34 TASK_ENQUEUE_REMSET_REFS,
35 };
36
GCWorkersTaskTypesToString(GCWorkersTaskTypes type)37 constexpr const char *GCWorkersTaskTypesToString(GCWorkersTaskTypes type)
38 {
39 switch (type) {
40 case GCWorkersTaskTypes::TASK_EMPTY:
41 return "Empty task";
42 case GCWorkersTaskTypes::TASK_MARKING:
43 return "Marking task";
44 case GCWorkersTaskTypes::TASK_REMARK:
45 return "Remark task";
46 case GCWorkersTaskTypes::TASK_FULL_MARK:
47 return "Marking task for full collection";
48 case GCWorkersTaskTypes::TASK_REGION_COMPACTING:
49 return "Region compacting task";
50 case GCWorkersTaskTypes::TASK_RETURN_FREE_PAGES_TO_OS:
51 return "Return free pages to the OS";
52 case GCWorkersTaskTypes::TASK_UPDATE_REMSET_REFS:
53 return "Update remset references task";
54 case GCWorkersTaskTypes::TASK_ENQUEUE_REMSET_REFS:
55 return "Enqueue remset references task";
56 default:
57 return "Unknown task";
58 }
59 }
60
61 class GCWorkersTask : public TaskInterface {
62 public:
taskType_(type)63 explicit GCWorkersTask(GCWorkersTaskTypes type = GCWorkersTaskTypes::TASK_EMPTY) : taskType_(type)
64 {
65 ASSERT(type == GCWorkersTaskTypes::TASK_EMPTY || type == GCWorkersTaskTypes::TASK_RETURN_FREE_PAGES_TO_OS);
66 }
67
68 ~GCWorkersTask() = default;
69 DEFAULT_COPY_SEMANTIC(GCWorkersTask);
70 DEFAULT_MOVE_SEMANTIC(GCWorkersTask);
71
IsEmpty()72 bool IsEmpty() const
73 {
74 return taskType_ == GCWorkersTaskTypes::TASK_EMPTY;
75 }
76
77 template <class GCWorkersTaskT>
Cast()78 std::enable_if_t<std::is_base_of_v<GCWorkersTask, GCWorkersTaskT>, GCWorkersTaskT *> Cast() const
79 {
80 return static_cast<GCWorkersTaskT *>(const_cast<GCWorkersTask *>(this));
81 }
82
83 template <class GCWorkersTaskT>
84 std::enable_if_t<!std::is_base_of_v<GCWorkersTask, GCWorkersTaskT>, GCWorkersTaskT *> Cast() const = delete;
85
GetType()86 GCWorkersTaskTypes GetType() const
87 {
88 return taskType_;
89 }
90
91 private:
92 GCWorkersTaskTypes taskType_;
93
94 protected:
95 using StorageType = void *;
96
GCWorkersTask(GCWorkersTaskTypes type,StorageType taskStorageData)97 GCWorkersTask(GCWorkersTaskTypes type, StorageType taskStorageData) : taskType_(type), storage_(taskStorageData)
98 {
99 ASSERT(storage_ != nullptr);
100 }
101
102 StorageType storage_ {nullptr}; // NOLINT(misc-non-private-member-variables-in-classes)
103 };
104
105 class GCMarkWorkersTask : public GCWorkersTask {
106 public:
107 using StackType = GCMarkingStackType;
GCMarkWorkersTask(GCWorkersTaskTypes type,StackType * markingStack)108 GCMarkWorkersTask(GCWorkersTaskTypes type, StackType *markingStack) : GCWorkersTask(type, markingStack)
109 {
110 ASSERT(type == GCWorkersTaskTypes::TASK_MARKING || type == GCWorkersTaskTypes::TASK_REMARK ||
111 type == GCWorkersTaskTypes::TASK_FULL_MARK);
112 }
113 DEFAULT_COPY_SEMANTIC(GCMarkWorkersTask);
114 DEFAULT_MOVE_SEMANTIC(GCMarkWorkersTask);
115 ~GCMarkWorkersTask() = default;
116
GetMarkingStack()117 StackType *GetMarkingStack() const
118 {
119 return static_cast<StackType *>(storage_);
120 }
121 };
122
123 class Region;
124
125 class GCRegionCompactWorkersTask : public GCWorkersTask {
126 public:
127 using RegionDataType = std::pair<Region *, ObjectVisitor>;
128
GCRegionCompactWorkersTask(RegionDataType * regionData)129 explicit GCRegionCompactWorkersTask(RegionDataType *regionData)
130 : GCWorkersTask(GCWorkersTaskTypes::TASK_REGION_COMPACTING, regionData)
131 {
132 }
133 DEFAULT_COPY_SEMANTIC(GCRegionCompactWorkersTask);
134 DEFAULT_MOVE_SEMANTIC(GCRegionCompactWorkersTask);
135 ~GCRegionCompactWorkersTask() = default;
136
GetRegionData()137 RegionDataType *GetRegionData() const
138 {
139 return static_cast<RegionDataType *>(storage_);
140 }
141 };
142
143 template <bool VECTOR>
144 class GCUpdateRefsWorkersTask : public GCWorkersTask {
145 public:
146 using MovedObjectsRange = std::conditional_t<VECTOR, Range<PandaVector<ObjectHeader *>::iterator>,
147 Range<PandaDeque<ObjectHeader *>::iterator>>;
148 // We need this to evenly split moved objects vector to ranges for gc workers
149 static constexpr int RANGE_SIZE = 4096;
150
GCUpdateRefsWorkersTask(MovedObjectsRange * movedObjects)151 explicit GCUpdateRefsWorkersTask(MovedObjectsRange *movedObjects)
152 : GCWorkersTask(GCWorkersTaskTypes::TASK_ENQUEUE_REMSET_REFS, movedObjects)
153 {
154 }
155 DEFAULT_COPY_SEMANTIC(GCUpdateRefsWorkersTask);
156 DEFAULT_MOVE_SEMANTIC(GCUpdateRefsWorkersTask);
157 ~GCUpdateRefsWorkersTask() = default;
158
GetMovedObjectsRange()159 MovedObjectsRange *GetMovedObjectsRange() const
160 {
161 return static_cast<MovedObjectsRange *>(storage_);
162 }
163 };
164
165 } // namespace panda::mem
166
167 #endif // PANDA_RUNTIME_MEM_GC_GC_WORKERS_TASKS_H
168