1 /* 2 * Copyright (c) 2025 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 COMMON_COMPONENTS_HEAP_COLLECTOR_REGION_RSET_H 17 #define COMMON_COMPONENTS_HEAP_COLLECTOR_REGION_RSET_H 18 19 #include <atomic> 20 #include <errno.h> 21 22 namespace common { 23 class RegionRSet { 24 public: 25 static constexpr size_t CARD_SIZE = 512; 26 using CardElement = uint64_t; 27 static_assert(std::atomic<CardElement>::is_always_lock_free); 28 static constexpr size_t CARD_TABLE_DATA_OFFSET = AlignUp<size_t>(sizeof(size_t), sizeof(CardElement)); 29 CreateRegionRSet(size_t regionSize)30 static RegionRSet *CreateRegionRSet(size_t regionSize) 31 { 32 CHECK_CC(regionSize % CARD_SIZE == 0); 33 size_t cardCnt = regionSize / CARD_SIZE; 34 size_t cardSize = cardCnt * sizeof(CardElement); 35 void *ptr = malloc(CARD_TABLE_DATA_OFFSET + cardSize); 36 if (ptr == nullptr) { 37 LOG_COMMON(FATAL) << "malloc failed, regionSize=" << regionSize << ", cardSize=" << cardSize 38 << ", errnor=" << errno; 39 UNREACHABLE(); 40 } 41 RegionRSet *rset = new (ptr) RegionRSet(cardCnt); 42 rset->ClearCardTable(); 43 return rset; 44 } 45 DestroyRegionRSet(RegionRSet * rset)46 static void DestroyRegionRSet(RegionRSet *rset) 47 { 48 free(rset); 49 } 50 MarkCardTable(size_t offset)51 bool MarkCardTable(size_t offset) 52 { 53 size_t cardIdx = (offset / kMarkedBytesPerBit) / kBitsPerWord; 54 size_t headMaskBitStart = (offset / kMarkedBytesPerBit) % kBitsPerWord; 55 CardElement headMaskBits = static_cast<CardElement>(1ULL << headMaskBitStart); 56 std::atomic<CardElement> *card = reinterpret_cast<std::atomic<CardElement> *>(&GetCardTable()[cardIdx]); 57 bool isMarked = ((card->load(std::memory_order_relaxed) & headMaskBits) != 0); 58 if (!isMarked) { 59 CardElement prev = card->fetch_or(headMaskBits, std::memory_order_relaxed); 60 isMarked = ((prev & headMaskBits) != 0); 61 return isMarked; 62 } 63 return true; 64 } 65 ClearCardTable()66 void ClearCardTable() 67 { 68 LOGF_CHECK(memset_s(GetCardTable(), cardCnt_ * sizeof(CardElement), 0, cardCnt_ * sizeof(CardElement)) == EOK) 69 << "memset_s fail, cardCnt=" << cardCnt_; 70 } 71 VisitAllMarkedCardBefore(const std::function<void (BaseObject *)> & func,HeapAddress regionStart,HeapAddress end)72 void VisitAllMarkedCardBefore(const std::function<void(BaseObject*)>& func, 73 HeapAddress regionStart, HeapAddress end) 74 { 75 for (size_t i = 0; i < cardCnt_; i++) { 76 CardElement card = GetCardTable()[i]; 77 size_t index = kBitsPerWord; 78 while (card != 0) { 79 index = static_cast<size_t>(__builtin_ctzll(card)); 80 ASSERT(index < kBitsPerWord); 81 HeapAddress offset = static_cast<HeapAddress>((i * kBitsPerWord) * kBitsPerByte + index * kBitsPerByte); 82 HeapAddress obj = regionStart + offset; 83 if (obj >= end) { 84 return; 85 } 86 func(reinterpret_cast<BaseObject*>(obj)); 87 card &= ~(static_cast<CardElement>(1ULL << index)); 88 } 89 } 90 } 91 private: RegionRSet(size_t cardCnt)92 explicit RegionRSet(size_t cardCnt) : cardCnt_(cardCnt) {} 93 ~RegionRSet() = default; 94 GetCardTable()95 CardElement *GetCardTable() const 96 { 97 return reinterpret_cast<CardElement *>(reinterpret_cast<uintptr_t>(this) + CARD_TABLE_DATA_OFFSET); 98 } 99 100 size_t cardCnt_ {0}; 101 }; 102 103 static_assert(RegionRSet::CARD_TABLE_DATA_OFFSET == AlignUp<size_t>(sizeof(RegionRSet), 104 sizeof(RegionRSet::CardElement))); 105 } 106 #endif // COMMON_COMPONENTS_HEAP_COLLECTOR_REGION_RSET_H 107