1/* 2 * Copyright (c) 2021 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#include "ecmascript/mem/concurrent_sweeper.h" 17#include "ecmascript/mem/heap.h" 18#include "ecmascript/mem/region-inl.h" 19#include "ecmascript/runtime_call_id.h" 20 21namespace panda::ecmascript { 22ConcurrentSweeper::ConcurrentSweeper(Heap *heap, EnableConcurrentSweepType type) 23 : heap_(heap), 24 enableType_(type) 25{ 26} 27 28void ConcurrentSweeper::PostTask(bool fullGC) 29{ 30 if (ConcurrentSweepEnabled()) { 31 if (!fullGC) { 32 Taskpool::GetCurrentTaskpool()->PostTask( 33 std::make_unique<SweeperTask>(heap_->GetJSThread()->GetThreadId(), this, OLD_SPACE)); 34 } 35 Taskpool::GetCurrentTaskpool()->PostTask( 36 std::make_unique<SweeperTask>(heap_->GetJSThread()->GetThreadId(), this, NON_MOVABLE)); 37 Taskpool::GetCurrentTaskpool()->PostTask( 38 std::make_unique<SweeperTask>(heap_->GetJSThread()->GetThreadId(), this, MACHINE_CODE_SPACE)); 39 } 40} 41 42void ConcurrentSweeper::Sweep(bool fullGC) 43{ 44 MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), ConcurrentSweepingInitialize); 45 if (ConcurrentSweepEnabled()) { 46 // Add all region to region list. Ensure all task finish 47 if (!fullGC) { 48 heap_->GetOldSpace()->PrepareSweeping(); 49 } 50 heap_->GetNonMovableSpace()->PrepareSweeping(); 51 heap_->GetMachineCodeSpace()->PrepareSweeping(); 52 // Prepare 53 isSweeping_ = true; 54 startSpaceType_ = fullGC ? NON_MOVABLE : OLD_SPACE; 55 for (int type = startSpaceType_; type < FREE_LIST_NUM; type++) { 56 remainingTaskNum_[type] = FREE_LIST_NUM - startSpaceType_; 57 } 58 } else { 59 if (!fullGC) { 60 heap_->GetOldSpace()->Sweep(); 61 } 62 heap_->GetNonMovableSpace()->Sweep(); 63 heap_->GetMachineCodeSpace()->Sweep(); 64 } 65 heap_->GetHugeObjectSpace()->Sweep(); 66 heap_->GetHugeMachineCodeSpace()->Sweep(); 67} 68 69void ConcurrentSweeper::AsyncSweepSpace(MemSpaceType type, bool isMain) 70{ 71 auto space = heap_->GetSpaceWithType(type); 72 space->AsyncSweep(isMain); 73 74 LockHolder holder(mutexs_[type]); 75 if (--remainingTaskNum_[type] == 0) { 76 cvs_[type].SignalAll(); 77 } 78} 79 80void ConcurrentSweeper::WaitAllTaskFinished() 81{ 82 if (!isSweeping_) { 83 return; 84 } 85 for (int i = startSpaceType_; i < FREE_LIST_NUM; i++) { 86 if (remainingTaskNum_[i] > 0) { 87 LockHolder holder(mutexs_[i]); 88 while (remainingTaskNum_[i] > 0) { 89 cvs_[i].Wait(&mutexs_[i]); 90 } 91 } 92 } 93} 94 95void ConcurrentSweeper::EnsureAllTaskFinished() 96{ 97 if (!isSweeping_) { 98 return; 99 } 100 for (int i = startSpaceType_; i < FREE_LIST_NUM; i++) { 101 WaitingTaskFinish(static_cast<MemSpaceType>(i)); 102 } 103 isSweeping_ = false; 104 if (IsRequestDisabled()) { 105 enableType_ = EnableConcurrentSweepType::DISABLE; 106 } 107} 108 109void ConcurrentSweeper::EnsureTaskFinished(MemSpaceType type) 110{ 111 CHECK_JS_THREAD(heap_->GetEcmaVM()); 112 EnsureTaskFinishedNoCheck(type); 113} 114 115void ConcurrentSweeper::EnsureTaskFinishedNoCheck(MemSpaceType type) 116{ 117 if (!isSweeping_) { 118 return; 119 } 120 WaitingTaskFinish(type); 121} 122 123void ConcurrentSweeper::WaitingTaskFinish(MemSpaceType type) 124{ 125 if (remainingTaskNum_[type] > 0) { 126 { 127 LockHolder holder(mutexs_[type]); 128 remainingTaskNum_[type]++; 129 } 130 AsyncSweepSpace(type, true); 131 LockHolder holder(mutexs_[type]); 132 while (remainingTaskNum_[type] > 0) { 133 cvs_[type].Wait(&mutexs_[type]); 134 } 135 } 136 SparseSpace *space = heap_->GetSpaceWithType(type); 137 space->FinishFillSweptRegion(); 138} 139 140void ConcurrentSweeper::TryFillSweptRegion() 141{ 142 for (int i = startSpaceType_; i < FREE_LIST_NUM; i++) { 143 SparseSpace *space = heap_->GetSpaceWithType(static_cast<MemSpaceType>(i)); 144 space->TryFillSweptRegion(); 145 } 146} 147 148void ConcurrentSweeper::ClearRSetInRange(Region *current, uintptr_t freeStart, uintptr_t freeEnd) 149{ 150 if (ConcurrentSweepEnabled()) { 151 // This clear may exist data race with array and jsobject trim, so use CAS 152 current->AtomicClearSweepingOldToNewRSetInRange(freeStart, freeEnd); 153 current->AtomicClearSweepingLocalToShareRSetInRange(freeStart, freeEnd); 154 } else { 155 current->ClearOldToNewRSetInRange(freeStart, freeEnd); 156 current->ClearLocalToShareRSetInRange(freeStart, freeEnd); 157 } 158 current->ClearCrossRegionRSetInRange(freeStart, freeEnd); 159} 160 161bool ConcurrentSweeper::SweeperTask::Run([[maybe_unused]] uint32_t threadIndex) 162{ 163 uint32_t sweepTypeNum = FREE_LIST_NUM - sweeper_->startSpaceType_; 164 for (size_t i = sweeper_->startSpaceType_; i < FREE_LIST_NUM; i++) { 165 auto type = static_cast<MemSpaceType>(((i + type_) % sweepTypeNum) + sweeper_->startSpaceType_); 166 sweeper_->AsyncSweepSpace(type, false); 167 } 168 return true; 169} 170 171void ConcurrentSweeper::EnableConcurrentSweep(EnableConcurrentSweepType type) 172{ 173 if (IsConfigDisabled()) { 174 return; 175 } 176 if (ConcurrentSweepEnabled() && isSweeping_ && type == EnableConcurrentSweepType::DISABLE) { 177 enableType_ = EnableConcurrentSweepType::REQUEST_DISABLE; 178 } else { 179 enableType_ = type; 180 } 181} 182} // namespace panda::ecmascript 183