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