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 *>> ®ions); 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