14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/mem/work_manager.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/mem/incremental_marker.h" 194514f5e3Sopenharmony_ci#include "ecmascript/mem/tlab_allocator-inl.h" 204514f5e3Sopenharmony_ci 214514f5e3Sopenharmony_cinamespace panda::ecmascript { 224514f5e3Sopenharmony_ciWorkManagerBase::WorkManagerBase(NativeAreaAllocator *allocator) 234514f5e3Sopenharmony_ci : spaceChunk_(allocator), workSpace_(0), spaceStart_(0), spaceEnd_(0) 244514f5e3Sopenharmony_ci{ 254514f5e3Sopenharmony_ci auto allocatedSpace = GetSpaceChunk()->Allocate(WORKNODE_SPACE_SIZE); 264514f5e3Sopenharmony_ci ASSERT(allocatedSpace != nullptr); 274514f5e3Sopenharmony_ci workSpace_ = ToUintPtr(allocatedSpace); 284514f5e3Sopenharmony_ci} 294514f5e3Sopenharmony_ci 304514f5e3Sopenharmony_ciWorkNode *WorkManagerBase::AllocateWorkNode() 314514f5e3Sopenharmony_ci{ 324514f5e3Sopenharmony_ci LockHolder lock(mtx_); 334514f5e3Sopenharmony_ci size_t allocatedSize = sizeof(WorkNode) + sizeof(Stack) + STACK_AREA_SIZE; 344514f5e3Sopenharmony_ci ASSERT(allocatedSize < WORKNODE_SPACE_SIZE); 354514f5e3Sopenharmony_ci 364514f5e3Sopenharmony_ci uintptr_t begin = spaceStart_; 374514f5e3Sopenharmony_ci if (begin + allocatedSize >= spaceEnd_) { 384514f5e3Sopenharmony_ci agedSpaces_.emplace_back(workSpace_); 394514f5e3Sopenharmony_ci workSpace_ = ToUintPtr(GetSpaceChunk()->Allocate(WORKNODE_SPACE_SIZE)); 404514f5e3Sopenharmony_ci spaceStart_ = workSpace_; 414514f5e3Sopenharmony_ci spaceEnd_ = workSpace_ + WORKNODE_SPACE_SIZE; 424514f5e3Sopenharmony_ci begin = spaceStart_; 434514f5e3Sopenharmony_ci } 444514f5e3Sopenharmony_ci spaceStart_ = begin + allocatedSize; 454514f5e3Sopenharmony_ci Stack *stack = reinterpret_cast<Stack *>(begin + sizeof(WorkNode)); 464514f5e3Sopenharmony_ci stack->ResetBegin(begin + sizeof(WorkNode) + sizeof(Stack), begin + allocatedSize); 474514f5e3Sopenharmony_ci WorkNode *work = reinterpret_cast<WorkNode *>(begin); 484514f5e3Sopenharmony_ci return new (work) WorkNode(stack); 494514f5e3Sopenharmony_ci} 504514f5e3Sopenharmony_ci 514514f5e3Sopenharmony_ciWorkManagerBase::~WorkManagerBase() 524514f5e3Sopenharmony_ci{ 534514f5e3Sopenharmony_ci GetSpaceChunk()->Free(reinterpret_cast<void *>(workSpace_)); 544514f5e3Sopenharmony_ci} 554514f5e3Sopenharmony_ci 564514f5e3Sopenharmony_ciWorkManager::WorkManager(Heap *heap, uint32_t threadNum) 574514f5e3Sopenharmony_ci : WorkManagerBase(heap->GetNativeAreaAllocator()), heap_(heap), threadNum_(threadNum), 584514f5e3Sopenharmony_ci continuousQueue_ { nullptr }, parallelGCTaskPhase_(UNDEFINED_TASK) 594514f5e3Sopenharmony_ci{ 604514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 614514f5e3Sopenharmony_ci continuousQueue_.at(i) = new ProcessQueue(); 624514f5e3Sopenharmony_ci } 634514f5e3Sopenharmony_ci} 644514f5e3Sopenharmony_ci 654514f5e3Sopenharmony_ciWorkManager::~WorkManager() 664514f5e3Sopenharmony_ci{ 674514f5e3Sopenharmony_ci Finish(); 684514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 694514f5e3Sopenharmony_ci continuousQueue_.at(i)->Destroy(); 704514f5e3Sopenharmony_ci delete continuousQueue_.at(i); 714514f5e3Sopenharmony_ci continuousQueue_.at(i) = nullptr; 724514f5e3Sopenharmony_ci } 734514f5e3Sopenharmony_ci} 744514f5e3Sopenharmony_ci 754514f5e3Sopenharmony_cibool WorkManager::Push(uint32_t threadId, TaggedObject *object) 764514f5e3Sopenharmony_ci{ 774514f5e3Sopenharmony_ci WorkNode *&inNode = works_.at(threadId).inNode_; 784514f5e3Sopenharmony_ci if (!inNode->PushObject(ToUintPtr(object))) { 794514f5e3Sopenharmony_ci PushWorkNodeToGlobal(threadId); 804514f5e3Sopenharmony_ci return inNode->PushObject(ToUintPtr(object)); 814514f5e3Sopenharmony_ci } 824514f5e3Sopenharmony_ci return true; 834514f5e3Sopenharmony_ci} 844514f5e3Sopenharmony_ci 854514f5e3Sopenharmony_civoid WorkManager::PushWorkNodeToGlobal(uint32_t threadId, bool postTask) 864514f5e3Sopenharmony_ci{ 874514f5e3Sopenharmony_ci WorkNode *&inNode = works_.at(threadId).inNode_; 884514f5e3Sopenharmony_ci if (!inNode->IsEmpty()) { 894514f5e3Sopenharmony_ci workStack_.Push(inNode); 904514f5e3Sopenharmony_ci inNode = AllocateWorkNode(); 914514f5e3Sopenharmony_ci if (postTask && heap_->IsParallelGCEnabled() && heap_->CheckCanDistributeTask() && 924514f5e3Sopenharmony_ci !(heap_->IsMarking() && heap_->GetIncrementalMarker()->IsTriggeredIncrementalMark())) { 934514f5e3Sopenharmony_ci heap_->PostParallelGCTask(parallelGCTaskPhase_); 944514f5e3Sopenharmony_ci } 954514f5e3Sopenharmony_ci } 964514f5e3Sopenharmony_ci} 974514f5e3Sopenharmony_ci 984514f5e3Sopenharmony_cibool WorkManager::Pop(uint32_t threadId, TaggedObject **object) 994514f5e3Sopenharmony_ci{ 1004514f5e3Sopenharmony_ci WorkNode *&outNode = works_.at(threadId).outNode_; 1014514f5e3Sopenharmony_ci WorkNode *&inNode = works_.at(threadId).inNode_; 1024514f5e3Sopenharmony_ci if (!outNode->PopObject(reinterpret_cast<uintptr_t *>(object))) { 1034514f5e3Sopenharmony_ci if (!inNode->IsEmpty()) { 1044514f5e3Sopenharmony_ci WorkNode *tmp = outNode; 1054514f5e3Sopenharmony_ci outNode = inNode; 1064514f5e3Sopenharmony_ci inNode = tmp; 1074514f5e3Sopenharmony_ci } else if (!PopWorkNodeFromGlobal(threadId)) { 1084514f5e3Sopenharmony_ci return false; 1094514f5e3Sopenharmony_ci } 1104514f5e3Sopenharmony_ci return outNode->PopObject(reinterpret_cast<uintptr_t *>(object)); 1114514f5e3Sopenharmony_ci } 1124514f5e3Sopenharmony_ci return true; 1134514f5e3Sopenharmony_ci} 1144514f5e3Sopenharmony_ci 1154514f5e3Sopenharmony_cibool WorkManager::PopWorkNodeFromGlobal(uint32_t threadId) 1164514f5e3Sopenharmony_ci{ 1174514f5e3Sopenharmony_ci return workStack_.Pop(&works_.at(threadId).outNode_); 1184514f5e3Sopenharmony_ci} 1194514f5e3Sopenharmony_ci 1204514f5e3Sopenharmony_cisize_t WorkManager::Finish() 1214514f5e3Sopenharmony_ci{ 1224514f5e3Sopenharmony_ci size_t aliveSize = 0; 1234514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 1244514f5e3Sopenharmony_ci WorkNodeHolder &holder = works_.at(i); 1254514f5e3Sopenharmony_ci if (holder.weakQueue_ != nullptr) { 1264514f5e3Sopenharmony_ci holder.weakQueue_->FinishMarking(continuousQueue_.at(i)); 1274514f5e3Sopenharmony_ci delete holder.weakQueue_; 1284514f5e3Sopenharmony_ci holder.weakQueue_ = nullptr; 1294514f5e3Sopenharmony_ci } 1304514f5e3Sopenharmony_ci if (holder.allocator_ != nullptr) { 1314514f5e3Sopenharmony_ci holder.allocator_->Finalize(); 1324514f5e3Sopenharmony_ci delete holder.allocator_; 1334514f5e3Sopenharmony_ci holder.allocator_ = nullptr; 1344514f5e3Sopenharmony_ci } 1354514f5e3Sopenharmony_ci holder.pendingUpdateSlots_.clear(); 1364514f5e3Sopenharmony_ci aliveSize += holder.aliveSize_; 1374514f5e3Sopenharmony_ci } 1384514f5e3Sopenharmony_ci FinishBase(); 1394514f5e3Sopenharmony_ci initialized_.store(false, std::memory_order_release); 1404514f5e3Sopenharmony_ci return aliveSize; 1414514f5e3Sopenharmony_ci} 1424514f5e3Sopenharmony_ci 1434514f5e3Sopenharmony_civoid WorkManager::Finish(size_t &aliveSize, size_t &promotedSize) 1444514f5e3Sopenharmony_ci{ 1454514f5e3Sopenharmony_ci aliveSize = Finish(); 1464514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 1474514f5e3Sopenharmony_ci WorkNodeHolder &holder = works_.at(i); 1484514f5e3Sopenharmony_ci promotedSize += holder.promotedSize_; 1494514f5e3Sopenharmony_ci if (holder.allocator_ != nullptr) { 1504514f5e3Sopenharmony_ci holder.allocator_->Finalize(); 1514514f5e3Sopenharmony_ci delete holder.allocator_; 1524514f5e3Sopenharmony_ci holder.allocator_ = nullptr; 1534514f5e3Sopenharmony_ci } 1544514f5e3Sopenharmony_ci } 1554514f5e3Sopenharmony_ci initialized_.store(false, std::memory_order_release); 1564514f5e3Sopenharmony_ci} 1574514f5e3Sopenharmony_ci 1584514f5e3Sopenharmony_civoid WorkManager::Initialize(TriggerGCType gcType, ParallelGCTaskPhase taskPhase) 1594514f5e3Sopenharmony_ci{ 1604514f5e3Sopenharmony_ci parallelGCTaskPhase_ = taskPhase; 1614514f5e3Sopenharmony_ci InitializeBase(); 1624514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 1634514f5e3Sopenharmony_ci WorkNodeHolder &holder = works_.at(i); 1644514f5e3Sopenharmony_ci holder.inNode_ = AllocateWorkNode(); 1654514f5e3Sopenharmony_ci holder.outNode_ = AllocateWorkNode(); 1664514f5e3Sopenharmony_ci holder.weakQueue_ = new ProcessQueue(); 1674514f5e3Sopenharmony_ci holder.weakQueue_->BeginMarking(continuousQueue_.at(i)); 1684514f5e3Sopenharmony_ci holder.aliveSize_ = 0; 1694514f5e3Sopenharmony_ci holder.promotedSize_ = 0; 1704514f5e3Sopenharmony_ci if (gcType != TriggerGCType::OLD_GC) { 1714514f5e3Sopenharmony_ci holder.allocator_ = new TlabAllocator(heap_); 1724514f5e3Sopenharmony_ci } 1734514f5e3Sopenharmony_ci } 1744514f5e3Sopenharmony_ci if (initialized_.load(std::memory_order_acquire)) { // LOCV_EXCL_BR_LINE 1754514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1764514f5e3Sopenharmony_ci UNREACHABLE(); 1774514f5e3Sopenharmony_ci } 1784514f5e3Sopenharmony_ci initialized_.store(true, std::memory_order_release); 1794514f5e3Sopenharmony_ci} 1804514f5e3Sopenharmony_ci 1814514f5e3Sopenharmony_ciSharedGCWorkManager::SharedGCWorkManager(SharedHeap *heap, uint32_t threadNum) 1824514f5e3Sopenharmony_ci : WorkManagerBase(heap->GetNativeAreaAllocator()), sHeap_(heap), threadNum_(threadNum), 1834514f5e3Sopenharmony_ci continuousQueue_ { nullptr }, sharedTaskPhase_(SHARED_UNDEFINED_TASK) 1844514f5e3Sopenharmony_ci{ 1854514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 1864514f5e3Sopenharmony_ci continuousQueue_.at(i) = new ProcessQueue(); 1874514f5e3Sopenharmony_ci } 1884514f5e3Sopenharmony_ci} 1894514f5e3Sopenharmony_ci 1904514f5e3Sopenharmony_ciSharedGCWorkManager::~SharedGCWorkManager() 1914514f5e3Sopenharmony_ci{ 1924514f5e3Sopenharmony_ci Finish(); 1934514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 1944514f5e3Sopenharmony_ci continuousQueue_.at(i)->Destroy(); 1954514f5e3Sopenharmony_ci delete continuousQueue_.at(i); 1964514f5e3Sopenharmony_ci continuousQueue_.at(i) = nullptr; 1974514f5e3Sopenharmony_ci } 1984514f5e3Sopenharmony_ci} 1994514f5e3Sopenharmony_ci 2004514f5e3Sopenharmony_civoid SharedGCWorkManager::Initialize(TriggerGCType gcType, SharedParallelMarkPhase taskPhase) 2014514f5e3Sopenharmony_ci{ 2024514f5e3Sopenharmony_ci sharedTaskPhase_ = taskPhase; 2034514f5e3Sopenharmony_ci InitializeBase(); 2044514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 2054514f5e3Sopenharmony_ci SharedGCWorkNodeHolder &holder = works_.at(i); 2064514f5e3Sopenharmony_ci holder.inNode_ = AllocateWorkNode(); 2074514f5e3Sopenharmony_ci holder.outNode_ = AllocateWorkNode(); 2084514f5e3Sopenharmony_ci holder.weakQueue_ = new ProcessQueue(); 2094514f5e3Sopenharmony_ci holder.weakQueue_->BeginMarking(continuousQueue_.at(i)); 2104514f5e3Sopenharmony_ci if (gcType == TriggerGCType::SHARED_FULL_GC) { 2114514f5e3Sopenharmony_ci holder.allocator_ = new SharedTlabAllocator(sHeap_); 2124514f5e3Sopenharmony_ci } 2134514f5e3Sopenharmony_ci } 2144514f5e3Sopenharmony_ci if (initialized_.load(std::memory_order_acquire)) { // LOCV_EXCL_BR_LINE 2154514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 2164514f5e3Sopenharmony_ci UNREACHABLE(); 2174514f5e3Sopenharmony_ci } 2184514f5e3Sopenharmony_ci initialized_.store(true, std::memory_order_release); 2194514f5e3Sopenharmony_ci} 2204514f5e3Sopenharmony_ci 2214514f5e3Sopenharmony_cisize_t SharedGCWorkManager::Finish() 2224514f5e3Sopenharmony_ci{ 2234514f5e3Sopenharmony_ci size_t aliveSize = 0; 2244514f5e3Sopenharmony_ci for (uint32_t i = 0; i < threadNum_; i++) { 2254514f5e3Sopenharmony_ci SharedGCWorkNodeHolder &holder = works_.at(i); 2264514f5e3Sopenharmony_ci if (holder.weakQueue_ != nullptr) { 2274514f5e3Sopenharmony_ci holder.weakQueue_->FinishMarking(continuousQueue_.at(i)); 2284514f5e3Sopenharmony_ci delete holder.weakQueue_; 2294514f5e3Sopenharmony_ci holder.weakQueue_ = nullptr; 2304514f5e3Sopenharmony_ci } 2314514f5e3Sopenharmony_ci aliveSize += holder.aliveSize_; 2324514f5e3Sopenharmony_ci if (holder.allocator_ != nullptr) { 2334514f5e3Sopenharmony_ci holder.allocator_->Finalize(); 2344514f5e3Sopenharmony_ci delete holder.allocator_; 2354514f5e3Sopenharmony_ci holder.allocator_ = nullptr; 2364514f5e3Sopenharmony_ci } 2374514f5e3Sopenharmony_ci } 2384514f5e3Sopenharmony_ci FinishBase(); 2394514f5e3Sopenharmony_ci initialized_.store(false, std::memory_order_release); 2404514f5e3Sopenharmony_ci return aliveSize; 2414514f5e3Sopenharmony_ci} 2424514f5e3Sopenharmony_ci 2434514f5e3Sopenharmony_cibool SharedGCWorkManager::Push(uint32_t threadId, TaggedObject *object) 2444514f5e3Sopenharmony_ci{ 2454514f5e3Sopenharmony_ci WorkNode *&inNode = works_.at(threadId).inNode_; 2464514f5e3Sopenharmony_ci if (!inNode->PushObject(ToUintPtr(object))) { 2474514f5e3Sopenharmony_ci PushWorkNodeToGlobal(threadId); 2484514f5e3Sopenharmony_ci return inNode->PushObject(ToUintPtr(object)); 2494514f5e3Sopenharmony_ci } 2504514f5e3Sopenharmony_ci return true; 2514514f5e3Sopenharmony_ci} 2524514f5e3Sopenharmony_ci 2534514f5e3Sopenharmony_cibool SharedGCWorkManager::PushToLocalMarkingBuffer(WorkNode *&markingBuffer, TaggedObject *object) 2544514f5e3Sopenharmony_ci{ 2554514f5e3Sopenharmony_ci if (UNLIKELY(markingBuffer == nullptr)) { 2564514f5e3Sopenharmony_ci markingBuffer = AllocateWorkNode(); 2574514f5e3Sopenharmony_ci } 2584514f5e3Sopenharmony_ci ASSERT(markingBuffer != nullptr); 2594514f5e3Sopenharmony_ci if (UNLIKELY(!markingBuffer->PushObject(ToUintPtr(object)))) { 2604514f5e3Sopenharmony_ci PushLocalBufferToGlobal(markingBuffer); 2614514f5e3Sopenharmony_ci ASSERT(markingBuffer == nullptr); 2624514f5e3Sopenharmony_ci markingBuffer = AllocateWorkNode(); 2634514f5e3Sopenharmony_ci return markingBuffer->PushObject(ToUintPtr(object)); 2644514f5e3Sopenharmony_ci } 2654514f5e3Sopenharmony_ci return true; 2664514f5e3Sopenharmony_ci} 2674514f5e3Sopenharmony_ci 2684514f5e3Sopenharmony_civoid SharedGCWorkManager::PushWorkNodeToGlobal(uint32_t threadId, bool postTask) 2694514f5e3Sopenharmony_ci{ 2704514f5e3Sopenharmony_ci WorkNode *&inNode = works_.at(threadId).inNode_; 2714514f5e3Sopenharmony_ci if (!inNode->IsEmpty()) { 2724514f5e3Sopenharmony_ci workStack_.Push(inNode); 2734514f5e3Sopenharmony_ci inNode = AllocateWorkNode(); 2744514f5e3Sopenharmony_ci if (postTask && sHeap_->IsParallelGCEnabled() && sHeap_->CheckCanDistributeTask()) { 2754514f5e3Sopenharmony_ci sHeap_->PostGCMarkingTask(sharedTaskPhase_); 2764514f5e3Sopenharmony_ci } 2774514f5e3Sopenharmony_ci } 2784514f5e3Sopenharmony_ci} 2794514f5e3Sopenharmony_ci 2804514f5e3Sopenharmony_civoid SharedGCWorkManager::PushLocalBufferToGlobal(WorkNode *&node, bool postTask) 2814514f5e3Sopenharmony_ci{ 2824514f5e3Sopenharmony_ci ASSERT(node != nullptr); 2834514f5e3Sopenharmony_ci ASSERT(!node->IsEmpty()); 2844514f5e3Sopenharmony_ci workStack_.Push(node); 2854514f5e3Sopenharmony_ci if (postTask && sHeap_->IsParallelGCEnabled() && sHeap_->CheckCanDistributeTask()) { 2864514f5e3Sopenharmony_ci sHeap_->PostGCMarkingTask(sharedTaskPhase_); 2874514f5e3Sopenharmony_ci } 2884514f5e3Sopenharmony_ci node = nullptr; 2894514f5e3Sopenharmony_ci} 2904514f5e3Sopenharmony_ci 2914514f5e3Sopenharmony_cibool SharedGCWorkManager::Pop(uint32_t threadId, TaggedObject **object) 2924514f5e3Sopenharmony_ci{ 2934514f5e3Sopenharmony_ci WorkNode *&outNode = works_.at(threadId).outNode_; 2944514f5e3Sopenharmony_ci WorkNode *&inNode = works_.at(threadId).inNode_; 2954514f5e3Sopenharmony_ci if (!outNode->PopObject(reinterpret_cast<uintptr_t *>(object))) { 2964514f5e3Sopenharmony_ci if (!inNode->IsEmpty()) { 2974514f5e3Sopenharmony_ci WorkNode *tmp = outNode; 2984514f5e3Sopenharmony_ci outNode = inNode; 2994514f5e3Sopenharmony_ci inNode = tmp; 3004514f5e3Sopenharmony_ci } else if (!PopWorkNodeFromGlobal(threadId)) { 3014514f5e3Sopenharmony_ci return false; 3024514f5e3Sopenharmony_ci } 3034514f5e3Sopenharmony_ci return outNode->PopObject(reinterpret_cast<uintptr_t *>(object)); 3044514f5e3Sopenharmony_ci } 3054514f5e3Sopenharmony_ci return true; 3064514f5e3Sopenharmony_ci} 3074514f5e3Sopenharmony_ci 3084514f5e3Sopenharmony_cibool SharedGCWorkManager::PopWorkNodeFromGlobal(uint32_t threadId) 3094514f5e3Sopenharmony_ci{ 3104514f5e3Sopenharmony_ci return workStack_.Pop(&works_.at(threadId).outNode_); 3114514f5e3Sopenharmony_ci} 3124514f5e3Sopenharmony_ci} // namespace panda::ecmascript 313