• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 ECMASCRIPT_MEM_WORK_MANAGER_H
17 #define ECMASCRIPT_MEM_WORK_MANAGER_H
18 
19 #include "ecmascript/mem/mark_stack.h"
20 #include "ecmascript/mem/slots.h"
21 #include "ecmascript/taskpool/taskpool.h"
22 
23 namespace panda::ecmascript {
24 using SlotNeedUpdate = std::pair<TaggedObject *, ObjectSlot>;
25 
26 static constexpr uint32_t MARKSTACK_MAX_SIZE = 100;
27 static constexpr uint32_t STACK_AREA_SIZE = sizeof(uintptr_t) * MARKSTACK_MAX_SIZE;
28 static constexpr uint32_t SPACE_SIZE = 8_KB;
29 
30 class Heap;
31 class Stack;
32 class SemiSpaceCollector;
33 class TlabAllocator;
34 class Region;
35 
36 enum ParallelGCTaskPhase {
37     SEMI_HANDLE_THREAD_ROOTS_TASK,
38     SEMI_HANDLE_SNAPSHOT_TASK,
39     SEMI_HANDLE_GLOBAL_POOL_TASK,
40     OLD_HANDLE_GLOBAL_POOL_TASK,
41     COMPRESS_HANDLE_GLOBAL_POOL_TASK,
42     CONCURRENT_HANDLE_GLOBAL_POOL_TASK,
43     CONCURRENT_HANDLE_OLD_TO_NEW_TASK,
44     UNDEFINED_TASK,
45     TASK_LAST  // Count of different Task phase
46 };
47 
48 class WorkNode {
49 public:
WorkNode(Stack * stack)50     explicit WorkNode(Stack *stack) : next_(nullptr), stack_(stack) {}
~WorkNode()51     ~WorkNode()
52     {
53         delete stack_;
54         stack_ = nullptr;
55     }
56 
57     NO_COPY_SEMANTIC(WorkNode);
58     NO_MOVE_SEMANTIC(WorkNode);
59 
PushObject(uintptr_t obj)60     bool PushObject(uintptr_t obj)
61     {
62         return stack_->PushBackChecked(obj);
63     }
64 
PopObject(uintptr_t * obj)65     bool PopObject(uintptr_t *obj)
66     {
67         if (IsEmpty()) {
68             return false;
69         }
70         auto object = ToVoidPtr(*obj);
71         if (object != nullptr) {
72             delete reinterpret_cast<WorkNode *>(object);
73         }
74         *obj = stack_->PopBackUnchecked();
75         return true;
76     }
77 
IsEmpty()78     bool IsEmpty() const
79     {
80         return stack_->IsEmpty();
81     }
82 
Next()83     WorkNode *Next() const
84     {
85         return next_;
86     }
87 
SetNext(WorkNode * node)88     void SetNext(WorkNode *node)
89     {
90         next_ = node;
91     }
92 
93 private:
94     WorkNode *next_;
95     Stack *stack_;
96 };
97 
98 class GlobalWorkStack {
99 public:
GlobalWorkStack()100     GlobalWorkStack() : top_(nullptr) {}
101     ~GlobalWorkStack() = default;
102 
103     NO_COPY_SEMANTIC(GlobalWorkStack);
104     NO_MOVE_SEMANTIC(GlobalWorkStack);
105 
Push(WorkNode * node)106     void Push(WorkNode *node)
107     {
108         if (node == nullptr) {
109             return;
110         }
111         os::memory::LockHolder lock(mtx_);
112         node->SetNext(top_);
113         top_ = node;
114     }
115 
Pop(WorkNode ** node)116     bool Pop(WorkNode **node)
117     {
118         os::memory::LockHolder lock(mtx_);
119         if (top_ == nullptr) {
120             return false;
121         }
122         *node = top_;
123         top_ = top_->Next();
124         return true;
125     }
126 
127 private:
128     WorkNode *top_ {nullptr};
129     os::memory::Mutex mtx_;
130 };
131 
132 struct WorkNodeHolder {
133     WorkNode *inNode_ {nullptr};
134     WorkNode *outNode_ {nullptr};
135     ProcessQueue *weakQueue_ {nullptr};
136     std::vector<SlotNeedUpdate> pendingUpdateSlots_;
137     TlabAllocator *allocator_ {nullptr};
138     size_t aliveSize_ = 0;
139     size_t promotedSize_ = 0;
140 };
141 
142 class WorkManager final {
143 public:
144     WorkManager() = delete;
145     WorkManager(Heap *heap, uint32_t threadNum);
146     ~WorkManager();
147 
148     void Initialize(TriggerGCType gcType, ParallelGCTaskPhase taskPhase);
149     size_t Finish();
150     void Finish(size_t &aliveSize, size_t &promotedSize);
151 
152     bool Push(uint32_t threadId, TaggedObject *object);
153     bool Push(uint32_t threadId, TaggedObject *object, Region *region);
154     bool Pop(uint32_t threadId, TaggedObject **object);
155 
156     bool PopWorkNodeFromGlobal(uint32_t threadId);
157     void PushWorkNodeToGlobal(uint32_t threadId, bool postTask = true);
158 
PushWeakReference(uint32_t threadId,JSTaggedType * weak)159     inline void PushWeakReference(uint32_t threadId, JSTaggedType *weak)
160     {
161         works_.at(threadId).weakQueue_->PushBack(weak);
162     }
163 
IncreaseAliveSize(uint32_t threadId,size_t size)164     inline void IncreaseAliveSize(uint32_t threadId, size_t size)
165     {
166         works_.at(threadId).promotedSize_ += size;
167     }
168 
IncreasePromotedSize(uint32_t threadId,size_t size)169     inline void IncreasePromotedSize(uint32_t threadId, size_t size)
170     {
171         works_.at(threadId).promotedSize_ += size;
172     }
173 
GetWeakReferenceQueue(uint32_t threadId)174     inline ProcessQueue *GetWeakReferenceQueue(uint32_t threadId) const
175     {
176         return works_.at(threadId).weakQueue_;
177     }
178 
GetTlabAllocator(uint32_t threadId)179     inline TlabAllocator *GetTlabAllocator(uint32_t threadId) const
180     {
181         return works_.at(threadId).allocator_;
182     }
183 
PushSlotNeedUpdate(uint32_t threadId,SlotNeedUpdate slot)184     inline void PushSlotNeedUpdate(uint32_t threadId, SlotNeedUpdate slot)
185     {
186         works_.at(threadId).pendingUpdateSlots_.emplace_back(slot);
187     }
188 
GetSlotNeedUpdate(uint32_t threadId,SlotNeedUpdate * slot)189     inline bool GetSlotNeedUpdate(uint32_t threadId, SlotNeedUpdate *slot)
190     {
191         std::vector<SlotNeedUpdate> &pendingUpdateSlots = works_.at(threadId).pendingUpdateSlots_;
192         if (pendingUpdateSlots.empty()) {
193             return false;
194         }
195         *slot = pendingUpdateSlots.back();
196         pendingUpdateSlots.pop_back();
197         return true;
198     }
199 
GetTotalThreadNum()200     inline uint32_t GetTotalThreadNum()
201     {
202         return threadNum_;
203     }
204 
205 private:
206     NO_COPY_SEMANTIC(WorkManager);
207     NO_MOVE_SEMANTIC(WorkManager);
208 
209     WorkNode *AllocateWorkNode();
210 
211     Heap *heap_;
212     uint32_t threadNum_;
213     std::array<WorkNodeHolder, MAX_TASKPOOL_THREAD_NUM + 1> works_;
214     std::array<ContinuousStack<JSTaggedType> *, MAX_TASKPOOL_THREAD_NUM + 1> continuousQueue_;
215     GlobalWorkStack workStack_;
216     uintptr_t workSpace_;
217     uintptr_t spaceStart_;
218     uintptr_t spaceEnd_;
219     std::vector<uintptr_t> agedSpaces_;
220     os::memory::Mutex mtx_;
221     ParallelGCTaskPhase parallelGCTaskPhase_;
222 };
223 }  // namespace panda::ecmascript
224 #endif  // ECMASCRIPT_MEM_WORK_MANAGER_H
225