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