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 16 #ifndef ACCOUNTING_CARD_TABLE_H 17 #define ACCOUNTING_CARD_TABLE_H 18 19 #include <atomic> 20 #include <cstddef> 21 #include <cstdint> 22 #include <type_traits> 23 24 #include "runtime/include/mem/panda_containers.h" 25 26 namespace panda::mem { 27 28 template <typename PtrType> 29 class CardPtrIterator { 30 public: 31 using reference = PtrType &; 32 using const_reference = typename std::add_const<PtrType &>::type; 33 using pointer = PtrType *; 34 35 // NOLINTNEXTLINE(readability-identifier-naming) CardPtrIterator(PtrType c)36 explicit CardPtrIterator(PtrType c) : card_(c) {} 37 38 CardPtrIterator &operator++() 39 { 40 card_ += 1; 41 return *this; 42 } 43 44 // NOLINTNEXTLINE(cert-dcl21-cpp) 45 CardPtrIterator operator++(int) 46 { 47 CardPtrIterator retval = *this; 48 ++(*this); 49 return retval; 50 } 51 52 bool operator==(CardPtrIterator other) const 53 { 54 return card_ == other.card_; 55 } 56 57 bool operator!=(CardPtrIterator other) const 58 { 59 return !(*this == other); 60 } 61 62 const_reference operator*() const 63 { 64 return card_; 65 } 66 67 reference operator*() 68 { 69 return card_; 70 } 71 72 virtual ~CardPtrIterator() = default; 73 74 DEFAULT_COPY_SEMANTIC(CardPtrIterator); 75 NO_MOVE_SEMANTIC(CardPtrIterator); 76 77 private: 78 // NOLINTNEXTLINE(readability-identifier-naming) 79 PtrType card_; 80 }; 81 82 enum CardTableProcessedFlag : uint32_t { 83 VISIT_MARKED = 1U, // visit marked cards 84 VISIT_PROCESSED = 1U << 1U, // visit parocessed cards 85 SET_PROCESSED = 1U << 2U, // set the visited cards processed 86 }; 87 88 class CardTable { 89 public: 90 class Card; 91 using CardPtr = Card *; 92 using CardAddress = uintptr_t; 93 using Iterator = CardPtrIterator<CardPtr>; 94 using ConstIterator = CardPtrIterator<const CardPtr>; 95 96 explicit CardTable(InternalAllocatorPtr internal_allocator, uintptr_t min_address, size_t size); 97 ~CardTable(); 98 CardTable(const CardTable &other) = delete; 99 CardTable &operator=(const CardTable &other) = delete; 100 CardTable(CardTable &&other) = delete; 101 CardTable &operator=(CardTable &&other) = delete; 102 103 void Initialize(); 104 bool IsMarked(uintptr_t addr) const; // returns true if the card(for the addr) state is marked 105 void MarkCard(uintptr_t addr); // set card state to the marked 106 bool IsClear(uintptr_t addr) const; // returns true if the card(for the addr) state is clear 107 void ClearCard(uintptr_t addr); // set card state to the cleared 108 void ClearAll(); // set card state to the cleared for the all cards 109 void ClearCardRange(uintptr_t begin_addr, uintptr_t end_addr); GetCardSize()110 static constexpr uint32_t GetCardSize() 111 { 112 return CARD_SIZE; 113 } GetCardsCount()114 size_t GetCardsCount() const 115 { 116 return cards_count_; 117 } 118 119 uintptr_t GetCardStartAddress(CardPtr card) const; // returns address of the first byte in the card 120 uintptr_t GetCardEndAddress(CardPtr card) const; // returns address of the last byte in the card 121 MemRange GetMemoryRange(CardPtr card) const; // returns memory range for the card 122 123 template <typename CardVisitor> 124 void VisitMarked(CardVisitor card_visitor, uint32_t processed_flag); 125 126 template <typename CardVisitor> 127 void VisitMarkedCompact(CardVisitor card_visitor); 128 129 // NOLINTNEXTLINE(readability-identifier-naming) begin()130 Iterator begin() 131 { 132 return Iterator(cards_); 133 } 134 135 // NOLINTNEXTLINE(readability-identifier-naming) end()136 Iterator end() 137 { 138 return Iterator(cards_ + cards_count_); 139 } 140 141 // NOLINTNEXTLINE(readability-identifier-naming) begin()142 ConstIterator begin() const 143 { 144 return ConstIterator(cards_); 145 } 146 147 // NOLINTNEXTLINE(readability-identifier-naming) end()148 ConstIterator end() const 149 { 150 return ConstIterator(cards_ + cards_count_); 151 } 152 GetCardBits()153 static constexpr uint8_t GetCardBits() 154 { 155 return LOG2_CARD_SIZE; 156 } 157 GetCardDirtyValue()158 static constexpr uint8_t GetCardDirtyValue() 159 { 160 return DIRTY_CARD; 161 } 162 163 class Card { 164 public: 165 Card() = default; 166 explicit Card(uint8_t val); 167 168 bool IsMarked() const; 169 void Mark(); 170 bool IsClear() const; 171 void Clear(); 172 bool IsProcessed() const; 173 void SetProcessed(); 174 bool IsYoung() const; 175 void SetYoung(); 176 177 ~Card() = default; 178 179 NO_COPY_SEMANTIC(Card); 180 NO_MOVE_SEMANTIC(Card); 181 182 private: 183 uint8_t GetCard() const; 184 void SetCard(uint8_t new_val); 185 186 static constexpr uint8_t YOUNG_VALUE = 3; 187 static constexpr uint8_t PROCESSED_VALUE = 2; 188 static constexpr uint8_t MARKED_VALUE = 1; 189 static constexpr uint8_t CLEAR_VALUE = 0; 190 191 std::atomic_uint8_t value_ = CLEAR_VALUE; 192 }; 193 194 CardPtr GetCardPtr(uintptr_t addr) const; // returns card address for the addr 195 GetMinAddress()196 ALWAYS_INLINE uintptr_t GetMinAddress() const 197 { 198 return min_address_; 199 } 200 201 void MarkCardsAsYoung(const MemRange &mem_range); 202 203 private: 204 void ClearCards(CardPtr start, size_t card_count); 205 size_t GetSize() const; // returns size of card table array 206 inline void FillRanges(PandaVector<MemRange> *ranges, const Card *start_card, const Card *end_card); 207 208 static constexpr uint8_t LOG2_CARD_SIZE = 12; 209 static constexpr uint32_t CARD_SIZE = 1U << LOG2_CARD_SIZE; 210 static constexpr uint8_t DIRTY_CARD = 1U; 211 212 CardPtr cards_ {nullptr}; 213 uintptr_t min_address_ {0}; 214 size_t cards_count_ {0}; 215 InternalAllocatorPtr internal_allocator_ {nullptr}; 216 }; 217 218 using CardVisitor = std::function<void(CardTable::CardPtr)>; 219 220 } // namespace panda::mem 221 222 #endif // ACCOUNTING_CARD_TABLE_H 223