14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_MEM_CONCURRENT_MARKER_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_MEM_CONCURRENT_MARKER_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include <array> 204514f5e3Sopenharmony_ci#include <atomic> 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_ci#include "ecmascript/common.h" 234514f5e3Sopenharmony_ci#include "ecmascript/mem/clock_scope.h" 244514f5e3Sopenharmony_ci#include "ecmascript/mem/space.h" 254514f5e3Sopenharmony_ci#include "ecmascript/mem/visitor.h" 264514f5e3Sopenharmony_ci#include "ecmascript/mem/work_manager.h" 274514f5e3Sopenharmony_ci#include "ecmascript/taskpool/task.h" 284514f5e3Sopenharmony_ci 294514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h" 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_cinamespace panda::ecmascript { 324514f5e3Sopenharmony_ciclass EcmaVM; 334514f5e3Sopenharmony_ciclass Heap; 344514f5e3Sopenharmony_ci// CONFIG_DISABLE means concurrent marker is disabled by options or macros and cannot be changed. 354514f5e3Sopenharmony_ci// REQUEST_DISABLE means we want to disable concurrent sweeper while it is marking. 364514f5e3Sopenharmony_ci// REQUEST_DISABLE can be ragarded as enable and will be changed into disable after this GC. 374514f5e3Sopenharmony_cienum class EnableConcurrentMarkType : uint8_t { 384514f5e3Sopenharmony_ci ENABLE, 394514f5e3Sopenharmony_ci CONFIG_DISABLE, 404514f5e3Sopenharmony_ci DISABLE, 414514f5e3Sopenharmony_ci REQUEST_DISABLE 424514f5e3Sopenharmony_ci}; 434514f5e3Sopenharmony_ci 444514f5e3Sopenharmony_ciclass ConcurrentMarker { 454514f5e3Sopenharmony_cipublic: 464514f5e3Sopenharmony_ci ConcurrentMarker(Heap *heap, EnableConcurrentMarkType type); 474514f5e3Sopenharmony_ci ~ConcurrentMarker() = default; 484514f5e3Sopenharmony_ci 494514f5e3Sopenharmony_ci static bool TryIncreaseTaskCounts() 504514f5e3Sopenharmony_ci { 514514f5e3Sopenharmony_ci size_t taskPoolSize = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum(); 524514f5e3Sopenharmony_ci { 534514f5e3Sopenharmony_ci LockHolder holder(taskCountMutex_); 544514f5e3Sopenharmony_ci // total counts of running concurrent mark tasks should be less than taskPoolSize 554514f5e3Sopenharmony_ci if (taskCounts_ + 1 < taskPoolSize) { 564514f5e3Sopenharmony_ci taskCounts_++; 574514f5e3Sopenharmony_ci return true; 584514f5e3Sopenharmony_ci } 594514f5e3Sopenharmony_ci } 604514f5e3Sopenharmony_ci LOG_FULL(INFO) << "Concurrent mark tasks in taskPool are full"; 614514f5e3Sopenharmony_ci return false; 624514f5e3Sopenharmony_ci } 634514f5e3Sopenharmony_ci 644514f5e3Sopenharmony_ci static void DecreaseTaskCounts() 654514f5e3Sopenharmony_ci { 664514f5e3Sopenharmony_ci LockHolder holder(taskCountMutex_); 674514f5e3Sopenharmony_ci taskCounts_--; 684514f5e3Sopenharmony_ci } 694514f5e3Sopenharmony_ci 704514f5e3Sopenharmony_ci /* 714514f5e3Sopenharmony_ci * Concurrent marking related configurations and utilities. 724514f5e3Sopenharmony_ci */ 734514f5e3Sopenharmony_ci void EnableConcurrentMarking(EnableConcurrentMarkType type); 744514f5e3Sopenharmony_ci 754514f5e3Sopenharmony_ci bool IsEnabled() const 764514f5e3Sopenharmony_ci { 774514f5e3Sopenharmony_ci return !IsDisabled(); 784514f5e3Sopenharmony_ci } 794514f5e3Sopenharmony_ci 804514f5e3Sopenharmony_ci bool IsDisabled() const 814514f5e3Sopenharmony_ci { 824514f5e3Sopenharmony_ci return enableMarkType_ == EnableConcurrentMarkType::DISABLE || 834514f5e3Sopenharmony_ci enableMarkType_ == EnableConcurrentMarkType::CONFIG_DISABLE; 844514f5e3Sopenharmony_ci } 854514f5e3Sopenharmony_ci 864514f5e3Sopenharmony_ci void ConfigConcurrentMark(bool enabled) 874514f5e3Sopenharmony_ci { 884514f5e3Sopenharmony_ci enableMarkType_ = enabled ? EnableConcurrentMarkType::ENABLE : 894514f5e3Sopenharmony_ci EnableConcurrentMarkType::CONFIG_DISABLE; 904514f5e3Sopenharmony_ci } 914514f5e3Sopenharmony_ci 924514f5e3Sopenharmony_ci bool IsRequestDisabled() const 934514f5e3Sopenharmony_ci { 944514f5e3Sopenharmony_ci return enableMarkType_ == EnableConcurrentMarkType::REQUEST_DISABLE; 954514f5e3Sopenharmony_ci } 964514f5e3Sopenharmony_ci 974514f5e3Sopenharmony_ci bool IsConfigDisabled() const 984514f5e3Sopenharmony_ci { 994514f5e3Sopenharmony_ci return enableMarkType_ == EnableConcurrentMarkType::CONFIG_DISABLE; 1004514f5e3Sopenharmony_ci } 1014514f5e3Sopenharmony_ci 1024514f5e3Sopenharmony_ci bool IsTriggeredConcurrentMark() const 1034514f5e3Sopenharmony_ci { 1044514f5e3Sopenharmony_ci return isConcurrentMarking_; 1054514f5e3Sopenharmony_ci } 1064514f5e3Sopenharmony_ci void ProcessConcurrentMarkTask(uint32_t threadId); 1074514f5e3Sopenharmony_ci void Mark(); 1084514f5e3Sopenharmony_ci void Finish(); 1094514f5e3Sopenharmony_ci void ReMark(); 1104514f5e3Sopenharmony_ci 1114514f5e3Sopenharmony_ci void HandleMarkingFinished(GCReason gcReason = GCReason::ALLOCATION_LIMIT); // call in vm thread. 1124514f5e3Sopenharmony_ci void WaitMarkingFinished(); // call in main thread 1134514f5e3Sopenharmony_ci void Reset(bool revertCSet = true); 1144514f5e3Sopenharmony_ci 1154514f5e3Sopenharmony_ci double GetDuration() const 1164514f5e3Sopenharmony_ci { 1174514f5e3Sopenharmony_ci return duration_; 1184514f5e3Sopenharmony_ci } 1194514f5e3Sopenharmony_ci 1204514f5e3Sopenharmony_ci double GetHeapObjectSize() const 1214514f5e3Sopenharmony_ci { 1224514f5e3Sopenharmony_ci return heapObjectSize_; 1234514f5e3Sopenharmony_ci } 1244514f5e3Sopenharmony_ci 1254514f5e3Sopenharmony_ciprivate: 1264514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(ConcurrentMarker); 1274514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(ConcurrentMarker); 1284514f5e3Sopenharmony_ci 1294514f5e3Sopenharmony_ci class RecursionScope { 1304514f5e3Sopenharmony_ci public: 1314514f5e3Sopenharmony_ci explicit RecursionScope(ConcurrentMarker* marker) : marker_(marker) 1324514f5e3Sopenharmony_ci { 1334514f5e3Sopenharmony_ci if (marker_->recursionDepth_++ != 0) { 1344514f5e3Sopenharmony_ci LOG_GC(FATAL) << "Recursion in ConcurrentMarker Constructor, depth: " << marker_->recursionDepth_; 1354514f5e3Sopenharmony_ci } 1364514f5e3Sopenharmony_ci } 1374514f5e3Sopenharmony_ci ~RecursionScope() 1384514f5e3Sopenharmony_ci { 1394514f5e3Sopenharmony_ci if (--marker_->recursionDepth_ != 0) { 1404514f5e3Sopenharmony_ci LOG_GC(FATAL) << "Recursion in ConcurrentMarker Destructor, depth: " << marker_->recursionDepth_; 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci } 1434514f5e3Sopenharmony_ci private: 1444514f5e3Sopenharmony_ci ConcurrentMarker* marker_ {nullptr}; 1454514f5e3Sopenharmony_ci }; 1464514f5e3Sopenharmony_ci 1474514f5e3Sopenharmony_ci void SetDuration(double duration) 1484514f5e3Sopenharmony_ci { 1494514f5e3Sopenharmony_ci duration_ = duration; 1504514f5e3Sopenharmony_ci } 1514514f5e3Sopenharmony_ci 1524514f5e3Sopenharmony_ci void InitializeMarking(); 1534514f5e3Sopenharmony_ci bool ShouldNotifyMarkingFinished(); // call in GC thread. 1544514f5e3Sopenharmony_ci void FinishMarking(); // call in GC thread. 1554514f5e3Sopenharmony_ci bool VerifyAllRegionsNonFresh(); 1564514f5e3Sopenharmony_ci 1574514f5e3Sopenharmony_ci static size_t taskCounts_; 1584514f5e3Sopenharmony_ci static Mutex taskCountMutex_; 1594514f5e3Sopenharmony_ci 1604514f5e3Sopenharmony_ci Heap *heap_ {nullptr}; 1614514f5e3Sopenharmony_ci EcmaVM *vm_ {nullptr}; 1624514f5e3Sopenharmony_ci JSThread *thread_ {nullptr}; 1634514f5e3Sopenharmony_ci 1644514f5e3Sopenharmony_ci // obtained from the shared heap instance. 1654514f5e3Sopenharmony_ci WorkManager *workManager_ {nullptr}; 1664514f5e3Sopenharmony_ci size_t heapObjectSize_ {0}; 1674514f5e3Sopenharmony_ci double duration_ {0.0}; 1684514f5e3Sopenharmony_ci EnableConcurrentMarkType enableMarkType_ {EnableConcurrentMarkType::CONFIG_DISABLE}; 1694514f5e3Sopenharmony_ci 1704514f5e3Sopenharmony_ci std::atomic<int> runningTaskCount_ {0}; 1714514f5e3Sopenharmony_ci bool notifyMarkingFinished_ {false}; // Use different value from markingFinished_ to prevent JSThread waking up 1724514f5e3Sopenharmony_ci // before FinishMarking finishes. 1734514f5e3Sopenharmony_ci bool markingFinished_ {false}; 1744514f5e3Sopenharmony_ci bool isConcurrentMarking_ {false}; 1754514f5e3Sopenharmony_ci Mutex waitMarkingFinishedMutex_; 1764514f5e3Sopenharmony_ci ConditionVariable waitMarkingFinishedCV_; 1774514f5e3Sopenharmony_ci int32_t recursionDepth_ {0}; 1784514f5e3Sopenharmony_ci ClockScope clockScope_; 1794514f5e3Sopenharmony_ci 1804514f5e3Sopenharmony_ci friend class Heap; 1814514f5e3Sopenharmony_ci}; 1824514f5e3Sopenharmony_ci} // namespace panda::ecmascript 1834514f5e3Sopenharmony_ci#endif // ECMASCRIPT_MEM_CONCURRENT_MARKER_H 184