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