• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 #ifndef PANDA_RUNTIME_MEM_GC_G1_G1_GC_H
16 #define PANDA_RUNTIME_MEM_GC_G1_G1_GC_H
17 
18 #include <functional>
19 
20 #include "runtime/mem/gc/card_table.h"
21 #include "runtime/mem/gc/gc.h"
22 #include "runtime/mem/gc/gc_barrier_set.h"
23 #include "runtime/mem/gc/g1/g1-allocator.h"
24 #include "runtime/mem/gc/g1/g1-marker.h"
25 #include "runtime/mem/gc/g1/collection_set.h"
26 #include "runtime/mem/gc/generational-gc-base.h"
27 #include "runtime/mem/heap_verifier.h"
28 #include "runtime/mem/gc/g1/g1_pause_tracker.h"
29 #include "runtime/mem/gc/g1/g1_analytics.h"
30 #include "runtime/mem/gc/g1/update_remset_worker.h"
31 
32 namespace panda {
33 class ManagedThread;
34 }  // namespace panda
35 namespace panda::mem {
36 
37 /// @brief Class for reference informantion collecting for rem-sets in G1 GC
38 class RefInfo {
39 public:
40     RefInfo() = default;
41 
RefInfo(ObjectHeader * object,uint32_t refOffset)42     RefInfo(ObjectHeader *object, uint32_t refOffset) : object_(object), refOffset_(refOffset) {}
43 
44     ~RefInfo() = default;
45 
GetObject()46     ObjectHeader *GetObject() const
47     {
48         return object_;
49     }
50 
GetReferenceOffset()51     uint32_t GetReferenceOffset() const
52     {
53         return refOffset_;
54     }
55 
56     DEFAULT_COPY_SEMANTIC(RefInfo);
57     DEFAULT_MOVE_SEMANTIC(RefInfo);
58 
59 private:
60     ObjectHeader *object_;
61     uint32_t refOffset_;
62 };
63 
64 /// @brief G1 alike GC
65 template <class LanguageConfig>
66 class G1GC : public GenerationalGC<LanguageConfig> {
67     using RefVector = PandaVector<RefInfo>;
68     using ReferenceCheckPredicateT = typename GC::ReferenceCheckPredicateT;
69     using MemRangeRefsChecker = std::function<bool(const MemRange &, Region *)>;
70     template <bool VECTOR>
71     using MovedObjectsContainer = std::conditional_t<VECTOR, PandaVector<PandaVector<ObjectHeader *> *>,
72                                                      PandaVector<PandaDeque<ObjectHeader *> *>>;
73 
74 public:
75     explicit G1GC(ObjectAllocatorBase *objectAllocator, const GCSettings &settings);
76 
77     ~G1GC() override;
78 
StopGC()79     void StopGC() override
80     {
81         GC::StopGC();
82         // GC is using update_remset_worker so we need to stop GC first before we destroy the worker
83         updateRemsetWorker_->DestroyWorker();
84     }
85 
86     NO_MOVE_SEMANTIC(G1GC);
87     NO_COPY_SEMANTIC(G1GC);
88 
89     void InitGCBits(panda::ObjectHeader *objHeader) override;
90 
91     void InitGCBitsForAllocationInTLAB(panda::ObjectHeader *object) override;
92 
IsPinningSupported()93     bool IsPinningSupported() const final
94     {
95         // G1 GC supports region pinning, so G1 can pin objects
96         return true;
97     }
98 
99     void WorkerTaskProcessing(GCWorkersTask *task, void *workerData) override;
100 
101     void MarkReferences(GCMarkingStackType *references, GCPhase gcPhase) override;
102 
103     void MarkObject(ObjectHeader *object) override;
104 
105     bool MarkObjectIfNotMarked(ObjectHeader *object) override;
106 
107     bool InGCSweepRange(const ObjectHeader *object) const override;
108 
109     void OnThreadTerminate(ManagedThread *thread, mem::BuffersKeepingFlag keepBuffers) override;
110     void OnThreadCreate(ManagedThread *thread) override;
111 
112     void PreZygoteFork() override;
113     void PostZygoteFork() override;
114 
115     void OnWaitForIdleFail() override;
116 
StartGC()117     void StartGC() override
118     {
119         updateRemsetWorker_->CreateWorker();
120         GC::StartGC();
121     }
122 
HasRefFromRemset(ObjectHeader * obj)123     bool HasRefFromRemset(ObjectHeader *obj)
124     {
125         for (auto &refVector : uniqueRefsFromRemsets_) {
126             auto it = std::find_if(refVector->cbegin(), refVector->cend(),
127                                    [obj](auto ref) { return ref.GetObject() == obj; });
128             if (it != refVector->cend()) {
129                 return true;
130             }
131         }
132         return false;
133     }
134 
135     void PostponeGCStart() override;
136     void PostponeGCEnd() override;
137     bool IsPostponeGCSupported() const override;
138 
139     void StartConcurrentScopeRoutine() const override;
140     void EndConcurrentScopeRoutine() const override;
141 
142     void ComputeNewSize() override;
143     bool Trigger(PandaUniquePtr<GCTask> task) override;
144 
145 protected:
GetG1ObjectAllocator()146     ALWAYS_INLINE ObjectAllocatorG1<LanguageConfig::MT_MODE> *GetG1ObjectAllocator() const
147     {
148         return static_cast<ObjectAllocatorG1<LanguageConfig::MT_MODE> *>(this->GetObjectAllocator());
149     }
150 
151     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
152     /// Queue with updated refs info
153     GCG1BarrierSet::ThreadLocalCardQueues *updatedRefsQueue_ {nullptr};
154     os::memory::Mutex queueLock_;
155     os::memory::Mutex gcWorkerQueueLock_;
156     // NOLINTEND(misc-non-private-member-variables-in-classes)
157 
158 private:
159     void CreateUpdateRemsetWorker();
160     void ProcessDirtyCards();
161     bool HaveGarbageRegions();
162 
163     bool HaveGarbageRegions(const PandaPriorityQueue<std::pair<uint32_t, Region *>> &regions);
164 
165     template <RegionFlag REGION_TYPE, bool FULL_GC>
166     void DoRegionCompacting(Region *region, bool useGcWorkers,
167                             PandaVector<PandaVector<ObjectHeader *> *> *movedObjectsVector);
168 
169     template <bool ATOMIC, bool CONCURRENTLY>
170     void CollectNonRegularObjects();
171 
172     template <bool ATOMIC, bool CONCURRENTLY>
173     void CollectEmptyRegions(GCTask &task, PandaVector<Region *> *emptyTenuredRegions);
174 
175     template <bool ATOMIC, bool CONCURRENTLY>
176     void ClearEmptyTenuredMovableRegions(PandaVector<Region *> *emptyTenuredRegions);
177 
178     bool NeedToPromote(const Region *region) const;
179 
180     template <bool ATOMIC, RegionFlag REGION_TYPE>
181     void RegionCompactingImpl(Region *region, const ObjectVisitor &movedObjectSaver);
182 
183     template <bool ATOMIC>
184     void RegionPromotionImpl(Region *region, const ObjectVisitor &movedObjectSaver);
185 
186     // Return whether all cross region references were processed in mem_range
187     template <typename Handler>
188     void IterateOverRefsInMemRange(const MemRange &memRange, Region *region, Handler &refsHandler);
189 
190     template <typename Visitor>
191     void CacheRefsFromDirtyCards(Visitor visitor);
192 
193     void InitializeImpl() override;
194 
195     bool NeedFullGC(const panda::GCTask &task);
196 
197     bool NeedToRunGC(const panda::GCTask &task);
198 
199     void RunPhasesImpl(GCTask &task) override;
200 
201     void RunFullGC(panda::GCTask &task);
202 
203     void RunMixedGC(panda::GCTask &task, const CollectionSet &collectionSet);
204 
205     /// Determine whether GC need to run concurrent mark or mixed GC
206     bool ScheduleMixedGCAndConcurrentMark(panda::GCTask &task);
207 
208     /// Start concurrent mark
209     void RunConcurrentMark(panda::GCTask &task);
210 
211     void RunPhasesForRegions([[maybe_unused]] panda::GCTask &task, const CollectionSet &collectibleRegions);
212 
213     void PreStartupImp() override;
214 
215     void VisitCard(CardTable::CardPtr card, const ObjectVisitor &objectVisitor, const CardVisitor &cardVisitor);
216 
217     /// GC for young generation. Runs with STW.
218     void RunGC(GCTask &task, const CollectionSet &collectibleRegions);
219 
220     /// GC for tenured generation.
221     void RunTenuredGC(const GCTask &task);
222 
223     /**
224      * Mark predicate with calculation of live bytes in region
225      * @see MarkStackCond
226      *
227      * @param object marked object from marking-stack
228      *
229      * @return true
230      */
231     static void CalcLiveBytesMarkPreprocess(const ObjectHeader *object, BaseClass *baseKlass);
232 
233     /**
234      * Mark predicate with calculation of live bytes in region, not atomically
235      * @see ConcurentMarkImpl
236      *
237      * @param object marked object from marking-stack
238      */
239     static void CalcLiveBytesNotAtomicallyMarkPreprocess(const ObjectHeader *object, BaseClass *baseKlass);
240 
241     /// Caches refs from remset and marks objects in collection set (young-generation + maybe some tenured regions).
242     MemRange MixedMarkAndCacheRefs(const GCTask &task, const CollectionSet &collectibleRegions);
243 
244     /**
245      * Mark roots and add them to the stack
246      * @param objects_stack
247      * @param visit_class_roots
248      * @param visit_card_table_roots
249      */
250     void MarkRoots(GCMarkingStackType *objectsStack, CardTableVisitFlag visitCardTableRoots,
251                    VisitGCRootFlags flags = VisitGCRootFlags::ACCESS_ROOT_ALL);
252 
253     /**
254      * Initial marks roots and fill in 1st level from roots into stack.
255      * STW
256      * @param objects_stack
257      */
258     void InitialMark(GCMarkingStackType *objectsStack);
259 
260     void MarkStackMixed(GCMarkingStackType *stack);
261 
262     void MarkStackFull(GCMarkingStackType *stack);
263 
264     bool IsInCollectionSet(ObjectHeader *object);
265 
266     /**
267      * Collect dead objects in young generation and move survivors
268      * @return true if moving was success, false otherwise
269      */
270     template <bool FULL_GC>
271     bool CollectAndMove(const CollectionSet &collectionSet);
272 
273     /**
274      * Collect verification info for CollectAndMove phase
275      * @param collection_set collection set for the current phase
276      * @return instance of verifier to be used to verify for updated references
277      */
278     [[nodiscard]] HeapVerifierIntoGC<LanguageConfig> CollectVerificationInfo(const CollectionSet &collectionSet);
279 
280     /**
281      * Verify updted references
282      * @param collect_verifier instance of the verifier that was obtained before references were updated
283      * @param collection_set collection set for the current phase
284      *
285      * @see CollectVerificationInfo
286      * @see UpdateRefsToMovedObjects
287      */
288     void VerifyCollectAndMove(HeapVerifierIntoGC<LanguageConfig> &&collectVerifier, const CollectionSet &collectionSet);
289 
290     template <bool FULL_GC, bool NEED_LOCK>
291     std::conditional_t<FULL_GC, UpdateRemsetRefUpdater<LanguageConfig, NEED_LOCK>,
292                        EnqueueRemsetRefUpdater<LanguageConfig>>
293     CreateRefUpdater(GCG1BarrierSet::ThreadLocalCardQueues *updatedRefQueue) const;
294 
295     /// Update all refs to moved objects
296     template <bool FULL_GC, bool USE_WORKERS>
297     void UpdateRefsToMovedObjects(MovedObjectsContainer<FULL_GC> *movedObjectsContainer);
298 
299     void Sweep();
300 
301     bool IsMarked(const ObjectHeader *object) const override;
302 
303     /// Start process of on pause marking
304     void FullMarking(panda::GCTask &task);
305 
306     /**
307      * Marking all objects on pause
308      * @param task gc task for current GC
309      * @param objects_stack stack for marked objects
310      * @param use_gc_workers whether do marking in parallel
311      */
312     void OnPauseMark(GCTask &task, GCMarkingStackType *objectsStack, bool useGcWorkers);
313 
314     /// Start process of concurrent marking
315     void ConcurrentMarking(panda::GCTask &task);
316 
317     /// Iterate over roots and mark them concurrently
318     NO_THREAD_SAFETY_ANALYSIS void ConcurentMarkImpl(GCMarkingStackType *objectsStack);
319 
320     void PauseTimeGoalDelay();
321 
322     void InitialMark(GCMarkingStackType &markingStack);
323 
324     /*
325      * Mark the heap in concurrent mode and calculate live bytes
326      */
327     void ConcurrentMark(GCMarkingStackType *objectsStack);
328 
329     /// ReMarks objects after Concurrent marking and actualize information about live bytes
330     void Remark(panda::GCTask const &task);
331 
332     /// Sweep VM refs for non-regular (humongous + nonmovable) objects
333     void SweepNonRegularVmRefs();
334 
335     void SweepRegularVmRefs();
336 
337     /// Return collectible regions
338     CollectionSet GetCollectibleRegions(panda::GCTask const &task, bool isMixed);
339     void AddOldRegionsMaxAllowed(CollectionSet &collectionSet);
340     void AddOldRegionsAccordingPauseTimeGoal(CollectionSet &collectionSet);
341 
342     CollectionSet GetFullCollectionSet();
343 
344     void UpdateCollectionSet(const CollectionSet &collectibleRegions);
345 
346     /// Estimate space in tenured to objects from collectible regions
347     bool HaveEnoughSpaceToMove(const CollectionSet &collectibleRegions);
348 
349     /// Check if we have enough free regions in tenured space
350     bool HaveEnoughRegionsToMove(size_t num);
351 
352     /**
353      * Add data from SATB buffer to the object stack
354      * @param object_stack - stack to add data to
355      */
356     void DrainSatb(GCAdaptiveStack *objectStack);
357 
358     void HandlePendingDirtyCards();
359 
360     void ReenqueueDirtyCards();
361 
362     void ClearSatb();
363 
364     /**
365      * Iterate over object references in rem sets.
366      * The Visitor is a functor which accepts an object (referee), the reference value,
367      * offset of the reference in the object and the flag whether the reference is volatile.
368      * The visitor can be called for the references to the collection set in the object or
369      * for all references in an object which has at least one reference to the collection set.
370      * The decision is implementation dependent.
371      */
372     template <class Visitor>
373     void VisitRemSets(const Visitor &visitor);
374 
375     template <class Visitor>
376     void UpdateRefsFromRemSets(const Visitor &visitor);
377 
378     MemRange CacheRefsFromRemsets(const MemRangeRefsChecker &refsChecker);
379 
380     void ClearRefsFromRemsetsCache();
381 
382     void ActualizeRemSets();
383 
384     bool ShouldRunTenuredGC(const GCTask &task) override;
385 
386     void RestoreYoungCards(const CollectionSet &collectionSet);
387 
388     void ClearYoungCards(const CollectionSet &collectionSet);
389 
390     void ClearDirtyAndYoungCards(const MemRange &dirtyCardsRange);
391 
392     size_t GetMaxMixedRegionsCount();
393 
394     void PrepareYoungRegionsForFullGC(const CollectionSet &collectionSet);
395 
396     void RestoreYoungRegionsAfterFullGC(const CollectionSet &collectionSet);
397 
398     template <typename Container>
399     void BuildCrossYoungRemSets(const Container &young);
400 
401     size_t CalculateDesiredEdenLengthByPauseDelay();
402     size_t CalculateDesiredEdenLengthByPauseDuration();
403 
404     template <bool ENABLE_BARRIER>
405     void UpdatePreWrbEntrypointInThreads();
406 
EnablePreWrbInThreads()407     void EnablePreWrbInThreads()
408     {
409         UpdatePreWrbEntrypointInThreads<true>();
410     }
411 
DisablePreWrbInThreads()412     void DisablePreWrbInThreads()
413     {
414         UpdatePreWrbEntrypointInThreads<false>();
415     }
416 
417     void EnsurePreWrbDisabledInThreads();
418 
419     G1GCPauseMarker<LanguageConfig> marker_;
420     G1GCConcurrentMarker<LanguageConfig> concMarker_;
421     G1GCMixedMarker<LanguageConfig> mixedMarker_;
422     /// Flag indicates if we currently in concurrent marking phase
423     std::atomic<bool> concurrentMarkingFlag_ {false};
424     /// Flag indicates if we need to interrupt concurrent marking
425     std::atomic<bool> interruptConcurrentFlag_ {false};
426     /// Function called in the post WRB
427     std::function<void(const void *, const void *)> postQueueFunc_ {nullptr};
428     /// Current pre WRB entrypoint: either nullptr or the real function
429     ObjRefProcessFunc currentPreWrbEntrypoint_ {nullptr};
430     /**
431      * After first process it stores humongous objects only, after marking them it's still store them for updating
432      * pointers from Humongous
433      */
GUARDED_BY(satbAndNewobjBufLock_)434     PandaList<PandaVector<ObjectHeader *> *> satbBuffList_ GUARDED_BY(satbAndNewobjBufLock_) {};
435     PandaVector<ObjectHeader *> newobjBuffer_ GUARDED_BY(satbAndNewobjBufLock_);
436     // The lock guards both variables: satb_buff_list_ and newobj_buffer_
437     os::memory::Mutex satbAndNewobjBufLock_;
438     UpdateRemsetWorker<LanguageConfig> *updateRemsetWorker_ {nullptr};
439     GCMarkingStackType concurrentMarkingStack_;
440     GCMarkingStackType::MarkedObjects mixedMarkedObjects_;
441     std::atomic<bool> isMixedGcRequired_ {false};
442     /// Number of tenured regions added at the young GC
443     size_t numberOfMixedTenuredRegions_ {2};
444     double regionGarbageRateThreshold_ {0.0};
445     double g1PromotionRegionAliveRate_ {0.0};
446     bool g1TrackFreedObjects_ {false};
447     bool isExplicitConcurrentGcEnabled_ {false};
448     CollectionSet collectionSet_;
449     // Max size of unique_refs_from_remsets_ buffer. It should be enough to store
450     // almost all references to the collection set.
451     // But any way there may be humongous arrays which contains a lot of references to the collection set.
452     // For such objects GC created a new RefVector, which will be cleared at the end of the collections.
453     static constexpr size_t MAX_REFS = 1024;
454     // Storages for references from remsets to the collection set.
455     // List elements have RefVector inside, with double size compare to previous one (starts from MAX_REFS)
456     // Each vector element contains an object from the remset and the offset of
457     // the field which refers to the collection set.
458     PandaList<RefVector *> uniqueRefsFromRemsets_;
459     // Dirty cards which are not fully processed before collection.
460     // These cards are processed later.
461     PandaUnorderedSet<CardTable::CardPtr> dirtyCards_;
462 #ifndef NDEBUG
463     bool uniqueCardsInitialized_ = false;
464 #endif  // NDEBUG
465     size_t regionSizeBits_;
466     G1PauseTracker g1PauseTracker_;
467     os::memory::Mutex concurrentMarkMutex_;
468     os::memory::Mutex mixedMarkedObjectsMutex_;
469     os::memory::ConditionVariable concurrentMarkCondVar_;
470     G1Analytics analytics_;
471 
472     template <class>
473     friend class RefCacheBuilder;
474     friend class G1GCTest;
475     friend class RemSetChecker;
476 };
477 
478 template <MTModeT MT_MODE>
479 class AllocConfig<GCType::G1_GC, MT_MODE> {
480 public:
481     using ObjectAllocatorType = ObjectAllocatorG1<MT_MODE>;
482     using CodeAllocatorType = CodeAllocator;
483 };
484 
485 }  // namespace panda::mem
486 
487 #endif  // PANDA_RUNTIME_MEM_GC_G1_G1_GC_H
488