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