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_GC_BARRIER_H 16 #define PANDA_GC_BARRIER_H 17 18 #include "libpandabase/mem/gc_barrier.h" 19 #include "libpandabase/mem/ringbuf/lock_free_ring_buffer.h" 20 #include "runtime/include/mem/panda_containers.h" 21 #include "runtime/include/mem/panda_string.h" 22 #include "runtime/mem/gc/card_table.h" 23 24 namespace ark::mem { 25 26 /// Base barrier set 27 class GCBarrierSet { 28 public: 29 GCBarrierSet() = delete; GCBarrierSet(mem::InternalAllocatorPtr allocator,BarrierType preType,BarrierType postType)30 GCBarrierSet(mem::InternalAllocatorPtr allocator, BarrierType preType, BarrierType postType) 31 : preType_(preType), 32 postType_(postType), 33 preOperands_(allocator->Adapter()), 34 postOperands_(allocator->Adapter()) 35 { 36 } 37 38 NO_COPY_SEMANTIC(GCBarrierSet); 39 NO_MOVE_SEMANTIC(GCBarrierSet); 40 virtual ~GCBarrierSet() = 0; 41 GetPreType()42 BarrierType GetPreType() const 43 { 44 ASSERT(IsPreBarrier(preType_)); 45 return preType_; 46 } 47 GetPostType()48 BarrierType GetPostType() const 49 { 50 ASSERT(IsPostBarrier(postType_)); 51 return postType_; 52 } 53 IsPreBarrierEnabled()54 virtual bool IsPreBarrierEnabled() 55 { 56 return !mem::IsEmptyBarrier(preType_); 57 } 58 59 /** 60 * Pre barrier. Used by interpreter. 61 * @param pre_val_addr - reference currently(before store/load happened) stored in the field 62 */ 63 virtual void PreBarrier(void *preValAddr) = 0; 64 65 /** 66 * Post barrier. Used by interpeter. 67 * @param obj_addr - address of object whose field we change 68 * @param offset - field offset 69 * @param val_addr - reference stored into or loaded from the field 70 */ 71 virtual void PostBarrier(const void *objAddr, size_t offset, void *valAddr) = 0; 72 73 /** 74 * Post barrier for range write. Used by interpeter. 75 * @param obj_addr - address of the object 76 * @param offset - offset from obj_addr 77 * @param count - written bytes count 78 */ 79 virtual void PostBarrier(const void *objAddr, size_t offset, size_t count) = 0; 80 81 /** 82 * Get barrier operand (literal, function pointer, address etc. See enum BarrierType for details. 83 * Should be used for barrier generation in Compiler. 84 * @param name - string with name of operand 85 * @return barrier operand (value is address or literal) 86 */ 87 BarrierOperand GetBarrierOperand(BarrierPosition barrierPosition, std::string_view name); 88 89 BarrierOperand GetPostBarrierOperand(std::string_view name); 90 91 protected: 92 /** 93 * Add barrier operand if there are no operands with this name 94 * @param barrier_position - pre or post position of barrier with added operand 95 * @param name - name of operand 96 * @param barrier_operand - operand 97 */ AddBarrierOperand(BarrierPosition barrierPosition,std::string_view name,const BarrierOperand & barrierOperand)98 void AddBarrierOperand(BarrierPosition barrierPosition, std::string_view name, const BarrierOperand &barrierOperand) 99 { 100 if (barrierPosition == BarrierPosition::BARRIER_POSITION_PRE) { 101 ASSERT(preOperands_.find(name) == preOperands_.end()); 102 preOperands_.insert({name.data(), barrierOperand}); 103 } else { 104 ASSERT(barrierPosition == BarrierPosition::BARRIER_POSITION_POST); 105 ASSERT(postOperands_.find(name) == postOperands_.end()); 106 postOperands_.insert({name.data(), barrierOperand}); 107 } 108 } 109 110 private: 111 BarrierType preType_; // Type of PRE barrier. 112 BarrierType postType_; // Type of POST barrier. 113 PandaMap<PandaString, BarrierOperand> preOperands_; 114 PandaMap<PandaString, BarrierOperand> postOperands_; 115 }; 116 117 /// BarrierSet with barriers do nothing 118 class GCDummyBarrierSet : public GCBarrierSet { 119 public: GCDummyBarrierSet(mem::InternalAllocatorPtr allocator)120 explicit GCDummyBarrierSet(mem::InternalAllocatorPtr allocator) 121 : GCBarrierSet(allocator, BarrierType::PRE_WRB_NONE, BarrierType::POST_WRB_NONE) 122 { 123 } 124 125 NO_COPY_SEMANTIC(GCDummyBarrierSet); 126 NO_MOVE_SEMANTIC(GCDummyBarrierSet); 127 ~GCDummyBarrierSet() override = default; 128 PreBarrier(void * preValAddr)129 void PreBarrier([[maybe_unused]] void *preValAddr) override {} 130 PostBarrier(const void * objAddr,size_t offset,void * storedValAddr)131 void PostBarrier([[maybe_unused]] const void *objAddr, [[maybe_unused]] size_t offset, 132 [[maybe_unused]] void *storedValAddr) override 133 { 134 } 135 PostBarrier(const void * objAddr,size_t offset,size_t count)136 void PostBarrier([[maybe_unused]] const void *objAddr, [[maybe_unused]] size_t offset, 137 [[maybe_unused]] size_t count) override 138 { 139 } 140 }; 141 142 class GCGenBarrierSet : public GCBarrierSet { 143 public: GCGenBarrierSet(mem::InternalAllocatorPtr allocator,CardTable * cardTable,uint8_t cardBits,uint8_t dirtyCardValue)144 GCGenBarrierSet(mem::InternalAllocatorPtr allocator, 145 /* POST ARGS: */ 146 CardTable *cardTable, uint8_t cardBits, uint8_t dirtyCardValue) 147 : GCBarrierSet(allocator, BarrierType::PRE_WRB_NONE, BarrierType::POST_INTERGENERATIONAL_BARRIER), 148 minAddr_(ToVoidPtr(cardTable->GetMinAddress())), 149 cardTableAddr_(reinterpret_cast<uint8_t *>(*cardTable->begin())), 150 cardBits_(cardBits), 151 dirtyCardValue_(dirtyCardValue), 152 cardTable_(cardTable) 153 { 154 // POST 155 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "MIN_ADDR", 156 BarrierOperand(BarrierOperandType::ADDRESS, BarrierOperandValue(minAddr_))); 157 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "CARD_TABLE_ADDR", 158 BarrierOperand(BarrierOperandType::UINT8_ADDRESS, BarrierOperandValue(cardTableAddr_))); 159 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "CARD_BITS", 160 BarrierOperand(BarrierOperandType::UINT8_LITERAL, BarrierOperandValue(cardBits))); 161 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "DIRTY_VAL", 162 BarrierOperand(BarrierOperandType::UINT8_LITERAL, BarrierOperandValue(dirtyCardValue))); 163 } 164 165 void PreBarrier(void *preValAddr) override; 166 167 void PostBarrier(const void *objAddr, size_t offset, void *storedValAddr) override; 168 169 void PostBarrier(const void *objAddr, size_t offset, size_t count) override; 170 171 ~GCGenBarrierSet() override = default; 172 173 NO_COPY_SEMANTIC(GCGenBarrierSet); 174 NO_MOVE_SEMANTIC(GCGenBarrierSet); 175 176 private: 177 // Store operands explicitly for interpreter perf 178 // POST BARRIER 179 /// Minimal address used by VM. Used as a base for card index calculation 180 void *minAddr_ {nullptr}; 181 /// Address of card table 182 uint8_t *cardTableAddr_ {nullptr}; 183 /// How many bits encoded by card (i.e. size covered by card = 2^card_bits_) 184 uint8_t cardBits_ {0}; 185 /// Value of dirty card 186 uint8_t dirtyCardValue_ {0}; 187 FIELD_UNUSED CardTable *cardTable_ {nullptr}; 188 }; 189 190 class GCG1BarrierSet : public GCBarrierSet { 191 public: 192 using ThreadLocalCardQueues = PandaVector<CardTable::CardPtr>; 193 static constexpr size_t G1_POST_BARRIER_RING_BUFFER_SIZE = 1024 * 8; 194 using G1PostBarrierRingBufferType = mem::LockFreeBuffer<mem::CardTable::CardPtr, G1_POST_BARRIER_RING_BUFFER_SIZE>; 195 GCG1BarrierSet(mem::InternalAllocatorPtr allocator,ObjRefProcessFunc preStoreFunc,ObjTwoRefProcessFunc postFunc,uint8_t regionSizeBitsCount,CardTable * cardTable,ThreadLocalCardQueues * updatedRefsQueue,os::memory::Mutex * queueLock)196 GCG1BarrierSet(mem::InternalAllocatorPtr allocator, 197 // PRE ARGS: 198 ObjRefProcessFunc preStoreFunc, 199 // POST ARGS: 200 ObjTwoRefProcessFunc postFunc, uint8_t regionSizeBitsCount, CardTable *cardTable, 201 ThreadLocalCardQueues *updatedRefsQueue, os::memory::Mutex *queueLock) 202 : GCBarrierSet(allocator, BarrierType::PRE_SATB_BARRIER, BarrierType::POST_INTERREGION_BARRIER), 203 preStoreFunc_(preStoreFunc), 204 postFunc_(postFunc), 205 regionSizeBitsCount_(regionSizeBitsCount), 206 cardTable_(cardTable), 207 minAddr_(ToVoidPtr(cardTable->GetMinAddress())), 208 updatedRefsQueue_(updatedRefsQueue), 209 queueLock_(queueLock) 210 { 211 ASSERT(preStoreFunc_ != nullptr); 212 ASSERT(postFunc_ != nullptr); 213 // PRE 214 AddBarrierOperand( 215 BarrierPosition::BARRIER_POSITION_PRE, "STORE_IN_BUFF_TO_MARK_FUNC", 216 BarrierOperand(BarrierOperandType::FUNC_WITH_OBJ_REF_ADDRESS, BarrierOperandValue(preStoreFunc_))); 217 // POST 218 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "REGION_SIZE_BITS", 219 BarrierOperand(BarrierOperandType::UINT8_LITERAL, BarrierOperandValue(regionSizeBitsCount_))); 220 AddBarrierOperand( 221 BarrierPosition::BARRIER_POSITION_POST, "UPDATE_CARD_FUNC", 222 BarrierOperand(BarrierOperandType::FUNC_WITH_TWO_OBJ_REF_ADDRESSES, BarrierOperandValue(postFunc_))); 223 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "CARD_TABLE_ADDR", 224 BarrierOperand(BarrierOperandType::UINT8_ADDRESS, 225 BarrierOperandValue(reinterpret_cast<uint8_t *>(*cardTable->begin())))); 226 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "MIN_ADDR", 227 BarrierOperand(BarrierOperandType::ADDRESS, BarrierOperandValue(minAddr_))); 228 } 229 230 bool IsPreBarrierEnabled() override; 231 232 void PreBarrier(void *preValAddr) override; 233 234 void PostBarrier(const void *objAddr, size_t offset, void *storedValAddr) override; 235 236 void PostBarrier(const void *objAddr, size_t offset, size_t count) override; 237 238 void Enqueue(CardTable::CardPtr card); 239 240 ~GCG1BarrierSet() override = default; 241 GetCardTable()242 CardTable *GetCardTable() const 243 { 244 return cardTable_; 245 } 246 247 NO_COPY_SEMANTIC(GCG1BarrierSet); 248 NO_MOVE_SEMANTIC(GCG1BarrierSet); 249 250 private: 251 void Invalidate(CardTable::CardPtr begin, CardTable::CardPtr last); 252 using PostFuncT = std::function<void(const void *, const void *)> *; 253 // Store operands explicitly for interpreter perf 254 // PRE BARRIER 255 ObjRefProcessFunc preStoreFunc_ {nullptr}; 256 // POST BARRIER 257 /// Function which is called for the post barrier if all conditions 258 ObjTwoRefProcessFunc postFunc_; 259 /// How much bits needed for the region 260 uint8_t regionSizeBitsCount_ {0}; 261 /// Card table pointer 262 CardTable *cardTable_ {nullptr}; 263 /// Minimal address used by VM. Used as a base for card index calculation 264 void *minAddr_ {nullptr}; 265 ThreadLocalCardQueues *updatedRefsQueue_; 266 os::memory::Mutex *queueLock_; 267 }; 268 269 } // namespace ark::mem 270 271 #endif // PANDA_GC_BARRIER_H 272