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#ifndef ECMASCRIPT_MEM_CONCURRENT_MARKER_H 17#define ECMASCRIPT_MEM_CONCURRENT_MARKER_H 18 19#include <array> 20#include <atomic> 21 22#include "ecmascript/common.h" 23#include "ecmascript/mem/clock_scope.h" 24#include "ecmascript/mem/space.h" 25#include "ecmascript/mem/visitor.h" 26#include "ecmascript/mem/work_manager.h" 27#include "ecmascript/taskpool/task.h" 28 29#include "ecmascript/platform/mutex.h" 30 31namespace panda::ecmascript { 32class EcmaVM; 33class Heap; 34// CONFIG_DISABLE means concurrent marker is disabled by options or macros and cannot be changed. 35// REQUEST_DISABLE means we want to disable concurrent sweeper while it is marking. 36// REQUEST_DISABLE can be ragarded as enable and will be changed into disable after this GC. 37enum class EnableConcurrentMarkType : uint8_t { 38 ENABLE, 39 CONFIG_DISABLE, 40 DISABLE, 41 REQUEST_DISABLE 42}; 43 44class ConcurrentMarker { 45public: 46 ConcurrentMarker(Heap *heap, EnableConcurrentMarkType type); 47 ~ConcurrentMarker() = default; 48 49 static bool TryIncreaseTaskCounts() 50 { 51 size_t taskPoolSize = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum(); 52 { 53 LockHolder holder(taskCountMutex_); 54 // total counts of running concurrent mark tasks should be less than taskPoolSize 55 if (taskCounts_ + 1 < taskPoolSize) { 56 taskCounts_++; 57 return true; 58 } 59 } 60 LOG_FULL(INFO) << "Concurrent mark tasks in taskPool are full"; 61 return false; 62 } 63 64 static void DecreaseTaskCounts() 65 { 66 LockHolder holder(taskCountMutex_); 67 taskCounts_--; 68 } 69 70 /* 71 * Concurrent marking related configurations and utilities. 72 */ 73 void EnableConcurrentMarking(EnableConcurrentMarkType type); 74 75 bool IsEnabled() const 76 { 77 return !IsDisabled(); 78 } 79 80 bool IsDisabled() const 81 { 82 return enableMarkType_ == EnableConcurrentMarkType::DISABLE || 83 enableMarkType_ == EnableConcurrentMarkType::CONFIG_DISABLE; 84 } 85 86 void ConfigConcurrentMark(bool enabled) 87 { 88 enableMarkType_ = enabled ? EnableConcurrentMarkType::ENABLE : 89 EnableConcurrentMarkType::CONFIG_DISABLE; 90 } 91 92 bool IsRequestDisabled() const 93 { 94 return enableMarkType_ == EnableConcurrentMarkType::REQUEST_DISABLE; 95 } 96 97 bool IsConfigDisabled() const 98 { 99 return enableMarkType_ == EnableConcurrentMarkType::CONFIG_DISABLE; 100 } 101 102 bool IsTriggeredConcurrentMark() const 103 { 104 return isConcurrentMarking_; 105 } 106 void ProcessConcurrentMarkTask(uint32_t threadId); 107 void Mark(); 108 void Finish(); 109 void ReMark(); 110 111 void HandleMarkingFinished(GCReason gcReason = GCReason::ALLOCATION_LIMIT); // call in vm thread. 112 void WaitMarkingFinished(); // call in main thread 113 void Reset(bool revertCSet = true); 114 115 double GetDuration() const 116 { 117 return duration_; 118 } 119 120 double GetHeapObjectSize() const 121 { 122 return heapObjectSize_; 123 } 124 125private: 126 NO_COPY_SEMANTIC(ConcurrentMarker); 127 NO_MOVE_SEMANTIC(ConcurrentMarker); 128 129 class RecursionScope { 130 public: 131 explicit RecursionScope(ConcurrentMarker* marker) : marker_(marker) 132 { 133 if (marker_->recursionDepth_++ != 0) { 134 LOG_GC(FATAL) << "Recursion in ConcurrentMarker Constructor, depth: " << marker_->recursionDepth_; 135 } 136 } 137 ~RecursionScope() 138 { 139 if (--marker_->recursionDepth_ != 0) { 140 LOG_GC(FATAL) << "Recursion in ConcurrentMarker Destructor, depth: " << marker_->recursionDepth_; 141 } 142 } 143 private: 144 ConcurrentMarker* marker_ {nullptr}; 145 }; 146 147 void SetDuration(double duration) 148 { 149 duration_ = duration; 150 } 151 152 void InitializeMarking(); 153 bool ShouldNotifyMarkingFinished(); // call in GC thread. 154 void FinishMarking(); // call in GC thread. 155 bool VerifyAllRegionsNonFresh(); 156 157 static size_t taskCounts_; 158 static Mutex taskCountMutex_; 159 160 Heap *heap_ {nullptr}; 161 EcmaVM *vm_ {nullptr}; 162 JSThread *thread_ {nullptr}; 163 164 // obtained from the shared heap instance. 165 WorkManager *workManager_ {nullptr}; 166 size_t heapObjectSize_ {0}; 167 double duration_ {0.0}; 168 EnableConcurrentMarkType enableMarkType_ {EnableConcurrentMarkType::CONFIG_DISABLE}; 169 170 std::atomic<int> runningTaskCount_ {0}; 171 bool notifyMarkingFinished_ {false}; // Use different value from markingFinished_ to prevent JSThread waking up 172 // before FinishMarking finishes. 173 bool markingFinished_ {false}; 174 bool isConcurrentMarking_ {false}; 175 Mutex waitMarkingFinishedMutex_; 176 ConditionVariable waitMarkingFinishedCV_; 177 int32_t recursionDepth_ {0}; 178 ClockScope clockScope_; 179 180 friend class Heap; 181}; 182} // namespace panda::ecmascript 183#endif // ECMASCRIPT_MEM_CONCURRENT_MARKER_H 184