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