• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 ark {
33 class ManagedThread;
34 }  // namespace ark
35 namespace ark::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(Region *, const MemRange &)>;
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(ark::ObjectHeader *objHeader) override;
90 
91     void InitGCBitsForAllocationInTLAB(ark::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     size_t GetOldCollectionSetCandidatesNumber();
163 
164     bool HaveGarbageRegions(const PandaPriorityQueue<std::pair<uint32_t, Region *>> &regions);
165 
166     template <RegionFlag REGION_TYPE, bool FULL_GC>
167     void DoRegionCompacting(Region *region, bool useGcWorkers,
168                             PandaVector<PandaVector<ObjectHeader *> *> *movedObjectsVector);
169 
170     template <bool ATOMIC, bool CONCURRENTLY>
171     void CollectNonRegularObjects();
172 
173     template <bool ATOMIC, bool CONCURRENTLY>
174     void CollectEmptyRegions(GCTask &task, PandaVector<Region *> *emptyTenuredRegions);
175 
176     template <bool ATOMIC, bool CONCURRENTLY>
177     void ClearEmptyTenuredMovableRegions(PandaVector<Region *> *emptyTenuredRegions);
178 
179     bool NeedToPromote(const Region *region) const;
180 
181     template <bool ATOMIC, RegionFlag REGION_TYPE>
182     void RegionCompactingImpl(Region *region, const ObjectVisitor &movedObjectSaver);
183 
184     template <bool ATOMIC>
185     void RegionPromotionImpl(Region *region, const ObjectVisitor &movedObjectSaver);
186 
187     // Return whether all cross region references were processed in mem_range
188     template <typename Handler>
189     void IterateOverRefsInMemRange(const MemRange &memRange, Region *region, Handler &refsHandler);
190 
191     template <typename Visitor>
192     void CacheRefsFromDirtyCards(GlobalRemSet &globalRemSet, Visitor visitor);
193 
194     void InitializeImpl() override;
195 
196     bool NeedFullGC(const ark::GCTask &task);
197 
198     bool NeedToRunGC(const ark::GCTask &task);
199 
200     void RunPhasesImpl(GCTask &task) override;
201 
202     void RunFullGC(ark::GCTask &task);
203     void TryRunMixedGC(ark::GCTask &task);
204     void CollectAndMoveTenuredRegions(const CollectionSet &collectionSet);
205     void CollectAndMoveYoungRegions(const CollectionSet &collectionSet);
206 
207     void RunMixedGC(ark::GCTask &task, const CollectionSet &collectionSet);
208 
209     /// Determine whether GC need to run concurrent mark or mixed GC
210     bool ScheduleMixedGCAndConcurrentMark(ark::GCTask &task);
211 
212     /// Start concurrent mark
213     void RunConcurrentMark(ark::GCTask &task);
214 
215     void RunPhasesForRegions([[maybe_unused]] ark::GCTask &task, const CollectionSet &collectibleRegions);
216 
217     void PreStartupImp() override;
218 
219     void VisitCard(CardTable::CardPtr card, const ObjectVisitor &objectVisitor, const CardVisitor &cardVisitor);
220 
221     /// GC for young generation. Runs with STW.
222     void RunGC(GCTask &task, const CollectionSet &collectibleRegions);
223 
224     /**
225      * Return true if garbage can be collected in single pass (VM supports it, no pinned objects, GC is not postponed
226      * etc) otherwise false
227      */
228     bool SinglePassCompactionAvailable();
229     void EvacuateCollectionSet(const GCTask &task);
230     void MergeRemSet(RemSet<> *remset);
231     void HandleReferences(const GCTask &task);
232     void ResetRegionAfterMixedGC();
233 
234     /// GC for tenured generation.
235     void RunTenuredGC(const GCTask &task);
236 
237     /**
238      * Mark predicate with calculation of live bytes in region
239      * @see MarkStackCond
240      *
241      * @param object marked object from marking-stack
242      *
243      * @return true
244      */
245     static void CalcLiveBytesMarkPreprocess(const ObjectHeader *object, BaseClass *baseKlass);
246 
247     /**
248      * Mark predicate with calculation of live bytes in region, not atomically
249      * @see ConcurentMarkImpl
250      *
251      * @param object marked object from marking-stack
252      */
253     static void CalcLiveBytesNotAtomicallyMarkPreprocess(const ObjectHeader *object, BaseClass *baseKlass);
254 
255     /// Caches refs from remset and marks objects in collection set (young-generation + maybe some tenured regions).
256     void MixedMarkAndCacheRefs(const GCTask &task, const CollectionSet &collectibleRegions);
257 
258     /**
259      * Mark roots and add them to the stack
260      * @param objects_stack
261      * @param visit_class_roots
262      * @param visit_card_table_roots
263      */
264     void MarkRoots(GCMarkingStackType *objectsStack, CardTableVisitFlag visitCardTableRoots,
265                    VisitGCRootFlags flags = VisitGCRootFlags::ACCESS_ROOT_ALL);
266 
267     /**
268      * Initial marks roots and fill in 1st level from roots into stack.
269      * STW
270      * @param objects_stack
271      */
272     void InitialMark(GCMarkingStackType *objectsStack);
273 
274     void MarkStackMixed(GCMarkingStackType *stack);
275 
276     void MarkStackFull(GCMarkingStackType *stack);
277 
278     bool IsInCollectionSet(ObjectHeader *object);
279 
280     template <bool FULL_GC>
281     void UpdateRefsAndClear(const CollectionSet &collectionSet, MovedObjectsContainer<FULL_GC> *movedObjectsContainer,
282                             PandaVector<PandaVector<ObjectHeader *> *> *movedObjectsVector,
283                             HeapVerifierIntoGC<LanguageConfig> *collectVerifier);
284 
285     /**
286      * Collect dead objects in young generation and move survivors
287      * @return true if moving was success, false otherwise
288      */
289     template <bool FULL_GC>
290     bool CollectAndMove(const CollectionSet &collectionSet);
291 
292     /**
293      * Collect verification info for CollectAndMove phase
294      * @param collection_set collection set for the current phase
295      * @return instance of verifier to be used to verify for updated references
296      */
297     [[nodiscard]] HeapVerifierIntoGC<LanguageConfig> CollectVerificationInfo(const CollectionSet &collectionSet);
298 
299     /**
300      * Verify updted references
301      * @param collect_verifier instance of the verifier that was obtained before references were updated
302      * @param collection_set collection set for the current phase
303      *
304      * @see CollectVerificationInfo
305      * @see UpdateRefsToMovedObjects
306      */
307     void VerifyCollectAndMove(HeapVerifierIntoGC<LanguageConfig> &&collectVerifier, const CollectionSet &collectionSet);
308 
309     template <bool FULL_GC, bool NEED_LOCK>
310     std::conditional_t<FULL_GC, UpdateRemsetRefUpdater<LanguageConfig, NEED_LOCK>,
311                        EnqueueRemsetRefUpdater<LanguageConfig>>
312     CreateRefUpdater(GCG1BarrierSet::ThreadLocalCardQueues *updatedRefQueue) const;
313 
314     template <class ObjectsContainer>
315     void ProcessMovedObjects(ObjectsContainer *movedObjects);
316 
317     /// Update refs to objects which were moved while garbage collection
318     template <bool FULL_GC, bool ENABLE_WORKERS, class Visitor>
319     void UpdateMovedObjectsReferences(MovedObjectsContainer<FULL_GC> *movedObjectsContainer, const Visitor &refUpdater);
320 
321     /// Update all refs to moved objects
322     template <bool FULL_GC, bool USE_WORKERS>
323     void UpdateRefsToMovedObjects(MovedObjectsContainer<FULL_GC> *movedObjectsContainer);
324 
325     void Sweep();
326 
327     bool IsMarked(const ObjectHeader *object) const override;
328 
329     /// Start process of on pause marking
330     void FullMarking(ark::GCTask &task);
331 
332     /**
333      * Marking all objects on pause
334      * @param task gc task for current GC
335      * @param objects_stack stack for marked objects
336      * @param use_gc_workers whether do marking in parallel
337      */
338     void OnPauseMark(GCTask &task, GCMarkingStackType *objectsStack, bool useGcWorkers);
339 
340     /// Start process of concurrent marking
341     void ConcurrentMarking(ark::GCTask &task);
342 
343     /// Iterate over roots and mark them concurrently
344     NO_THREAD_SAFETY_ANALYSIS void ConcurentMarkImpl(GCMarkingStackType *objectsStack);
345 
346     void PauseTimeGoalDelay();
347 
348     void InitialMark(GCMarkingStackType &markingStack);
349 
350     /*
351      * Mark the heap in concurrent mode and calculate live bytes
352      */
353     void ConcurrentMark(GCMarkingStackType *objectsStack);
354 
355     /// ReMarks objects after Concurrent marking and actualize information about live bytes
356     void Remark(ark::GCTask const &task);
357 
358     /// Sweep VM refs for non-regular (humongous + nonmovable) objects
359     void SweepNonRegularVmRefs();
360 
361     void SweepRegularVmRefs();
362 
363     /// Return collectible regions
364     CollectionSet GetCollectibleRegions(ark::GCTask const &task, bool isMixed);
365     void AddOldRegionsMaxAllowed(CollectionSet &collectionSet);
366     void AddOldRegionsAccordingPauseTimeGoal(CollectionSet &collectionSet);
367     uint64_t AddMoreOldRegionsAccordingPauseTimeGoal(CollectionSet &collectionSet,
368                                                      PandaPriorityQueue<std::pair<uint32_t, Region *>> candidates,
369                                                      uint64_t gcPauseTimeBudget);
370     void ReleasePagesInFreePools();
371 
372     CollectionSet GetFullCollectionSet();
373 
374     void UpdateCollectionSet(const CollectionSet &collectibleRegions);
375 
376     /// Interrupts release pages if the process is running
377     void InterruptReleasePagesIfNeeded();
378 
379     /**
380      * Starts release pages if the current status
381      *  of releasePagesInterruptFlag_ equals @param oldStatus
382      * @param oldStatus estimated status of releasePagesInterruptFlag_
383      */
384     void StartReleasePagesIfNeeded(ReleasePagesStatus oldStatus);
385 
386     /// Estimate space in tenured to objects from collectible regions
387     bool HaveEnoughSpaceToMove(const CollectionSet &collectibleRegions);
388 
389     /// Check if we have enough free regions in tenured space
390     bool HaveEnoughRegionsToMove(size_t num);
391 
392     /**
393      * Add data from SATB buffer to the object stack
394      * @param object_stack - stack to add data to
395      */
396     void DrainSatb(GCAdaptiveStack *objectStack);
397 
398     void HandlePendingDirtyCards();
399 
400     void ReenqueueDirtyCards();
401 
402     void ClearSatb();
403 
404     /**
405      * Iterate over object references in rem sets.
406      * The Visitor is a functor which accepts an object (referee), the reference value,
407      * offset of the reference in the object and the flag whether the reference is volatile.
408      * The visitor can be called for the references to the collection set in the object or
409      * for all references in an object which has at least one reference to the collection set.
410      * The decision is implementation dependent.
411      */
412     template <class Visitor>
413     void VisitRemSets(const Visitor &visitor);
414 
415     template <class Visitor>
416     void UpdateRefsFromRemSets(const Visitor &visitor);
417 
418     void CacheRefsFromRemsets(const MemRangeRefsChecker &refsChecker);
419     bool IsCollectionSetFullyPromoted() const;
420 
421     void ClearRefsFromRemsetsCache();
422 
423     void ActualizeRemSets();
424 
425     bool ShouldRunTenuredGC(const GCTask &task) override;
426 
427     void RestoreYoungCards(const CollectionSet &collectionSet);
428 
429     void ClearYoungCards(const CollectionSet &collectionSet);
430 
431     void ClearTenuredCards(const CollectionSet &collectionSet);
432 
433     size_t GetMaxMixedRegionsCount();
434 
435     void PrepareYoungRegionsForFullGC(const CollectionSet &collectionSet);
436 
437     void RestoreYoungRegionsAfterFullGC(const CollectionSet &collectionSet);
438 
439     template <typename Container>
440     void BuildCrossYoungRemSets(const Container &young);
441 
442     size_t CalculateDesiredEdenLengthByPauseDelay();
443     size_t CalculateDesiredEdenLengthByPauseDuration();
444 
445     template <bool ENABLE_BARRIER>
446     void UpdatePreWrbEntrypointInThreads();
447 
EnablePreWrbInThreads()448     void EnablePreWrbInThreads()
449     {
450         UpdatePreWrbEntrypointInThreads<true>();
451     }
452 
DisablePreWrbInThreads()453     void DisablePreWrbInThreads()
454     {
455         UpdatePreWrbEntrypointInThreads<false>();
456     }
457 
458     void EnsurePreWrbDisabledInThreads();
459 
460     size_t GetUniqueRemsetRefsCount() const;
461 
462     G1GCPauseMarker<LanguageConfig> marker_;
463     G1GCConcurrentMarker<LanguageConfig> concMarker_;
464     G1GCMixedMarker<LanguageConfig> mixedMarker_;
465     /// Flag indicates if we currently in concurrent marking phase
466     std::atomic<bool> concurrentMarkingFlag_ {false};
467     /// Flag indicates if we need to interrupt concurrent marking
468     std::atomic<bool> interruptConcurrentFlag_ {false};
469     /// Function called in the post WRB
470     std::function<void(const void *, const void *)> postQueueFunc_ {nullptr};
471     /// Current pre WRB entrypoint: either nullptr or the real function
472     ObjRefProcessFunc currentPreWrbEntrypoint_ {nullptr};
473     /**
474      * After first process it stores humongous objects only, after marking them it's still store them for updating
475      * pointers from Humongous
476      */
GUARDED_BY(satbAndNewobjBufLock_)477     PandaList<PandaVector<ObjectHeader *> *> satbBuffList_ GUARDED_BY(satbAndNewobjBufLock_) {};
478     PandaVector<ObjectHeader *> newobjBuffer_ GUARDED_BY(satbAndNewobjBufLock_);
479     // The lock guards both variables: satb_buff_list_ and newobj_buffer_
480     os::memory::Mutex satbAndNewobjBufLock_;
481     UpdateRemsetWorker<LanguageConfig> *updateRemsetWorker_ {nullptr};
482     GCMarkingStackType concurrentMarkingStack_;
483     GCMarkingStackType::MarkedObjects mixedMarkedObjects_;
484     std::atomic<bool> isMixedGcRequired_ {false};
485     /// Number of tenured regions added at the young GC
486     size_t numberOfMixedTenuredRegions_ {2};
487     double regionGarbageRateThreshold_ {0.0};
488     double g1PromotionRegionAliveRate_ {0.0};
489     bool g1TrackFreedObjects_ {false};
490     bool isExplicitConcurrentGcEnabled_ {false};
491     CollectionSet collectionSet_;
492     // Max size of unique_refs_from_remsets_ buffer. It should be enough to store
493     // almost all references to the collection set.
494     // But any way there may be humongous arrays which contains a lot of references to the collection set.
495     // For such objects GC created a new RefVector, which will be cleared at the end of the collections.
496     static constexpr size_t MAX_REFS = 1024;
497     // Storages for references from remsets to the collection set.
498     // List elements have RefVector inside, with double size compare to previous one (starts from MAX_REFS)
499     // Each vector element contains an object from the remset and the offset of
500     // the field which refers to the collection set.
501     PandaList<RefVector *> uniqueRefsFromRemsets_;
502     // Dirty cards which are not fully processed before collection.
503     // These cards are processed later.
504     PandaUnorderedSet<CardTable::CardPtr> dirtyCards_;
505 #ifndef NDEBUG
506     bool uniqueCardsInitialized_ = false;
507 #endif  // NDEBUG
508     size_t regionSizeBits_;
509     G1PauseTracker g1PauseTracker_;
510     os::memory::Mutex concurrentMarkMutex_;
511     os::memory::Mutex mixedMarkedObjectsMutex_;
512     os::memory::ConditionVariable concurrentMarkCondVar_;
513     G1Analytics analytics_;
514 
515     /// Flag indicates if we need to interrupt release physical pages to OS
516     std::atomic<ReleasePagesStatus> releasePagesInterruptFlag_ {ReleasePagesStatus::FINISHED};
517 
518     template <class>
519     friend class RefCacheBuilder;
520     friend class G1GCTest;
521     friend class RemSetChecker;
522     template <class>
523     friend class G1EvacuateRegionsWorkerState;
524 };
525 
526 template <MTModeT MT_MODE>
527 class AllocConfig<GCType::G1_GC, MT_MODE> {
528 public:
529     using ObjectAllocatorType = ObjectAllocatorG1<MT_MODE>;
530     using CodeAllocatorType = CodeAllocator;
531 };
532 
533 }  // namespace ark::mem
534 
535 #endif  // PANDA_RUNTIME_MEM_GC_G1_G1_GC_H
536