• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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