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 "libpandabase/os/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 os::memory::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 os::memory::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 SetDuration(double duration)139 void SetDuration(double duration) 140 { 141 duration_ = duration; 142 } 143 144 void InitializeMarking(); 145 void FinishMarking(float spendTime); 146 147 static size_t taskCounts_; 148 static os::memory::Mutex taskCountMutex_; 149 150 Heap *heap_ {nullptr}; 151 EcmaVM *vm_ {nullptr}; 152 JSThread *thread_ {nullptr}; 153 154 // obtained from the shared heap instance. 155 WorkManager *workManager_ {nullptr}; 156 size_t heapObjectSize_ {0}; 157 double duration_ {0.0}; 158 EnableConcurrentMarkType enableMarkType_ {EnableConcurrentMarkType::CONFIG_DISABLE}; 159 160 bool notifyMarkingFinished_ {false}; // notify js-thread that marking is finished and sweeping is needed 161 bool vmThreadWaitMarkingFinished_ {false}; // jsMainThread waiting for concurrentGC FINISHED 162 bool isConcurrentMarking_ {false}; 163 os::memory::Mutex waitMarkingFinishedMutex_; 164 os::memory::ConditionVariable waitMarkingFinishedCV_; 165 }; 166 } // namespace panda::ecmascript 167 #endif // ECMASCRIPT_MEM_CONCURRENT_MARKER_H 168